web-dev-qa-db-fra.com

Faire en sorte que la structure du menu corresponde à la hiérarchie des pages lors du changement de page

Les anciens thèmes WordPress tels que twentyten contenaient des fonctionnalités qui permettaient à la structure du menu de navigation de refléter les modifications de la hiérarchie des pages. Par exemple, si j'ai la hiérarchie de page arbitraire (et la structure de menu correspondante) ci-dessous:

  • UNE
  • B
    • Je
    • II
  • C
    • III

Si je devais éditer la page 'II' et changer son parent de B à 'C', la structure de mon menu de navigation principal serait mise à jour pour refléter immédiatement ce changement.

Cependant, avec les thèmes ultérieurs tels que vingt-quinze (ainsi que les modèles tiers), cette fonctionnalité n'est pas présente. J'ai consulté le fichier functions.php de twentyten et je ne trouve aucune preuve de la fonctionnalité appelée à partir de là, sauf si je néglige quelque chose.

Alors, naturellement, je veux créer ma propre fonction. Comment je ferais ça?

1
James Cushing

J'ai abordé ce problème et pense avoir la solution. N'hésitez pas à commenter en apportant des modifications ou des améliorations au texte ci-dessous!

Cette fonctionnalité peut être considérée comme une série de 5 étapes:

  1. Recueillir des informations sur le déménagement (l'enfant, son ancien parent et son nouveau parent)
  2. Trouvez les éléments de menu appropriés (l'enfant, son ancien parent et son nouveau parent)
  3. Déplacez l'enfant vers le nouveau parent approprié

1. Recueillir des informations sur le déménagement

Premièrement, nous devons obtenir une copie de la page avant et après son déplacement. Je l'ai fait avec deux crochets: pre_post_update et save_post_page. Dans le cas où le parent a changé (puisque ces hooks s'exécuteraient à chaque mise à jour de page), il appelle une fonction personnalisée appelée menu_match que je documenterai dans les étapes suivantes.

// Re-initialise post vars to prevent accidental moves
$old_post = NULL;
$new_post = NULL;

// Capture the post details before they change
add_action('pre_post_update', 'get_old_post_version');
function get_old_post_version($postID){
    global $old_post;
    $old_post = get_post($postID);
}

// Get the updated post details
add_action('save_post_page', 'get_new_post_version');
function get_new_post_version($postID){
    global $old_post, $new_post;
    $new_post = get_post($postID);

    // If the parent has changed, make the menu match the new heirarchy
    if($old_post->post_parent != $new_post->post_parent){
        menu_match($old_post, $new_post);
    }
}

2. Trouvez les éléments de menu appropriés

Le code pour cette étape et l’étape 3 sera tout en dessous de l’étape 3, car ils font partie de la même fonction et je pense qu’il sera préférable de lire pour les garder ensemble.

Cette étape consiste à obtenir les éléments du menu donné (dont l’ID sera spécifié pour le menu que vous souhaitez attacher à la hiérarchie de la page), puis à les pousser vers le tableau (pour l’enfant) si leur object_id (l’identifiant correspond à l’ID de l’ancienne page, ou à un autre tableau (pour le parent) si leur object_id correspond à l’ancien post_parent (l’ID de la page qui est le parent de l’ancienne page).

Remarque: je dis "ancienne page", ce qui signifie l'ancienne version de la page. Il n'y a pas de "supprimer et recréer" ici.

Si plus d'un élément parent et/ou enfant est trouvé, nous recherchons le bon appariement en vérifiant si le menu_item_parent de l'élément enfant (l'identifiant de l'élément de menu parent) correspond à l'identifiant du parent ... simple, non?

Enfin, nous trouvons le nouveau parent (l’élément dont le object_id correspond au post_parent de la new page).

3. Déplacez l'enfant vers le nouveau parent approprié

Assez simplement, cette étape implique simplement d'appeler wp_update_nav_menu_item pour mettre à jour l'élément enfant avec le nouvel ID parent. J'ai également rétabli d'autres propriétés pour la santé mentale.

La fonction menu_match est ci-dessous - il s’agit de ma première soumission "répondez à votre propre question", alors merci de me prévenir si j’ai abordé la question de manière totalement fausse! Il y a aussi quelques commentaires "TODO" qui suggèrent des améliorations qui pourraient être apportées à la fonction ... Je suis sûr qu'il y aura une manière plus propre de faire certaines de ces choses, mais c'est la façon dont j'ai utilisé!

function menu_match(&$old_post, &$new_post){
    // Set menu which we're manipulating...
    $menuID = 2;
    // ... and get its items
    $menu_items = wp_get_nav_menu_items($menuID);

    // Find all items which link to the page in question
    $old_child_items = array();
    foreach($menu_items as $m_item){
        if($m_item->object_id == $old_post->ID){
            array_Push($old_child_items, $m_item);  
        }
    }

    // If the post isn't top level, find all items which link to the parent in question
    $old_parent_items = array();
    if($old_post->post_parent != 0){
        foreach($menu_items as $m_item){
            if($m_item->object_id == $old_post->post_parent){
                array_Push($old_parent_items, $m_item);
            }
        }
    }

    // Pick the correct child (and parent if necessary)
    $child = NULL;
    $old_parent = NULL;
    foreach($old_child_items as $child_candidate){
        if(count($old_parent_items) > 0){
            // If there are parent items to look through, find the one which has the right ID
            foreach($old_parent_items as $parent_candidate){
                if($child_candidate->menu_item_parent == $parent_candidate->ID){
                    $child = $child_candidate;
                    $old_parent = $parent_candidate;
                }
            }
        }else{
            // If there are no parent items, pick the child item which has no parent
            if($child_candidate->menu_item_parent == 0){
                $child = $child_candidate;
            }
        }
    }

    if($child != NULL){
        // If the post isn't moving to top level, find all items which link to the new parent
        if($new_post->post_parent != 0){
            $new_parent_items = array();
            foreach($menu_items as $m_item){
                if($m_item->object_id == $new_post->post_parent){
                    array_Push($new_parent_items, $m_item);
                }
            }

            // TODO:    Add recursive upwards search in the event that there are two menu items
            //          for the desired parent.
            //
            // For now, assume the first match is correct, as there shouldn't be more than one
            // item pointing to the same parent.
            if(count($new_parent_items) > 0){
                $new_parentID = $new_parent_items[0]->ID;
            }else{
                // If no matches are found, put the item on the top level
                $new_parentID = 0;  
            }
        }else{
            // Post is moving to top level
            $new_parent_items = NULL;
            $new_parentID = 0;  
        }

        // Update the menu item with the new parent (and reinstate existing properties for sanity)
        $menu_update = wp_update_nav_menu_item($menuID, $child->db_id, array(
            'menu-item-status' => $child->post_status,
            'menu-item-post-name' => $child->post_name,
            'menu-item-type' => $child->post_type,
            'menu-item-parent-id' => $new_parentID,
            'menu-item-object-id' => $child->object_id,
            'menu-item-object' => $child->object,
            'menu-item-type' => $child->type,
            'menu-item-type-label' => $child->type_label,
            'menu-item-url' => $child->url
        ));
    }

    // TODO:    Handle overrides (in case a page doesn't want putting in the menu or
    //          moving from its current location)

    return;
}
0
James Cushing