1

I have a page.php in which I am defining a custom sub-menu to pass to header.php.

I've tried using a constant (clumsy, I know):

define("CUSTOM_MENU", "<ul><li>Test</li></ul>");

right after this, the code is including the header:

get_header();

In the header.php file, where the sub menu is, I am outputting either the custom sub-menu (if set), or a wp_nav_menu:

if (defined("CUSTOM_MENU"))
  echo constant("CUSTOM_MENU");
else
  wp_nav_menu(array(some stuff));

bizarrely though, the CUSTOM_MENU constant becomes empty the moment get_header() gets called - and stays empty for the rest of page.php:

 define("CUSTOM_MENU", "<ul><li>Test</li></ul>");

 echo constant("CUSTOM_MENU"); // The HTML code above

 get_header();

 echo constant("CUSTOM_MENU"); // Null!

This happens for any method of storing the custom menu data that I use. I have tried:

  • Different constant names
  • Namespaced constants
  • Global variables
  • A function with a static variable

I can't get my head around why this would happen! If get_header() somehow was including header.php using the http wrapper, then the value wouldn't be unset once we exit get_header() again.

What is going on here? Am I overlooking something obvious?

  • There's better ways to do this. For example, inside header.php you could check for is_page(), to output a different header in page.php. – Jacob Peattie Jul 23 '17 at 8:34
  • @Jacob I'm defining page-specific sub menus. (They have custom filtering functionality that I can't achieve with a normal wp_nav_menu()). The page-xxx.php file for each page would be the ideal location for defining each menu... although I'm open to whatever method works! – Pekka Jul 23 '17 at 10:16
2

There is most likely an issue of load order. The get_header() function does included your header.php file, so I'm not sure what's happening inside that template. One way to figure out is to include it using include() and check if the behavior is the same.

I would suggest you hook into the wp_head or init and define your constant there.

add_action('init', 'define_my_constant' );
function define_my_constant() {
    if ( ! defined( 'CUSTOM_MENU' ) && is_page() ) {
        define('CUSTOM_MENU', '<ul><li>Test</li></ul>');
    }
}

init is one of the earliest hooks that runs on WordPress, so your constant should be accessible in any theme or plugins at that point.

  • Didn't think of doing a simple include(), will try that out! I could hook into init, but I'm defining page-specific sub-menus. Each page's page-xxx.php file would be the ideal and most straightforward location for that... but if all else fails, I'll revert to that. – Pekka Jul 23 '17 at 10:17
  • 1
    @Pekka웃 Although you are right about the page-xxx.php, you can still do that by using if( is_page('xxx') ) in conjunction with a switch. This way your constant is available everywhere, even in plugins! – Jack Johansson Jul 23 '17 at 11:43
1

You could try to short-circut the wp_nav_menu() with this filter, for a given theme_location, on given pages:

/**
 * Filters whether to short-circuit the wp_nav_menu() output.
 *
 * Returning a non-null value to the filter will short-circuit
 * wp_nav_menu(), echoing that value if $args->echo is true,
 * returning that value otherwise.
 *
 * @since 3.9.0
 *
 * @see wp_nav_menu()
 *
 * @param string|null $output Nav menu output to short-circuit with. Default null.
 * @param stdClass    $args   An object containing wp_nav_menu() arguments.
 */
$nav_menu = apply_filters( 'pre_wp_nav_menu', null, $args );

Example:

Here we override the navgational menu output, at the primary theme location, for the test page:

add_filter( 'pre_wp_nav_menu', function( $nav_menu, $args )
{
    if ( 'primary' !== $args->theme_location )
        return $nav_menu;

     if( is_page( 'test' ) )
        $nav_menu = '<ul><li>Test</li></ul>';

    return $nav_menu;
}, 10, 2 );

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.