1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

$nodeBreadCrumbs usage

Discussion in 'XenForo Suggestions' started by Jake Bunce, Feb 10, 2012.

  1. Jake Bunce

    Jake Bunce XenForo Moderator Staff Member

    In reference to this problem with my addon:

    http://xenforo.com/community/threads/nodes-as-tabs-with-tab-selection.23295/page-10#post-308184

    I can't modify $nodeBreadCrumbs in the controller without affecting notices and body classes. This is a request for code changes to enable me to modify the breadcrumbs without affecting anything else.

    The problem I see is that $nodeBreadCrumbs is used for more than just breadcrumbs. Each content template uses $nodeBreadCrumbs to define two things:

    1) The breadcrumbs (through <xen:navigation> / <xen:breadcrumb>).

    2) The body classes (through <xen:container var="$bodyClasses">).

    So when I modify $nodeBreadCrumbs for the purpose of removing some breadcrumbs it has the following two unintended effects:

    1) It messes up inheritance of notices among nodes. By way of #1, $nodeBreadCrumbs is used by XenForo_Helper_Criteria:pageMatchesCriteria, which in that function exists as $containerData['navigation']. So removing some breadcrumbs can result in a notice not appearing in a child node when it is assigned to a parent node.

    2) It removes body classes for those breadcrumbs that I have removed.

    The only way I can figure to modify the breadcrumbs without affecting anything else is to re-render the breadcrumbs or container using template events which is less than ideal. Ideally I want to work with the data and not have to hack the templates.

    I am open to suggestions. But for the purpose of this report I would suggest that it's inappropriate to use $nodeBreadCrumbs for anything else other than breadcrumbs. Perhaps build another param that is less intended for a specific use, like $ancestors or $nodePath.
     
    Andrej, Boothby, EQnoble and 2 others like this.
  2. Jake Bunce

    Jake Bunce XenForo Moderator Staff Member

    I have been testing these solutions. Re-rendering the container works well. It only involves data manipulation, no html hacking. But it requires some maneuvering with the listeners to avoid problems of running listeners multiple times:

    Code event: template_post_render

    Code:
    	public static function breadCrumbs($templateName, &$content, array &$containerData, XenForo_Template_Abstract $template)
    	{
    		if ($templateName == 'PAGE_CONTAINER'
    		AND $nodeTabId = $template->getParam('nodeTabId')
    		AND $navigation = $template->getParam('navigation')
    		)
    		{
    			$foundTabCrumb = 0;
    			foreach ($navigation AS $key => $crumb)
    			{
    				if (!$foundTabCrumb)
    				{
    					unset($navigation[$key]);
    				}
    
    				if (isset($crumb['node_id'])
    				AND $crumb['node_id'] == $nodeTabId)
    				{
    					$foundTabCrumb = 1;
    				}
    			}
    
    			$template->setParam('navigation', $navigation);
    			$template->setParam('nodeTabId', 0);
    
    			// TEMPORARILY REMOVE RELEVANT LISTENERS FOR RE-RENDER
    			$listeners = XenForo_CodeEvent::getEventListeners('template_post_render');
    			XenForo_CodeEvent::setListeners(array('template_post_render' => false));
    
    			$content = $template->render();
    
    			XenForo_CodeEvent::setListeners(array('template_post_render' => $listeners));
    		}
    	}
    
    The nodeTabId param is used in removing breadcrumbs and also as a flag to prevent the listener from running again during the re-render. But I also had to add the blue code to prevent other listeners for the same event from running again during the re-render. It's a little complicated but it works. However this maneuvering does require my listener to run first so I set an execution order of 0. It also has the trivial side effect of outputting template errors twice.

    So I have a solution now. But this added complexity wouldn't be necessary if $nodeBreadCrumbs wasn't used for other stuff.

    Also, while working on re-rendering the container I realized that a template_pre_render event would make this workaround much easier. It would allow me to modify the params before the render and completely avoid the re-render.
     
    EQnoble likes this.
  3. Jake Bunce

    Jake Bunce XenForo Moderator Staff Member

    Even with the above solution I have encountered a conflict with the Ad Manager addon which does criteria checking in the template_post_render event:

    http://xenforo.com/community/threads/nodes-as-tabs.26687/page-5#post-352337

    The idea behind the above solution was to postpone the breadcrumb changes until after the criteria check is done in the view renderer, since the criteria check depends on the breadcrumb information in the container data. But the Ad Manager addon is doing its own criteria checking in template_post_render which breaks down because I have modified the breadcrumb information on which the criteria check depends, and I cannot possibly make my changes any later in the execution.

    So we are back to the original suggestion... don't use $nodeBreadCrumbs for anything else except breadcrumbs. That way I can modify it all the way up in the controller and not have to worry about breaking page criteria or body classes.
     
    EQnoble likes this.
  4. Jake Bunce

    Jake Bunce XenForo Moderator Staff Member

    one year bump :oops:

    What about creating an alternate breadcrumb array that is checked by the container? If $altNavigation then use it, else use regular $navigation. That way addons can modify the breadcrumbs by defining $altNavigation in the containerParams. That would fix the problem with minimal changes.

    edit - though you would be shortcutting <xen:navigation>/<xen:breadcrumb> which isn't good.
     
    Last edited: Jun 18, 2013
    Andrej and Boothby like this.

Share This Page