php - Primary navigation menu with timed items from custom post type

I have created a site (livermorevalleyopera) for a client. I made a custom post type for events. In the primary navigati

I have created a site (livermorevalleyopera) for a client. I made a custom post type for events. In the primary navigation I have a top level menu item "Season Events & Tickets" and the submenu items of that are the custom post type events. Right now I am manually adding and removing them via Appearance > Menus, but is there a way to programmatically add and remove them based on the date of the event? I've found lots of mention of adding custom post types dynamically based on user roles, but not to a submenu or added and removed by date.

EDIT: Below is the image of the menu. The top level item is static (Season Events & Tickets) where as all the submenu items below it will be programmatically populated by the titles of the posts within the Events CPT I created and removed programmatically the day after the event's last occurrence. FYI, Each event can happen as often as 4 times, so I have 4 date meta fields per event and a meta field to denote how many dates are in each event, so I can know which date meta fields to cycle through.

UPDATE 7/25/2019: I was having a problem getting the wp_update_nav_menu_item call to correctly record the nav menu item into the database. I first had to hardcode the $menu_id to the term_id of the primary menu so it would stop recording the menu item as an orphaned item. Then I had to add 'menu-item-type' as post_type, because it kept defaulting to custom and ignoring my $post variables. Below is my code which is a combination of multiple answers I've found to do checks to make sure it only adds the menu item on a new publish of an event in my custom post type.

add_action( 'save_post', 'prefix_update_menu', 10, 3 );
function prefix_update_menu($post_id, $post, $update) {

  $parent_menu_id = false;

  if ('lvo_event' !== $post->post_type) :
    return;
  endif;

  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) :
      return;
  endif;

  // Check permissions
  if ( 'page' == $post->post_type ) :
    if ( !current_user_can( 'edit_page', $post_id ) ) :
        return;
    endif;
  else :
    if ( !current_user_can( 'edit_post', $post_id ) ) :
        return;
    endif;
  endif;

  if ( false == $update ) :
    return;
  endif;    

  // New post only
  if ( $post->post_date !== $post->post_modified ) {
    return;
  }


  // Get main menu items
  $main_menu_items = wp_get_nav_menu_items( 'primary' );
  if ( ! $main_menu_items ) :
    return;
  endif;

  foreach ($main_menu_items as $menu_items):
    if ("Season Events & Tickets" == $menu_items->title):
        $parent_menu_id = $menu_items->ID;
    endif;
  endforeach;

  if ( false !== $parent_menu_id ) {
      // If you want to create menu items          
      wp_update_nav_menu_item( 2, 0, array(
        'menu-item-object-id' => $post->ID,
        'menu-item-object'    => $post->post_type,
        'menu-item-type'      => 'post_type',
        'menu-item-parent-id' => $parent_menu_id, // not sure if property is correct, please check it yourself
        'menu-item-status'    => 'publish'
      ));
  }

}

I have created a site (livermorevalleyopera) for a client. I made a custom post type for events. In the primary navigation I have a top level menu item "Season Events & Tickets" and the submenu items of that are the custom post type events. Right now I am manually adding and removing them via Appearance > Menus, but is there a way to programmatically add and remove them based on the date of the event? I've found lots of mention of adding custom post types dynamically based on user roles, but not to a submenu or added and removed by date.

EDIT: Below is the image of the menu. The top level item is static (Season Events & Tickets) where as all the submenu items below it will be programmatically populated by the titles of the posts within the Events CPT I created and removed programmatically the day after the event's last occurrence. FYI, Each event can happen as often as 4 times, so I have 4 date meta fields per event and a meta field to denote how many dates are in each event, so I can know which date meta fields to cycle through.

UPDATE 7/25/2019: I was having a problem getting the wp_update_nav_menu_item call to correctly record the nav menu item into the database. I first had to hardcode the $menu_id to the term_id of the primary menu so it would stop recording the menu item as an orphaned item. Then I had to add 'menu-item-type' as post_type, because it kept defaulting to custom and ignoring my $post variables. Below is my code which is a combination of multiple answers I've found to do checks to make sure it only adds the menu item on a new publish of an event in my custom post type.

add_action( 'save_post', 'prefix_update_menu', 10, 3 );
function prefix_update_menu($post_id, $post, $update) {

  $parent_menu_id = false;

  if ('lvo_event' !== $post->post_type) :
    return;
  endif;

  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) :
      return;
  endif;

  // Check permissions
  if ( 'page' == $post->post_type ) :
    if ( !current_user_can( 'edit_page', $post_id ) ) :
        return;
    endif;
  else :
    if ( !current_user_can( 'edit_post', $post_id ) ) :
        return;
    endif;
  endif;

  if ( false == $update ) :
    return;
  endif;    

  // New post only
  if ( $post->post_date !== $post->post_modified ) {
    return;
  }


  // Get main menu items
  $main_menu_items = wp_get_nav_menu_items( 'primary' );
  if ( ! $main_menu_items ) :
    return;
  endif;

  foreach ($main_menu_items as $menu_items):
    if ("Season Events & Tickets" == $menu_items->title):
        $parent_menu_id = $menu_items->ID;
    endif;
  endforeach;

  if ( false !== $parent_menu_id ) {
      // If you want to create menu items          
      wp_update_nav_menu_item( 2, 0, array(
        'menu-item-object-id' => $post->ID,
        'menu-item-object'    => $post->post_type,
        'menu-item-type'      => 'post_type',
        'menu-item-parent-id' => $parent_menu_id, // not sure if property is correct, please check it yourself
        'menu-item-status'    => 'publish'
      ));
  }

}
Share Improve this question edited Jul 25, 2019 at 22:35 Ryan asked Apr 19, 2019 at 16:42 RyanRyan 136 bronze badges 1
  • To clarify, you want the submenu to automatically show the next event(s) based on their date, and once the date passes, they no longer show in the submenu? Can you post a screenshot of what the menu looks like with your manual edits? – aryxus Commented Apr 19, 2019 at 19:58
