Tipos de publicaciones personalizadas anidadas con enlaces permanentes

9

Estoy tratando de configurar una estructura de tipo de publicación personalizada de varios niveles con enlaces permanentes parecidos authors/books/chapters, con autores, libros y capítulos configurados como su propio tipo de publicación personalizada. Por ejemplo, una URL típica en este sitio podría verse asíexample.com/authors/stephen-king/the-shining/chapter-3/

Cada capítulo solo puede pertenecer a un libro, y cada libro solo puede pertenecer a un autor. He considerado utilizar taxonomías en lugar de CPT para autores y libros, pero necesito asociar metadatos con cada elemento y prefiero la interfaz de publicación para esto.

Llegué a la mayor parte del camino simplemente configurando cada publicación personalizada como elemento secundario de una entrada en el nivel superior de CPT. Por ejemplo, creo el "Capítulo 3" y asigno "The Shining" como padre utilizando un meta-cuadro personalizado. "The Shining" a su vez tiene a "Stephen King" como padre. No he tenido ningún problema para crear estas relaciones.

Estoy usando etiquetas de reescritura en las fichas de CPT y los enlaces permanentes quieren funcionar, pero no son del todo correctos. Utilizando un analizador de reescritura, puedo ver que las reglas de reescritura se generan realmente, pero no parecen estar en el orden correcto, por lo que otras reglas se procesan primero.

Aquí hay una captura de pantalla de mi analizador de reescritura.

Así es como he registrado mis CPT:

function cpt_init() {

  $labels = array(
    'name' => 'Authors'
   );

  $args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true, 
    'show_in_menu' => true, 
    'query_var' => true,
    'rewrite' => array(
        'slug' => 'author',
        'with_front' => FALSE,
    ),
    'with_front' => false,
    'capability_type' => 'post',
    'has_archive' => false, 
    'hierarchical' => true,
    'menu_position' => null,
    'supports' => array( 'title', 'editor' )
  ); 

  register_post_type('authors',$args);

  $labels = array(
    'name' => 'Books'
  );

  $args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true, 
    'show_in_menu' => true, 
    'query_var' => true,
    'rewrite' => array(
        'slug' => 'author/%authors%',
        'with_front' => FALSE,
    ),
    'with_front' => false,
    'capability_type' => 'post',
    'has_archive' => false, 
    'hierarchical' => true,
    'menu_position' => null,
    'supports' => array( 'title', 'editor' )
  ); 

  register_post_type('books',$args);


  $labels = array(
    'name' => 'Chapters'
   );

  $args = array(
    'labels' => $labels,
    'public' => true,
    'publicly_queryable' => true,
    'show_ui' => true, 
    'show_in_menu' => true, 
    'query_var' => true,
    'rewrite' => array(
        'slug' => 'author/%authors%/%books%',
        'with_front' => FALSE,
    ),
    'with_front' => FALSE,
    'capability_type' => 'post',
    'has_archive' => false, 
    'hierarchical' => true,
    'menu_position' => null,
    'supports' => array( 'title', 'editor' )
  ); 

  register_post_type('chapters',$args);

}

add_action( 'init', 'cpt_init' );

Entonces, ¿hay alguna manera de cambiar la prioridad de mis reglas de reescritura para que los autores, los libros y los capítulos coincidan primero?

También sé que voy a tener que agregar un post_type_linkfiltro, pero eso parece secundario para obtener los enlaces permanentes en primer lugar. Si alguien sabe dónde puedo encontrar una descripción completa de cómo funciona ese filtro, se lo agradecería.

