Sitemaps abilities: register status reads + rebuild dispatch via Registrar#48767
Conversation
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖 🔴 Action required: Please include detailed testing steps, explaining how to test your change, like so: 🔴 Action required: We would recommend that you add a section to the PR description to specify whether this PR includes any changes to data or privacy, like so: Follow this PR Review Process:
If you have questions about anything, reach out in #jetpack-developers for guidance! Jetpack plugin: The Jetpack plugin has different release cadences depending on the platform:
If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack. |
Code Coverage SummaryCoverage changed in 1 file.
1 file is newly checked for coverage.
|
….xml (drop dup URL / synthetic last-build / reserved error; add real sitemaps[])
…fy Phan type contract
…ok tick, UTC) from request-rebuild
…x) for unambiguous timezone
c7f71a1 to
8bbafdd
Compare
Implements the Sitemaps module slice of the Abilities Everywhere plan (§3.3).
Summary
Sitemaps_Abilities(Registrar subclass) undermodules/sitemaps/abilities/, wired from the bottom ofmodules/sitemaps.phpso it only registers while the Sitemaps module is active.jetpack-sitemaps:jetpack-sitemaps/get-status— zero-arg read returning{ active, url, post_count, page_count, news_sitemap_enabled, sitemaps }.sitemapsis the child-sitemap list actually present in the servedsitemap.xmlindex — each entry{ loc, lastmod }, parsed from the stored master sitemap (no HTTP loopback), empty until a master sitemap exists. Gated onedit_posts(content managers can inspect sitemap state). Annotated readonly + idempotent.jetpack-sitemaps/request-rebuild— zero-arg dispatch returning{ dispatched, status, next_scheduled_at }withstatusinqueued/running/already_running. Gated onmanage_options(admin only). Annotated non-readonly + idempotent: returnsdispatched=false+status=runningwhen thejetpack-sitemap-state-locktransient is set (build in flight),dispatched=false+status=queuedwhen a cron tick is already scheduled, and otherwise schedules a single-eventjp_sitemap_cron_hooktick and returnsdispatched=true.next_scheduled_atis the nextjp_sitemap_cron_hooktick as an ISO 8601 UTC string with an explicitZzone designator, e.g.2026-05-19T19:33:20Z(ornullwhen nothing is scheduled, e.g.status=runningwith no future tick) so callers learn when the queued/pending build will run without a follow-up status read.get-statusdeliberately omits a synthetic "last build" scalar. It was previously derived from thejetpack-sitemap-stateoption'smax[master].lastmodprojection, which reads its initial/reset shape (nomax) even while a fully-builtsitemap.xmlis being served — so it reportednullfor sites that demonstrably have a working sitemap. Instead the ability surfaces the real per-childlastmodvalues straight from the served master document. The redundantmaster_sitemap_url(a duplicate ofurl) and the always-null reservedlast_errorwere also dropped.tests/php/src/Sitemaps_Abilities_Test.phpmirrorsMonitor_Abilities_Test: abstract getters, Registrar wiring (gate filter, per-ability allow-list, category auto-injection), permission callbacks (admin/editor/subscriber/anonymous matrix),get_statushappy path + module-off + news-filter,get_sitemap_entriesparsing (sitemapindex → entries, empty/malformed XML, missing-lastmod tolerance),request_rebuildthree-state dispatch + idempotency +next_scheduled_atderivation, and the gated-registration contract when the module is inactive.set_up()mirrorstear_down()'s cron/transient/option cleanup sorequest_rebuildcron assertions are isolated regardless of run order.Sitemaps_Abilities_Test_Stubtest double overrides the protected seams (get_master_sitemap_url,get_master_sitemap_xml,count_published) so success-path tests run the realget_sitemap_entriesparser against a known document without a librarian / permalink stack / wp_count_posts factory.blog_publicmust be1These abilities are wired from the bottom of
modules/sitemaps/sitemaps.php, whichmodules/sitemaps.phponlyincludes whenget_option( 'blog_public' ) === '1':So the effective gate is Sitemaps module active and
blog_public = 1, not the module flag alone. On sites with "Discourage search engines from indexing this site" enabled (blog_public = 0, the default on most local/dev environments) the entire sitemaps codebase — including this registrar — is skipped, andjetpack-sitemaps/*will be absent fromwp_get_abilities()/ the REST surface even thoughwp jetpack module listreports the module as Active. This is the module's pre-existing "no sitemaps on private sites" behavior, inherited intentionally; surfaced here because it is the most likely reason the abilities appear "not loading" during local testing.Test plan
Abilities run via
POST /wp-json/wp-abilities/v1/abilities/<name>/runwith a JSON body{"input": {}}(the run controller reads input from theinputkey; an empty/bare body yields400 ability_invalid_input).wp option update blog_public 1(otherwisemodules/sitemaps.phpskips loading the sitemap code entirely and nojetpack-sitemaps/*abilities register, regardless of module status).GET /wp-json/wp-abilities/v1/abilitiesdoes not list anyjetpack-sitemaps/*entries.blog_public = 1:POST /wp-json/wp-abilities/v1/abilities/jetpack-sitemaps/get-status/run(body{"input":{}}) as an editor returns{ active, url, post_count, page_count, news_sitemap_enabled, sitemaps }withactive=true. When a master sitemap exists,sitemapslists each child{ loc, lastmod }matching the servedsitemap.xml; before any build it is[].403 rest_ability_cannot_execute; as an anonymous user,401.POST /wp-json/wp-abilities/v1/abilities/jetpack-sitemaps/request-rebuild/runas admin, with nothing running/queued, returnsdispatched=true,status=queued, andnext_scheduled_at≈ now (ISO 8601 UTC, e.g.2026-05-19T19:33:20Z). A second immediate call returnsdispatched=false,status=queued, samenext_scheduled_at(no duplicate cron tick).jetpack-sitemap-state-locktransient set (and no pending tick), the same call returnsdispatched=false,status=running,next_scheduled_at=null.blog_public = 0, confirmjetpack-sitemaps/*abilities are absent (documents the inherited gate).