Add a comment  | 

1 Answer 1

Reset to default 0

Yes, I think it should be possible to add and remove nav menu items programmatically. You can use either wp_nav_menu_objects or wp_nav_menu_items filter to edit a nav menu. Or if you can edit the menu walker, you could add the event items inside it.

With the first filter you could use wp_update_nav_menu_item to create and save new menu items to database. You should be able to remove menu items with wp_delete_post. With the latter you will be dealing with the html of the nav menu so you can just append string of html to the menu.

If the event dates are stored as post meta, you can use custom field WP_Query to get events with future dates.

Here's a very rough example for using wp_nav_menu_objects that I conjured up based on the Codex and the code reference. Hopefully you can use this as a starting point for creating a working solution. This is by no means a working code example and needs tweaking, fine-tuning and maybe some typo fixing.

add_filter( 'wp_nav_menu_objects', 'prefix_wp_nav_menu_objects', 10, 2 );
function prefix_wp_nav_menu_objects( $menu_items, $args ) {
  // Check if correct menu  
  if ( 'my-theme-location' === $args['theme_location'] ) {
    // Loop items
    $time_now = time();
    foreach ( $menu_items as $key => $menu_item ) {
      // Add new items to correct submenu
      if ( $add_item_logic === $menu_item->property_to_compare ) { // add applicable logic
        $new_items = prefix_add_items_menu( $menu_item, $args );
        $menu_items = $menu_items + $new_items; // add new items to the menu item array
      } else if ( $remove_item_logic === $menu_item->property_to_compare ) { // add applicable logic
        $event_date = get_post_meta( $menu_item->db_id, 'event_date', true );
        if ( $event_date && strtotime( $event_date ) < $time_now ) {
          // Delete menu item permanently
          wp_delete_post( $menu_item->db_id ); // check if property is correct
          // Remove from menu item array
          unset( $menu_items[$key] );
        }
      }      
    }

  }

  return $menu_items;
}

function prefix_add_items_menu( $menu_item, $menu_args ) {
  $new_items = array();

  $query_args = array(
    'post_type'      => 'my_cpt_slug', // add correct cpt slug
    'posts_per_page' => 10, // adjust as needed
    'meta_key'       => 'event_date', // add correct meta key if date saved in post meta
    'meta_value'     => date( "Ymd" ), // change to how "event date" is stored
    'meta_compare'   => '>=' // change comparison methof if needed
  );
  $query = new WP_Query( $query_args );

  if ( $query->posts ) {

    foreach ( $query->posts as $event ) {

      // If you want to create menu items          
      wp_update_nav_menu_item( $menu_args['menu_id'], 0, array(
        'menu-item-title'     => $event->post_title,
        'menu-item-object-id' => $event->ID,
        'menu-item-object'    => $event->post_type,
        'menu-item-parent-id' => $menu_item->ID, // not sure if property is correct, please check it yourself
      ));

      // And / or push posts to menu items
      $new_items[] = array(
        'menu-item-title'     => $event->post_title,
        'menu-item-object-id' => $event->ID,
        'menu-item-object'    => $event->post_type,
        'menu-item-parent-id' => $menu_item->ID, // not sure if property is correct, please check it yourself
      );

    }    
  }

  return $new_items;
}

You can also check the related WPSE Q&A's on the matter,

Add items to a menu dynamically

Programmatically add a Navigation menu and menu items

Add items to a menu dynamically

Remove a menu item in menu

EDIT 1 Actually, you could perhaps update the menu on save_post, too, when a new event is published. This might be better way to update the menu now as I think about it more. Doing the update when a new post is published would mean that the update function is run less frequently thus taxing the site less overall.

For removing past events from the menu you could consider adding a custom wp cront event that would run once a day.

function prefix_update_menu( $post_id, $post ) {
  // New post only
  if ( $post->post_date !== $post->post_modified ) {
    return;
  }
  // Get main menu items
  $main_menu_items = wp_get_nav_menu_items( 'menu-id-slug-name-or-object' );
  if ( ! $main_menu_items ) {
    return;
  }

  // 1. foreach Loop menu items
  // 2. when correct submenu is matched add new menu item with wp_update_nav_menu_item
  // 3. optionally also remove passed events while doing the foreach loop
  // get post id from menu item with get_post_meta( $item->ID, '_menu_item_object_id', true );
  // then get event end date and current date for comparison
  // remove menu item with delete_postw p_delete_post( $item->ID );

}
add_action( 'save_post', 'prefix_update_menu', 10, 2 );

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745294982a4621084.html

相关推荐

  • php - Primary navigation menu with timed items from custom post type

    I have created a site (livermorevalleyopera) for a client. I made a custom post type for events. In the primary navigati

    4小时前
    20

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信