Dalton
fuente
¿Has considerado simplemente usar Pages? Obtendría la estructura de enlace permanente correcta automáticamente.
Michael Hampton
Definitivamente lo he considerado. El problema con las páginas es que podemos tener 100 elementos de nietos para un solo autor, lo que será muy difícil de administrar en las páginas de administración. Además, debemos poder realizar consultas por tipo de publicación.
Dalton
Estoy trabajando en una solución pero tengo una pregunta rápida: ¿es clave tener 'autor' delante de cada enlace permanente? Porque ese parece ser el fanático. Creo que es demasiado confuso WordPress, especialmente porque es una babosa de enlace permanente que también se usa para las páginas de autor de WP. Si se requiere tener 'autor', creo que todo esto aún es factible ... será más complicado.
Rachel Carden
Vaya, no me di cuenta de que el autor entraría en conflicto con la babosa de autor WP incorporada. No, eso no es obligatorio, podría ser cualquier cosa. Asumí que necesitaba algo allí porque es un CPT, pero podría ser fácilmente "escritores" o cualquier otra cosa.
Dalton
Me di cuenta de que la confusión en realidad radica en que los CPT comparten 'autor' como la babosa base. Una vez que establezca 'author' como el slug para los 'autores' de CPT, y luego configure 'author /% author%' para los 'libros' de CPT y 'author /% author% /% book%' para los capítulos de CPT ' ', entonces WordPress piensa que las publicaciones para' libros 'y las publicaciones para' capítulos 'son literalmente publicaciones secundarias jerárquicas para' autores '. ¿Tiene sentido? En mis pruebas, podría mantener 'autor' como base para los 'autores' de CPT y funciona bien. Entonces, reemplace mi pregunta anterior con: ¿necesita 'autor' o la babosa puede comenzar con% author%?
Rachel Carden

Respuestas:

11

Si desea mantener "autores" como la babosa de base en los enlaces permanentes, es decir example.com/authors/stephen-king/ para el CPT de "autores", example.com/authors/stephen-king/the-shining/ para el 'libros' CPT y example.com/authors/stephen-king/the-shining/chapter-3/ para los 'capítulos' CPT, WordPress pensará que casi todo es una publicación de 'autores' o un hijo jerárquico de 'autores' 'publicar y, dado que ese no es el caso, WordPress finalmente se vuelve muy confundido.

Dicho esto, hay una solución alternativa que es bastante básica, pero siempre que su estructura de enlace permanente siempre siga el mismo orden, es decir, la palabra 'autores' siempre es seguida por una babosa de autor, que siempre es seguida por una babosa de libro que siempre se sigue por una babosa de capítulo, entonces deberías estar listo.

En esta solución, no es necesario definir el slug de reescritura en la definición de tipo de publicación personalizada para 'capítulos' y 'libros', sino establecer el slug de reescritura de 'autores' como simplemente 'autores', colocar el siguiente código en sus funciones.php archivar y "vaciar" sus reglas de reescritura.

add_action( 'init', 'my_website_add_rewrite_tag' );
function my_website_add_rewrite_tag() {
    // defines the rewrite structure for 'chapters', needs to go first because the structure is longer
    // says that if the URL matches this rule, then it should display the 'chapters' post whose post name matches the last slug set
    add_rewrite_rule( '^authors/([^/]*)/([^/]*)/([^/]*)/?','index.php?chapters=$matches[3]','top' );
    // defines the rewrite structure for 'books'
    // says that if the URL matches this rule, then it should display the 'books' post whose post name matches the last slug set
    add_rewrite_rule( '^authors/([^/]*)/([^/]*)/?','index.php?books=$matches[2]','top' );   
}

// this filter runs whenever WordPress requests a post permalink, i.e. get_permalink(), etc.
// we will return our custom permalink for 'books' and 'chapters'. 'authors' is already good to go since we defined its rewrite slug in the CPT definition.
add_filter( 'post_type_link', 'my_website_filter_post_type_link', 1, 4 );
function my_website_filter_post_type_link( $post_link, $post, $leavename, $sample ) {
    switch( $post->post_type ) {

        case 'books':

            // I spoke with Dalton and he is using the CPT-onomies plugin to relate his custom post types so for this example, we are retrieving CPT-onomy information. this code can obviously be tweaked with whatever it takes to retrieve the desired information.
            // we need to find the author the book belongs to. using array_shift() makes sure only one author is allowed
            if ( $author = array_shift( wp_get_object_terms( $post->ID, 'authors' ) ) ) {
                if ( isset( $author->slug ) ) {
                    // create the new permalink
                    $post_link = home_url( user_trailingslashit( 'authors/' . $author->slug . '/' . $post->post_name ) );
                }
            }

            break;

        case 'chapters':

            // I spoke with Dalton and he is using the CPT-onomies plugin to relate his custom post types so for this example, we are retrieving CPT-onomy information. this code can obviously be tweaked with whatever it takes to retrieve the desired information.
            // we need to find the book it belongs to. using array_shift() makes sure only one book is allowed
            if ( $book = array_shift( wp_get_object_terms( $post->ID, 'books' ) ) ) {

                // now to find the author the book belongs to. using array_shift() makes sure only one author is allowed
                $author = array_shift( wp_get_object_terms( $book->term_id, 'authors' ) );

                if ( isset( $book->slug ) && $author && isset( $author->slug ) ) {
                    // create the new permalink
                    $post_link = home_url( user_trailingslashit( 'authors/' . $author->slug . '/' . $book->slug . '/' . $post->post_name ) );
                }

            }

            break;

    }
    return $post_link;
}

