Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I'm writing a plugin that creates a custom post type named "my_plugin_lesson":

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

The custom post type has an archive, and the URL of the archive is:


I want to customize the look of this archive; I want to list the posts in a table format, rather than the standard WordPress blog post archive. I understand that a custom archive template could be created in the theme by making the archive-my_plugin_lesson.php file; however, I would like the plugin to work with any theme.

How can I alter the content of the archive page without adding or modifying theme files?

Edit: I understand that I could use the archive_template filter hook. However, all this does is replace the theme template, which still needs to be theme-specific. For example, just about every theme template will need the get_header, get_sidebar, and get_footer functions, but what should the id of the content <div> be? This is different in every theme.

What I would like to do is to replace the content itself with my own content, and use that in place of the archive page for my custom post type.

share|improve this question

2 Answers 2

What you need is hooking template_include filter and selectively load your template inside plugin.

As a good practice, if you plan to distribute your plugin, you should check if archive-my_plugin_lesson.php (or maybe myplugin/archive-lesson.php) exists in theme, if not use the plugin version.

In this way is easy for users replace the template via theme (or child theme) without edit the plugin code.

This is the method used by popular plugins, e.g. WooCommmerce, just to say one name.

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;

More info on Codex for

share|improve this answer
This still just replaces the theme's template file, right? What do I put in my plugin's archive-lesson.php file? It would need to be different to work with each theme. Even the default "Twenty" themes do not agree on what div/section containers are that surround the content. –  Ben Miller Sep 29 '13 at 4:35

You can use the filter single_template. A basic example taken 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" );
share|improve this answer
I think the filter hook for an archive template is archive_template, but I don't think this will work for what I am trying to do. I've edited my question with more information. –  Ben Miller Sep 28 '13 at 4:49

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.