Intégration d'un type d'article personnalisé dans une hiérarchie de pages

13

Je crée un thème avec un type de publication personnalisé pour les membres de l'équipe. J'ai également la structure de page suivante:

about  <-- this is a page
about/team-members  <-- this is a page, lists all the team members
about/team-members/joe-bloggs  <-- this is a custom post type (team member) entry

La troisième structure ici utilise les pages about et team member, mais utilise ensuite le slug de type de publication personnalisé pour donner l’impression que ses parents sont membres de l’équipe et about. Pour ce faire, j'ai défini les options suivantes dans le type de publication personnalisé:

...
'rewrite' => array( 'slug' => 'about/team-members', 'with_front' => false)
...

Cela fonctionne très bien, mais lorsque je passe au niveau de membre de l’équipe, je n’obtiens plus les classes de la page actuelle, des ancêtres actuels sur les pages parentes. Je sais pourquoi, parce que techniquement, nous ne sommes pas sur une page parent de ces pages. Cependant, y at-il un moyen de tromper / corriger / bodge pour que les pages apparaissent comme des parents?

J'avais très bien réussi cela en utilisant des pages pour les membres de l'équipe. Toutefois, un type de publication personnalisé a été choisi à la place pour faciliter son utilisation par l'administrateur.

Merci les gars + les filles!

    
posée Ben Everard 28.03.2011 - 20:20

6 réponses

6

Lorsque vous travaillez avec des pages, vous pouvez sélectionner une page parent et cette valeur est enregistrée comme numéro d'identification de la page parent dans le champ post_parent de la page enfant dans la base de données.

Dans votre cas, vous utilisez un type de publication personnalisé. Vous devez donc créer votre propre métabox pour la page parent. quelque chose comme:

/* Define the custom box */
add_action('add_meta_boxes', 'child_cpt_add_custom_box');

/* Adds a box to the main column on the custom post type edit screens */
function child_cpt_add_custom_box() {
    add_meta_box('child_cpt', __( 'My child_cpt parent'),'team_member_inner_custom_box','team_member');
}

/* Prints the box content */
function team_member_inner_custom_box() {
    global $post;
    // Use nonce for verification
    wp_nonce_field( plugin_basename(__FILE__), 'team_member_inner_custom_box' );
    echo 'Select the parent page';
    $mypages = get_pages();
    echo '<select name="cpt_parent">';
    foreach($mypages as $page){     
        echo '<option value="'.$page->ID.'"';
        if ($page->ID == $post->post_parent) {echo ' selected';}
        echo '>"'.$page->post_title.'</option>';
    }
    echo '</select>';
}
/* Do something with the data entered */
add_action('wp_insert_post_data', 'myplugin_save_postdata');

/* When the post is saved, saves our custom data */
function myplugin_save_postdata( $data, $postarr ) {
    global $post;
      // verify this came from the our screen and with proper authorization,
      // because save_post can be triggered at other times

      if ( !wp_verify_nonce( $_POST['team_member_inner_custom_box'], plugin_basename(__FILE__) ) )
          return $data;

      // verify if this is an auto save routine. 
      // If it is our form has not been submitted, so we dont want to do anything
      if ( defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) 
          return $data;
      // OK, we're authenticated: we need to find and save the data

      if ($post->post_type == "team_member")
          $data['post_parent'] = $_POST['cpt_parent'];

     return $data;
}

Cela n'a rien à voir avec register_post_type . Vous incitez WordPress à penser qu’il s’agit d’une page enfant d’un autre type de message (page).

    
réponse donnée Bainternet 28.03.2011 - 21:37
0

J'y suis allé avec un marcheur personnalisé pour obtenir quelque chose de similaire ... évite les champs personnalisés, mais toutes les publications d'un type doivent s'asseoir en dessous du même point dans l'arborescence des pages.

class Walker_Page_CustomPostTypeHack extends Walker_Page {
    function walk($elements, $max_depth) {
        $called_with = func_get_args();
        // current page is arg 3... see walk_page_tree for why
        $current_page = $called_with[3];

        // if there's no parent - see if we can find one.
        // some ACF options would be an easy way to make this configurable instad of constants
        if ($current_page === 0) {
            global $wp_query;
            $current_post = $wp_query->get_queried_object();
            switch ($current_post->post_type) {
                case 'course':
                    $current_page = POST_COURSES;
                    break;
                case 'project':
                    $current_page = POST_PROJECTS;
                    break;
                case 'story':
                    $current_page = POST_STORIES;
                    break;
            }
        }

        // now pass on into parent
        $called_with[3] = $current_page;
        return call_user_func_array(array('parent', 'walk'), $called_with);
    }

}
    
