marketing + seo: the three-week tester campaign, schedule-post --link, the not-indexed audit
gates / gates (push) Successful in 6m15s

COPY.md section 7: five Hungarian posts for Tue/Thu 19:00 over three weeks, each
with a source comment per claim and one link. The Monday post (2026-10-12, 6.2)
is untouched and no slot shares its day.

fb_probe.py gains --link (default unchanged). Every scheduled post used to
attach the home page's preview card whatever its text said, so a post about
/teszteles would have sent the people who clicked its card to the home page.
build_parser() split out of main() so a test can parse argv. Red-proved: both
new tests fail with "Namespace object has no attribute link" without the flag.

Search Console audit (seo-2026-10-10/not-indexed.md): all seven not-indexed
URLs with a verdict each - four expected by design, two waiting on Google's
crawl queue, one fault on our side. That one is /api/contact, the contact
form's POST endpoint crawled as a page; robots.txt now disallows /api/. The
performance baseline (0 clicks, 47 impressions, position 73, nine queries) is
recorded there to compare against in a month.
This commit is contained in:
2026-10-10 16:13:21 +02:00
parent 9d530b8f4a
commit 5bea5f2ebf
6 changed files with 313 additions and 8 deletions
+17 -8
View File
@@ -516,9 +516,9 @@ def scenario_sched_dry(g, page):
return 0, res
def scenario_sched_post(g, page, message, when):
def scenario_sched_post(g, page, message, when, link=POST_LINK):
pid, ptok = page["id"], page["token"]
c = g.call("P1-create", "POST", pid + "/feed", ptok, form=schedule_form(message, when))
c = g.call("P1-create", "POST", pid + "/feed", ptok, form=schedule_form(message, when, link=link))
if not c.ok:
log("P REFUSED: %s" % json.dumps(c.err, ensure_ascii=False))
return 6, {"created": False, "error": c.err}
@@ -543,8 +543,8 @@ def scenario_sched_post(g, page, message, when):
# ---------------------------------------------------------------- main
def main(argv=None):
global VERBOSE
def build_parser():
"""The CLI surface, separate from main() so a test can parse argv without running a command."""
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument("-v", action="store_true", help="print each call: method, path (no query), status, error")
ap.add_argument("--version", default="v26.0", help="Graph API version (default v26.0)")
@@ -555,9 +555,18 @@ def main(argv=None):
help="COPY.md section to post, e.g. 6.1 or 6.2 (schedule-post)")
ap.add_argument("--at", default=None,
help="when to publish, 'YYYY-MM-DD HH:MM' in Europe/Budapest (schedule-post)")
ap.add_argument("--link", default=POST_LINK,
help="schedule-post: the URL whose preview card is attached (default %s). "
"The card is what a reader clicks, so a post about one page names that page "
"here, not just in its text." % POST_LINK)
ap.add_argument("--dry", action="store_true",
help="schedule-post: the throwaway link+schedule check, then delete it")
a = ap.parse_args(argv)
return ap
def main(argv=None):
global VERBOSE
a = build_parser().parse_args(argv)
VERBOSE = a.v
try:
token = load_key(a.credentials)
@@ -607,9 +616,9 @@ def run(cmd, g, token, a=None):
except (ValueError, OSError) as e:
log("REFUSED: %s" % e)
return 2
log("P section %s: %d characters, publishing at %s (epoch %d)"
% (a.section, len(message), a.at, when))
rc, _ = scenario_sched_post(g, page, message, when)
log("P section %s: %d characters, link %s, publishing at %s (epoch %d)"
% (a.section, len(message), a.link, a.at, when))
rc, _ = scenario_sched_post(g, page, message, when, link=a.link)
log("schedule-post: done (rc=%d)" % rc)
return rc
rc, _ = scenario_d(g, page, 0)
+17
View File
@@ -107,6 +107,23 @@ class ScheduleForm(unittest.TestCase):
f = fb_probe.schedule_form("x", fb_probe.time.time() + 3600, link=None)
self.assertNotIn("link", f)
def test_a_per_post_link_reaches_the_form(self):
"""2026-10-10: the campaign posts each point at their OWN page, and the preview CARD is what
a reader clicks. Before --link existed, every scheduled post attached https://felhom.eu/ no
matter what its text said, so a post about /teszteles sent its readers to the home page.
This pins the whole path: the CLI flag must reach the form."""
a = fb_probe.build_parser().parse_args(
["schedule-post", "--section", "7.1", "--at", "2026-10-13 19:00",
"--link", "https://felhom.eu/teszteles"])
self.assertEqual(a.link, "https://felhom.eu/teszteles")
f = fb_probe.schedule_form("x", fb_probe.time.time() + 3600, link=a.link)
self.assertEqual(f["link"], "https://felhom.eu/teszteles")
self.assertEqual(f["published"], "false") # still unreachable, even with a link set
def test_link_defaults_to_the_home_page_when_the_flag_is_absent(self):
a = fb_probe.build_parser().parse_args(["schedule-post", "--at", "2026-10-13 19:00"])
self.assertEqual(a.link, "https://felhom.eu/")
class ScheduleWindow(unittest.TestCase):
NOW = 1_760_000_000