在 WordPress 中删除导航菜单时重置自定义字段

reset custom field when navigation menu is deleted in WordPress

我有一个与所有帖子和页面关联的自定义字段。它是所有导航菜单的下拉菜单。 这是我填充自定义字段下拉列表的方式:(字段名称是 custom_menu...)

function acf_load_menu_field_choices( $field ) {

    // reset choices
    $field['choices'] = array();

    $menus = get_terms( 'nav_menu', array( 'hide_empty' => true ) );

    $blank_list = json_encode(array( "name" => "Select Menu", "slug" => "")); 
    $blank_list = json_decode($blank_list);
    array_unshift($menus, $blank_list);
    foreach ( $menus as $val ) {

        $value = $val->slug;
        $label = $val->name;

        $field['choices'][ $value ] = $label;
    }

    // return the field
    return $field;

}
add_filter('acf/load_field/name=custom_menu', 'acf_load_menu_field_choices');

这是我在每个页面上使用的常用菜单位置:

function register_custom_menu() {  //function to register new menu
     register_nav_menu('custom-menu',__( 'Custom Menu' ));
}
add_action( 'init', 'register_custom_menu' );

然后我根据每个页面上的自定义字段菜单将菜单动态分配到位置 custom-menu

这里是加载每个页面时触发的函数:

add_action("wp_ajax_load_custom_menu", "load_custom_menu");
add_action("wp_ajax_nopriv_load_custom_menu", "load_custom_menu");
function load_custom_menu(){
    $post_id = $_POST['page_id'];
    $page_custom_menu = get_field('custom_menu', $post_id);
    if(empty($page_custom_menu) || $page_custom_menu == "primary") return;
    $locations = get_theme_mod( 'nav_menu_locations' );
    if(!empty($locations)) {
        foreach($locations as $locationId => $menuValue) { 
            if($locationId == "custom-menu") $menu = get_term_by('slug', $page_custom_menu, 'nav_menu');  
            if(isset($menu)) { $locations[$locationId] = $menu->term_id; }
        } 
    } 
    set_theme_mod('nav_menu_locations', $locations);

    wp_nav_menu( array( 
        'theme_location' => 'custom-menu', 
        'menu_id' => 'primary-menu', 
        'menu_class' => 'main-nav underline-decoration l-to-r-line level-arrows-on outside-item-remove-margin',
        'container' => false
        ) 
    );

    wp_die();
}

此 ajax 函数在 ready 事件上触发并接收一个名为 page_idPOST 值。此函数检查 custom-menu 的给定 page_id 的自定义字段值,并将该菜单分配给名为 custom-menu.

menu location

这是我的 JavaScript 以备不时之需:

jQuery(document).ready( function($){
    let customMenu;
    let page_id = script_vars.postID;
    $.post(dtLocal.ajaxurl, { action: "load_custom_menu", page_id: page_id }, resp => customMenu = resp);
    $(window).scroll(() => {
        if(customMenu !== "0"){
            $("#phantom .main-nav").remove();
            $("#phantom .menu-box").html(customMenu);
        }
    })
})

这就是我的代码的工作方式,到目前为止一切正常。

问题来了 每当我从 Appearence>Menus>Delete Menu 中删除导航菜单时,我的自定义菜单开始出现意外行为,因为自定义字段值仍指向已删除的菜单。 我想在这里做的是,我想在删除菜单时删除自定义字段首先,我想获取已删除菜单的 slug,然后找到带有该 slug 的自定义字段值,最后,删除或重置该自定义字段。

您正在寻找需要一个参数的操作 wp_delete_nav_menu - menu id。那个时候你的导航菜单将被删除的问题,所以你将无法接受它。

如果您可以存储导航菜单 ID 而不是 slug,那将大大简化事情。

acf_load_menu_field_choices中替换:

foreach ( $menus as $val ) {
    $value = $val->term_id;
    $label = $val->name;
    $field['choices'][ $value ] = $label;
}

load_custom_menu中:

$page_custom_menu = get_field('custom_menu', $post_id);
if(empty($page_custom_menu) || $page_custom_menu == /* Should be your primary menu ID */) return;
$locations = get_theme_mod( 'nav_menu_locations' );
if(!empty($locations)) {
    foreach($locations as $locationId => $menuValue) {
        if($locationId == "custom-menu") $menu = get_term_by('id', $page_custom_menu, 'nav_menu');
        if(isset($menu)) { $locations[$locationId] = $menu->term_id; }
    }
}

完成这些更改后,您需要重写 custom_menu 全部 posts\pages。

之后,当您删除菜单时,以下函数将删除所有相关字段。它仅在典型的 ACF 字段(字符串)而不是自定义字段上进行了测试,但应该也能很好地处理您的代码。

add_action('wp_delete_nav_menu', 'delete_all_acf_fields_with_menu', 10, 1);
function delete_all_acf_fields_with_menu($term_id) {
    $args = array(
        'post_type'        => array('post', 'page'),
        'posts_per_page'   => -1,
        'meta_key' => 'custom_menu',
        'meta_value' => $term_id,
    );
    $posts = get_posts($args);
    if( $posts ) {
        foreach( $posts as $p ) {
            delete_field('custom_menu', $p->ID);
        }
    }
}

WordPress 中的菜单只是 terms in a taxonomy。所以你可以使用所有的钩子这个术语。

特别是 pre_delete_term 挂钩。

add_action( 'pre_delete_term', 'my_func' );
function my_func($term, $taxonomy){

  // Check the taxonomy is really 'menu', then check term
}