Obtenga más información sobre el complemento CPT-onomies

Rachel Carden
fuente
Esto funciona perfectamente, gracias! Siento que acabo de aprender mucho. El complemento CPT-onomies también es realmente genial. wordpress.org/extend/plugins/cpt-onomies
Dalton
Tengo la sensación de que puede encontrar algunos obstáculos a medida que crece su "biblioteca", pero ya tengo un código en mente, así que, si lo hace, hágamelo saber.
Rachel Carden
@RachelCarden ¿Qué haces cuando dos libros tienen el mismo título pero diferentes autores? ¡Habrá una colisión en la URL reescrita! ¿Cómo resuelves esto?
Segfault
1
@Segfault Deberá recuperar todas las babosas de autor para poder codificarlas en las reglas de reescritura: foreach ($ author_slugs como $ author_slug) {add_rewrite_rule ('^ autores /'. $ Author_slug. '/ ([ ^ /] *) / ([^ /] *) /? ',' index.php? autores = '. $ author_slug.' & chapters = $ coincide [2] ',' top '); add_rewrite_rule ('^ autores /'. $ author_slug. '/([^/font>*)/?','index.php?authors='. $ author_slug. '& books = $ coincide [1]', 'arriba') ; }
Rachel Carden
@Segfault Puede usar get_terms () , si está utilizando una CPT-onomy, o get_posts () para recuperar los nombres de publicaciones / babosas.
Rachel Carden
4

No tengo experiencia personal con tal escenario, pero Randy Hoyt hizo una presentación en WordCamp San Fran el pasado fin de semana sobre "Tipos de publicaciones subordinadas" que suena como de lo que estás hablando.

Aquí está su página para la charla que incluye sus diapositivas de presentación y enlaces a un complemento que creó para trabajar con tipos de publicaciones subordinadas: http://randyhoyt.com/wordpress/subordinate-post-types/

mannieschumpert
fuente
Gracias, esto parece un buen recurso. Sin embargo, no está claro si esto es compatible con las relaciones de los nietos (no lo parece en mis pruebas) y en realidad no ayuda con los enlaces permanentes. Ya he descubierto una manera de establecer las relaciones entre mi hijo / padre (aunque esta es una buena manera de hacerlo), pero los enlaces permanentes son realmente el problema en el que estoy atrapado ahora.
Dalton
1

Las reglas se agregarán a extra_rules_top de WP_Rewrite en el orden en que se agregan las permastructs adicionales. Por lo tanto, cambiar el orden en que registra los tipos de publicación cambiará el orden de las reglas de reescritura que se generan, haciendo que la reescritura del capítulo coincida primero. Sin embargo, dado que está utilizando query_var de los otros post_types, wp_query puede terminar coincidiendo con uno de esos como el nombre de la publicación consultada antes de coincidir con el capítulo que desee.

Crearía nuevas etiquetas de reescritura para representar los marcadores de posición para el autor principal y el libro principal, es decir:

add_rewrite_tag('%parent-book%', '([^/]+)', 'parent_book=');

Al hacer esto, tendrá que filtrar 'query_vars' para hacer público 'parent_book'. Luego, deberá agregar un filtro a pre_get_posts que convertirá el nombre establecido como parent_book query_var en post_id y lo establecerá como 'post_parent'.

prettyboymp
fuente
¿Podría proporcionar ejemplos de código para los filtros que mencionó? Además, ¿cómo sería la etiqueta de reescritura para el nieto CPT?
Dalton