带有来自自定义帖子类型的计时项目的主导航菜单

时间:2019-04-19 作者:Ryan

我已经创建了一个网站(livermorevalleyopera.com) 对于客户。我为事件定制了一个帖子类型。在主导航中,我有一个顶级菜单项“Season Events&Tickets”,其子菜单项是自定义post类型的事件。现在,我正在通过“外观”>“菜单”手动添加和删除它们,但是否有方法根据事件日期以编程方式添加和删除它们?我发现很多人提到根据用户角色动态添加自定义帖子类型,但没有提到添加到子菜单或按日期添加和删除。

EDIT: 下面是菜单的图像。顶层项目是静态的(季节事件和门票),与下面的所有子菜单项目一样,它将以编程方式由事件CPT中的帖子标题填充,CPT I在事件最后发生的第二天以编程方式创建和删除。仅供参考,每个事件可能发生4次,因此我每个事件有4个日期元字段,一个元字段表示每个事件中有多少个日期,因此我可以知道要循环的日期元字段。

Livermore Valley Opera Events Menu

UPDATE 7/25/2019:我在获取wp_update_nav_menu_item 调用将导航菜单项正确记录到数据库中。我首先必须硬编码$menu_idterm_id 使其停止将菜单项记录为孤立项。然后我不得不补充\'menu-item-type\'post_type, 因为它一直默认为custom 忽略我的$post 变量。下面是我的代码,它是我找到的多个答案的组合,我会进行检查,以确保它只在自定义帖子类型中新发布事件时添加菜单项。

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\'
      ));
  }

}

1 个回复
最合适的回答,由SO网友:Antti Koskinen 整理而成

是的,我认为应该可以通过编程方式添加和删除nav菜单项。您可以使用wp_nav_menu_objectswp_nav_menu_items 筛选以编辑导航菜单。或者如果您可以编辑menu walker, 您可以在其中添加事件项。

使用您可以使用的第一个过滤器wp_update_nav_menu_item 创建新菜单项并将其保存到数据库。您应该能够使用删除菜单项wp_delete_post. 对于后者,您将处理nav菜单的html,因此您可以将html字符串附加到菜单中。

如果事件日期存储为post meta,则可以使用custom field WP_Query 获取具有未来日期的事件。

下面是一个非常粗略的示例wp_nav_menu_objects 这是我根据法典和代码参考而想到的。希望您可以将此作为创建工作解决方案的起点<这绝不是一个有效的代码示例,需要调整、微调,也许还需要一些排版

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;
}
您还可以查看相关的WPSE Q&;A关于这件事,

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实际上,您可以在上更新菜单save_post, 发布新事件时也是如此。这可能是更好的方式来更新菜单,因为我现在想得更多。发布新帖子时进行更新意味着更新功能的运行频率较低,从而降低了网站的总体负担。

要从菜单中删除过去的事件,可以考虑添加一个每天运行一次的自定义wp cront事件。

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 );