réponse donnée benlumley 09.02.2013 - 11:04
0

Clause de non-responsabilité: Après avoir essayé, cela ne semble plus être un problème pour moi, car, du moins pour moi, cela ne fonctionne que sur mon installation de WP 3.9.2. Impossible de trouver un suivi des bogues selon.

J'ai ensemble un petit plugin pour tester cela, ce qui pourrait aider quelqu'un. Mais comme je l’ai dit plus haut, je ne pouvais pas reproduire le problème dans une installation WordPress courante. J'ai séparé le plugin en quatre fichiers, ils vont ensemble dans un répertoire à l'intérieur du répertoire du plugin.

plugin-cpt_menu_hierarchy.php :

<?php
defined( 'ABSPATH' ) OR exit;
/**
 * Plugin Name: CPT Menu Hierarchy Fix?
 * Description: CPT Menu Hierarchy Fix?
 * Author:      ialocin
 * Author URL:  http://wordpress.stackexchange.com/users/22534/ialocin
 * Plugin URL:  http://wordpress.stackexchange.com/q/13308/22534
 */

// registering nonsense post type
include 'include-register_post_type.php';

// adding meta box to nosense custom post type
include 'include-cpt_parent_meta_box.php';

// menu highlighting fix
include 'include-menu_highlighting.php';

include-register_post_type.php :

<?php
defined( 'ABSPATH' ) OR exit;

// See: http://codex.wordpress.org/Function_Reference/register_post_type
add_action( 'init', 'wpse13308_basic_reigister_post_type');
function wpse13308_basic_reigister_post_type() {
    $args = array(
        'public' => true,
        'label'  => 'Nonsense'
    );
    register_post_type( 'nonsense', $args );
}

include-cpt_parent_meta_box.php :

<?php
defined( 'ABSPATH' ) OR exit;

// pretty much like @bainternet's answer

// Add Meta Box
add_action( 'add_meta_boxes', 'nonsense_add_meta_box' );
function nonsense_add_meta_box() {
    add_meta_box(
        'nonsense',
        __( 'Nonsense parent' ),
        'nonsense_inner_meta_box',
        'nonsense'
    );
}

// Meta Box Content
function nonsense_inner_meta_box() {
    global $post;

    wp_nonce_field(
        plugin_basename( __FILE__ ),
        'nonsense_inner_meta_box'
    );
    echo 'Parent Page:&nbsp;&nbsp;';
    $mypages = get_pages();
    echo '<select name="cpt_parent">';
    foreach($mypages as $page){     
        echo '<option value="'.$page->ID.'"';
        if ($page->ID == $post->post_parent) {echo ' selected';}
        echo '>'.$page->post_title.'</option>';
    }
    echo '</select>';
}

// Save Data From Meta Box
add_action( 'wp_insert_post_data', 'nonsense_save_meta_box_data' );
function nonsense_save_meta_box_data( $data, $postarr ) {
    global $post;

    if (
        ! wp_verify_nonce(
            $_POST['nonsense_inner_meta_box'],
            plugin_basename( __FILE__ )
        )
    ) {
        return $data;
    }

    if (
        defined('DOING_AUTOSAVE')
        && DOING_AUTOSAVE
    ) {
        return $data;
    }

    if ( $post->post_type == 'nonsense' ) {
        $data['post_parent'] = $_POST['cpt_parent'];
    }
    return $data;
}

include-menu_highlighting.php :

<?php
defined( 'ABSPATH' ) OR exit;

// altering WordPress' nav menu classes via »nav_menu_css_class« filter
add_filter( 'nav_menu_css_class', 'wpse13308_fix_nav_menu_highlighting', 10, 2 );
function wpse13308_fix_nav_menu_highlighting( $classes, $item ) {
    // data of the current post
    global $post;

    // setting up some data from the current post
    $current_post_post_type = $post->post_type;
    $current_post_parent_id = $post->post_parent;
    // id of the post the current menu item represents
    $current_menu_item_id   = $item->object_id;

    // do this for a certain post type
    if( $current_post_post_type == 'nonsense' ) {
        // remove unwanted highlighting class via array_filter and callback
        // http://php.net/manual/de/function.array-filter.php
        $classes = array_filter(
            $classes,
            'wpse13308_remove_highlighting_classes'
        );
        // when the parents id equals the menu items id, we want to
        // highlight the parent menu item, so we check for:
        if( $current_post_parent_id == $current_menu_item_id ) {
            // use the css class used for highlighting
            $classes[] = 'replace-with-css-class';
        }
    }
    return $classes;
}

