1

I'm using React to build the front-end of a site which uses Wordpress for the back-end. In particular, I'm using the Wordpress REST API to pull in and display content.

By default, the Wordpress REST API doesn't expose menu information, so I've extended it to include it:

function get_menu( $data ) {
  return wp_get_nav_menu_items( $data[ 'slug' ] );
}

add_action( 'rest_api_init', function () {

  register_rest_route( 'custom', '/menus/(?P<slug>[a-zA-Z0-9-]+)', 
    array(
      'methods'  => 'GET',
      'callback' => 'get_menu'
    )
  );

});

Now I can access my menu information with a request like the following:

http://localhost:8888/learn-react/admin/wp-json/custom/menus/main-menu

The response I get for each of the items included in the menu looks like this:

ID: 13
attr_title: ""
classes: [""]
comment_count: "0"
comment_status: "closed"
db_id: 13
description: ""
filter: "raw"
guid: "http://localhost:8888/learn-react/admin/?p=13"
menu_item_parent: "0"
menu_order: 3
object: "page"
object_id: "8"
ping_status: "closed"
pinged: ""
post_author: "1"
post_content: " "
post_content_filtered: ""
post_date: "2018-02-10 08:57:52"
post_date_gmt: "2018-02-10 08:57:52"
post_excerpt: ""
post_mime_type: ""
post_modified: "2018-02-10 08:57:52"
post_modified_gmt: "2018-02-10 08:57:52"
post_name: "13"
post_parent: 0
post_password: ""
post_status: "publish"
post_title: ""
post_type: "nav_menu_item"
target: ""
title: "About"
to_ping: ""
type: "post_type"
type_label: "Page"
url: "http://localhost:8888/learn-react/admin/about/"
xfn: ""

My problem is I'm trying to use this data to put a link on each menu item, but since I'm using React Router I don't need the whole url (which is provided in the data above), but only the final slug. Here's my menu component:

class MainMenu extends React.Component {

  componentDidMount() {
    this.props.fetchMainMenu();
  }

  render() {

    let menuItemsArray = store.getState().menuReducer.mainMenuItems;     
    let menuItems = menuItemsArray.map( ( menuItem, index ) => {    

      return( 
        <li key={ index }>
          <Link to={ menuItem.url }>{ menuItem.title }</Link>
        </li>
      )
    })
    return (
      <ul>{ menuItems }</ul>
    )
  }
}

Using menuItem.url generates the following href, of course:

http://localhost:3000/http://localhost:8888/learn-react/admin/about/

while, like I said, I would need something like menuItem.slug to generate:

http://localhost:3000/learn-react/admin/about/

What options do I have?

  • Option A: filter the output of wp_get_nav_menu_items() to not return full URLs. Option B: remove the http://localhost:8888/ part in your React script. Have you tried either? – swissspidy Feb 16 '18 at 10:30
  • No, I haven't tried either of the options you suggest, but I was actually hoping for a way to achieve my goal by extending the API and adding a 'slug' parameter to the JSON response I posted above somehow. I realize it's probably more complicated, but it sounds cleaner to me. Otherwise I will try your ideas. – grazianodev Feb 16 '18 at 15:54
2

I had the same challenge, and fixed it by adding it to the response. Example:

function get_menu() {
    # Change 'menu' to your own navigation slug.
    $menu_items = wp_get_nav_menu_items('menu');
    foreach($menu_items as $menu_item) {
        // ALTERNATIVE: $slug = get_post_field( 'post_name', $menu_item->object_id );
        $slug = basename( get_permalink($menu_item->object_id) );
        $menu_item->slug = $slug;
    }
    return $menu_items;
}

add_action( 'rest_api_init', function () {
        register_rest_route( 'myroutes', '/menu', array(
        'methods' => 'GET',
        'callback' => 'get_menu',
    ) );
} );

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.