In this tutorial we will create a Custom post Type named Terms
, use Advanced Custom Fields PRO (with ACF Repeater Field) to make a beautiful admin interface and create a new Custom Post Type Item programatically with JavaScript via WP REST API using Nonce authentication.
Needed Plugins
First, download and install the following plugins:
- ACF to REST API Version 3.0.1-beta FREE
- Advanced Custom Fields PRO Version 5.6.0
Create Custom post with Post Type Generator
// Register Custom Post Type - Terms
function term_post_type()
{
$labels = array(
'name' => _x('Terms', 'Post Type General Name', 'text_domain'),
'singular_name' => _x('Term', 'Post Type Singular Name', 'text_domain'),
'menu_name' => __('Terms', 'text_domain'),
'name_admin_bar' => __('Terms', 'text_domain'),
'archives' => __('Term Archives', 'text_domain'),
'attributes' => __('Term Attributes', 'text_domain'),
'parent_item_colon' => __('Parent Term:', 'text_domain'),
'all_items' => __('All Terms', 'text_domain'),
'add_new_item' => __('Add New Term', 'text_domain'),
'add_new' => __('Add New', 'text_domain'),
'new_item' => __('New Term', 'text_domain'),
'edit_item' => __('Edit Term', 'text_domain'),
'update_item' => __('Update Term', 'text_domain'),
'view_item' => __('View Term', 'text_domain'),
'view_items' => __('View Terms', 'text_domain'),
'search_items' => __('Search Term', 'text_domain'),
'not_found' => __('Not found', 'text_domain'),
'not_found_in_trash' => __('Not found in Trash', 'text_domain'),
'featured_image' => __('Featured Image', 'text_domain'),
'set_featured_image' => __('Set featured image', 'text_domain'),
'remove_featured_image' => __('Remove featured image', 'text_domain'),
'use_featured_image' => __('Use as featured image', 'text_domain'),
'insert_into_item' => __('Insert into term', 'text_domain'),
'uploaded_to_this_item' => __('Uploaded to this term', 'text_domain'),
'items_list' => __('Terms list', 'text_domain'),
'items_list_navigation' => __('Terms list navigation', 'text_domain'),
'filter_items_list' => __('Filter terms list', 'text_domain'),
);
$rewrite = array(
'slug' => 'term',
'with_front' => true,
'pages' => true,
'feeds' => true,
);
$args = array(
'label' => __('Term', 'text_domain'),
'description' => __('Term Post Type Description', 'text_domain'),
'labels' => $labels,
'supports' => array( 'title', 'excerpt', 'author', 'revisions', 'custom-fields', ),
'taxonomies' => array( 'category', 'post_tag' ),
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'menu_position' => 5,
'menu_icon' => 'dashicons-book',
'show_in_admin_bar' => true,
'show_in_nav_menus' => true,
'can_export' => true,
'has_archive' => true,
'exclude_from_search' => false,
'publicly_queryable' => true,
'rewrite' => $rewrite,
'capability_type' => 'post',
'show_in_rest' => true,
'rest_base' => 'terms',
);
register_post_type('term_post_type', $args);
}
add_action('init', 'term_post_type', 0);
To hide default Posts
menu entry add the following code into functions.php
file in your theme:
/* Remove 'Posts' entry from admin menu */
function post_remove() {
remove_menu_page('edit.php');
}
add_action('admin_menu', 'post_remove');
Now we have a nice looking menu:
Create Custom Fields with Advanced Custom Fields PRO – ACF Repeater Field
Because we would like to have a custom looking entry page with only the fields we actually use, we will install ACF plugin and then create a new Field Group of entry fields for our custom post type Terms. The structure of the fields is the following:
Label | Name | Type |
---|---|---|
Approved | term_approved | True/ False |
New | term_new | True/False |
Origin | term_origin | Text |
Definitions | definitions | Repeater |
– Approved | definition_approved | True/False |
– Definition | definition | Text |
– Likes | definition_likes | Number |
– Author | definition_author | Text |
– Examples | examples | Repeater |
– – Approved | example_approved | True False |
– – Example | example | Text area |
– – Author | example_author | Text |
– Related Terms | related_terms | Post Object |
Here is also the screenshot of the whole page:
Create a new Term
Now we have enerything we need to create a new term, so let’s add a new one. In navigation select Terms > Add
new:
and populate the fields:
Now we can examine how the post looks like if we send a GET request. I suggest you use Postman as it is easy to install and use, but if you prefer you can also visit <YOUR_WORDPRESS_URL>/wp-json/wp/v2/terms/
Postman
You can see we have all our ACF fields saved in the object acf
.
Let’s now prepare a sample JavaScript file that will enter a new term.
WordPress Nonce for Authentication
For authentication we will use Nonce. You can read more about it in WordPress Codex.
Add to your functions.php
the following code that will generate nonce.
function my_resources()
{
wp_enqueue_script(
'my_script',
get_template_directory_uri() . '/my_script.js',
null, // dependency
1.0, // version
true // loads script in footer
);
wp_localize_script(
'my_script', // handle - name of script
'magicalData', // name - name of the object we want to output
array('nonce' => wp_create_nonce('wp_rest')) // data - output
);
}
add_action('wp_enqueue_scripts', 'my_resources');
This code outputs the value of nonce into your page:
<script type='text/javascript'>
/* <![CDATA[ */
var magicalData = {"nonce":"397e0b60df"};
/* ]]> */
</script>
Next, to define the key for ACF to REST API we will later use to define fields we would like to send to REST AP add to functions.php
:
// DEFINE the KEY for post meta_keys to send data to
add_filter('acf/rest_api/key', function ($key, $request, $type) {
return 'terms';
}, 10, 3);
Now we can add a script my_script.js
to our theme to handle a new post entry.
Notice the terms
object in postContent
with new entries for ACF Repeater Field, magicalData.nonce
usage and of course change <YOUR_WORDPRESS_URL>
to your page URL.
var postContent = {
'title': 'Beautiful term',
'terms': {
'term_approved': true,
'term_new': true,
'term_origin': 'Ang. Fake ',
'definitions': [ {
'definition_approved': true,
'definition': 'The best definition ever',
'definition_author': 'Roxy',
'examples': [ {
'example': 'Some strange usage of the word',
'example_author': 'Ruby',
'example_approved': true
},
{
'example': 'What is beautiful?',
'example_author': 'Rocky',
'example_approved': true
}
],
'definition_likes': 0,
},
{
'definition': 'What about this one',
'definition_approved': true,
'definition_author': 'Red',
'examples': [ {
'example': 'Another example',
'example_author': 'Ron',
'example_approved': true
} ],
'definition_likes': 0,
}
],
// related_terms : ''
},
'status': 'publish' // or draft if you don't want to publish it
};
var createPost = new Promise( ( resolve, reject ) => {
var headers = new Headers( {
'Content-Type': 'application/json;charset=UTF-8',
'X-WP-Nonce': magicalData.nonce
} );
console.log( JSON.stringify( postContent ) );
var post = fetch( '<YOUR_WORDPRESS_URL>/wp-json/wp/v2/terms/', {
credentials: 'same-origin',
method: 'POST',
body: JSON.stringify( postContent ),
headers: headers
} )
.then( response => {
if ( response.ok ) {
return resolve( response );
} else {
reject( Error( response ) );
}
} )
.catch( error => {
console.log( error );
} );
} );
createPost.then( data => {
// display the name of the blog
console.log( data );
}, error => {
console.log( error );
} );
Now if we visit the WordPress page, a new post will be generated and saved.
Of course this code is not suitable for a live page, but it shows you how to use WP REST API with JavaScript to create custom post entries in the database. You can evolve it into anything you like.