Cree una página de archivo personalizada para un tipo de publicación personalizada en un complemento


11

Estoy escribiendo un complemento que crea un tipo de publicación personalizado llamado "my_plugin_lesson":

$args = array (
    'public' => true,
    'has_archive' => true,
    'rewrite' => array('slug' => 'lessons', 'with_front' => false)
);
register_post_type ('my_plugin_lesson', $args);

El tipo de publicación personalizada tiene un archivo, y la URL del archivo es:

http://example.com/lessons

Quiero personalizar el aspecto de este archivo; Quiero enumerar las publicaciones en formato de tabla, en lugar del archivo estándar de publicaciones de blog de WordPress. Entiendo que se puede crear una plantilla de archivo personalizada en el tema haciendo el archive-my_plugin_lesson.phparchivo; Sin embargo, me gustaría que el complemento funcione con cualquier tema.

¿Cómo puedo alterar el contenido de la página de archivo sin agregar o modificar archivos de tema?

Editar: entiendo que podría usar el archive_templategancho de filtro. Sin embargo, todo lo que hace es reemplazar la plantilla del tema, que aún debe ser específica del tema. Por ejemplo, casi todas las plantilla de temas necesitará los get_header, get_sidebary get_footerfunciones, pero lo que si el identificador del contenido de <div>ser? Esto es diferente en cada tema.

Lo que me gustaría hacer es reemplazar el contenido en sí con mi propio contenido y usarlo en lugar de la página de archivo para mi tipo de publicación personalizada.

Respuestas:


12

Lo que necesita es enganchar el template_includefiltro y cargar selectivamente su plantilla dentro del complemento.

Como buena práctica, si planea distribuir su complemento, debe verificar si archive-my_plugin_lesson.php(o tal vez myplugin/archive-lesson.php) existe en el tema, si no utiliza la versión del complemento.

De esta forma, es fácil para los usuarios reemplazar la plantilla a través del tema (o tema secundario) sin editar el código del complemento.

Este es el método utilizado por complementos populares, por ejemplo, WooCommmerce, solo para decir un nombre.

add_filter('template_include', 'lessons_template');

function lessons_template( $template ) {
  if ( is_post_type_archive('my_plugin_lesson') ) {
    $theme_files = array('archive-my_plugin_lesson.php', 'myplugin/archive-lesson.php');
    $exists_in_theme = locate_template($theme_files, false);
    if ( $exists_in_theme != '' ) {
      return $exists_in_theme;
    } else {
      return plugin_dir_path(__FILE__) . 'archive-lesson.php';
    }
  }
  return $template;
}

Más información sobre Codex para


Esto todavía reemplaza el archivo de plantilla del tema, ¿verdad? ¿Qué pongo en el archivo archive-lesson.php de mi plugin? Tendría que ser diferente para trabajar con cada tema. Incluso los temas predeterminados "Veinte" no están de acuerdo en qué contenedores div / section rodean el contenido.
Ben Miller - Recuerda a Mónica el

7

Puede usar el archive_templategancho para procesar el contenido de la plantilla de archivo de un tema, utilizando el esquema a continuación, pero obviamente solo podrá procesar una fracción de los temas, dado que una plantilla puede contener básicamente cualquier cosa antigua. .

El esquema consiste en cargar la plantilla en una cadena ( $tpl_str) en el archive_templatefiltro, sustituir su contenido, incluir la cadena (usando el truco eval( '?>' . $tpl_str );) y luego devolver un archivo en blanco para que includeaparezca "wp-includes / template-loader.php" se convierte en un no-op.

A continuación se muestra una versión pirateada del código que uso en un complemento, que apunta a plantillas "clásicas" que usan get_template_party está más preocupado por el procesamiento de plantillas individuales que por el archivo, pero debería ayudarlo a comenzar. La configuración es que el complemento tiene un subdirectorio llamado "plantillas" que contiene un archivo en blanco ("null.php") y plantillas de contenido (por ejemplo, "content-single-posttype1.php", "content-archive-postype1.php") así como una plantilla alternativa "single.php" para el caso único, y utiliza una versión personalizada de get_template_partese aspecto en este directorio.

define( 'MYPLUGIN_FOLDER', dirname( __FILE__ ) . '/' );
define( 'MYPLUGIN_BASENAME', basename( MYPLUGIN_FOLDER ) );

add_filter( 'single_template', 'myplugin_single_template' );
add_filter( 'archive_template', 'myplugin_archive_template' );

