Support » Plugin: MultilingualPress » MultiLingual-Press + Max Mega Menu = PHP Fatal Error

  • Resolved Tim Reeves

    (@tim-reeves)


    I was getting errors like this:

    Got error 'PHP message: PHP Fatal error:  Uncaught TypeError:
    Argument 1 passed to Mlp_Nav_Menu_Frontend::maybe_delete_obsolete_item() must be an instance of WP_Post, instance of stdClass given,
    called in /var/www/vhosts/ayurveda.report/httpdocs/wp-content/plugins/multilingual-press/inc/nav-menu/Mlp_Nav_Menu_Frontend.php on line 53 and
    defined in /var/www/vhosts/ayurveda.report/httpdocs/wp-content/plugins/multilingual-press/inc/nav-menu/Mlp_Nav_Menu_Frontend.php:74
    Stack trace:
    #0 /var/www/vhosts/ayurveda.report/httpdocs/wp-content/plugins/multilingual-press/inc/nav-menu/Mlp_Nav_Menu_Frontend.php(53): Mlp_Nav_Menu_Frontend->maybe_delete_obsolete_item(Object(stdClass))
    #1 /var/www/vhosts/ayurveda.report/httpdocs/wp-includes/class-wp-hook.php(300): Mlp_Nav_Menu_Frontend->filter_items(Array)
    #2 /var/www/vhosts/ayurveda.report/httpdocs/wp-includes/plugin.php(203): WP_Hook->apply_filters(Array, Array)
    #3 /var/www/vhosts/ayurveda.report/httpdocs/wp-includes/nav-menu-template.php(189): apply_filters('wp_nav_menu_obj...', A...

    If I deactivate either of the plugins, the site works again.

    I’ve looked at the code: MultiLingual-Press does Type Hinting on its function arguments, in particular where a Post is expected the hint is “WP_Post”.
    That normally works, and is no doubt good practice… BUT will fail if any other plugin has created or recast post objects without explicitly making them of type WP_Post. Sadly, it seems that Max Mega Menu (and its clone AP Mega Menu) are creating navigation objects without specifying their type, so they default to StdClass. Then, when they get “walked” by some function in MultiLingual-Press, we end up with the type mismatch fatal error.

    I also checked out how WordPress itself handles this topic: The expected object function argument type WP_Post is often documented in comment, but never type hinted. So WordPress itself always carefully makes menu items which are of type WP_Post, but never, so to speak, forces the issue. You’ll find code like this: $_post = new WP_Post( $post );

    References to consult:

    https://codex.wordpress.org/Plugin_API/Filter_Reference/nav_menu_link_attributes => $item – Object containing item details. E.G: If the link is to a page $item will be a WP_Post object

    https://stackoverflow.com/questions/7839059/type-hinting-for-any-object

    http://php.net/manual/en/functions.arguments.php

    Now the really interesting question: Should MultiLingual-Press be more pragmatic and less purist, and remove the type hints to match WordPress itself?
    Or should Max Mega Menu be improved to ensure that all the menu item objects it modifies or creates are of type WP_Post?

    My personal preference would be for Max Mega Menu to ensure the correct type is set, but I don’t really mind as long as a solution pops up soon… because I’ve had to shift to “Mega Main Menu”, but in general definitely prefer the way Max Mega Menu works.

    This forum post is going in identical wording on the support forums of both plugins. Hope this analysis helps!

    Tim

