définir un CPT en tant que parent d'une page

4

J'ai un type de message personnalisé appelé Event qui est enregistré comme suit:

add_action('init', 'register_custom_post_types');

function register_custom_post_types() {
   $event_capabilities = array(
      'publish_posts' => 'publish_events',
      'edit_posts' => 'edit_events',
      'edit_others_posts' => 'edit_others_event',
      'delete_posts' => 'delete_events',
      'delete_published_posts' => 'delete_published_events',
      'delete_others_posts' => 'delete_others_events',
      'read_private_posts' => 'read_private_events',
      'edit_post' => 'edit_event',
      'delete_post' => 'delete_event',
      'read_post' => 'read_event',
   );
   register_post_type('event',
      array(
        'labels' => array(
            'name' => __( 'Event' )
         ),
        'rewrite' => 'event',
        'public' => true,
        'has_archive' => true,
        'show_ui' => true,
        'menu_position' => 8,
        'capability_type' => array('event', 'events'),
        'capabilities' => $event_capabilities,
        'supports' => array('title', 'thumbnail', 'page-attributes'),
        'map_meta_cap' => true,
        'hierarchical' => true,
      )
   );
}

J'aimerais pouvoir définir un événement en tant que parent d'une page ordinaire. En d'autres termes, j'aimerais que tous mes événements apparaissent dans l'élément Parent select sous le Page Attributes .

J'ai lu de nombreux articles sur la définition d'un CPT en tant qu'enfant d'une page, mais pas l'inverse.

    
posée Cyclonecode 30.09.2015 - 09:21

2 réponses

5

Le défi que nous essayons de relever est comment:

  • ne pas supprimer ni remplacer la méta-boîte d'attribut de page actuelle

  • conservez les informations hiérarchiques dans la liste déroulante.

Nous supposons que nous sommes sur l'écran d'édition d'une seule page et que nous souhaitons ajouter le type de message event post à la liste déroulante page parent .

.

La liste déroulante est affichée à l'aide de la fonction wp_dropdown_pages() , qui appelle la fonction get_pages() . Il ne prend en charge qu'un seul type de message.

Voici deux manières de procéder:

Méthode n ° 1 - Modifier le code SQL

Voici un moyen expérimental, puisqu'il traite des modifications SQL.

Comme il n'y a pas de moyen évident de filtrer la requête SQL générée dans get_pages() , nous pouvons utiliser le filtre général query pour nos besoins.

Pour rendre le menu déroulant plus convivial, lorsqu'il contient des titres provenant de plusieurs types de publication, nous utilisons le filtre list_pages pour ajouter des informations sur le type de publication.

Exemple:

Au lieu d’afficher les options telles que:

"(no parent)"
"About the Music Hall"
    "History"
    "Location"
"Concerts"
    "Of Monsters and Men"
    "Vienna Philharmonic Orchestra"
"Tickets"

nous obtenons:

"(no parent)"
"page - About the Music Hall"
    "page  - History" 
    "page  - Location"
"event - Concerts"
    "event - Of Monsters and Men"
    "event - Vienna Philharmonic Orchestra"
"page - Tickets"

plug-in de démonstration:

Voici l'extrait de code qui pourrait être placé dans un plugin à des fins de test:

/**
 * Add the hierarchical 'event' post type, to the 'page' parent drop-down.
 *
 * @link http://wordpress.stackexchange.com/a/204439/26350
 */ 
is_admin() && add_filter( 'page_attributes_dropdown_pages_args', function( $dropdown_args, $post )
{
     // Only do this for the 'page' post type on the single edit 'page' screen
     if( 'page' === get_current_screen()->id && 'page' === $post->post_type )
     {
        // Modify the options' titles
        add_filter( 'list_pages', 'wpse_add_post_type_info_in_options', 10, 2 );

        // Modify the get_pages() query
        add_filter( 'query', function( $sql )
        {
            // Only run this once
            if( ! did_action( 'wpse_change_cpt' ) )
            {
                do_action( 'wpse_change_cpt' );

                // Adjust the post type part of the query - add the 'event' post type
                $sql = str_replace( 
                    "post_type = 'page' ", 
                    "post_type IN ( 'event', 'page' ) ", 
                    $sql 
                );
            }
            return $sql;
        } );
    }
    return $dropdown_args;
}, 10, 2 );

où:

function wpse_add_post_type_info_in_options ( $title, $page )
{
    return $page->post_type . ' - ' . $title;
}

