/** * Add the canonical uri to the head. * * @return void * * @since 3.5 */ public function onAfterDispatch() { $doc = $this->app->getDocument(); if (!$this->app->isSite() || $doc->getType() !== 'html') { return; } $sefDomain = $this->params->get('domain', ''); // Don't add a canonical html tag if no alternative domain has added in SEF plugin domain field. if (empty($sefDomain)) { return; } // Check if a canonical html tag already exists (for instance, added by a component). $canonical = ''; foreach ($doc->_links as $linkUrl => $link) { if (isset($link['relation']) && $link['relation'] === 'canonical') { $canonical = $linkUrl; break; } } // If a canonical html tag already exists get the canonical and change it to use the SEF plugin domain field. if (!empty($canonical)) { // Remove current canonical link. unset($doc->_links[$canonical]); // Set the current canonical link but use the SEF system plugin domain field. $canonical = $sefDomain . JUri::getInstance($canonical)->toString(array('path', 'query', 'fragment')); } else { $canonical = $sefDomain . JUri::getInstance()->toString(array('path', 'query', 'fragment')); } // Add the canonical link. $doc->addHeadLink(htmlspecialchars($canonical), 'canonical'); }
/** * Add the canonical uri to the head. * * @return void * * @since 3.5 */ public function onAfterDispatch() { $doc = $this->app->getDocument(); if (!$this->app->isSite() || $doc->getType() !== 'html') { return; } $uri = JUri::getInstance(); $domain = $this->params->get('domain'); if ($domain === false || $domain === '') { $domain = $uri->toString(array('scheme', 'host', 'port')); } $link = $domain . JRoute::_('index.php?' . http_build_query($this->app->getRouter()->getVars()), false); if (rawurldecode($uri->toString()) !== $link) { $doc->addHeadLink(htmlspecialchars($link), 'canonical'); } }
/** * Determines if the message should be displayed * * @return boolean * * @since __DEPLOY_VERSION__ */ private function shouldDisplayMessage() { // Only on admin app if (!$this->app->isAdmin()) { return false; } // Only if authenticated if (JFactory::getUser()->guest) { return false; } // Only on HTML documents if ($this->app->getDocument()->getType() !== 'html') { return false; } // Only on full page requests if ($this->app->input->getCmd('tmpl', 'index') === 'component') { return false; } // Only to com_cpanel if ($this->app->input->get('option') != 'com_cpanel') { return false; } return true; }
/** * Listener for the `onContentPrepare` event * * @param string $context The context of the content being passed to the plugin. * @param object &$article The article object. Note $article->text is also available * @param object &$params The article params * @param integer $page The 'page' number * * @return void * * @since 1.1 */ public function onContentPrepare($context, &$article, &$params, $page) { /* * Validate the plugin should run in the current context */ // Has the plugin already triggered? if (self::$hasProcessedCategory) { return; } // Context check - This only works for com_content if (strpos($context, 'com_content') === false) { self::$hasProcessedCategory = true; return; } // Check if the plugin is enabled if (JPluginHelper::isEnabled('content', 'joomlarrssb') == false) { self::$hasProcessedCategory = true; return; } // Make sure the document is an HTML document $document = $this->app->getDocument(); if ($document->getType() != 'html') { self::$hasProcessedCategory = true; return; } /* * Start processing the plugin event */ // Set the parameters $view = $this->app->input->getCmd('view', ''); // Check whether we're displaying the plugin in the current view if ($this->params->get('view' . ucfirst($view), '1') == '0') { self::$hasProcessedCategory = true; return; } // The featured view is not yet supported and the article view never will be if (in_array($view, ['article', 'featured'])) { self::$hasProcessedCategory = true; return; } // Get the requested category /** @var JTableCategory $category */ $category = JTable::getInstance('Category'); $category->load($this->app->input->getUint('id')); // Build the URL for the plugins to use - the site URL should only be the scheme and host segments, JRoute will take care of the rest $siteURL = JUri::getInstance()->toString(['scheme', 'host', 'port']); $itemURL = $siteURL . JRoute::_(ContentHelperRoute::getCategoryRoute($category->id)); // Check if there is a category image to use for the metadata $categoryParams = json_decode($category->params, true); if (isset($categoryParams['image']) && !empty($categoryParams['image'])) { $imageURL = $categoryParams['image']; // If the image isn't prefixed with http then assume it's relative and put the site URL in front if (strpos($imageURL, 'http') !== 0) { $imageURL = substr(JUri::root(), 0, -1) . (substr($imageURL, 0, 1) !== '/' ? '/' : '') . $imageURL; } if (!$document->getMetaData('og:image')) { $document->setMetaData('og:image', $imageURL, 'property'); } if (!$document->getMetaData('twitter:image')) { $document->setMetaData('twitter:image', $imageURL); } } $description = !empty($category->metadesc) ? $category->metadesc : strip_tags($category->description); // OpenGraph metadata if (!$document->getMetaData('og:title')) { $document->setMetaData('og:title', $category->title, 'property'); } if (!$document->getMetaData('og:type')) { $document->setMetaData('og:type', 'article', 'property'); } if (!$document->getMetaData('og:url')) { $document->setMetaData('og:url', $itemURL, 'property'); } // Twitter Card metadata if (!$document->getMetaData('twitter:title')) { $document->setMetaData('twitter:title', JHtml::_('string.truncate', $category->title, 70, true, false)); } // Add the description too if it isn't empty if (!empty($category->description)) { if (!$document->getMetaData('og:description')) { $document->setMetaData('og:description', $description, 'property'); } if (!$document->getMetaData('twitter:description')) { $document->setMetaData('twitter:description', $description); } } // We're done here self::$hasProcessedCategory = true; }
/** * Convert the site URL to fit to the HTTP request. * * @return void */ public function onAfterRender() { if (!$this->app->isSite() || $this->app->get('sef', '0') == '0') { return; } // Replace src links. $base = JUri::base(true) . '/'; $buffer = $this->app->getBody(); // For feeds we need to search for the URL with domain. $prefix = $this->app->getDocument()->getType() === 'feed' ? JUri::root() : ''; // Replace index.php URI by SEF URI. if (strpos($buffer, 'href="' . $prefix . 'index.php?') !== false) { preg_match_all('#href="' . $prefix . 'index.php\\?([^"]+)"#m', $buffer, $matches); foreach ($matches[1] as $urlQueryString) { $buffer = str_replace('href="' . $prefix . 'index.php?' . $urlQueryString . '"', 'href="' . trim($prefix, '/') . JRoute::_('index.php?' . $urlQueryString) . '"', $buffer); } $this->checkBuffer($buffer); } // Check for all unknown protocals (a protocol must contain at least one alpahnumeric character followed by a ":"). $protocols = '[a-zA-Z0-9\\-]+:'; $attributes = array('href=', 'src=', 'srcset=', 'poster='); foreach ($attributes as $attribute) { if (strpos($buffer, $attribute) !== false) { $regex = '#\\s+' . $attribute . '"(?!/|' . $protocols . '|\\#|\')([^"]*)"#m'; $buffer = preg_replace($regex, ' ' . $attribute . '"' . $base . '$1"', $buffer); $this->checkBuffer($buffer); } } // Replace all unknown protocals in javascript window open events. if (strpos($buffer, 'window.open(') !== false) { $regex = '#onclick="window.open\\(\'(?!/|' . $protocols . '|\\#)([^/]+[^\']*?\')#m'; $buffer = preg_replace($regex, 'onclick="window.open(\'' . $base . '$1', $buffer); $this->checkBuffer($buffer); } // Replace all unknown protocols in onmouseover and onmouseout attributes. $attributes = array('onmouseover=', 'onmouseout='); foreach ($attributes as $attribute) { if (strpos($buffer, $attribute) !== false) { $regex = '#' . $attribute . '"this.src=([\']+)(?!/|' . $protocols . '|\\#|\')([^"]+)"#m'; $buffer = preg_replace($regex, $attribute . '"this.src=$1' . $base . '$2"', $buffer); $this->checkBuffer($buffer); } } // Replace all unknown protocols in CSS background image. if (strpos($buffer, 'style=') !== false) { $regex = '#style=\\s*[\'\\"](.*):\\s*url\\s*\\([\'\\"]?(?!/|' . $protocols . '|\\#)([^\\)\'\\"]+)[\'\\"]?\\)#m'; $buffer = preg_replace($regex, 'style="$1: url(\'' . $base . '$2$3\')', $buffer); $this->checkBuffer($buffer); } // Replace all unknown protocols in OBJECT param tag. if (strpos($buffer, '<param') !== false) { // OBJECT <param name="xx", value="yy"> -- fix it only inside the <param> tag. $regex = '#(<param\\s+)name\\s*=\\s*"(movie|src|url)"[^>]\\s*value\\s*=\\s*"(?!/|' . $protocols . '|\\#|\')([^"]*)"#m'; $buffer = preg_replace($regex, '$1name="$2" value="' . $base . '$3"', $buffer); $this->checkBuffer($buffer); // OBJECT <param value="xx", name="yy"> -- fix it only inside the <param> tag. $regex = '#(<param\\s+[^>]*)value\\s*=\\s*"(?!/|' . $protocols . '|\\#|\')([^"]*)"\\s*name\\s*=\\s*"(movie|src|url)"#m'; $buffer = preg_replace($regex, '<param value="' . $base . '$2" name="$3"', $buffer); $this->checkBuffer($buffer); } // Replace all unknown protocols in OBJECT tag. if (strpos($buffer, '<object') !== false) { $regex = '#(<object\\s+[^>]*)data\\s*=\\s*"(?!/|' . $protocols . '|\\#|\')([^"]*)"#m'; $buffer = preg_replace($regex, '$1data="' . $base . '$2"', $buffer); $this->checkBuffer($buffer); } // Use the replaced HTML body. $this->app->setBody($buffer); }