Viewing 7 replies - 1 through 7 (of 7 total)
  • Plugin Contributor Thorsten Frommen

    (@tfrommen)

    Hi Tim,

    long story short: WordPress creates a WP_Post object, and anyone messing with internal data (structures) is doing it wrong.

    While I understand this is annoying and could be fixed by removing the type hint, this is not what we will do.

    There is no (valid) reason for anyone to manipulate whatever data (structure) one gets from the system; although this is, of course, not new to us.

    Cheers,
    Thorsten

    Hi Thorsten,

    many thanks for your very prompt response. I understand your point of view well!

    That said, there has been a very interesting response from the Author of Max Mega Menu, where he points that that not only his, but some other plugins will add non-WP_Post objects to the menu.

    Perhaps you could comment on his suggestion that Multilingual-Press could check the type of the object rather than forcing it with a type hint?

    Thanks!

    Tim

    Plugin Contributor Thorsten Frommen

    (@tfrommen)

    Hi,

    yes, I already saw that thanks to the WordPress.org Matcher on Slack.

    I just replied there.

    Cheers,
    Thorsten

    Hi Thorsten,

    sorry to bug you with this again, but I have an update and a question.

    Tom (of Max Mega Menu) made an interesting suggestion in his youngest post on this topic – that you could bump up the priority of your filter from the default 10 to 9, that this would make your plugin compatible with a fair number of others…

    I have tried his suggestion and it works.

    /multilingual-press/inc/nav-menu/Mlp_Nav_Menu_Controller.php   Line 91
    
    Old: add_filter( 'wp_nav_menu_objects', array ( $frontend, 'filter_items' ) );
    New: add_filter( 'wp_nav_menu_objects', array ( $frontend, 'filter_items' ), 9, 2 );

    My question is: Could you imagine adding that? I really really would like to work with both plugins, and it would make yours more compatible with some others too. If you say “nope” then I have a really hard decision ahead of me – to use a different plugin or to manually add my fix on each update – igitt 🙂

    Cheers,

    Tim

    Plugin Contributor Thorsten Frommen

    (@tfrommen)

    Hi Tim,

    yes, I saw the reply, but was caught up in other stuff.

    Anyway, I don’t really like to do this. The reason is that it is no more than an adaptation to one specific plugin (version). As soon as another plugin comes around the corner and also uses a higher priority (meaning: lower number) than 10, I’d have to change it again. Then the next plugin comes along and hooks into another filter where it also manipulates WordPress data (structures), and again I’d have to step in. And so on…

    It would be a completely different thing if this was about making MultilingualPress more compatible with another plugin per se. But it is, in fact, trying to make sure that nothing breaks even if (or better: even though) other plugins are doing it wrong.

    I hope this makes sense.

    But, for your specific use case, you could get around this yourself, like so:

    
    add_action( 'inpsyde_mlp_init', function ( Inpsyde_Property_List_Interface $data ) {
    
    	if ( is_admin() ) {
    		return;
    	}
    
    	remove_action( 'inpsyde_mlp_loaded', 'mlp_nav_menu_init' );
    
    	add_action( 'inpsyde_mlp_loaded', function () use ( $data ) {
    
    		$language_api = $data->get( 'language_api' );
    
    		( new Mlp_Nav_Menu_Controller(
    			$language_api,
    			$data->get( 'assets' )
    		) )->initialize();
    
    		add_action( 'template_redirect', function () use ( $language_api ) {
    
    			$frontend = new Mlp_Nav_Menu_Frontend( '_blog_id', $language_api );
    			add_filter( 'wp_nav_menu_objects', [ $frontend, 'filter_items' ], 9 ); // <-- HERE is your change. ;)
    		} );
    	} );
    } );
    

    While the above code might look a little hacky, it actually performs quite well. No instantiated objects being discarded, nothing duplicate/redundant.

    Cheers,
    Thorsten

    Hi Thorsten,

    that’s really kind of you to work out and publish that – muchas gracias!

    While the code looks good, I can’t get it to work…

    First I tried using the plugin Custom css-js-php, adding the code as an action for “inpsyde_mlp_init” and giving the function itself a name. But no joy.

    So then I upgraded my Weaver Xtreme Theme (highly recommendable) to the Plus Version, which allows to add arbitrary PHP code in its own (many many) settings. The author writes “This option is intended to allow you to add WordPress Actions and Filters to the Visitor View of your site. This PHP code is executed at the very beginning of the theme’s header.php template file before any HTML is emitted.” But again, no joy.

    Then I looked at your code and noticed “if ( is_admin() ) { return; }”. Since the site is currently being developed, and uses a “Coming soon” plugin, I have to be logged in to see it. Maybe that was the problem? I tried removing that line – but no, still no joy. Nor when “Coming soon” disabled and using another browser.

    I’m a bit fazed – the code looks plausible to me (although I’m not an expert) – so either I am not including it correctly, or there is a problem with it.

    Do you have any ideas?

    Thanks – really!

    Tim

    Plugin Contributor Thorsten Frommen

    (@tfrommen)

    Hey Tim,

    the code has to go in a dedicated (preferably: MU) plugin. Even the theme’s functions.php would be too late, as well as the methods mentioned before.

    Have a nice week!
    Thorsten

Viewing 7 replies - 1 through 7 (of 7 total)
  • The topic ‘MultiLingual-Press + Max Mega Menu = PHP Fatal Error’ is closed to new replies.