Skip to content

REST URL Unification Plan (Phase 2)

Status: phase 2 is done. PHP, OpenAPI, skills, and clients use canonical {product}/{slug}/v1. There is no dual-register / alias / rewrite. Old URLs return 404. The tables below are the historical old → new mapping.

This page was a work plan. PHP namespaces were not changed in phase 1; phase 2 switched URLs without dual routes.

Input: endpoint inventory (current URLs).

All REST APIs of all products use one form:

{product}/{slug}/v1
Part Value
{product} Product REST prefix. Plugins: wp2lms, wp2lms-pro, wp2tutor, wp2tutor-forms, wp2tutor-bot. WP2 Platform is an exception: the URL uses wp2, not wp2platform. The plugin id / repository remain wp2platform.
{slug} module identifier (whether in the plugin core or an add-on makes no difference)
v1 REST version of this family

There is no separate “core = {product}/v1” pattern. A new module registers only {product}/{slug}/v1. {product} is the owner’s REST prefix (for platform, this is wp2, not the plugin id).

Forbidden in new code:

  • {product}/module/{slug}/v1
  • {product}/v1 without a module segment
  • REST prefix wp2platform/… (only in old code being removed)
  • a foreign root (wp2lms-local-sync, wp2turbo, shared wp2tutor/v1 for forms/bot)

Old addresses are not supported: no dual registration, no deprecated alias in OpenAPI, no nginx rewrite, no “sunset period.” In a single change, PHP registers only the canonical form, while clients (Studio, skills, SPA, CLI, admin UIs) migrate at the same time. The old URL returns 404.

Reference implementations of the {product}/{slug}/v1 form already in the code:

  • Embed Packages wp2lms-pro/embed-packages/v1
  • Studio Sync wp2/studio-sync/v1 — PHP src/Modules/StudioSync/, client STUDIO_SYNC_REST_BASE, CLI wp studio-sync. Do not rework (including changing it to wp2/studio/v1).

Media Playback is currently wp2/media-playback/v1 — in phase 2 it remains wp2/media-playback/v1. The Embed Packages dual registration (wp2platform/module/embed-packages/v1) is removed.

Full URL: /wp-json/{product}/{slug}/v1{route}.

Do not repeat {slug} in {route}. If the slug is currently in the route (wp2/license/v1/products), after migration it moves into the namespace, and the route begins with the next segment (/products).

Before After
{product}/module/{slug}/v1{route} {product}/{slug}/v1{route} — the same {route}
{product}/v1/{slug}{route} {product}/{slug}/v1{route}
foreign root {legacy}/v1{route} {product}/{slug}/v1{route}

The only exception is when {route} would become empty after removing the slug: the canonical form is then GET|POST …/{product}/{slug}/v1 (module root) or an explicit short resource (/chat). One option is selected below for each such family, without alternatives.

blog_id and other query parameters are not part of the namespace; they remain query parameters as they are now.

Rule for the remaining A platform families: remove /module/ and replace the wp2platform prefix with wp2. For B platform families: wp2/{slug}/v1. For D: wp2/{slug}/v1. Other plugins: {plugin-id}/{slug}/v1 as shown in the table.

Studio Sync is already canonical (wp2/studio-sync/v1) — its table row is for reference, not a phase 2 task.

Family Current Target
Site Manager wp2/site-manager/v1 wp2/site-manager/v1
Site Duplicator wp2/site-duplicator/v1 wp2/site-duplicator/v1
Post Duplicator wp2/post-duplicator/v1 wp2/post-duplicator/v1
Multi Network wp2/multi-network/v1 wp2/multi-network/v1
Media Converter wp2/media-converter/v1 wp2/media-converter/v1
Subtitles & Timecodes wp2/media-subtitles-timecodes/v1 wp2/media-subtitles-timecodes/v1
Enable Media Replace wp2/enable-media-replace/v1 wp2/enable-media-replace/v1
Studio Sync wp2/studio-sync/v1 already canonical — do not touch
Passwordless wp2/passwordless/v1 wp2/passwordless/v1
Magic Links wp2/magic-links/v1 wp2/magic-links/v1
Media Playback wp2/media-playback/v1 wp2/media-playback/v1
License wp2/license/v1/… wp2/license/v1
Course Manager wp2/course-manager/v1/… wp2/course-manager/v1
Elementor Style Presets wp2/elementor-style-presets/v1/… wp2/elementor-style-presets/v1
Local Sync wp2/local-sync/v1 wp2/local-sync/v1
Static Builder wp2lms/static-builder/v1 wp2lms/static-builder/v1
Turbo wp2lms/turbo/v1 wp2lms/turbo/v1
Embed Packages canonical wp2lms-pro/embed-packages/v1 no change
Embed Packages alias wp2platform/module/embed-packages/v1 remove registration; canonical form only: wp2lms-pro/embed-packages/v1
Tutor AI wp2tutor/v1 + /ai-chat wp2tutor/ai/v1
Tutor Embedding wp2tutor/v1 + /embedding/… wp2tutor/embedding/v1
Tutor RAG wp2tutor/v1 + /rag-chunks/… wp2tutor/rag/v1
Forms wp2tutor/v1 + /wp2tutor-form/form/… wp2tutor-forms/form/v1
Forms i18n wp2tutor/v1 + /wp2tutor-form/i18n/… wp2tutor-forms/i18n/v1
Bot Telegram / VK / Deep Chat wp2tutor/v1 + /telegram|vk|deepchat/… wp2tutor-bot/telegram/v1, …/vk/v1, …/deepchat/v1