function myplugin_single_template( $template ) {
    static $using_null = array();

    // Adjust with your custom post types.
    $post_types = array( 'posttype1', );

    if ( is_single() || is_archive() ) {
        $template_basename = basename( $template );
        // This check can be removed.
        if ( $template == '' || substr( $template_basename, 0, 4 ) == 'sing' || substr( $template_basename, 0, 4 ) == 'arch' ) {
            $post_type = get_post_type();
            $slug = is_archive() ? 'archive' : 'single';
            if ( in_array( $post_type, $post_types ) ) {
                // Allow user to override.
                if ( $single_template = myplugin_get_template( $slug, $post_type ) ) {
                    $template = $single_template;
                } else {
                    // If haven't gone through all this before...
                    if ( empty( $using_null[$slug][$post_type] ) ) {
                        if ( $template && ( $content_template = myplugin_get_template( 'content-' . $slug, $post_type ) ) ) {
                            $tpl_str = file_get_contents( $template );
                            // You'll have to adjust these regexs to your own case - good luck!
                            if ( preg_match( '/get_template_part\s*\(\s*\'content\'\s*,\s*\'' . $slug . '\'\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE )
                            || preg_match( '/get_template_part\s*\(\s*\'content\'\s*,\s*get_post_format\s*\(\s*\)\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE )
                            || preg_match( '/get_template_part\s*\(\s*\'content\'\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE )
                            || preg_match( '/get_template_part\s*\(\s*\'[^\']+\'\s*,\s*\'' . $slug . '\'\s*\)/', $tpl_str, $matches, PREG_OFFSET_CAPTURE ) ) {
                                $using_null[$slug][$post_type] = true;
                                $tpl_str = substr( $tpl_str, 0, $matches[0][1] ) . 'include \'' . $content_template . '\'' . substr( $tpl_str, $matches[0][1] + strlen( $matches[0][0] ) );
                                // This trick includes the $tpl_str.
                                eval( '?>' . $tpl_str );
                            }
                        }
                    }
                    if ( empty( $using_null[$slug][$post_type] ) ) {
                        // Failed to parse - look for fall back template.
                        if ( file_exists( MYPLUGIN_FOLDER . 'templates/' . $slug . '.php' ) ) {
                            $template = MYPLUGIN_FOLDER . 'templates/' . $slug . '.php';
                        }
                    } else {
                        // Success! "null.php" is just a blank zero-byte file.
                        $template = MYPLUGIN_FOLDER . 'templates/null.php';
                    }
                }
            }
        }
    }
    return $template;
}

function myplugin_archive_template( $template ) {
    return myplugin_single_template( $template );
}

La costumbre get_template_part:

/*
 * Version of WP get_template_part() that looks in theme, then parent theme, and finally in plugin template directory (sub-directory "templates").
 * Also looks initially in "myplugin" sub-directory if any in theme and parent theme directories so that plugin templates can be kept separate.
 */
function myplugin_get_template( $slug, $part = '' ) {
    $template = $slug . ( $part ? '-' . $part : '' ) . '.php';

    $dirs = array();

    if ( is_child_theme() ) {
        $child_dir = get_stylesheet_directory() . '/';
        $dirs[] = $child_dir . MYPLUGIN_BASENAME . '/';
        $dirs[] = $child_dir;
    }

    $template_dir = get_template_directory() . '/';
    $dirs[] = $template_dir . MYPLUGIN_BASENAME . '/';
    $dirs[] = $template_dir;
    $dirs[] = MYPLUGIN_FOLDER . 'templates/';

    foreach ( $dirs as $dir ) {
        if ( file_exists( $dir . $template ) ) {
            return $dir . $template;
        }
    }
    return false;
}

Para completar, aquí está el recurso "single.php", que usa la costumbre get_template_part:

<?php
get_header(); ?>

    <div id="primary" class="content-area">
        <div id="content" class="clearfix">
            <?php while ( have_posts() ) : the_post(); ?>

            <?php if ( $template = myplugin_get_template( 'content-single', get_post_type() ) ) include $template; else get_template_part( 'content', 'single' ); ?>

                <?php
                    // If comments are open or we have at least one comment, load up the comment template
                    if ( comments_open() || '0' != get_comments_number() ) :
                        comments_template();
                    endif;
                ?>

            <?php endwhile; ?>

        </div><!-- #content -->
    </div><!-- #primary -->

<?php get_sidebar(); ?>
<?php get_footer(); ?>

1

He estado reflexionando sobre la misma pregunta, y esta es la solución hipotética que se me ocurrió:

  • Dentro del complemento, cree un código corto que genere su bucle de archivo de la forma que desee.
  • Al crear el tipo de publicación personalizada, no habilite la opción 'archivar'.
  • Agregue una hoja de estilo que controle todos los estilos del contenido de su bucle.

Luego de la activación del complemento, cree una página usando wp_insert_post con el nombre como tipo de publicación y el contenido como código corto.

Puede proporcionar opciones en el código abreviado para consideraciones de estilo adicionales, o agregar clases al contenedor de publicación para que coincidan con los estilos específicos del tema o personalizados. El usuario también puede agregar contenido adicional antes / después del ciclo editando la página.


A pesar de que no soy el OP, estaba buscando una solución al mismo problema. He seguido su solución hipotética y ahora puedo confirmar que también funciona en la práctica.
Lucio Crusca

Hola genial! Me alegro de que esto fuera útil para alguien. Me había olvidado por completo de esto.
SkyShab

0

Puedes usar el filtro single_template. Un ejemplo básico tomado del Codex :

function get_custom_post_type_template($single_template) {
     global $post;

     if ($post->post_type == 'my_post_type') {
          $single_template = dirname( __FILE__ ) . '/post-type-template.php';
     }
     return $single_template;
}

add_filter( "single_template", "get_custom_post_type_template" );

Creo que el enlace de filtro para una plantilla de archivo es archive_template, pero no creo que esto funcione para lo que estoy tratando de hacer. He editado mi pregunta con más información.
Ben Miller - Recuerda a Monica el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.