为插件中的自定义帖子类型创建自定义存档页面

时间:2013-09-27 作者:Ben Miller - Remember Monica

我正在编写一个插件,创建一个名为“my\\u plugin\\u lesson”的自定义帖子类型:

$args = array (
    \'public\' => true,
    \'has_archive\' => true,
    \'rewrite\' => array(\'slug\' => \'lessons\', \'with_front\' => false)
);
register_post_type (\'my_plugin_lesson\', $args);
自定义帖子类型具有存档,存档的URL为:

http://example.com/lessons

我想自定义此存档的外观;我想以表格格式列出帖子,而不是标准的WordPress博客帖子存档。我知道,可以通过使archive-my_plugin_lesson.php 文件然而,我希望插件可以与任何主题一起使用。

如何在不添加或修改主题文件的情况下更改存档页的内容?

Edit:我知道我可以使用archive_template 过滤器挂钩。然而,所有这些只是替换主题模板,它仍然需要特定于主题。例如,几乎每个主题模板都需要get_header, get_sidebar, 和get_footer 函数,但内容的id应该是什么<div> 是这在每个主题上都是不同的。

我想做的是将内容本身替换为我自己的内容,并将其替换为我自定义帖子类型的存档页面。

4 个回复
SO网友:gmazzap

你需要的是挂钩template_include 过滤并有选择地将模板加载到插件中。

作为一个良好的实践,如果您计划分发插件,您应该检查archive-my_plugin_lesson.php (或者可能myplugin/archive-lesson.php) 存在于主题中,如果不存在,请使用插件版本。

这样,用户就可以轻松地通过主题(或子主题)替换模板,而无需编辑插件代码。

这是流行插件(例如WooCommmerce)使用的方法,只需说出一个名称即可。

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;
}
有关Codex的更多信息

SO网友:bonger

您可以使用archive_template 通过使用下面的方案,钩子来处理主题归档模板的内容,但很明显,由于模板基本上可以包含任何旧内容,因此您只能处理一小部分主题。

方案是将模板加载到字符串中($tpl_str) 在archive_template 过滤、替换内容、包括字符串(使用技巧eval( \'?>\' . $tpl_str );), 然后返回一个空白文件,以便include 在“wp-includes/template-loader.php”中,变成了一个no-op。

下面是我在插件中使用的代码的黑客版本,其目标是使用get_template_part 与归档相比,它更关心的是处理单个模板,但应该可以帮助您开始。设置是,插件有一个名为“templates”的子目录,其中包含一个空白文件(“null.php”)和内容模板(例如“content-single-posttype1.php”、“content-archive-posttype1.php”)以及用于单个案例的回退模板“single.php”,并使用get_template_part 在该目录中查找的。

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 );
}
海关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;
}
为了完整起见,这里有一个后备的“single.php”,它使用自定义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(); ?>

SO网友:SkyShab

我一直在思考同一个问题,这是我提出的假设性解决方案:

在插件中,创建一个快捷码,以您想要的方式输出归档循环插件激活后,使用wp\\u insert\\u post创建一个页面,名称为帖子类型,内容为短代码。

您可以在快捷码中提供选项以考虑其他样式,也可以向帖子容器中添加类以匹配特定主题或自定义样式。用户还可以通过编辑页面在循环之前/之后添加其他内容。

SO网友:Eyal

您可以使用过滤器single_template. 所举的基本示例from the 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" );

结束
为插件中的自定义帖子类型创建自定义存档页面 - 小码农CODE - 行之有效找到问题解决它

为插件中的自定义帖子类型创建自定义存档页面

时间:2013-09-27 作者:Ben Miller - Remember Monica

我正在编写一个插件,创建一个名为“my\\u plugin\\u lesson”的自定义帖子类型:

$args = array (
    \'public\' => true,
    \'has_archive\' => true,
    \'rewrite\' => array(\'slug\' => \'lessons\', \'with_front\' => false)
);
register_post_type (\'my_plugin_lesson\', $args);
自定义帖子类型具有存档,存档的URL为:

http://example.com/lessons

我想自定义此存档的外观;我想以表格格式列出帖子,而不是标准的WordPress博客帖子存档。我知道,可以通过使archive-my_plugin_lesson.php 文件然而,我希望插件可以与任何主题一起使用。

如何在不添加或修改主题文件的情况下更改存档页的内容?

Edit:我知道我可以使用archive_template 过滤器挂钩。然而,所有这些只是替换主题模板,它仍然需要特定于主题。例如,几乎每个主题模板都需要get_header, get_sidebar, 和get_footer 函数,但内容的id应该是什么<div> 是这在每个主题上都是不同的。

我想做的是将内容本身替换为我自己的内容,并将其替换为我自定义帖子类型的存档页面。

4 个回复
SO网友:gmazzap

你需要的是挂钩template_include 过滤并有选择地将模板加载到插件中。

作为一个良好的实践,如果您计划分发插件,您应该检查archive-my_plugin_lesson.php (或者可能myplugin/archive-lesson.php) 存在于主题中,如果不存在,请使用插件版本。

这样,用户就可以轻松地通过主题(或子主题)替换模板,而无需编辑插件代码。

这是流行插件(例如WooCommmerce)使用的方法,只需说出一个名称即可。

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;
}
有关Codex的更多信息

SO网友:bonger

您可以使用archive_template 通过使用下面的方案,钩子来处理主题归档模板的内容,但很明显,由于模板基本上可以包含任何旧内容,因此您只能处理一小部分主题。

方案是将模板加载到字符串中($tpl_str) 在archive_template 过滤、替换内容、包括字符串(使用技巧eval( \'?>\' . $tpl_str );), 然后返回一个空白文件,以便include 在“wp-includes/template-loader.php”中,变成了一个no-op。

下面是我在插件中使用的代码的黑客版本,其目标是使用get_template_part 与归档相比,它更关心的是处理单个模板,但应该可以帮助您开始。设置是,插件有一个名为“templates”的子目录,其中包含一个空白文件(“null.php”)和内容模板(例如“content-single-posttype1.php”、“content-archive-posttype1.php”)以及用于单个案例的回退模板“single.php”,并使用get_template_part 在该目录中查找的。

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 );
}
海关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;
}
为了完整起见,这里有一个后备的“single.php”,它使用自定义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(); ?>

SO网友:SkyShab

我一直在思考同一个问题,这是我提出的假设性解决方案:

在插件中,创建一个快捷码,以您想要的方式输出归档循环插件激活后,使用wp\\u insert\\u post创建一个页面,名称为帖子类型,内容为短代码。

您可以在快捷码中提供选项以考虑其他样式,也可以向帖子容器中添加类以匹配特定主题或自定义样式。用户还可以通过编辑页面在循环之前/之后添加其他内容。

SO网友:Eyal

您可以使用过滤器single_template. 所举的基本示例from the 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" );