WordPress.org

Make WordPress Core

Opened 7 months ago

Last modified 3 months ago

#46652 new enhancement

Add "template_loaded" action after a template has been included as part of the template hierarchy

Reported by: adamtomat315 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 5.1
Component: Bootstrap/Load Keywords: needs-patch reporter-feedback
Focuses: Cc:
PR Number:

Description

As part of the template hierarchy, WordPress works out what template it should use. It then passes this template through the template_include filter, which allows you to change the template name.

This template is then included and that's the end of things. Here's the current snippet showing the filter and the include (from here https://core.trac.wordpress.org/browser/tags/5.1.1/src/wp-includes/template-loader.php#L77)

<?php

// ...

if ( $template = apply_filters( 'template_include', $template ) ) {
    include( $template );
} elseif ( current_user_can( 'switch_themes' ) ) {

// ...


However, we need to run some code after the template has been included. We can't rely on the next action to fire (which is get_header I believe)

---

I suggest that a new action is added after the template is included. For example:

<?php

// ...

if ( $template = apply_filters( 'template_include', $template ) ) {
    include( $template );
    
    // Add an action here
    do_action('template_included', $template);
} elseif ( current_user_can( 'switch_themes' ) ) {

// ...

---

For some context, as to why we need this change... we have some code that allows us to use PHP classes (controllers) in these template files. We currently hook into "template_include", do the include ourselves then prevent WP from doing the include by not returning anything. However we are running into issues where other hooks on "template_include" not behaving correctly now because we are not returning the template.

We can get around this for now by making sure our filter runs last by setting a high priority. However it would be ideal for us to run our code after the include has been done. Happy to provide more details or code if needed.

Change History (2)

#1 @desrosj
5 months ago

  • Keywords needs-patch reporter-feedback added

Hey @adamtomat315,

Welcome to Trac!

Can you provide a bit more detail about the type of code you would be looking to run at this point in the loading process?

#2 @adamtomat315
3 months ago

Sure thing. We have a MVC Framework built on top of WordPress called Lumberjack. As part of this, we add the functionality to allow classes in files like page.php, single.php etc - to act as controllers.

For example, page.php would look like this:

<?php

namespace App;

use Rareloop\Lumberjack\Page;
use Timber\Timber;

class PageController
{
    public function handle()
    {
        $context = Timber::get_context();
        $page = new Page();

        $context['post'] = $page;
        $context['title'] = $page->title;
        $context['content'] = $page->content;

        return view('templates/generic-page.twig', $context);
    }
}

In order to achieve this, the Lumberjack Framework has to currently hook into the "template_include" function in order to detect whether or not the "PageController" class exists.

Our code is open-source so you can see the whole class here:
https://github.com/Rareloop/lumberjack-core/blob/v4.2.0/src/Providers/WordPressControllersServiceProvider.php#L18

In short, we have to manually include the template ourselves. We don't want to do this, but we have to in order to check to see if the the class exists before we do anything else. Due to some of the complexities of what we are doing, we cannot return a value from our 'template_include' function, which prevents any other filters after ours from running. The biggest issue we've had here is WooCommerce + Lumberjack, as our code is preventing WooCommerce's template_include filter to run.

That being said, there are some work arounds for us but they are all hacky. In an ideal world we would just hook in after the template has been included and it doesn't matter so much if we don't return anything as the template will still always be included.

Hope that makes some sense! Any questions let me know.

Note: See TracTickets for help on using tickets.