Full URLs (Where the Route Is Not “the Same Suffix”)

Section titled “Full URLs (Where the Route Is Not “the Same Suffix”)”

Platform A families: {route} is the same as in the inventory, NS wp2/{slug}/v1. The B, D, tutor, forms, and bot families are listed below. Studio Sync is not included in the URL table because it is already wp2/studio-sync/v1.

The prefix is /wp-json/ everywhere.

Studio Sync — Complete, Outside Phase 2 Work

Section titled “Studio Sync — Complete, Outside Phase 2 Work”

Code: onepix/wp2platform/src/Modules/StudioSync/ (AbstractRestController → namespace wp2/studio-sync/v1). OpenAPI: the same paths in wp2platform-modules.yaml. Client: onepix/wp2studio/electron/runtime/core/constants.ts (STUDIO_SYNC_REST_BASE). CLI: wp studio-sync.

Do not: rename again, use wp2/studio/v1, or dual-register with the old wp2platform/module/wp2sync/v1.

METHOD Current Target
GET wp2/license/v1/products wp2/license/v1/products
POST wp2/license/v1/{product_id}/activate wp2/license/v1/{product_id}/activate
POST …/deactivate wp2/license/v1/{product_id}/deactivate
GET …/status wp2/license/v1/{product_id}/status
GET …/data wp2/license/v1/{product_id}/data
METHOD Current Target
GET wp2/course-manager/v1/sidebar wp2/course-manager/v1/sidebar
PUT …/reorder wp2/course-manager/v1/reorder
PUT …/assign wp2/course-manager/v1/assign
PATCH …/sections/{id} wp2/course-manager/v1/sections/{id}
METHOD Current Target
GET / POST wp2/elementor-style-presets/v1/presets wp2/elementor-style-presets/v1/presets
GET / PATCH …/presets/{id} wp2/elementor-style-presets/v1/presets/{id}
METHOD Current Target
GET wp2/local-sync/v1/projects wp2/local-sync/v1/projects
POST …/sync wp2/local-sync/v1/sync
POST …/validate wp2/local-sync/v1/validate

CLI (pages-cli / local-sync), if it calls REST or prints NS, uses the same canonical form.