et un peu de nettoyage:

add_filter( 'wp_dropdown_pages', function( $output )
{
    if( did_action( 'wpse_change_cpt' ) )
        remove_filter( 'list_pages', 'wpse_add_post_type_info_in_options', 10, 2 );

    return $output;
} );

Méthode n ° 2 - N'utilisez que wp_dropdown_pages()

Ici, nous laissons exécuter wp_dropdown_pages() deux fois, puis nous le fusionnons en un seul menu déroulant; une fois pour le type de message page et de nouveau pour le type de message event :

/**
 * Add the hierarchical 'event' post type, to the 'page' parent drop-down.
 *
 * @link http://wordpress.stackexchange.com/a/204439/26350
 */ 
is_admin() && add_filter( 'page_attributes_dropdown_pages_args', 'wpse_attributes', 99, 2 );

function wpse_attributes( $dropdown_args, $post )
{
    // Run this filter callback only once
    remove_filter( current_filter(), __FUNCTION__, 99 );

    // Only do this for the 'page' post type on the edit page screen
    if( 'page' === get_current_screen()->id && 'page' === $post->post_type )
    {
        // Modify the input arguments, for the 'event' drop-down
        $modified_args = $dropdown_args;
        $modified_args['post_type'] = 'page';
        $modified_args['show_option_no_change'] = __( '=== Select Events here below: ===' );            
        $modified_args['show_option_none'] = false;

        // Add the 'event' drop-down
        add_filter( 'wp_dropdown_pages', function( $output ) use ( $modified_args )
        {
            // Only run it once
            if( ! did_action( 'wpse_dropdown' ) )
            {
                do_action( 'wpse_dropdown' );

                // Create our second drop-down for events
                $output .= wp_dropdown_pages( $modified_args );

                // Adjust the output, so we only got a single drop-down
                $output = str_replace( 
                    [ "<select name='parent_id' id='parent_id'>", "</select>"],
                    '', 
                    $output 
                );
                $output = "<select name='parent_id' id='parent_id'>" . $output . "</select>";
            }
            return $output;
        } );
    }
    return $dropdown_args;
}

Ici, les deux listes déroulantes hiérarchiques sont séparées par l’option vide === Sélectionnez Événements ci-dessous: === .

Exemple:

"(no parent)"
"About the Music Hall"
    "History"
    "Location"
"Tickets"
"=== Select Events here below: ==="
"Concerts"
    "Of Monsters and Men"
    "Vienna Philharmonic Orchestra"

Réglage de la requête principale

Supposons maintenant que nous créons une page intitulée Of Monsters And Men - Info avec le omam-info slug et sélectionnons l'événement Of Monsters And Men en tant que parent, avec le omam slug.

Ensuite, le chemin serait

example.tld/omam/omam-info

mais cela donne une erreur 404. La raison en est que la vérification get_page_path() dans la classe \WP_Query , pour la requête principale, échoue:

