So, I'm in the process of writing a plugin for a specific site.

I understand WordPress picks the page template from the theme, with php script names according to the chart below. However, I'd like to write a script for my plugin and have WordPress include my script when it searches for the page template.

I know this is typically the job of the theme. I also know child themes are used to override this behavior. Is this something plugins can do as well?

WordPress Template Page Hierarchy

  • Is the template for a page and you want it to appear as an option in the dropdown, or is it a template for a custom post type? The following question and answer may help: wordpress.stackexchange.com/questions/17385/… Jan 25 '19 at 20:39
  • It's for a post type for a number of posts vs. a single / selectable page template.
    – Codesmith
    Jan 25 '19 at 23:26

WordPress has a template_include filter which you can use.

// Add a filter to 'template_include' hook
add_filter( 'template_include', 'wpse_force_template' );
function wpse_force_template( $template ) {
    // If the current url is an archive of any kind
    if( is_archive() ) {
        // Set this to the template file inside your plugin folder
        $template = WP_PLUGIN_DIR .'/'. plugin_basename( dirname(__FILE__) ) .'/archive.php';
    // Always return, even if we didn't change anything
    return $template;

It would be wise to allow your users to decide which archives are affected. Many sites have custom post types and may not want those archives affected like other post types. You can add an options page that dynamically pulls all post types on the current site and allows them to toggle your plugin on or off for each. Once you have that, you'll need to again dynamically pull all post types, and then dynamically build "if" statements for each one. For example, if(is_archive('event') && $eventtoggle == true - if it's an archive of this specific type and the user toggled the plugin on for this specific type.

  • 1
    There’s also an archive_template filter that only runs on archive requests.
    – Milo
    Jan 29 '19 at 23:24

In addition to the correct answer above, let's say you have a custom post type called "links".

WordPress automatically requests an archive called "archive-links.php". Either in your plugin or in your theme, plus the page for the single instance of an CPT entry.

// Template Logic
function cc_links_init_template_logic($original_template) {
    // Check Theme Template or Plugin Template for archive-links.php

    $file = trailingslashit(get_template_directory()) . 'archive-links.php';

    if(is_post_type_archive('links')) {
    // some additional logic goes here^.
        if(file_exists($file)) {
            return trailingslashit(get_template_directory()).'archive-links.php';
        } else {
            return plugin_dir_path(__DIR__) . 'templates/archive-links.php';
    } elseif(is_singular('links')) {
        if(file_exists(get_template_directory_uri() . '/single-links.php')) {
            return get_template_directory_uri() . '/single-links.php';
        } else {
            return plugin_dir_path(__DIR__) . 'templates/single-links.php';

    return $original_template;
add_action('template_include', 'cc_links_init_template_logic');
//add_filter( 'archive_template', 'get_custom_post_type_template' ) ;
add_filter('archive_template', 'yourplugin_get_custom_archive_template');
function yourplugin_get_custom_archive_template($template) {
    global $wp_query;
    if (is_post_type_archive('articles')) {
        $templates[] = 'archive-articles.php';
        $template = yourplugin_locate_plugin_template($templates);
    return $template;
function yourplugin_locate_plugin_template($template_names, $load = false, $require_once = true) {
    if (!is_array($template_names)) {
        return '';
    $located = '';
    $this_plugin_dir = WP_PLUGIN_DIR . '/' . str_replace(basename(__FILE__), "", plugin_basename(__FILE__));
    foreach ($template_names as $template_name) {
        if (!$template_name) continue;
        if (file_exists(STYLESHEETPATH . '/' . $template_name)) {
            $located = STYLESHEETPATH . '/' . $template_name;
        } elseif (file_exists(TEMPLATEPATH . '/' . $template_name)) {
            $located = TEMPLATEPATH . '/' . $template_name;
        } elseif (file_exists($this_plugin_dir . '/templates/' . $template_name)) {
            $located = $this_plugin_dir . '/templates/' . $template_name;
    if ($load && $located != '') {
        load_template($located, $require_once);
    return $located;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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