// callback to remove highlighting classes
function wpse13308_remove_highlighting_classes( $class ) {
    return
        (
            // use the class(es) you need, overview over nav menu item css classes:
            // http://codex.wordpress.org/Function_Reference/wp_nav_menu#Menu_Item_CSS_Classes
            $class == 'highlight-class'
            // uncomment next line if you want to check for more then one class
            // repeat the line if you want to check for a third, fourth and so on
            // || $class == 'replace-with-css-class'
        ) 
        ? false
        : true
    ;
}


  • Ceci est un exemple de code quelque peu généralisé.
  • Il doit être adapté au cas d'utilisation réel.
réponse donnée Nicolai 26.08.2014 - 13:45
0

Une solution possible consiste à enregistrer le type de message personnalisé à about/team-members de manière programmée à chaque fois que le type de message personnalisé est enregistré.

Voici les étapes:

  1. Vous pouvez utiliser le hook de save_post pour "intercepter" chaque fois que quelqu'un tente de sauvegarder un message.
  2. Si ce message correspond au type de message personnalisé que vous recherchez, continuez.
  3. Assurez-vous de définir le parent de la publication personnalisée sur la page souhaitée (vous pouvez coder en dur l'ID de la page tant que vous ne le supprimez pas). Vous pouvez utiliser wp_update_post pour enregistrer le parent (je n'ai pas essayé cela moi-même, mais je ne vois pas pourquoi ne fonctionne pas).
réponse donnée Shahar Dekel 26.08.2014 - 18:45
0

J'ai eu un peu plus de temps pour approfondir cela moi-même (désolé si j'ai perdu du temps à quiconque), et je me suis dit que pour moi, le meilleur moyen de résoudre le problème de surbrillance serait de refaire ce que _wp_menu_item_classes_by_context() est en train de faire, c'est une itération sur tous les parents et les ancêtres de l'élément de menu qui agit comme le parent de mon type de publication personnalisé et ajoutez les classes de manière appropriée.

Etant donné que je souhaitais également que la page parent de mon type de message personnalisé soit corrigée et facilement modifiable sans devoir mettre à jour tous les messages une fois que le parent a été modifié, j'ai décidé d'utiliser une option au lieu de renseigner le champ post_parent de mon type de poste personnalisé posts. J'utilise ACF pour cela depuis que je l'utilise quand même dans mon thème, mais utiliser la fonctionnalité par défaut de WordPress le ferait bien sûr aussi.

Pour mes besoins, je pourrais utiliser le filtre wp_nav_menu_objects . . De plus, je devais filtrer l'option page_for_posts afin qu'elle soit renvoyée. une valeur faussement / vide, cela évite que la page de publication par défaut ne soit également mise en évidence.

Notez que je ne suis pas allé jusqu'au bout, le filtre n'ajoute que les classes current-menu-ancestor et current-menu-parent , car cela suffisait à mes besoins!

/**
 * Filters the 'page_for_posts' option on specific custom post types in
 * order to avoid the wrong menu item being marked as
 * 'current-page-parent'.
 *
 * @see _wp_menu_item_classes_by_context()
 */
function wpse13308_pre_option_page_for_posts_filter()
{
    $types = array
    (
        'my_custom_post_type_x',
        'my_custom_post_type_y',
        'my_custom_post_type_z'
    );
    if(in_array(get_post_type(), $types))
    {
        return 0;
    }
    return false;
}
add_filter('pre_option_page_for_posts', 'wpse13308_pre_option_page_for_posts_filter');


/**
 * Returns the current posts parent page ID
 *
 * @return int
 */
function wpse13308_get_parent_page_id()
{
    $postType = get_post_type();
    $parentPageId = null;
    switch($postType)
    {
        case 'my_custom_post_type_x':
        case 'my_custom_post_type_y':
        case 'my_custom_post_type_z':
            $parentPageId = (int)get_field('page_for_' . $postType, 'options')->ID;
            break;

        case 'post':
            $parentPageId = (int)get_option('page_for_posts');
            break;
    }
    return $parentPageId;
}

