I found myself in a strange situation where I needed to know if a page had a child. Natively the WP API lets you know if a page has a parent but not the reverse.
First I had to write a function that writes some data to a custom field if a page has a child. Then I started writing this post and realized I needed to do the reverse and now I’ve written a function that writes data to a parent when the child is created.
//sets a custom field to indicate if a page has children to save a call later add_action( 'save_post', 'has_child_meta' ); function has_child_meta(){ global $post; $post_id = $post->ID; if (get_post_type($post_id)==='page'){ $args = array( 'parent' => $post_id, 'post_type' => 'page', 'post_status' => 'publish', 'number' => 1, //we only need one ); $pages = get_pages($args); $number = sizeof($pages); if ($number != 0 ) { add_post_meta($post_id, 'has_children', 1, true); } else { add_post_meta($post_id, 'has_children', 0, true); } } }
//sets a custom field to indicate if a page has children to save a call later add_action( 'save_post', 'has_child_meta_to_parent' ); function has_child_meta_to_parent(){ global $post; $parent = $post->post_parent; if ($parent != 0 ) { add_post_meta($parent, 'has_children', 1, true); } else { add_post_meta($parent, 'has_children', 0, true); } } }
Now that I had the data being written to the custom field, I needed to make that data visible in the WP REST API. Luckily, Jeff put up a snippet for that not too long ago.
//PUTS has_children INTO THE API function children_get_post_meta_cb($object, $field_name, $request){ return get_post_meta($object['id'], $field_name, true); } function children_update_post_meta_cb($value, $object, $field_name){ return update_post_meta($object['id'], $field_name, $value); } add_action('rest_api_init', function(){ register_rest_field('page', 'has_children', array( 'get_callback' => 'children_get_post_meta_cb', 'update_callback' => 'children_update_post_meta_cb', 'schema' => null ) ); });
Now I also wanted to be able to return data based on the contents of the has_children field. This filter1 does that. Now a URL like the one below will give me pages with children but without parents.
/wp-json/wp/v2/pages?_embed&per_page=30&has_children=1&parent=0
//THIS LETS US SEARCH BY has_children variables add_filter( 'rest_page_query', function( $args, $request ) { $has_children = $request->get_param( 'has_children' ); if ( ! empty( $has_children ) ) { $args['meta_query'] = array( array( 'key' => 'has_children', 'value' => $has_children, 'compare' => '=', ) ); } return $args; }, 10, 2 );
This will help me make a fairly large menu structure more manageable and I figured having something like this all in one place might help someone else.
1 I usually call things ‘chunks’ of code but I’m trying to improve my vocab.