wp2lms/static-builder/v1/{pages,builds,…} → wp2lms/static-builder/v1/{same route}. Migrate CLI bin/static-builder/* together with skill 10.

METHOD Current Target
POST wp2lms/turbo/v1/xapi-actor/session wp2lms/turbo/v1/xapi-actor/session
POST wp2lms/turbo/v1/gravity-forms/submit wp2lms/turbo/v1/gravity-forms/submit
POST wp2lms/turbo/v1/dsh/expand wp2lms/turbo/v1/dsh/expand
GET wp2lms/turbo/v1/static/{id} wp2lms/turbo/v1/static/{id}
METHOD Current Target
GET / POST wp2tutor/v1/ai-chat wp2tutor/ai/v1/chat
POST wp2tutor/v1/embedding/sync wp2tutor/embedding/v1/sync
POST …/embedding/statuses wp2tutor/embedding/v1/statuses
POST …/embedding/diagnostics wp2tutor/embedding/v1/diagnostics
GET / POST wp2tutor/v1/rag-chunks/datatables wp2tutor/rag/v1/datatables
GET …/rag-chunks/chunk/{id_chunk} wp2tutor/rag/v1/chunk/{id_chunk}
METHOD Current Target
POST wp2tutor/v1/wp2tutor-form/form/updateDefinition wp2tutor-forms/form/v1/updateDefinition
POST …/updateShortcode wp2tutor-forms/form/v1/updateShortcode
POST …/updateStyles wp2tutor-forms/form/v1/updateStyles
POST …/updateL10n wp2tutor-forms/form/v1/updateL10n
POST …/updateRunner wp2tutor-forms/form/v1/updateRunner
GET …/getRunnerData wp2tutor-forms/form/v1/getRunnerData
GET wp2tutor/v1/wp2tutor-form/i18n/locale wp2tutor-forms/i18n/v1/locale
GET …/i18n/translation wp2tutor-forms/i18n/v1/translation
METHOD Current Target
POST wp2tutor/v1/telegram/webhook/{bot_id} wp2tutor-bot/telegram/v1/webhook/{bot_id}
POST wp2tutor/v1/vk/callback/{channel_id} wp2tutor-bot/vk/v1/callback/{channel_id}
POST / OPTIONS wp2tutor/v1/deepchat/chat/{channel_id} wp2tutor-bot/deepchat/v1/chat/{channel_id}

The WP2 Sync → Studio Sync rename and canonical wp2/studio-sync/v1 form are already complete. This plan does not repeat them or change the slug to studio.

The Playground bundle in wp2studio is a platform mirror and must be updated through the build.

Current: __construct($app_name) → namespace {app_name}/v1, route_path = namespace + rest_base. This is precisely the forbidden B pattern.

Target:

namespace = {product}/{slug}/v{n}
rest_base = resource within the module (not a duplicate slug)

Constructor: product + slug (both non-empty). License: ('wp2', 'license') — REST prefix wp2, while the plugin remains wp2platform. rest_base does not duplicate the slug.

One namespace per controller — the canonical one. Do not register the old {app_name}/v1.

Do not retain the one-argument constructor: subclasses (platform, tutor, forms) migrate in the same change as core.

Modules that do not use this base (Studio Sync, already at wp2/studio-sync/v1; Local Sync; Static Builder; Turbo; bot) set the {product}/{slug}/v1 string according to the table.

None. The old REST URL, CLI name, and OpenAPI path are removed in the same change that introduces the canonical form. Do not rename WP_Error codes in this epic (they are not URLs).

The client and server for a family are deployed together. Do not deploy a plugin with the new NS until the skill / SPA / admin UI for that family has been migrated. Bot webhooks: change the URL in Telegram/VK administration when deploying.

Family Where to Update
Studio Sync do not touch — already wp2/studio-sync/v1
Static Builder .agents/skills/10-static-builder; onepix/wp2lms/bin/static-builder/*
Media Converter / subtitles .agents/skills/media-hls-encode, media-whisper-tracks (_common.py NS)
Passwordless / Magic Links onepix/wp2platform/src/Modules/PasswordlessLogin; onepix/wp2platform/src/Modules/MagicLinks
Local Sync .agents/skills/09-local-sync, 06-page-builder; PHP Local Sync REST already
Turbo onepix/wp2lms/src/Modules/Turbo/**; Pulse/MOS bundles if they hardcode wp2lms/turbo/v1
Forms builder JS / rest_url in wp2tutor-forms; wp2tutor/rest_controllers filter
Bot + Deep Chat webhook URL registration in channel admin UIs
License / Sections / Presets admin JS/PHP get_rest_url() / rest_url() in those modules
Embed Packages alias agents/docs that still call wp2platform/module/embed-packages
Site Manager and other A families admin UIs of the respective modules (rest_url / DualRest)

Still out of scope: AnalogWP, /wp/v2/*, AJAX. In phase 2 scope: WP-CLI for the same families — new names immediately, without aliases for old commands.

Public bot webhooks: during deployment, the operator must change the URL in Telegram/VK. The old path does not respond.

  • Only the canonical {product}/{slug}/v1 form in PHP and YAML.
  • Fail if a PHP endpoint is absent from YAML, or if YAML/PHP still contains /module/, bare {product}/v1, REST prefix wp2platform/, wp2lms-local-sync, wp2turbo, the embed-packages alias, or shared wp2tutor/v1 for forms/bot.
  • Do not treat NAMESPACE_ALIAS in the scanner as normal: there is no second NS.
  • Invoke from wp2-site prebuild as now.
  • Do not parse OpenAPI from PHP as the sole canonical source.
  • PHPUnit / REST: the canonical URL responds.
  • The family’s old URL returns 404 (negative test).
  • Forms/bot: no registration on wp2tutor/v1.

The client and PHP for one family comprise one release (linked MRs are merged together).

  1. Infrastructure: RestController (product, slug); audit only the canonical form.
  2. Remove the Embed Packages alias; do not touch canonical wp2lms-pro/embed-packages/v1.
  3. Remaining A platform families + Static Builder: platform → wp2/{slug}/v1 (not wp2platform/…); Static Builder → wp2lms/static-builder/v1. Update clients immediately (skills 10 / HLS / Whisper, passwordless, admin UIs). Skip Studio Sync.
  4. B platform: License, Course Manager, Presets.
  5. Local Sync + skill 09 + CLI.
  6. Turbo + Pulse/MOS bundles.
  7. Tutor: ai / embedding / rag.
  8. Forms: its own product, decouple wp2tutor/rest_controllers.
  9. Bot: new webhook URLs; change them in channel administration in the same deployment.

First code: steps 2–3. Do not add Studio Sync to the queue.

  • Canonical form strictly {product}/{slug}/v1, route without a duplicate slug, URLs as shown in the tables above.
  • Only the canonical form in PHP and OpenAPI: platform uses wp2/{slug}/v1, other plugins use {plugin-id}/{slug}/v1. No /module/, no bare {product}/v1, no REST prefix wp2platform/.
  • npm run audit:openapi passes.
  • Clients from the grep table and CLI are migrated in the same change.
  • DoD tests pass, including 404 for the old URL.
  • No references to the old path in onepix/ (except negative tests). Update the Playground mirror through the build, not manually.

Phase 2 is complete (steps 1–10). Studio Sync remains out of scope (already canonical).