I am looking to use the rest API to use WordPress as a headless CMS, but I am curious as to how best to get a page using the path.

Example, if Wordpress is hosted at cms.example.com and my frontend is at example.com. If I create a page at cms.example.com/services/service-a I would want it accessible on the frontend at example.com/services/service-a. If my front end takes 'services/service-a' how can I find the right page?

My first thought was using the slug, until I realized the slug only matches the last part. In this example the slug would be 'service-a' not 'service\service-a'. I can specify a slug and a parent ID but this would require a a call for each level or hierarchy to work up the tree to get the parent id.

I have also briefly considered ignoring all previous levels of hierarchy and just looking at the last part of the path to use the slug, but I am not sure if that would have any unintended consequences. EDIT: Thinking about it more I am decidedly against this method as it is possible for two pages at different areas of hierarchy to have the same slug resulting in a different path.

I was thinking to setup a custom endpoint to take the path, run it through the get_page_by_path() function then return the id. But that means each page load would require 2 API calls, or at least each page load that isn't at the first level of hierarchy.

But wanting to limit each request to a single API call I am thinking either if possible add a custom argument to the pages API endpoint to specify a full path to search by for the response, or else if that is not explicitly possible creating my own endpoint to accept the path argument then return the matching page object. Obviously in this case my preference would be for the former over the latter as that should require less work for a plugin and make the most out of the existing code in WordPress.

Is it possible to add a custom option to an existing endpoint? Is there a better method to do this with a single API call?

2 Answers 2


It is usually easier for me to decide how the front end should behave, and then determine how to get the appropriate data. So, in your example, services would be a module with some functionality, and then service-a would be the slug.

However, if you only care about the URL looking the same you can use pushState to change the URL in the browser without loading a new page. The "link" property in the posts API response could be parsed to get you the full path. As long as you get a unique identifier (e.g. slug) at the end, this would essentially make the middle of the path meaningless, but it could still be populated immediately after loading the page.

  • I am intentionally leaving page hierarchy ambiguous to support any page hierarchy created in WordPress without any code changes, Also worth noting the "frontend" is actually server-side not javascript. Which is probably going to raise more questions about why I would use something other than WordPress for the frontend if its still going to be server-side. Essentially I am trying to embed pages and posts managed by WordPress into a custom web application where the web app functionality is significant and it don't make sense to bring into WordPress as a plugin.
    – user3452
    Jun 6, 2020 at 3:44

I found a filter hook "rest_page_query" and I was going to try to add a custom query var to the official pages endpoint, but while I could get the custom query var from my filter I could not figure out how to affect the output based on it.

However while looking at a custom endpoint I realized its super simple and was just easier to do that.

So I just put this code in a custom plugin:

add_action( 'rest_api_init', function () {
  register_rest_route( 'custom/v1', '/pages', array(
    'methods' => 'GET',
    'callback' => 'my_page_from_path',
  ) );
} );

function my_page_from_path( $request ) {
    $path = $request->get_param( 'path' );
    $page = get_page_by_path( $path, ARRAY_A );
    return rest_ensure_response( $page );

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.