Home>Support>Custom locate_template function

Custom locate_template function

Right now the post_loop widget uses the following to look for loop template files in inc/widgets/post-loop-helper.php on line 18

$headers = get_file_data( locate_template( $template ), array(
    'loop_name' => 'Loop Name',
) );

This does not allow the use of plugins to extend the post loop widget because the people who work on core have been arguing about adding a filter for 8 years https://core.trac.wordpress.org/ticket/13239

where as simply adding a filter in core could solve the issue on wp-includes/template.php line 643ish

$located = apply_filters( 'locate_template', $template_names );

I do not think that is going to happen anytime soon. I request a change to this code!

WooCommerce uses it’s own wc_get_template function to do this and handles this type of thing rather well.
You could add a try catch there, because get_file_data will fail if locate_template is blank.

Or maybe something like

$template_options = array();
if( ! empty( $templates ) ) {
    foreach( $templates as $template ) {
        $located_template = locate_template( $template );
        $located_template = apply_filters( 'siteorigin_panels_postloop_locate_templates', $located_template, $template );
        if( $located_template ){
            $headers = get_file_data( $located_template , array(
                'loop_name' => 'Loop Name',
            ) );
            $template_options[ $template ] = esc_html( ! empty( $headers['loop_name'] ) ? $headers['loop_name'] : $template );
        }
    }
}

So that developers can do fun things! Here is an example of the fun things I just did with this code

function custom_post_loop_templates($templates) {
    $templates[] = 'templates/loop-list.php';
    return $templates;
}

add_filter( 'siteorigin_panels_postloop_templates', 'custom_post_loop_templates' );
function locate_template($located, $template_name){
    if('templates/loop-list.php' === $template_name){
        $located = MY_PLUGIN_DIR.'/'.$template_name;
    }
    return $located;
}

add_filter( 'siteorigin_panels_postloop_locate_templates', 'locate_loop_template', 10, 2 );

This is our free support forum. Replies can take several days. If you need fast email support, please purchase a SiteOrigin Premium license.

  1. 6 years, 8 months ago Alex S
    Hi, I Work Here

    Hi Adrock42,

    Interesting idea. One question though, is there a benefit to this method over siteorigin_panels_postloop_templates? Based on your outlined example it looks like you’re swapping over the templates that are present in the theme already. Those templates are actually only present if your theme adds them as we don’t include any default post loop templates.

  2. 6 years, 8 months ago Adrock42

    This allows templates to be in a plugin, or anywhere you like, in the same way that WooCommerce allows that kind of thing. Unless I’m missing that in the documentation somewhere

  3. 6 years, 8 months ago Adrock42

    Also, the way it is currently written, an error is generated in the PHP error log displaying an error for fOpen. get_file_data() should not be run unless you have that first variable. When the error is thrown, it would be nice to have a proper error like “That template wasn’t found”.

  4. 6 years, 8 months ago Alex S
    Hi, I Work Here

    Hi Adrock42,

    Everything above the siteorigin_panels_postloop_templates filter is purely for automatically finding templates. The filter itself allows you to manually exclude and include any file if desired. So it should be able to do what you’re after. Can you please try it? I’m more than happy to log this as a request but unless I can provide a specific advantage over the current inclusion method, it’s unlikely to be included.

    Regarding the error, I’ve forwarded your report to the development team.

  5. 6 years, 8 months ago Adrock42

    I have used siteorigin_panels_postloop_templates in the above code. What the extra bit allows you to do is find templates outside the theme directory. currently, you use locate_template( $template ) to find a template, which only looks in STYLESHEETPATH, TEMPLATEPATH, or the wp-includes/theme-compat/ folder. locate_template does not (yet) have a filter to add directories or theme files outside those 3 places. The jury is still out on if that will happen. Honestly, the headaches there might outweigh the rewards.

    If the siteorigin_panels_postloop_templates filter will add template files from a plugin, then I cannot find the documentation, nor the code paths to make it work, so…

    That is the advantage, allowing a dev to target a theme file in a plugin for the postloop widget. It should be noted MY_PLUGIN_DIR in the above code is defined in my plugin as something else.

    A sample use case for is as follows. A dev has CPTs that are added in a plugin. They would want to offer page builder support with that plugin/cpt and offer custom templates that work for that CPT that might have custom fields. The dev would want all of that contained in one plugin

  6. 6 years, 8 months ago Adrock42

    another approach would be simply making a so_get_template wrapper that has a filter in it to check dev added folder first. This is how WooCommerce does it. After the filter, use locate_template to search the remaining default template places. Then, where ever you use locate_template, replace with so_get_template.

  7. 6 years, 8 months ago Adrock42

    I had to put the following in siteorigin-panels/inc/widgets/post-loop.php so that the template would render to the front

    self::$rendering_loop = true;
    if(strpos('/'.$instance['template'], '/content') !== false) {
        while( have_posts() ) {
            the_post();
            //locate_template($instance['template'], true, false);
            $template = locate_template($instance['template']);
            $template = apply_filters( 'siteorigin_panels_postloop_locate_templates', $template, $instance['template'] );
            include($template);
        }
    }
    else {
        //locate_template($instance['template'], true, false);
        $template = locate_template($instance['template']);
        $template = apply_filters( 'siteorigin_panels_postloop_locate_templates', $template, $instance['template'] );
        include($template);
    }
    self::$rendering_loop = false;
Replies on this thread are closed. Please create a new thread if you have a question, or purchase a SiteOrigin Premium license if you need one-on-one email support.

Get The Most Out of SiteOrigin with SiteOrigin Premium

Find Out More