4

I'm trying to create a custom page on my domain that has the url 'http://example.com/test/slug', however the slug does not seem to support slashes (the slug '/test/slug' turns into '/testslug'). Is it possible using the rest api to create a page on a custom url? Also, I populate the 'meta' dictionary, however the page created does not contain a meta 'description' tag in the header. How can I correctly create custom meta tags?

import requests

url = 'http://example.com/wp-json/wp/v2/pages'
data = {'content': '<h2>test content</h2>',
 'meta': {'description': 'this is a test meta field'},
 'slug': 'test/slug',
 'status': 'publish',
 'title': 'test title'}

resp = requests.post(url, json=data, auth=('user','pass'), headers={'Content-Type':'application/json'})

3 Answers 3

2
+250

the slug does not seem to support slashes (the slug '/test/slug' turns into '/testslug').

Yes, because whether you use the REST API or the admin UI for creating Pages, the slug is limited to alphanumeric characters, plus dashes (-) and underscores (_). See https://developer.wordpress.org/rest-api/reference/pages/#schema-slug.

You can remove the limitation by adding remove_filter( 'sanitize_title', 'sanitize_title_with_dashes', 10, 3 ); to the theme's functions.php file (or a custom plugin); however, visiting the page (URL) would by default throw a 404 (not found) error. There are ways to fix that, but in short, you should not remove the filter.

Is it possible using the rest api to create a page on a custom url?

No it's not, not by default.

However, if you want http://example.com/test/slug to serve/show a Page/Post/etc. be it created via the REST API or not, then you can use custom URL rewrite rules, e.g. via add_rewrite_rule().

the page created does not contain a meta 'description' tag in the header. How can I correctly create custom meta tags?

You need to register the meta key, which in your case is description.

See

And you can register it using the register_meta() function in wp-includes/meta.php.

Example for your description meta:

<?php
// The object type. For custom post types, this is 'post';
// for custom comment types, this is 'comment'. For user meta,
// this is 'user'.
$object_type = 'post'; // 'post' even for Pages
$args1 = array( // Validate and sanitize the meta value.
    // Note: currently (4.7) one of 'string', 'boolean', 'integer',
    // 'number' must be used as 'type'. The default is 'string'.
    'type'         => 'string',
    // Shown in the schema for the meta key.
    'description'  => 'A meta key associated with a string meta value.',
    // Return a single value of the type.
    'single'       => true,
    // Show in the WP REST API response. Default: false.
    'show_in_rest' => true,
);
register_meta( $object_type, 'description', $args1 );

To quickly test if the meta description was successfully registered and that it's being available from the REST API, perform a GET request to http://example.com/wp-json/wp/v2/pages/<id> where <id> is the Page ID.

Sign up to request clarification or add additional context in comments.

Comments

2

First, make sure your Permalinks settings is "Post Name".

This can be configured under http://<yoursite.com>/wp-admin/options-permalink.php

I have studied "Custom Permalinks" plugin code to understand how to answer this question, it saves a metadata called "custom_permalink" and does heavy INNER JOINS to make WordPress core work with "fake" sub-slugs.

I came up with a different solution. The trick here is to create a fake parent page to serve as a base URL for children pages. I have written it in PHP, since I don't know Python.

<?php

require_once('helpers.php');

define('API_URL', 'http://temp.localhost');

# Let's get all pages in an array
$pages = curlGet(API_URL.'/wp-json/wp/v2/pages');

# Your usual $args
$args = array(
    'title' => 'API TEST',
    'status' => 'draft',
    'content' => 'content',
    'slug' => 'some/thing'
);

# We intercept it here, before sending to WordPress
$args = maybe_add_parent($args);

$response = curlPost( API_URL.'/wp-json/wp/v2/pages/', $args );

/**
*   Receives an $args array that would be sent to WordPress API and checks if we need to add a parent page
*/
function maybe_add_parent(array $args) {
    if (array_key_exists('slug', $args)) {
        # Has parent?
        if (strpos($args['slug'], '/') !== false) {
            $parent = explode('/', $args['slug']);
            # For simplicity sake let's do it parent/chidren slugs only
            if (count($parent) !== 2) {
                die('This script can only run parent/children slugs');
            }
            $slug = array_pop($parent);

            # Here, we will check the parent to see if it exists.
            $parent_id = slug_exists($parent[0]);
            if ($parent_id === false) {
                # If it does not, it will create it and return it's ID
                $parent_id = create_parent($parent[0]);
            }
            # Add parent ID to $args.
            $args['parent'] = $parent_id;
            # Rename the slug
            $args['slug'] = $slug;
        }
    }
    return $args;
}

/**
*   Checks if a given slug exists in $pages
*/
function slug_exists(string $slug) {
    global $pages;
    foreach ($pages as $page) {
        # Checks if a "Parent" page with this slug exists
        if ($page['slug'] == $slug && $page['parent'] == 0) {
            return true;
        }
    }
    return false;
}

/**
*   Creates a parent page
*/
function create_parent(string $slug) {
    $args = array(
        'title' => $slug,
        'status' => 'draft',
        'content' => '',
        'slug' => $slug
    );
    $response = json_decode(curlPost( API_URL.'/wp-json/wp/v2/pages/', $args ));
    return $response->id;
}

The script does the following:

  • Send a GET request for all the pages on the website.
  • Intercepts an $args array that would be sent to the WordPress API.
  • Checks if this $args contains a slug in the format parent/child
  • If it does, check if parent page exists
  • If it doesn't, it will create this page as a draft and return it's ID
  • It the parent already exists, it will just return it's ID
  • With the Parent ID, it will modify $args adding parent key and return $args
  • When WordPress sees that that page has a parent, it will automatically add it's slug in the url, as in parent/child

It works:

slug api wordpress create page

Comments

1

To get the URL structure you want, the most straightforward way is to create a child page that references an already existing page as it's parent.

To amend your example above:

import requests

url = 'http://example.com/wp-json/wp/v2/pages'
parent_page = 43 # assuming that page with URL '/test' has id of 42
data = {'content': '<h2>test content</h2>',
 'meta': {'description': 'this is a test meta field'},
 'slug': 'slug',
 'status': 'publish',
 'title': 'test title'
 'parent': parent_page} # <--

resp = requests.post(url, json=data, auth=('user','pass'), headers={'Content-Type':'application/json'})

Would give you a new page at example.com/test/slug

Reference to arguments for "Create a Page", (POST /wp/v2/pages) on WordPress rest API Handbook: https://developer.wordpress.org/rest-api/reference/pages/#create-a-page

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.