Getting post meta via WordPress REST API

If you find this free website useful – why don’t you support this with a donation? It is easy…. read more ….

This the second post post in my series about getting and updating WordPress data via a spreadsheet.  The first post focused on the basics of Google Apps Scripting and the API call to the WP REST API – if you haven’t seen it you can read it here.

This post is about meta data. In case you are not really clear, meta data in WordPress post terms are any extra data that isn’t part of the WordPress post schema.  More often or not this data is created and maintained by plugins.

To give you a clear example, if say you use Yoast SEO plugin, the Yoast SEO version of the post title is stored in meta data item called _yoast_wpseo_title  these are also known as custom fields, and WordPress treats custom fields starting with an _ as hidden.

I read many posts on howto access meta and most of them were wrong and out dated.  The WP  Rest documentation tells you about problems with meta  and also warns you they are changing their thoughts on this – so beware – this may even be out of date soon.

If you look at the ‘posts schema’ you will see an entry for meta, but more often than not, you will see an entry “meta”:[]  i.e. empty, even if it is not e.g. curl http://demo.wp-api.org/wp-json/wp/v2/posts/1 

For unsetialized ( i.e. text string meta) the solution is much simpler that many blog posts I read make out,  you just need to tell WordPress that the meta can be exposed in the API.

To do this, you are going to need to write ( or copy at least ) some PHP code.   Some tutorials, will tell you that you add extra code to your theme’s functions.php, whilst this will work, this is not the right way to do things, themes are for layouts, plugins are for functions. If you add it to your (child) theme and one day you change your theme then the extra features will break.  So write a plugin, its not hard.

Before you write the plugin, you will have been testing on a website on the internet ( you have to as Google can’t see your local host ), so here is a quick and easy way to get editing on your remote site without faffing around with FTP etc.   Install ICEcoder with this plugin to be able to follow along.

Once you are in the editor navigate to the wp-content/plugins folder, right click on plugins and select ‘New File’ and give your plugin a name like myfunctions.php .

The copy the code below and paste it into the code area and ctrl-s  to save it.

<?php
/**
 * Plugin Name:       My Custom Code
 * Plugin URI:        http://fullworks.net/wordpress-plugins
 * Description:       Custom code
 * Version:           1.0
 * Author:            Fullworks
 * Author URI:        http://fullworks.net/
 *
 */
if ( ! defined( 'WPINC' ) ) {
	die;
}
add_action( 'rest_api_init', 'register_posts_meta_field' );

function register_posts_meta_field() {
    $object_type = 'post';
    $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, '_yoast_wpseo_title', $args1 );
}

Lets just take a second to explain what we are doing.

when the Rest API is initiated ‘rest_api_init’  we are calling our function which is basically registering _yoast_wpseo_title   but this time it is setting it to show in the Rest API ‘show_in_rest’ => true,

OK, so when you have saved your plugin, go to your admin > plugins and find it, and activate it, hopefully it activates without errors.

So you now are ready to go, let just extend the script we wrote in the first article to also read the meta items.

If you are following this along, you will obviously need to install the Yoast SEO plugin into your remote test WordPress, and also set a few Yoast titles up in posts.

The script code would now look like this

function onOpen() {
  // setup a custom menu
  SpreadsheetApp.getUi() 
      .createMenu('WordPress')
      .addItem('Get Posts', 'getPosts')
      .addToUi();
  setupSheet();
}

function setupSheet() {
  // just clear sheet and set & style headings
 var ss = SpreadsheetApp.getActiveSpreadsheet();
  // set the tab to post - just for neatness
 var sheetname = ss.getSheets()[0].setName('Posts');
  // clear the sheet
 var range = ss.getDataRange();
 range.clear();
 //set headings
  ss.getRange('A1').setValue('Post ID');
  ss.getRange('B1').setValue('Title');
  ss.getRange('C1').setValue('Yoast Title');
  ss.getRange('D1').setValue('Updated');
  
  ss.getRange('A1:C1').setFontWeight('bold');
  ss.getRange('A1:C1').setFontStyle('italic');

}