if ( '' != $qv['pagename'] ) {
    $this->queried_object = get_page_by_path($qv['pagename']);
    if ( !empty($this->queried_object) )
        $this->queried_object_id = (int) $this->queried_object->ID;
    else
        unset($this->queried_object);

Cela est dû au fait qu'ici, get_page_by_path() ne vérifie que les types page et attachment post, et non le type event post. Malheureusement, il n'y a pas de filtre explicite pour changer cela.

Nous pourrions bien sûr utiliser le filtre query , comme nous l'avons fait ci-dessus, mais essayons une autre solution de contournement.

Nous pouvons essayer d'ajuster les propriétés non attribuées queried_object_id et queried_object_id de l'objet \WP_Query avec:

/**
 * Support for page slugs with any kind event parent hierarchy
 *
 * @link http://wordpress.stackexchange.com/a/204439/26350
 */
add_action( 'pre_get_posts', function( \WP_Query $q )
{
    if( 
            ! is_admin()               // Front-end only
        &&  $q->is_main_query()        // Target the main query
        &&  $q->get( 'pagename' )      // Check for pagename query variable
        &&  ! $q->get( 'post_type' )   // Target the 'page' post type
        && $page = get_page_by_path( $q->get( 'pagename' ), OBJECT, [ 'page', 'event', 'attachment' ] ) 
    ) {
        if( is_a( $page, '\WP_Post' ) )
        {                
            $q->queried_object_id = $page->ID;
            $q->queried_object = $page;
        }
    }
} );

Cela devrait également prendre en charge un nombre quelconque de parents d'événements, comme la hiérarchie suivante:

ecample.tld/event-grandparent/event-parent/event-child/page-slug

Remarque

Pour les menus déroulants parents de l'écran edit.php , nous pourrions utiliser le filtre quick_edit_dropdown_pages_args , au lieu du filtre page_attributes_dropdown_pages_args que nous avons utilisé ci-dessus.

    
réponse donnée birgire 02.10.2015 - 23:21
1

Premièrement, vous devez supprimer la méta-boîte Attributs de page , puis ajouter la vôtre tout en conservant tout intact, à l'exception de la modification du type de publication parent. Voici mes codes, modifiés pour fonctionner avec votre type de message events post. J'ai essayé de le faire copier / coller, mais si vous rencontrez des erreurs, merci de me le faire savoir.

/* Remove the core Page Attribute Metabox */
function event_remove_pa_meta_boxes() {
  remove_meta_box( 'pageparentdiv', 'page', 'side' );
}
add_action( 'do_meta_boxes', 'event_remove_pa_meta_boxes' );

/* Set the Page Attribute Metabox again*/
function events_pa_meta_box( $post ) {

    add_meta_box(
        'event-select',
        __( 'Page Attributes', 'textdomain' ),
        'events_selectors_box',
        'page',
        'side',
        'core'
    );
}
add_action( 'add_meta_boxes_page', 'events_pa_meta_box' );

/* Recreate the meta box. */
function events_selectors_box( $post ) {

    /* Set Events as Post Parent */
    $parents = get_posts(
        array(
            'post_type'   => 'event', 
            'orderby'     => 'title', 
            'order'       => 'ASC', 
            'numberposts' => -1 
        )
    );

    echo '<p><strong>Parent</strong></p><label class="screen-reader-text" for="parent_id">Parent</label>';
    if ( !empty( $parents ) ) {

        echo '<select id="parent_id" name="parent_id">';

        foreach ( $parents as $parent ) {
            printf( '<option value="%s"%s>%s</option>', esc_attr( $parent->ID ), selected( $parent->ID, $post->post_parent, false ), esc_html( $parent->post_title ) );
        }

        echo '</select>';

    } else {

        echo '<p>Please <a href="' . admin_url( "post-new.php?post_type=event" ) . '">create an event first</a>.</p>';

    }

    /* Page Templates */

    if ( 'page' == $post->post_type && 0 != count( get_page_templates( $post ) ) && get_option( 'page_for_posts' ) != $post->ID ) {

        $template = !empty($post->page_template) ? $post->page_template : false;

        echo '<p><strong>Template</strong></p><label class="screen-reader-text" for="page_template">Page Template</label>';

        echo '<select id="page_template" name="page_template">';

        $default_title = apply_filters( 'default_page_template_title',  __( 'Default Template' ), 'meta-box' );

        echo '<option value="default">' . esc_html( $default_title ) . '</option>'      

            page_template_dropdown($template);

        echo '</select>';

    }

    /* Page Order */
    echo '<p><strong>' . _e('Order') .'</strong></p>';

    echo '<label class="screen-reader-text" for="menu_order">'. _e('Order') . '</label><input name="menu_order" type="text" size="4" id="menu_order" value="'. esc_attr($post->menu_order) .'" />';

    /* Help Paragraph */
    if ( 'page' == $post->post_type && get_current_screen()->get_help_tabs() ) { ?>
        echo '<p>' . _e( 'Need help? Use the Help tab in the upper right of your screen.' ) . '</p>';
    }
}  

MODIFIER: Je viens de remarquer qu’il existe un filtre pour modifier les arguments par défaut dans la méta-boîte de l’attribut de page:

$dropdown_args = array(
    'post_type'        => $post->post_type,
    'exclude_tree'     => $post->ID,
    'selected'         => $post->post_parent,
    'name'             => 'parent_id',
    'show_option_none' => __('(no parent)'),
    'sort_column'      => 'menu_order, post_title',
    'echo'             => 0,
);

$dropdown_args = apply_filters( 'page_attributes_dropdown_pages_args', $dropdown_args, $post );  

Il pourrait donc exister un moyen très facile de faire ce que vous voulez.

    
réponse donnée Abhik 03.10.2015 - 13:03

Lire d'autres questions sur les étiquettes