1

I'm building a site with WP-API (v2). I'm attempting to add a REST field according to documentation that includes anything from body_class.

However, body_class is returning either one class (one added by my theme) or no classes (when the condition in the theme that adds the class is false).

Here's the relevant code in my api.php file (included via functions.php).

// Obtain body classes
function bsd_get_body_class( $data, $object, $request ) {
  $classes = get_body_class();

  return $classes;
}

// Obtain post classes
function bsd_get_post_classes( $data, $post, $request ) {
  return get_post_class();
}

function bsd_rest_fields() {
  register_rest_field(['page', 'post'], 'body-class', array(
      'get_callback' => 'bsd_get_body_class'
    )
  );

  register_rest_field(['post'], 'post-classes', array(
    'get_callback' => 'bsd_get_post_classes'
    )
  );
}

add_action( 'rest_api_init', 'bsd_rest_fields', 15 );

The post_classes function works perfectly and I can access that data in my state; the body_classes does not, however.

Using body_class in other theme files works fine--the body classes are applied in, for instance, page templates.

It's interesting to note that doing print_r(get_body_class()) inside my functions.php file also returns one (or zero) classes, but inside a template file, it works fine.

  • It looks like the rest_api_init action is called before the $wp object is instantiated, so I have to figure out how to hook the function into the wp action, I think, inside the REST API callback. – bigsweater Mar 14 '16 at 21:53
  • If you look here: core.trac.wordpress.org/browser/tags/4.4.2/src/wp-includes/… you can see the conditions that add each of the classes. – czerspalace Mar 14 '16 at 21:54
  • @czerspalace Yes, the conditions (and filters in my theme) are fine--what I'm trying to do is add the classes to a field in the REST API. However, the API hook rest_api_init appears to fire before the $wp object is set up, so my callback (bsd_get_body_class) is returning an empty array. (At least, I think that's what's happening.) – bigsweater Mar 14 '16 at 21:59
  • Ahh ok. Which body classes were you expecting to be present? Or based on the link, which conditions did you expect to be true? – czerspalace Mar 14 '16 at 22:36
  • @czerspalace All of them, haha. But the array is empty (or just contains the class added in my theme). I think my solution will be to add the results of get_body_class as post meta to my posts/pages, and then use the API to access the meta, rather than the function get_body_class. That seems like the easiest/cleanest way to do it. – bigsweater Mar 14 '16 at 23:20
0

get_body_class() relies on $wp_query to do its thing, which is apparently a no-go for the JSON API.

I considered creating a global object to hold the body class, and just using that to keep the body_class up to date...but that wouldn't work without page reloads, and there would be no assurance that the object was up-to-date.

The only way I could get it to remotely work was by hijacking the main $wp_query object, which is a no-no.

The semi-working code looked something like:

function bsd_get_body_class($id) {
  global $wp_query;
  $wp_query = $orig_query;

  $new_query = new WP_Query( array( 'p' => $id, 'post_type' => 'any' ) );

  $wp_query = $new_query;
  $classes = get_body_class();

  wp_reset_postdata(); 

  $wp_query = $old_query;

  return $classes;
} 

// Add $classes as a REST field to the API according to docs

Even then, though, $classes didn't necessarily match the output of body_class() inside my template files, I think because it happened earlier in the query than in the templates.

So I scrapped it.

I ended up writing a simple class builder in JS that re-creates some of the WP functionality, instead of using the API and storing the classes in my app's state. It looks like this:

export const bodyClass = (data) => {
  var classes = [];

  if (data['id'] && data['type'])
    classes.push(data['type'] + '-id-' + data['id']);
  if (data['type'])
    classes.push(data['type']);
  if (data['is-front-page'] === true)
    classes.push('home')
  else
    classes.push('internal');

  return classes;
}

If somebody out there knows a good way to get presentational data from the WP API, I'm all ears, but after days of hacking, I couldn't find a reliable, consistent way to get the classes out of $wp_query. (post_classes, on the other hand, works like a charm.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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