function getPosts(){
  setupSheet();
  // loop here as we need get back posts in chunks, Rest API max is 100 post
  offset = 0;
  per_page = 10;
  while ( (got=getPage(offset,per_page)) > 0 ) {
    offset+=got;
    Logger.log('offset %s', offset);
  }
}


function getPage(offset,per_page) {
  // gets posts in chunks of per_page
  var ui = SpreadsheetApp.getUi();  // used for error messages
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  
  var options = {
      'method': 'get',
      "contentType" : "application/json",
      'muteHttpExceptions': true
    }
  var apiHost = 'http://mytestdomain/wp-json';   // set to your own domain
  url = apiHost + '/wp/v2/posts?per_page='+per_page+'&offset='+offset;
  try {
    var response = UrlFetchApp.fetch(url, options);
    var data = JSON.parse(response)
    // loop through the map and output to sheet
    for (i = 0; i < data.length; i++) {
     row=offset+i+2;  // set the row to make sure it is below header and takes into account the paging
     ss.getRange('A'+row).setValue(data[i].id);
     ss.getRange('B'+row).setValue(data[i].title.rendered);
     ss.getRange('C'+row).setValue(data[i].meta._yoast_wpseo_title);
     ss.getRange('D'+row).setValue(data[i].modified);
  }
    return data.length;
  } catch(error) {
    var result = ui.alert( error.toString());
  }
  return 0;
}

See what I did there, just inserted column C as a title and put .meta._yoast_wpseo_title   into column C

Change the domain to your actual internet available test domain. Save and run from the spreadsheet. Refer back to the first article if you need to see how.

If you have any questions or comments, please leave them.

In the next post I will work through a method to get authentication so you can later update.


by

Tags:

Comments

11 responses to “Getting post meta via WordPress REST API”

  1. […] How to get meta data, if you inspect what you get back you will find meta[] by default, and meta data is most useful -> post is here […]

  2. […] we have already built the getPosts function in post one, and modified it for meta in post two, and done the basics for JWT authorisation in post three I will concentrate on the updating posts […]

  3. Aleks avatar

    Hey there!

    Are you certain about the very first part with register_meta(…)? Because my meta[] still remains empty in the response after it’s done. When I use register_rest_field () however, it works. If you are interested, here is my question on StackOverflow: https://stackoverflow.com/questions/49533689/retrieving-post-meta-with-rest-api-using-register-meta

    Kind regards
    Aleks

    1. Alan avatar
      Alan

      Hi Alex,

      Absolutely this code works ( WP 4.9.4 ) the key element is the hook
      add_action( 'rest_api_init', 'register_posts_meta_field' );

      Alan

      1. Aleks avatar

        Thank you for your reply! i tried it again as you suggested and disabled any other parts of code which were hooked into init or rest_api_init hooks to avoid possible side effects. The meta field is still empty.

        Probably I should’ve mentioned, that I’m using a custom post type. As stated in the codex, when registering it I set ‘supports’ => [‘custom-fields’]. May be there is something else what I’m missing in the register_post_type() and that is crucial for the meta to show up? I update the StackOverflow with details to that part of code.

        1. Alan avatar
          Alan

          Your stack exchange code uses the object type of the custom post name `CompanyPostType::POST_TYPE_NAME`

          but this is incorrect, it should be post even for a CPT

          1. Aleks avatar

            Nice! That was the reason! Thank you for your time!

          2. Alan avatar
            Alan

            No problem, just kicking myself I didn’t notice your issue quicker.

  4. […] first post covered reading basic post information into a spreadsheet.  The second post was about getting meta data from the REST API, which can be a little […]

  5. Mukeshwar Singh avatar
    Mukeshwar Singh

    Hey, does this code just shows the meta title and description or we can update it as well?

    1. Alan Special avatar
      Alan Special

      Thank you for your interest, indeed the first line says ‘This the second post post in my series about getting and updating WordPress data via a spreadsheet’

      You have to work through all 4 post til you get to updating solution.

      It has been several years since I visited the code so there may be tweaks that can be improved however the principals remain solid.

Leave a Reply

Your email address will not be published. Required fields are marked *