vendor/contao/core-bundle/src/Resources/contao/modules/ModuleBreadcrumb.php line 47

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Contao.
  4.  *
  5.  * (c) Leo Feyer
  6.  *
  7.  * @license LGPL-3.0-or-later
  8.  */
  9. namespace Contao;
  10. use Symfony\Component\Routing\Exception\ExceptionInterface;
  11. /**
  12.  * Front end module "breadcrumb".
  13.  */
  14. class ModuleBreadcrumb extends Module
  15. {
  16.     /**
  17.      * Template
  18.      * @var string
  19.      */
  20.     protected $strTemplate 'mod_breadcrumb';
  21.     /**
  22.      * Display a wildcard in the back end
  23.      *
  24.      * @return string
  25.      */
  26.     public function generate()
  27.     {
  28.         $request System::getContainer()->get('request_stack')->getCurrentRequest();
  29.         if ($request && System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request))
  30.         {
  31.             $objTemplate = new BackendTemplate('be_wildcard');
  32.             $objTemplate->wildcard '### ' $GLOBALS['TL_LANG']['FMD']['breadcrumb'][0] . ' ###';
  33.             $objTemplate->title $this->headline;
  34.             $objTemplate->id $this->id;
  35.             $objTemplate->link $this->name;
  36.             $objTemplate->href StringUtil::specialcharsUrl(System::getContainer()->get('router')->generate('contao_backend', array('do'=>'themes''table'=>'tl_module''act'=>'edit''id'=>$this->id)));
  37.             return $objTemplate->parse();
  38.         }
  39.         return parent::generate();
  40.     }
  41.     /**
  42.      * Generate the module
  43.      */
  44.     protected function compile()
  45.     {
  46.         /** @var PageModel $objPage */
  47.         global $objPage;
  48.         $type null;
  49.         $pageId $objPage->id;
  50.         $pages = array($objPage);
  51.         $items = array();
  52.         $blnShowUnpublished System::getContainer()->get('contao.security.token_checker')->isPreviewMode();
  53.         // Get all pages up to the root page
  54.         $objPages PageModel::findParentsById($objPage->pid);
  55.         if ($objPages !== null)
  56.         {
  57.             while ($pageId && $type != 'root' && $objPages->next())
  58.             {
  59.                 $type $objPages->type;
  60.                 $pageId $objPages->pid;
  61.                 $pages[] = $objPages->current();
  62.             }
  63.         }
  64.         // Get the first active regular page and display it instead of the root page
  65.         if ($type == 'root')
  66.         {
  67.             $objFirstPage PageModel::findFirstPublishedByPid($objPages->id);
  68.             $items[] = array
  69.             (
  70.                 'isRoot'   => true,
  71.                 'isActive' => false,
  72.                 'href'     => (($objFirstPage !== null) ? $this->getPageFrontendUrl($objFirstPage) : Environment::get('base')),
  73.                 'title'    => StringUtil::specialchars($objPages->pageTitle ?: $objPages->titletrue),
  74.                 'link'     => $objPages->title,
  75.                 'data'     => (($objFirstPage !== null) ? $objFirstPage->row() : array()),
  76.                 'class'    => ''
  77.             );
  78.             array_pop($pages);
  79.         }
  80.         for ($i=(\count($pages)-1); $i>0$i--)
  81.         {
  82.             // Skip pages that require an item (see #3450) and hidden or unpublished pages
  83.             if ($pages[$i]->requireItem || ($pages[$i]->hide && !$this->showHidden) || (!$pages[$i]->published && !$blnShowUnpublished))
  84.             {
  85.                 continue;
  86.             }
  87.             // Get href
  88.             switch ($pages[$i]->type)
  89.             {
  90.                 case 'redirect':
  91.                     $href $pages[$i]->url;
  92.                     if (strncasecmp($href'mailto:'7) === 0)
  93.                     {
  94.                         $href StringUtil::encodeEmail($href);
  95.                     }
  96.                     break;
  97.                 case 'forward':
  98.                     if ($pages[$i]->jumpTo)
  99.                     {
  100.                         $objNext PageModel::findPublishedById($pages[$i]->jumpTo);
  101.                     }
  102.                     else
  103.                     {
  104.                         $objNext PageModel::findFirstPublishedRegularByPid($pages[$i]->id);
  105.                     }
  106.                     if ($objNext instanceof PageModel)
  107.                     {
  108.                         $href $this->getPageFrontendUrl($objNext);
  109.                         break;
  110.                     }
  111.                     // no break
  112.                 default:
  113.                     $href $this->getPageFrontendUrl($pages[$i]);
  114.                     break;
  115.             }
  116.             // Do not add non-root pages with an empty URL to the breadcrumbs
  117.             if ($href)
  118.             {
  119.                 $items[] = array
  120.                 (
  121.                     'isRoot'   => false,
  122.                     'isActive' => false,
  123.                     'href'     => $href,
  124.                     'title'    => StringUtil::specialchars($pages[$i]->pageTitle ?: $pages[$i]->titletrue),
  125.                     'link'     => $pages[$i]->title,
  126.                     'data'     => $pages[$i]->row(),
  127.                     'class'    => ''
  128.                 );
  129.             }
  130.         }
  131.         // Only add active article(s) to the breadcrumbs if the current page does not require an item (see #3450)
  132.         if (isset($_GET['articles']) && !$pages[0]->requireItem)
  133.         {
  134.             $items[] = array
  135.             (
  136.                 'isRoot'   => false,
  137.                 'isActive' => false,
  138.                 'href'     => $this->getPageFrontendUrl($pages[0]),
  139.                 'title'    => StringUtil::specialchars($pages[0]->pageTitle ?: $pages[0]->titletrue),
  140.                 'link'     => $pages[0]->title,
  141.                 'data'     => $pages[0]->row(),
  142.                 'class'    => ''
  143.             );
  144.             list($strSection$strArticle) = explode(':'Input::get('articles')) + array(nullnull);
  145.             if ($strArticle === null)
  146.             {
  147.                 $strArticle $strSection;
  148.             }
  149.             $objArticle ArticleModel::findByIdOrAlias($strArticle);
  150.             $strAlias $objArticle->alias ?: $objArticle->id;
  151.             if ($objArticle->inColumn != 'main')
  152.             {
  153.                 $strAlias $objArticle->inColumn ':' $strAlias;
  154.             }
  155.             if ($objArticle !== null)
  156.             {
  157.                 $items[] = array
  158.                 (
  159.                     'isRoot'   => false,
  160.                     'isActive' => true,
  161.                     'href'     => $this->getPageFrontendUrl($pages[0], '/articles/' $strAlias),
  162.                     'title'    => StringUtil::specialchars($objArticle->titletrue),
  163.                     'link'     => $objArticle->title,
  164.                     'data'     => $objArticle->row(),
  165.                     'class'    => ''
  166.                 );
  167.             }
  168.         }
  169.         // Active page
  170.         else
  171.         {
  172.             $items[] = array
  173.             (
  174.                 'isRoot'   => false,
  175.                 'isActive' => true,
  176.                 // Use the current request without query string for the current page (see #3450)
  177.                 'href'     => strtok(Environment::get('request'), '?'),
  178.                 'title'    => StringUtil::specialchars($pages[0]->pageTitle ?: $pages[0]->title),
  179.                 'link'     => $pages[0]->title,
  180.                 'data'     => $pages[0]->row(),
  181.                 'class'    => ''
  182.             );
  183.         }
  184.         // Mark the first element (see #4833)
  185.         $items[0]['class'] = 'first';
  186.         // HOOK: add custom logic
  187.         if (isset($GLOBALS['TL_HOOKS']['generateBreadcrumb']) && \is_array($GLOBALS['TL_HOOKS']['generateBreadcrumb']))
  188.         {
  189.             foreach ($GLOBALS['TL_HOOKS']['generateBreadcrumb'] as $callback)
  190.             {
  191.                 $this->import($callback[0]);
  192.                 $items $this->{$callback[0]}->{$callback[1]}($items$this);
  193.             }
  194.         }
  195.         $this->Template->getSchemaOrgData = static function () use ($items): array
  196.         {
  197.             $jsonLd = array(
  198.                 '@type' => 'BreadcrumbList',
  199.                 'itemListElement' => array()
  200.             );
  201.             $position 0;
  202.             $htmlDecoder System::getContainer()->get('contao.string.html_decoder');
  203.             foreach ($items as $item)
  204.             {
  205.                 $jsonLd['itemListElement'][] = array(
  206.                     '@type' => 'ListItem',
  207.                     'position' => ++$position,
  208.                     'item' => array(
  209.                         '@id' => $item['href'] ?: './',
  210.                         'name' => $htmlDecoder->inputEncodedToPlainText($item['link'])
  211.                     )
  212.                 );
  213.             }
  214.             return $jsonLd;
  215.         };
  216.         $this->Template->items $items;
  217.         // Tag the pages
  218.         if (!System::getContainer()->has('fos_http_cache.http.symfony_response_tagger'))
  219.         {
  220.             return;
  221.         }
  222.         $tags = array();
  223.         foreach ($items as $item)
  224.         {
  225.             if (isset($item['data']['id']))
  226.             {
  227.                 $tags[] = 'contao.db.tl_page.' $item['data']['id'];
  228.             }
  229.         }
  230.         if (!empty($tags))
  231.         {
  232.             $responseTagger System::getContainer()->get('fos_http_cache.http.symfony_response_tagger');
  233.             $responseTagger->addTags($tags);
  234.         }
  235.     }
  236.     private function getPageFrontendUrl(PageModel $pageModel$strParams=null)
  237.     {
  238.         try
  239.         {
  240.             return $pageModel->getFrontendUrl($strParams);
  241.         }
  242.         catch (ExceptionInterface $exception)
  243.         {
  244.             return '';
  245.         }
  246.     }
  247. }
  248. class_alias(ModuleBreadcrumb::class, 'ModuleBreadcrumb');