diff --git a/boker/app.py b/boker/app.py
index bd8fdce..4be0978 100644
--- a/boker/app.py
+++ b/boker/app.py
@@ -51,11 +51,18 @@ def create_app(config_overrides: dict | None = None) -> Flask:
@app.context_processor
def inject_globals() -> dict:
+ base_url = app.config.get("APP_BASE_URL", "https://myboker.org").rstrip("/")
return {
"app_version": app.config["APP_VERSION"],
"current_user_id": current_user_id(),
"is_logged_in": is_logged_in(),
"current_user_is_site_admin": is_site_admin(),
+ "seo_site_url": base_url,
+ "seo_canonical_url": f"{base_url}{request.path}",
+ "seo_default_description": (
+ "Free home poker league tracker for sessions, ledgers, leaderboards, "
+ "settlement, buy-ins, cashouts, and private game records."
+ ),
}
app.register_blueprint(public_bp)
diff --git a/boker/routes/public.py b/boker/routes/public.py
index 063b7fb..0cf144f 100644
--- a/boker/routes/public.py
+++ b/boker/routes/public.py
@@ -1,8 +1,11 @@
#!/usr/bin/env python3
from __future__ import annotations
-from flask import Blueprint, flash, redirect, render_template, request, url_for
-from flask import current_app
+from datetime import date
+from xml.sax.saxutils import escape as xml_escape
+
+from flask import Blueprint, Response, current_app, flash, redirect, render_template, request, url_for
+from sqlalchemy.exc import SQLAlchemyError
from boker.charts import cumulative_profit_series, player_session_series, session_breakdown_series
from boker.config import ELIGIBLE_MIN_SESSIONS
@@ -18,11 +21,74 @@ from boker.utils import session_label, session_sort_key
public_bp = Blueprint("public", __name__)
+def _absolute_url(path: str) -> str:
+ base_url = current_app.config.get("APP_BASE_URL", "https://myboker.org").rstrip("/")
+ return f"{base_url}{path}"
+
+
+def _sitemap_url(path: str, priority: str, changefreq: str = "weekly") -> str:
+ return (
+ " \n"
+ f" {xml_escape(_absolute_url(path))}\n"
+ f" {date.today().isoformat()}\n"
+ f" {changefreq}\n"
+ f" {priority}\n"
+ " "
+ )
+
+
@public_bp.get("/")
def home():
return render_template("landing.html")
+@public_bp.get("/robots.txt")
+def robots_txt():
+ body = "\n".join(
+ [
+ "User-agent: *",
+ "Allow: /",
+ "Disallow: /internal/",
+ "Disallow: /account/",
+ "Sitemap: " + _absolute_url(url_for("public.sitemap_xml")),
+ "",
+ ]
+ )
+ return Response(body, mimetype="text/plain")
+
+
+@public_bp.get("/sitemap.xml")
+def sitemap_xml():
+ urls = [
+ _sitemap_url(url_for("public.home"), "1.0", "weekly"),
+ _sitemap_url(url_for("public.explore"), "0.8", "daily"),
+ _sitemap_url(url_for("public.help"), "0.7", "monthly"),
+ _sitemap_url(url_for("public.privacy"), "0.3", "yearly"),
+ _sitemap_url(url_for("public.terms"), "0.3", "yearly"),
+ ]
+
+ from boker.db import database_extensions_available
+
+ if database_extensions_available():
+ try:
+ from boker.league_repositories import list_public_leagues
+
+ for league in list_public_leagues():
+ urls.append(_sitemap_url(url_for("leagues.dashboard", league_ref=league.url_ref), "0.6", "weekly"))
+ urls.append(_sitemap_url(url_for("leagues.leaderboard", league_ref=league.url_ref), "0.5", "weekly"))
+ urls.append(_sitemap_url(url_for("leagues.sessions", league_ref=league.url_ref), "0.5", "weekly"))
+ except SQLAlchemyError:
+ current_app.logger.warning("Sitemap public league query failed", exc_info=True)
+
+ body = (
+ '\n'
+ '\n'
+ + "\n".join(urls)
+ + "\n\n"
+ )
+ return Response(body, mimetype="application/xml")
+
+
@public_bp.get("/help")
def help():
return render_template("support.html")
diff --git a/templates/base.html b/templates/base.html
index 52e4214..be15448 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -1,12 +1,25 @@
+ {% set page_title %}{% block title %}myboker.org{% endblock %}{% endset %}
+ {% set page_description %}{% block meta_description %}{{ seo_default_description }}{% endblock %}{% endset %}
- {% block title %}myboker.org{% endblock %}
+ {{ page_title | trim }}
+
+
+
+
+
+
+
+
+
+
+ {% block structured_data %}{% endblock %}
diff --git a/templates/explore.html b/templates/explore.html
index 68ce088..5ba57c2 100644
--- a/templates/explore.html
+++ b/templates/explore.html
@@ -1,5 +1,6 @@
{% extends "base.html" %}
-{% block title %}Explore leagues · myboker.org{% endblock %}
+{% block title %}Explore Public Home Poker Leagues · myboker.org{% endblock %}
+{% block meta_description %}Browse public home poker league results, leaderboards, sessions, and player stats from groups using myboker.org.{% endblock %}
{% block content %}