/**
 * Adds proper context based classes so that the parent menu items are
 * being highlighted properly for custom post types and regular posts.
 *
 * @param array $menuItems
 * @return array
 *
 * @see _wp_menu_item_classes_by_context()
 */
function wpse13308_wp_nav_menu_objects_filter(array $menuItems)
{
    $parentPageId = wpse13308_get_parent_page_id();

    if($parentPageId !== null)
    {
        $activeAncestorItemIds = array();
        $activeParentItemIds = array();
        foreach($menuItems as $menuItem)
        {
            if((int)$parentPageId === (int)$menuItem->object_id)
            {
                $ancestorId = (int)$menuItem->db_id;

                while
                (
                    ($ancestorId = (int)get_post_meta($ancestorId, '_menu_item_menu_item_parent', true)) &&
                    !in_array($ancestorId, $activeAncestorItemIds)
                )
                {
                    $activeAncestorItemIds[] = $ancestorId;
                }
                $activeParentItemIds[] = (int)$menuItem->db_id;
            }
        }
        $activeAncestorItemIds = array_filter(array_unique($activeAncestorItemIds));
        $activeParentItemIds = array_filter(array_unique($activeParentItemIds));

        foreach($menuItems as $key => $menuItem)
        {
            $classes = $menuItems[$key]->classes;
            if(in_array(intval($menuItem->db_id), $activeAncestorItemIds))
            {
                $classes[] = 'current-menu-ancestor';
                $menuItems[$key]->current_item_ancestor = true;
            }

            if(in_array($menuItem->db_id, $activeParentItemIds))
            {
                $classes[] = 'current-menu-parent';
                $menuItems[$key]->current_item_parent = true;
            }

            $menuItems[$key]->classes = array_unique($classes);
        }
    }

    return $menuItems;
}
add_filter('wp_nav_menu_objects', 'wpse13308_wp_nav_menu_objects_filter');

Par souci d'exhaustivité, lors de la saisie de post_parent (voir La réponse de @ Bainternet a>) au lieu d'utiliser des options, la récupération de l'ID parent pourrait ressembler à ceci:

/**
 * Returns the current posts parent page ID
 *
 * @return int
 */
function wpse13308_get_parent_page_id()
{
    $parentPageId = null;
    $post = get_post();
    switch($post->post_type)
    {
        case 'my_custom_post_type_x':
        case 'my_custom_post_type_y':
        case 'my_custom_post_type_z':
            $parentPageId = (int)$post->post_parent;
            break;

        case 'post':
            $parentPageId = (int)get_option('page_for_posts');
            break;
    }
    return $parentPageId;
}
    
réponse donnée ndm 26.08.2014 - 17:02
-1
<?php
the_post();

// $postType holds all the information of the post type of the current post you are viewing
$postType = get_post_type_object(get_post_type());

// $postSlug is the slug you defined in the rewrite column: about/team-members
$postSlug = $postType->rewrite['slug'];

// $datas = { [0] => 'about', [1] => 'team-members' }
$datas = explode('/', $postSlug);

// $pageSlug = 'about'
$pageSlug = $datas[0];

// all the page information you require.
$page = get_page_by_path($pageSlug, OBJECT, 'page');
?>

enlace enlace

EDIT 1:

Les pointeurs ne fonctionnant pas:

add_filter('wp_nav_menu_objects', 'my_menu_class_edit');
function my_menu_class_edit($items)
{
    if (is_single()) {
        $postType = get_post_type_object(get_post_type());
        $postSlug = $postType->rewrite['slug'];
        if($postSlug  != 'about/team-members')
            return $items;
        $datas = explode('/', $postSlug);
        $pageAbout = get_page_by_path($datas[0], OBJECT, 'page');
        $pageTeamMembers = get_page_by_path($datas[1], OBJECT, 'page');

        foreach ($items as $item) {
            if ($item->title == $pageAbout->post_title) {
                $item->classes[] = 'current-ancestor';
            } else if ($item->title == $pageTeamMembers->post_title) {
                $item->classes[] = 'current-page';
            }
        }
   }
    return $items;
}
    
réponse donnée aifrim 26.08.2014 - 19:00

Lire d'autres questions sur les étiquettes