2

Background

I am trying to add page templates from inside of a plugin. For this question, I have trimmed my code down into a test plugin which has two files, the PHP main plugin file, and a PHP template file.

wp-plugins/test-plugin/test-plugin.php

wp-plugins/test-plugin/templates/test-template.php

The plugin has two pieces. First off, I tap into the template_include filter, and I return the path to the template file (test-template.php).

Next, I have a new extension of Walker_Page, called Walker_Page_New in this example. In the file, it is a word for word copy of Walker_Page.

Current Code

test-plugin.php

<?php

/**
 * Plugin Name: Test Plugin
 * Version: 1.0
 * Author: Andy Mercer
 * Author URI: http://www.andymercer.net
 * License: GPL2
 */ 

add_filter( 'template_include', 'test_get_template' );

function test_get_template( $template ) {

    $template_path = plugin_dir_path( __FILE__ ) . 'templates/test-template.php';

    if ( file_exists( $template_path ) ) {

        $template = $template_path;

    }

    return $template;

}


class Walker_Page_New extends Walker_Page {

    // THE CODE IN HERE IS AN EXACT COPY OF WALKER_PAGE

    // I AM NOT ENTERING IT ALL IN THIS QUESTION BECAUSE IT'S A COUPLE HUNDRED LINES OF CODE

}

test-template.php

<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
    <head>
        ...head stuff...
    </head>
    <body>
        <?php if (have_posts()) : while (have_posts()) : the_post(); ?>
        <div>
            <?php $ancestors = get_ancestors( get_the_ID(), 'page' );
            wp_list_pages([
                'title_li' => '',
                'sort_column' => 'menu_order',
                'child_of' => $ancestors[0],
                'depth' => 2,
                'walker' => 'Walker_Page_New',
            ]); ?>
        </div>
        <div>
            <?php the_title(); ?>
            <?php the_content() ?>
        </div>
        <?php endwhile; endif; ?>
        <?php wp_footer(); ?>
    </body>
</html>

Problem

When I then load the page, I only get this error:

Fatal error: Uncaught Error: Using $this when not in object context in C:...\wp-includes\class-wp-walker.php:199

What is triggering this error is the call to wp_list_pages() with a custom Walker. When I remove the Walker, I am fine and everything works as expected.

Research

From looking around, the only specific mention of this I have found is semi-related here: https://github.com/Automattic/amp-wp/issues/412#issuecomment-240871878, where it's stated that using template_include will cause this:

e.g. we would no longer have the $this context in the templates

Question

Is it expected that using template_include will break stuff? Should I use template_redirect instead?

2 Answers 2

1

Your walker argument in wp_list_pages should be an instance, not a string.

'walker' => new Walker_Page_New()
1

WordPress has no concept of passing explicit context to templates. When template is loaded by it several globals will be made explicitly available, but even that is borderline irrelevant.

Overall you have to deal with global scope inside WP templates, one way or another. Approaches vary and in the end it is up to you. Typical solutions can be:

  • creating your own globals;
  • adding your extra data to native WP globals;
  • creating functions/methods to access your context.
3
  • Thanks, Rarst. Would you have any pointers on how to go about saving the $this for Walkers?
    – Kelderic
    Commented May 30, 2017 at 18:35
  • Walker part seems missing from your questions really, I don’t follow why would your Walker needs access to another object and what precisely $this it refers to.
    – Rarst
    Commented May 30, 2017 at 18:50
  • I have reduced by code to a test plugin, with two files, that reproduces the error. I've added the code to the question.
    – Kelderic
    Commented May 30, 2017 at 20:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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