Initial commit

This commit is contained in:
2018-04-02 08:07:38 +02:00
commit 7330c1ed3e
2054 changed files with 405203 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Backend\Module;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
use TYPO3\CMS\Extbase\Utility\LocalizationUtility;
/**
* TYPO3 Backend module base
*/
abstract class AbstractModule extends ActionController
{
// ########################################################################
// Attributes
// ########################################################################
/**
* Backend Form Protection object
*
* @var \TYPO3\CMS\Core\FormProtection\BackendFormProtection
*/
protected $formProtection;
// ########################################################################
// Methods
// ########################################################################
/**
* Initializes the controller before invoking an action method.
*
* Override this method to solve tasks which all actions have in
* common.
*
* @return void
* @api
*/
protected function initializeAction()
{
$this->formProtection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get();
}
/**
* Translate list
*
* @param array $list Translation keys
*
* @return array
*/
protected function translateList(array $list)
{
unset($token);
foreach ($list as &$token) {
if (!empty($token)) {
if (is_array($token)) {
$token = $this->translateList($token);
} else {
$token = $this->translate($token);
}
}
}
unset($token);
return $list;
}
/**
* Translate key
*
* @param string $key Translation key
* @param null|array $arguments Arguments (vsprintf)
*
* @return null|string
*/
protected function translate($key, array $arguments = null)
{
$ret = LocalizationUtility::translate($key, $this->extensionName, $arguments);
// Not translated handling
if ($ret === null) {
$ret = '[-' . $key . '-]';
}
return $ret;
}
/**
* Create session token
*
* @param string $formName Form name/Session token name
*
* @return string
*/
protected function sessionToken($formName)
{
$token = $this->formProtection->generateToken($formName);
return $token;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Backend\Module;
/**
* TYPO3 Backend module standalone
*/
abstract class AbstractStandardModule extends AbstractModule
{
}

View File

@@ -0,0 +1,34 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Backend\Module;
/**
* TYPO3 Backend module tree
*/
abstract class AbstractTreeModule extends AbstractModule
{
}

View File

@@ -0,0 +1,75 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Backend\Validator;
/**
* TYPO3 Backend field validation: float
*/
class FloatValidator
{
/**
* Returns JavaScript validation function body
*
* @return string
*/
public function returnFieldJS()
{
return '
value = value.replace(/[^-0-9,.]/g,\'\');
var ret = 0;
try {
if (isNaN(value) ) {
value = 0;
}
ret = parseFloat(value);
} catch(e) {}
if (isNaN(ret) ) {
ret = 0;
}
return ret;
';
}
/**
* Validate number on serverside
*
* @param string $value Value
* @param mixed $is_in Is in value (config)
* @param mixed $set Set
*
* @return float
*/
public function evaluateFieldValue($value, $is_in, &$set)
{
return (float)$value;
}
}

View File

@@ -0,0 +1,36 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
/**
* Class tx_metaseo_backend_validation_float
* (Used in TCA because of namespace issues)
*
* @deprecated
*/
class tx_metaseo_backend_validation_float extends \Metaseo\Metaseo\Backend\Validator\FloatValidator
{
}

View File

@@ -0,0 +1,156 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Command;
use Metaseo\Metaseo\Utility\ConsoleUtility;
use Metaseo\Metaseo\Utility\DatabaseUtility;
use Metaseo\Metaseo\Utility\GeneralUtility;
use Metaseo\Metaseo\Utility\RootPageUtility;
use Metaseo\Metaseo\Utility\SitemapUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility as Typo3GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\CommandController;
/**
* TYPO3 Command controller
*/
class MetaseoCommandController extends CommandController
{
/**
* Get whole list of sitemap entries
*
* @return string
*/
public function garbageCollectorCommand()
{
// Expire sitemap entries
SitemapUtility::expire();
}
/**
* Clear sitemap for one root page
*
* @param string $rootPageId Site root page id or domain
*
* @return string
*/
public function clearSitemapCommand($rootPageId)
{
$rootPageId = $this->getRootPageIdFromId($rootPageId);
if ($rootPageId !== null) {
$query = 'DELETE FROM tx_metaseo_sitemap
WHERE page_rootpid = ' . DatabaseUtility::quote($rootPageId, 'tx_metaseo_sitemap') . '
AND is_blacklisted = 0';
DatabaseUtility::exec($query);
ConsoleUtility::writeLine('Sitemap cleared');
} else {
ConsoleUtility::writeErrorLine('No such root page found');
ConsoleUtility::terminate(1);
}
}
/**
* Get whole list of sitemap entries
*
* @param string $rootPageId Site root page id or domain
*
* @return string
*/
public function sitemapCommand($rootPageId)
{
$rootPageId = $this->getRootPageIdFromId($rootPageId);
if ($rootPageId !== null) {
$domain = RootPageUtility::getDomain($rootPageId);
$query = 'SELECT page_url
FROM tx_metaseo_sitemap
WHERE page_rootpid = ' . DatabaseUtility::quote($rootPageId, 'tx_metaseo_sitemap') . '
AND is_blacklisted = 0';
$urlList = DatabaseUtility::getCol($query);
foreach ($urlList as $url) {
if ($domain) {
$url = GeneralUtility::fullUrl($url, $domain);
}
ConsoleUtility::writeLine($url);
}
} else {
ConsoleUtility::writeErrorLine('No such root page found');
ConsoleUtility::terminate(1);
}
}
/**
* Detect root page from id (either PID or sys_domain)
*
* @param integer|string $var
*
* @return integer|null
*/
protected function getRootPageIdFromId($var)
{
if (is_numeric($var)) {
// Passed variable is numeric
$pageId = (int)$var;
/** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */
$objectManager = Typo3GeneralUtility::makeInstance(
'TYPO3\\CMS\\Extbase\\Object\\ObjectManager'
);
/** @var \TYPO3\CMS\Frontend\Page\PageRepository $pageRepo */
$pageRepo = $objectManager->get('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
$page = $pageRepo->getPage($pageId);
if (empty($page['is_siteroot'])) {
throw new \RuntimeException('MetaSEO: Page with UID "' . $pageId . '" is no valid root page');
}
return $page['uid'];
}
// Passed variable is domain name
$query = 'SELECT pid
FROM sys_domain
WHERE domainName = ' . DatabaseUtility::quote($var, 'sys_domain') . '
AND hidden = 0';
$pid = DatabaseUtility::getOne($query);
if (empty($pid)) {
return null;
}
return $pid;
}
}

View File

@@ -0,0 +1,232 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo;
use TYPO3\CMS\Core\SingletonInterface;
/**
* Connector
*/
class Connector implements SingletonInterface
{
// ########################################################################
// Attributes
// ########################################################################
/**
* Data store
*
* @var array
*/
protected static $store = array(
'flag' => array(),
'meta' => array(),
'meta:og' => array(),
'custom' => array(),
'pagetitle' => array(),
'sitemap' => array(),
);
// ########################################################################
// Page title methods
// ########################################################################
/**
* Set page title
*
* @param string $value Page title
* @param boolean $updateTsfe Update TSFE values
*/
public static function setPageTitle($value, $updateTsfe = true)
{
$value = (string)$value;
if ($updateTsfe && !empty($GLOBAL['TSFE'])) {
$GLOBAL['TSFE']->page['title'] = $value;
$GLOBAL['TSFE']->indexedDocTitle = $value;
}
self::$store['pagetitle']['pagetitle.title'] = $value;
}
/**
* Set page title suffix
*
* @param string $value Page title suffix
*/
public static function setPageTitleSuffix($value)
{
self::$store['pagetitle']['pagetitle.suffix'] = $value;
}
/**
* Set page title prefix
*
* @param string $value Page title Prefix
*/
public static function setPageTitlePrefix($value)
{
self::$store['pagetitle']['pagetitle.prefix'] = $value;
}
/**
* Set page title (absolute)
*
* @param string $value Page title
* @param boolean $updateTsfe Update TSFE values
*/
public static function setPageTitleAbsolute($value, $updateTsfe = true)
{
if ($updateTsfe && !empty($GLOBALS['TSFE'])) {
$GLOBALS['TSFE']->page['title'] = $value;
$GLOBALS['TSFE']->indexedDocTitle = $value;
}
self::$store['pagetitle']['pagetitle.absolute'] = $value;
}
/**
* Set page title sitetitle
*
* @param string $value Page title
*/
public static function setPageTitleSitetitle($value)
{
self::$store['pagetitle']['pagetitle.sitetitle'] = $value;
}
// ########################################################################
// MetaTag methods
// ########################################################################
/**
* Set meta tag
*
* @param string $key Metatag name
* @param string $value Metatag value
*/
public static function setMetaTag($key, $value)
{
$key = (string)$key;
$value = (string)$value;
if (strpos($key, 'og:') === 0) {
self::setOpenGraphTag($key, $value);
}
self::$store['meta'][$key] = $value;
}
/**
* Set opengraph tag
*
* @param string $key Metatag name
* @param string $value Metatag value
*/
public static function setOpenGraphTag($key, $value)
{
$key = (string)$key;
$value = (string)$value;
self::$store['flag']['meta:og:external'] = true;
self::$store['meta:og'][$key] = $value;
}
/**
* Set meta tag
*
* @param string $key Metatag name
* @param string $value Metatag value
*/
public static function setCustomMetaTag($key, $value)
{
$key = (string)$key;
$value = (string)$value;
self::$store['custom'][$key] = $value;
}
/**
* Disable meta tag
*
* @param string $key Metatag name
*/
public static function disableMetaTag($key)
{
$key = (string)$key;
self::$store['meta'][$key] = null;
}
// ########################################################################
// Sitemap methods
// ########################################################################
/**
* Set sitemap index expiration in days
*
* @param integer $days Entry expiration in days
*/
public static function setSitemapIndexExpiration($days)
{
self::$store['sitemap']['expiration'] = abs($days);
}
// ########################################################################
// Control methods
// ########################################################################
// TODO
// ########################################################################
// General methods
// ########################################################################
/**
* Get store
*
* @param string $key Store key (optional, if empty whole store is returned)
*
* @return array
*/
public static function getStore($key = null)
{
$ret = null;
if ($key !== null) {
if (isset(self::$store[$key])) {
$ret = self::$store[$key];
}
} else {
$ret = self::$store;
}
return $ret;
}
}

View File

@@ -0,0 +1,227 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller;
use Exception;
use Metaseo\Metaseo\DependencyInjection\Utility\HttpUtility;
use Metaseo\Metaseo\Exception\Ajax\AjaxException;
use TYPO3\CMS\Core\Http\AjaxRequestHandler;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
/**
* TYPO3 Backend ajax module base
*/
abstract class AbstractAjaxController
{
const CONTENT_FORMAT_JSON = 'json';
/**
* Json status indicators
*/
const JSON_ERROR = 'error';
const JSON_ERROR_NUMBER = 'errorNumber';
// ########################################################################
// Attributes
// ########################################################################
/**
* POST vars (transformed from json)
*
* @var array
*/
protected $postVar;
/**
* Sorting field
*/
protected $sortField;
/**
* Sorting dir
*
* @var string
*/
protected $sortDir;
/**
* TYPO3 Object manager
*
* @var \TYPO3\CMS\Extbase\Object\ObjectManager
*/
protected $objectManager;
// ########################################################################
// Methods
// ########################################################################
public function __construct()
{
$this->postVar = array();
}
/**
* Collect and process POST vars and stores them into $this->postVars
*/
protected function fetchParams()
{
$rawPostVarList = GeneralUtility::_POST();
foreach ($rawPostVarList as $key => $value) {
$this->postVar[$key] = json_decode($value);
}
// Sorting data
if (!empty($rawPostVarList['sort'])) {
$this->sortField = $this->escapeSortField((string)$rawPostVarList['sort']);
}
if (!empty($rawPostVarList['dir'])) {
switch (strtoupper($rawPostVarList['dir'])) {
case 'ASC':
$this->sortDir = 'ASC';
break;
case 'DESC':
$this->sortDir = 'DESC';
break;
}
}
}
/**
* Escape for sql sort fields
*
* @param string $value Sort value
*
* @return string
*/
protected function escapeSortField($value)
{
return preg_replace('[^_a-zA-Z]', '', $value);
}
/**
* Init
*/
protected function init()
{
$this->fetchParams();
// Include ajax local lang
$this->getLanguageService()->includeLLFile('EXT:metaseo/Resources/Private/Language/locallang.xlf');
if (!isset($this->objectManager)) {
$this->objectManager = GeneralUtility::makeInstance(
'TYPO3\\CMS\\Extbase\\Object\\ObjectManager'
);
}
}
/**
* @return string
*/
abstract protected function getAjaxPrefix();
/**
* Returns a json formatted error response with http error status specified in the Exception
* The message is created with $ajaxObj->setContent instead of setError because $ajaxObj->setError
* always sets http status 500 and does not respect content format.
*
* @param Exception $exception
* @param AjaxRequestHandler $ajaxObj
*
* @return void
*/
protected function ajaxExceptionHandler(Exception $exception, AjaxRequestHandler &$ajaxObj)
{
$responseArray = array();
if ($exception instanceof AjaxException) {
$responseArray[self::JSON_ERROR] = $this->translate($exception->getMessage());
$this->getHttpUtility()->sendHttpHeader($exception->getHttpStatus());
$errorCode = $exception->getCode();
if (!empty($errorCode)) {
$responseArray[self::JSON_ERROR_NUMBER] = $exception->getCode();
}
} else {
$responseArray[self::JSON_ERROR] = $exception->getMessage();
$this->getHttpUtility()->sendHttpHeader(HttpUtility::HTTP_STATUS_INTERNAL_SERVER_ERROR);
}
$ajaxObj->setContent($responseArray);
}
/**
* Translate a key to the current chosen language
*
* @param $messageKey string
*
* @return string
*/
protected function translate($messageKey)
{
return $this
->getLanguageService()
->getLL($messageKey);
}
/**
* Get the TYPO3 CMS LanguageService
*
* @return \TYPO3\CMS\Lang\LanguageService
*/
protected function getLanguageService()
{
return $GLOBALS['LANG'];
}
/**
* @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
*/
protected function getBackendUserAuthentication()
{
return $GLOBALS['BE_USER'];
}
/**
* @return HttpUtility
*/
protected function getHttpUtility()
{
return $this->objectManager->get('Metaseo\\Metaseo\\DependencyInjection\\Utility\\HttpUtility');
}
/**
* @param ObjectManager $objectManager
*
* @return $this
*/
public function setObjectManager(ObjectManager $objectManager)
{
$this->objectManager = $objectManager;
return $this;
}
}

View File

@@ -0,0 +1,412 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax;
use Exception;
use Metaseo\Metaseo\Controller\AbstractAjaxController;
use Metaseo\Metaseo\Controller\Ajax\PageSeo as PageSeo;
use Metaseo\Metaseo\DependencyInjection\Utility\HttpUtility;
use Metaseo\Metaseo\Exception\Ajax\AjaxException;
use TYPO3\CMS\Core\Http\AjaxRequestHandler;
/**
* TYPO3 Backend ajax module page
*/
abstract class AbstractPageSeoController extends AbstractAjaxController implements PageSeoInterface
{
const LIST_TYPE = 'undefined';
const AJAX_PREFIX = 'tx_metaseo_controller_ajax_pageseo_';
// ########################################################################
// Attributes
// ########################################################################
/**
* List of page uids which have templates
*
* @var array
*/
protected $templatePidList;
/**
* @var array
*/
protected $fieldList;
// ########################################################################
// Methods
// ########################################################################
public function __construct()
{
parent::__construct();
$this->templatePidList = array();
$this->initFieldList();
}
abstract protected function initFieldList();
/**
* @inheritDoc
*/
public function indexAction($params = array(), AjaxRequestHandler &$ajaxObj = null)
{
try {
$this->init();
$ajaxObj->setContent($this->executeIndex());
} catch (Exception $exception) {
$this->ajaxExceptionHandler($exception, $ajaxObj);
}
$ajaxObj->setContentFormat(self::CONTENT_FORMAT_JSON);
$ajaxObj->render();
}
/**
* @return array
*
* @throws AjaxException
*/
protected function executeIndex()
{
$pid = (int)$this->postVar['pid'];
$depth = (int)$this->postVar['depth'];
$sysLanguage = (int)$this->postVar['sysLanguage'];
// Store last selected language
$this->getBackendUserAuthentication()
->setAndSaveSessionData('MetaSEO.sysLanguage', $sysLanguage);
if (empty($pid)) {
throw new AjaxException(
'message.error.typo3_page_not_found',
'[0x4FBF3C0C]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
$page = $this->getPageSeoDao()->getPageById($pid);
$list = $this->getIndex($page, $depth, $sysLanguage);
return array(
'results' => count($list),
'rows' => array_values($list),
);
}
/**
* Return default tree
*
* This function is made for list manipulation in subclasses (method template design pattern)
*
* @param array $page Root page
* @param integer $depth Depth
* @param integer $sysLanguage System language
*
* @return array
*/
protected function getIndex(array $page, $depth, $sysLanguage)
{
return $this->getPageSeoDao()->index($page, $depth, $sysLanguage, $this->fieldList);
}
/**
* @inheritDoc
*/
public function updateAction($params = array(), AjaxRequestHandler &$ajaxObj = null)
{
try {
$this->init();
$ajaxObj->setContent($this->executeUpdate());
} catch (Exception $exception) {
$this->ajaxExceptionHandler($exception, $ajaxObj);
}
$ajaxObj->setContentFormat(self::CONTENT_FORMAT_JSON);
$ajaxObj->render();
}
/**
* @return array
*
* @throws AjaxException
*/
protected function executeUpdate()
{
if (empty($this->postVar['pid']) || empty($this->postVar['field'])) {
throw new AjaxException(
'message.warning.incomplete_data_received.message',
'[0x4FBF3C02]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
$pid = (int)$this->postVar['pid'];
$fieldName = strtolower((string)$this->postVar['field']);
$fieldValue = (string)$this->postVar['value'];
$sysLanguage = (int)$this->postVar['sysLanguage'];
// validate field name: must match exactly to list of known field names
if (!in_array($fieldName, array_merge($this->fieldList, array('title')))) {
throw new AjaxException(
'message.warning.incomplete_data_received.message',
'[0x4FBF3C23]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
if (empty($fieldName)) {
throw new AjaxException(
'message.warning.incomplete_data_received.message',
'[0x4FBF3C03]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
// ############################
// Security checks
// ############################
// check if user is able to modify pages
if (!$this->getBackendUserAuthentication()->check('tables_modify', 'pages')) {
// No access
throw new AjaxException(
'message.error.access_denied',
'[0x4FBF3BE2]',
HttpUtility::HTTP_STATUS_UNAUTHORIZED
);
}
$page = $this->getPageSeoDao()->getPageById($pid);
// check if page exists and user can edit this specific record
if (empty($page) || !$this->getBackendUserAuthentication()->doesUserHaveAccess($page, 2)) {
// No access
throw new AjaxException(
'message.error.access_denied',
'[0x4FBF3BCF]',
HttpUtility::HTTP_STATUS_UNAUTHORIZED
);
}
// check if user is able to modify the field of pages
if (!$this->getBackendUserAuthentication()
->check('non_exclude_fields', 'pages:' . $fieldName)
) {
// No access
throw new AjaxException(
'message.error.access_denied',
'[0x4FBF3BD9]',
HttpUtility::HTTP_STATUS_UNAUTHORIZED
);
}
// also check for sys language
if (!empty($sysLanguage)) {
// check if user is able to modify pages
if (!$this->getBackendUserAuthentication()
->check('tables_modify', 'pages_language_overlay')
) {
// No access
throw new AjaxException(
'message.error.access_denied',
'[0x4FBF3BE2]',
HttpUtility::HTTP_STATUS_UNAUTHORIZED
);
}
// check if user is able to modify the field of pages
if (!$this->getBackendUserAuthentication()
->check('non_exclude_fields', 'pages_language_overlay:' . $fieldName)
) {
// No access
throw new AjaxException(
'message.error.access_denied',
'[0x4FBF3BD9]',
HttpUtility::HTTP_STATUS_UNAUTHORIZED
);
}
}
// ############################
// Transformations
// ############################
switch ($fieldName) {
case 'lastupdated':
// transform to unix timestamp
$fieldValue = strtotime($fieldValue);
break;
}
// ############################
// Update
// ############################
return $this->getPageSeoDao()->updatePageTableField($pid, $sysLanguage, $fieldName, $fieldValue);
}
/**
* @inheritDoc
*/
public function updateRecursiveAction($params = array(), AjaxRequestHandler &$ajaxObj = null)
{
try {
$this->init();
$ajaxObj->setContent($this->executeUpdateRecursive());
} catch (Exception $exception) {
$this->ajaxExceptionHandler($exception, $ajaxObj);
}
$ajaxObj->setContentFormat(self::CONTENT_FORMAT_JSON);
$ajaxObj->render();
}
/**
* @return array
*
* @throws AjaxException
*/
protected function executeUpdateRecursive()
{
if (empty($this->postVar['pid']) || empty($this->postVar['field'])) {
throw new AjaxException(
'message.warning.incomplete_data_received.message',
'[0x4FBF3C04]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
$pid = $this->postVar['pid'];
$sysLanguage = (int)$this->postVar['sysLanguage'];
$page = $this->getPageSeoDao()->getPageById($pid);
$list = $this->getPageSeoDao()->index($page, 999, $sysLanguage, array());
$count = 0;
foreach ($list as $key => $page) {
$this->postVar['pid'] = $key;
$this->executeUpdate();
$count++;
}
return array(
'updateCount' => $count, //not in use yet
);
}
/**
* @inheritDoc
*/
protected function getAjaxPrefix()
{
return self::AJAX_PREFIX;
}
/**
* @return \Metaseo\Metaseo\Dao\PageSeoDao
*/
protected function getPageSeoDao()
{
return $this
->objectManager
->get('Metaseo\\Metaseo\\Dao\\PageSeoDao')
->setPageTreeView($this->getPageTreeView())
->setDataHandler($this->getDataHandler());
}
/**
* @return \TYPO3\CMS\Core\DataHandling\DataHandler
*/
protected function getDataHandler()
{
return $this->objectManager->get('TYPO3\\CMS\\Core\\DataHandling\\DataHandler');
}
/**
* @return \TYPO3\CMS\Backend\Tree\View\PageTreeView
*/
protected function getPageTreeView()
{
return $this->objectManager->get('TYPO3\\CMS\\Backend\\Tree\\View\\PageTreeView');
}
/**
* @return \Metaseo\Metaseo\DependencyInjection\Utility\FrontendUtility
*/
protected function getFrontendUtility()
{
return $this
->objectManager
->get('Metaseo\\Metaseo\\DependencyInjection\\Utility\\FrontendUtility')
->setPageRepository($this->getPageRepository());
}
/**
* @return \TYPO3\CMS\Frontend\Page\PageRepository
*/
protected function getPageRepository()
{
return $this->objectManager->get('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
}
/**
* Returns array of classes which contain Ajax controllers with <ajaxPrefix> => <className)
*
* @todo replace class concatenation with e.g. 'UrlController::class' as of PHP 5.5 (renders $namespace obsolete)
*
* @return array
*/
public static function getBackendAjaxClassNames()
{
$nameSpace = __NAMESPACE__ . '\\PageSeo';
$ajaxPrefix = self::AJAX_PREFIX;
return array(
//$ajaxPrefix . PageSeo\AdvancedController::LIST_TYPE
// => $nameSpace . '\\' . 'AdvancedController',//unused
$ajaxPrefix . PageSeo\GeoController::LIST_TYPE => $nameSpace . '\\' . 'GeoController',
$ajaxPrefix . PageSeo\MetaDataController::LIST_TYPE => $nameSpace . '\\' . 'MetaDataController',
$ajaxPrefix . PageSeo\PageTitleController::LIST_TYPE => $nameSpace . '\\' . 'PageTitleController',
$ajaxPrefix . PageSeo\PageTitleSimController::LIST_TYPE => $nameSpace . '\\' . 'PageTitleSimController',
$ajaxPrefix . PageSeo\SearchEnginesController::LIST_TYPE => $nameSpace . '\\' . 'SearchEnginesController',
$ajaxPrefix . PageSeo\UrlController::LIST_TYPE => $nameSpace . '\\' . 'UrlController',
);
}
}

View File

@@ -0,0 +1,55 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax;
use TYPO3\CMS\Core\Http\AjaxRequestHandler;
abstract class AbstractPageSeoSimController extends AbstractPageSeoController implements PageSeoSimulateInterface
{
/**
* @inheritDoc
*/
public function simulateAction($params = array(), AjaxRequestHandler &$ajaxObj = null)
{
try {
$this->init();
$ajaxObj->setContent($this->executeSimulate());
} catch (\Exception $exception) {
$this->ajaxExceptionHandler($exception, $ajaxObj);
}
$ajaxObj->setContentFormat(self::CONTENT_FORMAT_JSON);
$ajaxObj->render();
}
/**
* @return array
*
* @throws \Metaseo\Metaseo\Exception\Ajax\AjaxException
*/
abstract protected function executeSimulate();
}

View File

@@ -0,0 +1,182 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax\PageSeo;
use Metaseo\Metaseo\Controller\Ajax\AbstractPageSeoController;
use Metaseo\Metaseo\DependencyInjection\Utility\HttpUtility;
use Metaseo\Metaseo\Exception\Ajax\AjaxException;
use Metaseo\Metaseo\Utility\DatabaseUtility;
class AdvancedController extends AbstractPageSeoController
{
const LIST_TYPE = 'advanced';
/**
* @inheritDoc
*/
protected function initFieldList()
{
$this->fieldList = array();
}
/**
* @inheritDoc
*/
public function executeIndex()
{
if (empty($this->postVar['pid'])) {
throw new AjaxException(
'message.error.typo3_page_not_found',
'[0x4FBF3C0E]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
$ret = array();
$pid = (int)$this->postVar['pid'];
$sysLanguage = (int)$this->postVar['sysLanguage'];
// check uid of pages language overlay
$query = 'SELECT tag_name,
tag_value
FROM tx_metaseo_metatag
WHERE pid = ' . (int)$pid . '
AND sys_language_uid = ' . (int)$sysLanguage;
$rowList = DatabaseUtility::getAll($query);
foreach ($rowList as $row) {
$ret[$row['tag_name']] = $row['tag_value'];
}
return array(
'results' => count($ret),
'rows' => array_values($ret),
);
}
/**
* @inheritDoc
*/
protected function executeUpdate()
{
if (empty($this->postVar['pid']) || empty($this->postVar['metaTags'])) {
throw new AjaxException(
'message.error.typo3_page_not_found',
'[0x4FBF3C0F]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
$pid = (int)$this->postVar['pid'];
$metaTagList = (array)$this->postVar['metaTags'];
$sysLanguage = (int)$this->postVar['sysLanguage'];
$this->clearMetaTags($pid, $sysLanguage);
$metaTagGroup = 2;
foreach ($metaTagList as $metaTagName => $metaTagValue) {
if (is_scalar($metaTagValue)) {
$metaTagValue = trim($metaTagValue);
if (strlen($metaTagValue) > 0) {
$this->updateMetaTag($pid, $sysLanguage, $metaTagName, $metaTagValue);
}
} elseif (is_array($metaTagValue)) {
foreach ($metaTagValue as $subTagName => $subTagValue) {
$this->updateMetaTag(
$pid,
$sysLanguage,
array($metaTagName, $subTagName),
$subTagValue,
$metaTagGroup++
);
}
}
}
return array();
}
/**
* Clear all meta tags for one page
*
* @param integer $pid PID
* @param integer|null $sysLanguage system language id
*/
protected function clearMetaTags($pid, $sysLanguage)
{
$query = 'DELETE FROM tx_metaseo_metatag
WHERE pid = ' . (int)$pid . '
AND sys_language_uid = ' . (int)$sysLanguage;
DatabaseUtility::exec($query);
}
/**
* @param integer $pid PID
* @param integer|NULL $sysLanguage System language id
* @param string|array $metaTag MetaTag name
* @param string $value MetaTag value
* @param integer $tagGroup MetaTag group
*/
protected function updateMetaTag($pid, $sysLanguage, $metaTag, $value, $tagGroup = null)
{
$tstamp = time();
$crdate = time();
$cruserId = $this->getBackendUserAuthentication()->user['uid'];
$subTagName = '';
if (is_array($metaTag)) {
list($metaTag, $subTagName) = $metaTag;
}
if ($tagGroup === null) {
$tagGroup = 1;
}
$query = 'INSERT INTO tx_metaseo_metatag
(pid, tstamp, crdate, cruser_id, sys_language_uid,
tag_name, tag_subname, tag_value, tag_group)
VALUES (
' . (int)$pid . ',
' . (int)$tstamp . ',
' . (int)$crdate . ',
' . (int)$cruserId . ',
' . (int)$sysLanguage . ',
' . DatabaseUtility::quote($metaTag) . ',
' . DatabaseUtility::quote($subTagName) . ',
' . DatabaseUtility::quote($value) . ',
' . (int)$tagGroup . '
) ON DUPLICATE KEY UPDATE
tstamp = VALUES(tstamp),
tag_value = VALUES(tag_value)';
DatabaseUtility::execInsert($query);
}
}

View File

@@ -0,0 +1,47 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax\PageSeo;
use Metaseo\Metaseo\Controller\Ajax\AbstractPageSeoController;
class GeoController extends AbstractPageSeoController
{
const LIST_TYPE = 'geo';
/**
* @inheritDoc
*/
protected function initFieldList()
{
$this->fieldList = array(
'tx_metaseo_geo_lat',
'tx_metaseo_geo_long',
'tx_metaseo_geo_place',
'tx_metaseo_geo_region'
);
}
}

View File

@@ -0,0 +1,66 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax\PageSeo;
use Metaseo\Metaseo\Controller\Ajax\AbstractPageSeoController;
class MetaDataController extends AbstractPageSeoController
{
const LIST_TYPE = 'metadata';
protected function initFieldList()
{
$this->fieldList = array(
'keywords',
'description',
'abstract',
'author',
'author_email',
'lastupdated',
);
}
/**
* @inheritDoc
*/
protected function getIndex(array $page, $depth, $sysLanguage)
{
$list = $this->getPageSeoDao()->index($page, $depth, $sysLanguage, $this->fieldList);
unset($row);
foreach ($list as &$row) {
if (!empty($row['lastupdated'])) {
$row['lastupdated'] = date('Y-m-d', $row['lastupdated']);
} else {
$row['lastupdated'] = '';
}
}
unset($row);
return $list;
}
}

View File

@@ -0,0 +1,89 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax\PageSeo;
use Metaseo\Metaseo\Controller\Ajax\AbstractPageSeoSimController;
use Metaseo\Metaseo\DependencyInjection\Utility\HttpUtility;
use Metaseo\Metaseo\Exception\Ajax\AjaxException;
use TYPO3\CMS\Core\Utility\GeneralUtility as Typo3GeneralUtility;
class PageTitleController extends AbstractPageSeoSimController
{
const LIST_TYPE = 'pagetitle';
/**
* @inheritDoc
*/
protected function initFieldList()
{
$this->fieldList = array(
'tx_metaseo_pagetitle',
'tx_metaseo_pagetitle_rel',
'tx_metaseo_pagetitle_prefix',
'tx_metaseo_pagetitle_suffix',
);
}
/**
* @inheritDoc
*/
protected function executeSimulate()
{
$pid = (int)$this->postVar['pid'];
if (empty($pid)) {
throw new AjaxException(
'message.error.typo3_page_not_found',
'[0x4FBF3C08]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
$page = $this->getPageSeoDao()->getPageById($pid);
if (empty($page)) {
throw new AjaxException(
'message.error.typo3_page_not_found',
'[0x4FBF3C09]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
// Load TYPO3 classes
$this->getFrontendUtility()->initTsfe($page, null, $page, null);
$pagetitle = Typo3GeneralUtility::makeInstance(
'Metaseo\\Metaseo\\Page\\Part\\PagetitlePart'
);
return array(
'title' => $pagetitle->main($page['title']),
);
}
}

View File

@@ -0,0 +1,101 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax\PageSeo;
use Metaseo\Metaseo\Controller\Ajax\AbstractPageSeoController;
class PageTitleSimController extends AbstractPageSeoController
{
const LIST_TYPE = 'pagetitlesim';
/**
* @inheritDoc
*/
protected function initFieldList()
{
$this->fieldList = array(
'title',
'tx_metaseo_pagetitle',
'tx_metaseo_pagetitle_rel',
'tx_metaseo_pagetitle_prefix',
'tx_metaseo_pagetitle_suffix',
);
}
/**
* @inheritDoc
*/
protected function getIndex(array $page, $depth, $sysLanguage)
{
$list = $this->getPageSeoDao()->index($page, $depth, $sysLanguage, $this->fieldList);
$uidList = array_keys($list);
if (!empty($uidList)) {
// Check which pages have templates (for caching and faster building)
$this->templatePidList = array();
$pidList = $this->getTemplateDao()->checkForTemplateByUidList($uidList);
foreach ($pidList as $pid) {
$this->templatePidList[$pid] = $pid;
}
// Build simulated title
foreach ($list as &$row) {
$row['title_simulated'] = $this->simulateTitle($row, $sysLanguage);
}
}
return $list;
}
/**
* Generate simulated page title
*
* @param array $page Page
* @param integer $sysLanguage System language
*
* @return string
*/
protected function simulateTitle(array $page, $sysLanguage)
{
$this->getFrontendUtility()->initTsfe($page, null, $page, null, $sysLanguage);
$pagetitle = $this->objectManager->get('Metaseo\\Metaseo\\Page\\Part\\PagetitlePart');
$ret = $pagetitle->main($page['title']);
return $ret;
}
/**
* @return \Metaseo\Metaseo\Dao\TemplateDao
*/
protected function getTemplateDao()
{
return $this->objectManager->get('Metaseo\\Metaseo\\Dao\\TemplateDao');
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax\PageSeo;
use Metaseo\Metaseo\Controller\Ajax\AbstractPageSeoController;
class SearchEnginesController extends AbstractPageSeoController
{
const LIST_TYPE = 'searchengines';
/**
* @inheritDoc
*/
protected function initFieldList()
{
$this->fieldList = array(
'tx_metaseo_canonicalurl',
'tx_metaseo_is_exclude',
'tx_metaseo_priority',
);
}
}

View File

@@ -0,0 +1,109 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax\PageSeo;
use Metaseo\Metaseo\Controller\Ajax\AbstractPageSeoSimController;
use Metaseo\Metaseo\DependencyInjection\Utility\HttpUtility;
use Metaseo\Metaseo\Exception\Ajax\AjaxException;
use Metaseo\Metaseo\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
class UrlController extends AbstractPageSeoSimController
{
const LIST_TYPE = 'url';
/**
* @inheritDoc
*/
protected function initFieldList()
{
$this->fieldList = array(
'title',
'url_scheme',
'alias',
'tx_realurl_pathsegment',
'tx_realurl_pathoverride',
'tx_realurl_exclude',
);
}
/**
* @inheritDoc
*/
protected function executeSimulate()
{
$pid = (int)$this->postVar['pid'];
if (empty($pid)) {
throw new AjaxException(
'message.error.typo3_page_not_found',
'[0x4FBF3C0A]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
$page = $this->getPageSeoDao()->getPageById($pid);
if (empty($page)) {
throw new AjaxException(
'message.error.typo3_page_not_found',
'[0x4FBF3C0B]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
if (ExtensionManagementUtility::isLoaded('realurl')) {
// Disable caching for url
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']['_DEFAULT']['enableUrlDecodeCache'] = 0;
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']['_DEFAULT']['enableUrlEncodeCache'] = 0;
$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['realurl']['_DEFAULT']['disablePathCache'] = 1;
}
$this->getFrontendUtility()->initTsfe($page, null, $page, null);
$ret = $this->getFrontendUtility()->getTypoLinkUrl(array('parameter' => $page['uid']));
if (!empty($ret)) {
$ret = GeneralUtility::fullUrl($ret);
}
if (empty($ret)) {
throw new AjaxException(
'message.error.url_generation_failed',
'[0x4FBF3C01]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
return array(
'url' => $ret,
);
}
}

View File

@@ -0,0 +1,69 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax;
use TYPO3\CMS\Core\Http\AjaxRequestHandler;
interface PageSeoInterface
{
/**
* Executes an AJAX request which displays the data (usually as a list)
*
* @param array $params Array of parameters from the AJAX interface, currently unused (as of 6.2.14)
* becomes available starting with 7.4.0 (c048cede,
* https://forge.typo3.org/issues/68186)
* @param AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
*
* @return void
*/
public function indexAction($params = array(), AjaxRequestHandler &$ajaxObj = null);
/**
* Executes an AJAX request which updates the data in the database
*
* @param array $params Array of parameters from the AJAX interface, currently unused (as of 6.2.14)
* becomes available starting with 7.4.0 (c048cede,
* https://forge.typo3.org/issues/68186)
* @param AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
*
* @return void
*/
public function updateAction($params = array(), AjaxRequestHandler &$ajaxObj = null);
/**
* Executes an AJAX request which updates the data in the database recursively
*
* @param array $params Array of parameters from the AJAX interface, currently unused (as of 6.2.14)
* becomes available starting with 7.4.0 (c048cede,
* https://forge.typo3.org/issues/68186)
* @param AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
*
* @return void
*/
public function updateRecursiveAction($params = array(), AjaxRequestHandler &$ajaxObj = null);
}

View File

@@ -0,0 +1,44 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax;
use TYPO3\CMS\Core\Http\AjaxRequestHandler;
interface PageSeoSimulateInterface extends PageSeoInterface
{
/**
* Executes an AJAX request which simulates field values
*
* @param array $params Array of parameters from the AJAX interface, currently unused (as of 6.2.14)
* becomes available starting with 7.4.0 (c048cede,
* https://forge.typo3.org/issues/68186)
* @param AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
*
* @return void
*/
public function simulateAction($params = array(), AjaxRequestHandler &$ajaxObj = null);
}

View File

@@ -0,0 +1,389 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax;
use Exception;
use Metaseo\Metaseo\Controller\AbstractAjaxController;
use Metaseo\Metaseo\DependencyInjection\Utility\HttpUtility;
use Metaseo\Metaseo\Exception\Ajax\AjaxException;
use Metaseo\Metaseo\Utility\DatabaseUtility;
use Metaseo\Metaseo\Utility\SitemapUtility;
use TYPO3\CMS\Core\Http\AjaxRequestHandler;
/**
* TYPO3 Backend ajax module sitemap
*/
class SitemapController extends AbstractAjaxController implements SitemapInterface
{
const AJAX_PREFIX = 'tx_metaseo_controller_ajax_sitemap';
/**
* @inheritDoc
*/
public function indexAction($params = array(), AjaxRequestHandler &$ajaxObj = null)
{
try {
$this->init();
$ajaxObj->setContent($this->executeIndex());
} catch (Exception $exception) {
$this->ajaxExceptionHandler($exception, $ajaxObj);
}
$ajaxObj->setContentFormat(self::CONTENT_FORMAT_JSON);
$ajaxObj->render();
}
/**
* Return sitemap entry list for root tree
*
* @return array
*/
protected function executeIndex()
{
// Init
$rootPid = (int)$this->postVar['pid'];
$offset = (int)$this->postVar['start'];
$itemsPerPage = (int)$this->postVar['pagingSize'];
$searchFulltext = trim((string)$this->postVar['criteriaFulltext']);
$searchPageUid = trim((int)$this->postVar['criteriaPageUid']);
$searchPageLanguage = trim((string)$this->postVar['criteriaPageLanguage']);
$searchPageDepth = trim((string)$this->postVar['criteriaPageDepth']);
$searchIsBlacklisted = (bool)trim((string)$this->postVar['criteriaIsBlacklisted']);
// ############################
// Criteria
// ############################
$where = array();
// Root pid limit
$where[] = 's.page_rootpid = ' . (int)$rootPid;
// Fulltext
if (!empty($searchFulltext)) {
$where[] = 's.page_url LIKE ' . DatabaseUtility::quote('%' . $searchFulltext . '%', 'tx_metaseo_sitemap');
}
// Page id
if (!empty($searchPageUid)) {
$where[] = 's.page_uid = ' . (int)$searchPageUid;
}
// Language
if ($searchPageLanguage != -1 && strlen($searchPageLanguage) >= 1) {
$where[] = 's.page_language = ' . (int)$searchPageLanguage;
}
// Depth
if ($searchPageDepth != -1 && strlen($searchPageDepth) >= 1) {
$where[] = 's.page_depth = ' . (int)$searchPageDepth;
}
if ($searchIsBlacklisted) {
$where[] = 's.is_blacklisted = 1';
}
// Filter blacklisted page types
$where[] = DatabaseUtility::conditionNotIn(
'p.doktype',
SitemapUtility::getDoktypeBlacklist()
);
// Build where
$where = DatabaseUtility::buildCondition($where);
// ############################
// Pager
// ############################
// Fetch total count of items with this filter settings
$query = 'SELECT COUNT(*) AS count
FROM tx_metaseo_sitemap s
INNER JOIN pages p ON p.uid = s.page_uid
WHERE ' . $where;
$itemCount = DatabaseUtility::getOne($query);
// ############################
// Sort
// ############################
// default sort
$sort = 's.page_depth ASC, s.page_uid ASC';
if (!empty($this->sortField) && !empty($this->sortDir)) {
// already filtered
$sort = $this->sortField . ' ' . $this->sortDir;
}
// ############################
// Fetch sitemap
// ############################
$query = 'SELECT s.uid,
s.page_rootpid,
s.page_uid,
s.page_language,
s.page_url,
s.page_depth,
s.page_type,
s.is_blacklisted,
p.tx_metaseo_is_exclude,
FROM_UNIXTIME(s.tstamp) as tstamp,
FROM_UNIXTIME(s.crdate) as crdate
FROM tx_metaseo_sitemap s
INNER JOIN pages p ON p.uid = s.page_uid
WHERE ' . $where . '
ORDER BY ' . $sort . '
LIMIT ' . (int)$offset . ', ' . (int)$itemsPerPage;
$list = DatabaseUtility::getAll($query);
return array(
'results' => $itemCount,
'rows' => $list,
);
}
/**
* @inheritDoc
*/
public function blacklistAction($params = array(), AjaxRequestHandler &$ajaxObj = null)
{
try {
$this->init();
$ajaxObj->setContent($this->executeBlacklist());
} catch (Exception $exception) {
$this->ajaxExceptionHandler($exception, $ajaxObj);
}
$ajaxObj->setContentFormat(self::CONTENT_FORMAT_JSON);
$ajaxObj->render();
}
/*
* Blacklist sitemap entries
*
* @return array
*
* @throws AjaxException
*/
protected function executeBlacklist()
{
$uidList = $this->postVar['uidList'];
$rootPid = (int)$this->postVar['pid'];
$uidList = DatabaseUtility::connection()->cleanIntArray($uidList);
if (empty($uidList) || empty($rootPid)) {
throw new AjaxException(
'message.warning.incomplete_data_received.message',
'[0x4FBF3C10]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
$where = array();
$where[] = 'page_rootpid = ' . (int)$rootPid;
$where[] = DatabaseUtility::conditionIn('uid', $uidList);
$where = DatabaseUtility::buildCondition($where);
$query = 'UPDATE tx_metaseo_sitemap
SET is_blacklisted = 1
WHERE ' . $where;
DatabaseUtility::exec($query);
return array();
}
/**
* @inheritDoc
*/
public function whitelistAction($params = array(), AjaxRequestHandler &$ajaxObj = null)
{
try {
$this->init();
$ajaxObj->setContent($this->executeWhitelist());
} catch (Exception $exception) {
$this->ajaxExceptionHandler($exception, $ajaxObj);
}
$ajaxObj->setContentFormat(self::CONTENT_FORMAT_JSON);
$ajaxObj->render();
}
/*
* Whitelist sitemap entries
*
* @return array
*
* @throws AjaxException
*/
protected function executeWhitelist()
{
$uidList = $this->postVar['uidList'];
$rootPid = (int)$this->postVar['pid'];
$uidList = DatabaseUtility::connection()->cleanIntArray($uidList);
if (empty($uidList) || empty($rootPid)) {
throw new AjaxException(
'message.warning.incomplete_data_received.message',
'[0x4FBF3C12]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
$where = array();
$where[] = 'page_rootpid = ' . (int)$rootPid;
$where[] = DatabaseUtility::conditionIn('uid', $uidList);
$where = DatabaseUtility::buildCondition($where);
$query = 'UPDATE tx_metaseo_sitemap
SET is_blacklisted = 0
WHERE ' . $where;
DatabaseUtility::exec($query);
return array();
}
/**
* @inheritDoc
*/
public function deleteAction($params = array(), AjaxRequestHandler &$ajaxObj = null)
{
try {
$this->init();
$ajaxObj->setContent($this->executeDelete());
} catch (Exception $exception) {
$this->ajaxExceptionHandler($exception, $ajaxObj);
}
$ajaxObj->setContentFormat(self::CONTENT_FORMAT_JSON);
$ajaxObj->render();
}
/**
* Delete sitemap entries
*
* @return array
*
* @throws AjaxException
*/
protected function executeDelete()
{
$uidList = $this->postVar['uidList'];
$rootPid = (int)$this->postVar['pid'];
$uidList = DatabaseUtility::connection()->cleanIntArray($uidList);
if (empty($uidList) || empty($rootPid)) {
throw new AjaxException(
'message.warning.incomplete_data_received.message',
'[0x4FBF3C11]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
$where = array();
$where[] = 'page_rootpid = ' . (int)$rootPid;
$where[] = DatabaseUtility::conditionIn('uid', $uidList);
$where = DatabaseUtility::buildCondition($where);
$query = 'DELETE FROM tx_metaseo_sitemap
WHERE ' . $where;
DatabaseUtility::exec($query);
return array();
}
/**
* @inheritDoc
*/
public function deleteAllAction($params = array(), AjaxRequestHandler &$ajaxObj = null)
{
try {
$this->init();
$ajaxObj->setContent($this->executeDeleteAll());
} catch (Exception $exception) {
$this->ajaxExceptionHandler($exception, $ajaxObj);
}
$ajaxObj->setContentFormat(self::CONTENT_FORMAT_JSON);
$ajaxObj->render();
}
/**
* Delete all sitemap entries
*
* @return array
*
* @throws AjaxException
*/
protected function executeDeleteAll()
{
$rootPid = (int)$this->postVar['pid'];
if (empty($rootPid)) {
throw new AjaxException(
'message.warning.incomplete_data_received.message',
'[0x4FBF3C12]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
$where = array();
$where[] = 'page_rootpid = ' . (int)$rootPid;
$where = DatabaseUtility::buildCondition($where);
$query = 'DELETE FROM tx_metaseo_sitemap
WHERE ' . $where;
DatabaseUtility::exec($query);
return array();
}
/**
* @inheritDoc
*/
protected function getAjaxPrefix()
{
return self::AJAX_PREFIX;
}
/**
* Returns array of classes which contain Ajax controllers with <ajaxPrefix> => <className)
*
* @return array
*/
public static function getBackendAjaxClassNames()
{
return array(
self::AJAX_PREFIX => __CLASS__,
);
}
}

View File

@@ -0,0 +1,95 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller\Ajax;
use TYPO3\CMS\Core\Http\AjaxRequestHandler;
interface SitemapInterface
{
/**
* Executes an AJAX request which displays the data (usually as a list)
*
* @param array $params Array of parameters from the AJAX interface, currently unused (as of 6.2.14)
* becomes available starting with 7.4.0 (c048cede,
* https://forge.typo3.org/issues/68186)
* @param AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
*
* @return void
*/
public function indexAction($params = array(), AjaxRequestHandler &$ajaxObj = null);
/**
* Blacklists a sitemap entry so that it does not appear in the sitemap presented to search engines
*
* @param array $params Array of parameters from the AJAX interface, currently unused (as of 6.2.14)
* becomes available starting with 7.4.0 (c048cede,
* https://forge.typo3.org/issues/68186)
* @param AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
*
* @return void
*/
public function blacklistAction($params = array(), AjaxRequestHandler &$ajaxObj = null);
/**
* Undoes the blacklist operation
*
* @param array $params Array of parameters from the AJAX interface, currently unused (as of 6.2.14)
* becomes available starting with 7.4.0 (c048cede,
* https://forge.typo3.org/issues/68186)
* @param AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
*
* @return void
*/
public function whitelistAction($params = array(), AjaxRequestHandler &$ajaxObj = null);
/**
* Deletes an entry from the sitemap. Entry will reappear as soon as it's indexed again
*
* @param array $params Array of parameters from the AJAX interface, currently unused (as of 6.2.14)
* becomes available starting with 7.4.0 (c048cede,
* https://forge.typo3.org/issues/68186)
* @param AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
*
* @return void
*/
public function deleteAction($params = array(), AjaxRequestHandler &$ajaxObj = null);
/**
* Performs delete operation for all the entries in the sitemap
*
* @param array $params Array of parameters from the AJAX interface, currently unused (as of 6.2.14)
* becomes available starting with 7.4.0 (c048cede,
* https://forge.typo3.org/issues/68186)
* @param AjaxRequestHandler $ajaxObj Object of type AjaxRequestHandler
*
* @return void
*/
public function deleteAllAction($params = array(), AjaxRequestHandler &$ajaxObj = null);
}

View File

@@ -0,0 +1,152 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller;
use Metaseo\Metaseo\Backend\Module\AbstractStandardModule;
use Metaseo\Metaseo\Utility\BackendUtility;
use Metaseo\Metaseo\Utility\DatabaseUtility;
use Metaseo\Metaseo\Utility\RootPageUtility;
use TYPO3\CMS\Backend\Utility\BackendUtility as Typo3BackendUtility;
use TYPO3\CMS\Core\Messaging\FlashMessage;
/**
* TYPO3 Backend module root settings
*/
class BackendControlCenterController extends AbstractStandardModule
{
// ########################################################################
// Attributes
// ########################################################################
// ########################################################################
// Methods
// ########################################################################
/**
* Main action
*/
public function mainAction()
{
// #################
// Root page list
// #################
$rootPageList = BackendUtility::getRootPageList();
$rootIdList = array_keys($rootPageList);
$rootPidCondition = null;
if (!empty($rootIdList)) {
$rootPidCondition = 'p.uid IN (' . implode(',', $rootIdList) . ')';
} else {
$rootPidCondition = '1=0';
}
// #################
// Root setting list (w/ automatic creation)
// #################
// check which root pages have no root settings
$query = 'SELECT p.uid
FROM pages p
LEFT JOIN tx_metaseo_setting_root seosr
ON seosr.pid = p.uid
AND seosr.deleted = 0
WHERE ' . $rootPidCondition . '
AND seosr.uid IS NULL';
$rowList = DatabaseUtility::getAll($query);
foreach ($rowList as $row) {
$tmpUid = $row['uid'];
$query = 'INSERT INTO tx_metaseo_setting_root (pid, tstamp, crdate, cruser_id)
VALUES (' . (int)$tmpUid . ',
' . (int)time() . ',
' . (int)time() . ',
' . (int)$GLOBALS['BE_USER']->user['uid'] . ')';
DatabaseUtility::execInsert($query);
}
$rootSettingList = BackendUtility::getRootPageSettingList();
// #################
// Domain list
// ##################
// Fetch domain name
$query = 'SELECT uid,
pid,
domainName,
forced
FROM sys_domain
WHERE hidden = 0
ORDER BY forced DESC,
sorting';
$rowList = DatabaseUtility::getAll($query);
$domainList = array();
foreach ($rowList as $row) {
$domainList[$row['pid']][$row['uid']] = $row;
}
// #################
// Build root page list
// #################
unset($page);
foreach ($rootPageList as $pageId => &$page) {
// Domain list
$page['domainList'] = '';
if (!empty($domainList[$pageId])) {
$page['domainList'] = $domainList[$pageId];
}
// Settings
$page['rootSettings'] = array();
if (!empty($rootSettingList[$pageId])) {
$page['rootSettings'] = $rootSettingList[$pageId];
}
// Settings available
$page['settingsLink'] = Typo3BackendUtility::editOnClick(
'&edit[tx_metaseo_setting_root][' . $rootSettingList[$pageId]['uid'] . ']=edit'
);
$page['sitemapLink'] = RootPageUtility::getSitemapIndexUrl($pageId);
$page['robotsTxtLink'] = RootPageUtility::getRobotsTxtUrl($pageId);
}
unset($page);
// check if there is any root page
if (empty($rootPageList)) {
$this->addFlashMessage(
$this->translate('message.warning.noRootPage.message'),
$this->translate('message.warning.noRootPage.title'),
FlashMessage::WARNING
);
}
$this->view->assign('RootPageList', $rootPageList);
}
}

View File

@@ -0,0 +1,293 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller;
use Metaseo\Metaseo\Backend\Module\AbstractStandardModule;
use Metaseo\Metaseo\Controller\Ajax\AbstractPageSeoController;
use Metaseo\Metaseo\Controller\Ajax\PageSeo\GeoController;
use Metaseo\Metaseo\Controller\Ajax\PageSeo\MetaDataController;
use Metaseo\Metaseo\Controller\Ajax\PageSeo\PageTitleController;
use Metaseo\Metaseo\Controller\Ajax\PageSeo\PageTitleSimController;
use Metaseo\Metaseo\Controller\Ajax\PageSeo\SearchEnginesController;
use Metaseo\Metaseo\Controller\Ajax\PageSeo\UrlController;
use Metaseo\Metaseo\Utility\DatabaseUtility;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Backend\Utility\IconUtility;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* TYPO3 Backend module page seo
*/
class BackendPageSeoController extends AbstractStandardModule
{
// ########################################################################
// Attributes
// ########################################################################
// ########################################################################
// Methods
// ########################################################################
/**
* Main action
*/
public function mainAction()
{
$this->handleSubAction(MetaDataController::LIST_TYPE);
}
/**
* Geo action
*/
public function geoAction()
{
$this->handleSubAction(GeoController::LIST_TYPE);
}
/**
* searchengines action
*/
public function searchenginesAction()
{
$this->handleSubAction(SearchEnginesController::LIST_TYPE);
}
/**
* url action
*/
public function urlAction()
{
$this->handleSubAction(UrlController::LIST_TYPE);
}
/**
* pagetitle action
*/
public function pagetitleAction()
{
$this->handleSubAction(PageTitleController::LIST_TYPE);
}
/**
* pagetitlesim action
*/
public function pagetitlesimAction()
{
$this->handleSubAction(PageTitleSimController::LIST_TYPE);
}
/**
* @param string $listType
*/
protected function handleSubAction($listType)
{
$pageId = (int) GeneralUtility::_GP('id');
if (empty($pageId)) {
$this->addFlashMessage(
$this->translate('message.warning.no_valid_page.message'),
$this->translate('message.warning.no_valid_page.title'),
FlashMessage::WARNING
);
return;
}
// Load PageTS
$pageTsConf = BackendUtility::getPagesTSconfig($pageId);
// Build language list
$defaultLanguageText = $this->translate('default.language');
$languageFullList = array(
0 => array(
'label' => $this->translate('default.language'),
'flag' => '',
),
);
if (!empty($pageTsConf['mod.']['SHARED.']['defaultLanguageFlag'])) {
$languageFullList[0]['flag'] = $pageTsConf['mod.']['SHARED.']['defaultLanguageFlag'];
}
if (!empty($pageTsConf['mod.']['SHARED.']['defaultLanguageLabel'])) {
$label = $pageTsConf['mod.']['SHARED.']['defaultLanguageLabel'];
$languageFullList[0]['label'] = $this->translate('default.language.named', array($label));
$defaultLanguageText = $pageTsConf['mod.']['SHARED.']['defaultLanguageLabel'];
}
// Fetch other flags
$query = 'SELECT uid,
title,
flag
FROM sys_language
WHERE hidden = 0';
$rowList = DatabaseUtility::getAll($query);
foreach ($rowList as $row) {
$languageFullList[$row['uid']] = array(
'label' => htmlspecialchars($row['title']),
'flag' => htmlspecialchars($row['flag']),
);
}
// Languages
$languageList = array();
foreach ($languageFullList as $langId => $langRow) {
$flag = '';
// Flag (if available)
if (!empty($langRow['flag'])) {
$flag .= '<span class="t3-icon t3-icon-flags t3-icon-flags-' . $langRow['flag']
. ' t3-icon-' . $langRow['flag'] . '"></span>';
$flag .= '&nbsp;';
}
// label
$label = $langRow['label'];
$languageList[] = array(
$langId,
$label,
$flag
);
}
$sysLanguageDefault = (int)$GLOBALS['BE_USER']->getSessionData('MetaSEO.sysLanguage');
if (empty($sysLanguageDefault)) {
$sysLanguageDefault = 0;
}
// ############################
// HTML
// ############################
$realUrlAvailable = ExtensionManagementUtility::isLoaded('realurl');
$ajaxController = AbstractPageSeoController::AJAX_PREFIX . $listType;
if (!array_key_exists($ajaxController, AbstractPageSeoController::getBackendAjaxClassNames())) {
throw new \RuntimeException('Ajax controller with this name was not registered by MetaSEO.');
}
$metaSeoConf = array(
'ajaxController' => $ajaxController,
'pid' => (int)$pageId,
'renderTo' => 'tx-metaseo-sitemap-grid',
'pagingSize' => 50,
'depth' => 2,
'sortField' => 'crdate',
'sortDir' => 'DESC',
'filterIcon' => IconUtility::getSpriteIcon(
'actions-system-tree-search-open'
),
'dataLanguage' => $languageList,
'sysLanguage' => $sysLanguageDefault,
'listType' => $listType,
'criteriaFulltext' => '',
'realurlAvailable' => $realUrlAvailable,
'sprite' => array(
'edit' => IconUtility::getSpriteIcon('actions-document-open'),
'info' => IconUtility::getSpriteIcon('actions-document-info'),
'editor' => IconUtility::getSpriteIcon('actions-system-options-view'),
),
);
$metaSeoLang = array(
'pagingMessage' => 'pager.results',
'pagingEmpty' => 'pager.noresults',
'boolean_yes' => 'boolean.yes',
'boolean_no' => 'boolean.no',
'button_save' => 'button.save',
'button_saverecursively' => 'button.saverecursively',
'button_saverecursively_tooltip' => 'button.saverecursively.tooltip',
'button_cancel' => 'button.cancel',
'labelDepth' => 'label.depth',
'labelSearchFulltext' => 'label.search.fulltext',
'emptySearchFulltext' => 'empty.search.fulltext',
'labelSearchPageLanguage' => 'label.search.page_language',
'emptySearchPageLanguage' => '',
'page_uid' => 'header.sitemap.page_uid',
'page_title' => 'header.sitemap.page_title',
'page_keywords' => 'header.sitemap.page_keywords',
'page_description' => 'header.sitemap.page_description',
'page_abstract' => 'header.sitemap.page_abstract',
'page_author' => 'header.sitemap.page_author',
'page_author_email' => 'header.sitemap.page_author_email',
'page_lastupdated' => 'header.sitemap.page_lastupdated',
'page_geo_lat' => 'header.sitemap.page_geo_lat',
'page_geo_long' => 'header.sitemap.page_geo_long',
'page_geo_place' => 'header.sitemap.page_geo_place',
'page_geo_region' => 'header.sitemap.page_geo_region',
'page_tx_metaseo_pagetitle' => 'header.sitemap.page_tx_metaseo_pagetitle',
'page_tx_metaseo_pagetitle_rel' => 'header.sitemap.page_tx_metaseo_pagetitle_rel',
'page_tx_metaseo_pagetitle_prefix' => 'header.sitemap.page_tx_metaseo_pagetitle_prefix',
'page_tx_metaseo_pagetitle_suffix' => 'header.sitemap.page_tx_metaseo_pagetitle_suffix',
'page_title_simulated' => 'header.pagetitlesim.title_simulated',
'page_searchengine_canonicalurl' => 'header.searchengine_canonicalurl',
'page_searchengine_is_exclude' => 'header.searchengine_is_excluded',
'searchengine_is_exclude_disabled' => 'searchengine.is_exclude_disabled',
'searchengine_is_exclude_enabled' => 'searchengine.is_exclude_enabled',
'page_sitemap_priority' => 'header.sitemap.priority',
'page_url_scheme' => 'header.url_scheme',
'page_url_scheme_default' => 'page.url_scheme_default',
'page_url_scheme_http' => 'page.url_scheme_http',
'page_url_scheme_https' => 'page.url_scheme_https',
'page_url_alias' => 'header.url_alias',
'page_url_realurl_pathsegment' => 'header.url_realurl_pathsegment',
'page_url_realurl_pathoverride' => 'header.url_realurl_pathoverride',
'page_url_realurl_exclude' => 'header.url_realurl_exclude',
'qtip_pagetitle_simulate' => 'qtip.pagetitle_simulate',
'qtip_url_simulate' => 'qtip.url_simulate',
'metaeditor_title' => 'metaeditor.title',
'metaeditor_tab_opengraph' => 'metaeditor.tab.opengraph',
'metaeditor_button_hin' => 'metaeditor.button.hint',
'value_from_base' => 'value.from_base',
'value_from_overlay' => 'value.from_overlay',
'value_only_base' => 'value.only_base',
'value_default' => 'value_default',
);
// translate list
$metaSeoLang = $this->translateList($metaSeoLang);
$metaSeoLang['emptySearchPageLanguage'] = $defaultLanguageText;
$this->view->assign(
'JavaScript',
'Ext.namespace("MetaSeo.overview");
MetaSeo.overview.conf = ' . json_encode($metaSeoConf) . ';
MetaSeo.overview.conf.lang = ' . json_encode($metaSeoLang) . ';
'
);
}
}

View File

@@ -0,0 +1,147 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller;
use Metaseo\Metaseo\Backend\Module\AbstractStandardModule;
use Metaseo\Metaseo\Utility\BackendUtility;
use Metaseo\Metaseo\Utility\DatabaseUtility;
use TYPO3\CMS\Backend\Utility\BackendUtility as Typo3BackendUtility;
use TYPO3\CMS\Core\Messaging\FlashMessage;
/**
* TYPO3 Backend module root settings
*/
class BackendRootSettingsController extends AbstractStandardModule
{
// ########################################################################
// Attributes
// ########################################################################
// ########################################################################
// Methods
// ########################################################################
/**
* Main action
*/
public function mainAction()
{
// #################
// Root page list
// #################
$rootPageList = BackendUtility::getRootPageList();
$rootIdList = array_keys($rootPageList);
$rootPidCondition = null;
if (!empty($rootIdList)) {
$rootPidCondition = 'p.uid IN (' . implode(',', $rootIdList) . ')';
} else {
$rootPidCondition = '1=0';
}
// #################
// Root setting list (w/ automatic creation)
// #################
// check which root pages have no root settings
$query = 'SELECT p.uid
FROM pages p
LEFT JOIN tx_metaseo_setting_root seosr
ON seosr.pid = p.uid
AND seosr.deleted = 0
WHERE ' . $rootPidCondition . '
AND seosr.uid IS NULL';
$uidList = DatabaseUtility::getCol($query);
foreach ($uidList as $tmpUid) {
$query = 'INSERT INTO tx_metaseo_setting_root (pid, tstamp, crdate, cruser_id)
VALUES (' . (int)$tmpUid . ',
' . (int)time() . ',
' . (int)time() . ',
' . (int)$GLOBALS['BE_USER']->user['uid'] . ')';
DatabaseUtility::execInsert($query);
}
$rootSettingList = BackendUtility::getRootPageSettingList();
// #################
// Domain list
// ##################
// Fetch domain name
$query = 'SELECT uid,
pid,
domainName,
forced
FROM sys_domain
WHERE hidden = 0
ORDER BY forced DESC,
sorting';
$rowList = DatabaseUtility::getAll($query);
$domainList = array();
foreach ($rowList as $row) {
$domainList[$row['pid']][$row['uid']] = $row;
}
// #################
// Build root page list
// #################
unset($page);
foreach ($rootPageList as $pageId => &$page) {
// Domain list
$page['domainList'] = '';
if (!empty($domainList[$pageId])) {
$page['domainList'] = $domainList[$pageId];
}
// Settings
$page['rootSettings'] = array();
if (!empty($rootSettingList[$pageId])) {
$page['rootSettings'] = $rootSettingList[$pageId];
}
// Settings available
$page['settingsLink'] = Typo3BackendUtility::editOnClick(
'&edit[tx_metaseo_setting_root][' . $rootSettingList[$pageId]['uid'] . ']=edit'
);
}
unset($page);
// check if there is any root page
if (empty($rootPageList)) {
$this->addFlashMessage(
$this->translate('message.warning.noRootPage.message'),
$this->translate('message.warning.noRootPage.title'),
FlashMessage::WARNING
);
}
$this->view->assign('RootPageList', $rootPageList);
}
}

View File

@@ -0,0 +1,349 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Controller;
use Metaseo\Metaseo\Backend\Module\AbstractStandardModule;
use Metaseo\Metaseo\Controller\Ajax\SitemapController;
use Metaseo\Metaseo\Utility\BackendUtility;
use Metaseo\Metaseo\Utility\DatabaseUtility;
use Metaseo\Metaseo\Utility\SitemapUtility;
use TYPO3\CMS\Backend\Utility\BackendUtility as Typo3BackendUtility;
use TYPO3\CMS\Backend\Utility\IconUtility;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* TYPO3 Backend module sitemap
*/
class BackendSitemapController extends AbstractStandardModule
{
// ########################################################################
// Attributes
// ########################################################################
// ########################################################################
// Methods
// ########################################################################
/**
* Main action
*/
public function mainAction()
{
// Init
$rootPageList = BackendUtility::getRootPageList();
$rootSettingList = BackendUtility::getRootPageSettingList();
// ############################
// Fetch
// ############################
// Get statistics
$query = 'SELECT s.page_rootpid,
COUNT(*) AS sum_total,
COUNT(s.page_uid) AS sum_pages
FROM tx_metaseo_sitemap s
INNER JOIN pages p
ON p.uid = s.page_uid
AND p.deleted = 0
AND ' . DatabaseUtility::conditionNotIn(
'p.doktype',
SitemapUtility::getDoktypeBlacklist()
) . '
GROUP BY page_rootpid';
$statsList = DatabaseUtility::getAllWithIndex($query, 'page_rootpid');
// Fetch domain name
$query = 'SELECT uid,
pid,
domainName,
forced
FROM sys_domain
WHERE hidden = 0
ORDER BY forced DESC,
sorting';
$rowList = DatabaseUtility::getAll($query);
$domainList = array();
foreach ($rowList as $row) {
$pid = $row['pid'];
if (!empty($row['forced'])) {
$domainList[$pid] = $row['domainName'];
} elseif (empty($domainList[$pid])) {
$domainList[$pid] = $row['domainName'];
}
}
// #################
// Build root page list
// #################
unset($page);
foreach ($rootPageList as $pageId => &$page) {
$stats = array(
'sum_pages' => 0,
'sum_total' => 0,
'sum_xml_pages' => 0,
);
// Setting row
$settingRow = array();
if (!empty($rootSettingList[$pageId])) {
$settingRow = $rootSettingList[$pageId];
}
// Calc stats
if (!empty($statsList[$pageId])) {
foreach ($statsList[$pageId] as $statsKey => $statsValue) {
$stats[$statsKey] = $statsValue;
}
}
$joinWhere = DatabaseUtility::conditionNotIn(
'p.doktype',
SitemapUtility::getDoktypeBlacklist()
);
// Root statistics
$query = 'SELECT COUNT(s.page_uid)
FROM tx_metaseo_sitemap s
INNER JOIN pages p
ON p.uid = s.page_uid
AND ' . $joinWhere . '
WHERE s.page_rootpid = ' . (int)$pageId;
$stats['sum_pages'] = DatabaseUtility::getOne($query);
$pagesPerXmlSitemap = 1000;
if (!empty($settingRow['sitemap_page_limit'])) {
$pagesPerXmlSitemap = $settingRow['sitemap_page_limit'];
}
$sumXmlPages = ceil($stats['sum_total'] / $pagesPerXmlSitemap);
$stats['sum_xml_pages'] = sprintf($this->translate('sitemap.xml.pages.total'), $sumXmlPages);
$page['stats'] = $stats;
}
unset($page);
// check if there is any root page
if (empty($rootPageList)) {
$this->addFlashMessage(
$this->translate('message.warning.noRootPage.message'),
$this->translate('message.warning.noRootPage.title'),
FlashMessage::WARNING
);
}
$this->view->assign('RootPageList', $rootPageList);
}
/**
* Sitemap action
*/
public function sitemapAction()
{
$params = GeneralUtility::_GP('tx_metaseo_metaseometaseo_metaseositemap');
$rootPid = $params['pageId'];
if (empty($rootPid)) {
return;
}
$rootPageList = BackendUtility::getRootPageList();
$rootPage = $rootPageList[$rootPid];
// ###############################
// Fetch
// ###############################
$pageTsConf = Typo3BackendUtility::getPagesTSconfig($rootPid);
$languageFullList = array(
0 => array(
'label' => $this->translate('default.language'),
'flag' => '',
),
);
if (!empty($pageTsConf['mod.']['SHARED.']['defaultLanguageFlag'])) {
$languageFullList[0]['flag'] = $pageTsConf['mod.']['SHARED.']['defaultLanguageFlag'];
}
if (!empty($pageTsConf['mod.']['SHARED.']['defaultLanguageLabel'])) {
$languageFullList[0]['label'] = $pageTsConf['mod.']['SHARED.']['defaultLanguageLabel'];
}
// Fetch domain name
$query = 'SELECT uid,
title,
flag
FROM sys_language
WHERE hidden = 0';
$rowList = DatabaseUtility::getAll($query);
foreach ($rowList as $row) {
$languageFullList[$row['uid']] = array(
'label' => htmlspecialchars($row['title']),
'flag' => htmlspecialchars($row['flag']),
);
}
// Languages
$languageList = array();
$languageList[] = array(
-1,
$this->translate('empty.search.page_language'),
);
foreach ($languageFullList as $langId => $langRow) {
$flag = '';
// Flag (if available)
if (!empty($langRow['flag'])) {
$flag .= '<span class="t3-icon t3-icon-flags t3-icon-flags-' . $langRow['flag']
. ' t3-icon-' . $langRow['flag'] . '"></span>';
$flag .= '&nbsp;';
}
// label
$label = $langRow['label'];
$languageList[] = array(
$langId,
$label,
$flag
);
}
// Depth
$depthList = array();
$depthList[] = array(
-1,
$this->translate('empty.search.page_depth'),
);
$query = 'SELECT DISTINCT page_depth
FROM tx_metaseo_sitemap
WHERE page_rootpid = ' . (int)$rootPid;
foreach (DatabaseUtility::getCol($query) as $depth) {
$depthList[] = array(
$depth,
$depth,
);
}
// ###############################
// Page/JS
// ###############################
$metaSeoConf = array(
'ajaxController' => SitemapController::AJAX_PREFIX,
'pid' => (int)$rootPid,
'renderTo' => 'tx-metaseo-sitemap-grid',
'pagingSize' => 50,
'sortField' => 'crdate',
'sortDir' => 'DESC',
'filterIcon' => IconUtility::getSpriteIcon(
'actions-system-tree-search-open'
),
'dataLanguage' => $languageList,
'dataDepth' => $depthList,
'criteriaFulltext' => '',
'criteriaPageUid' => '',
'criteriaPageLanguage' => '',
'criteriaPageDepth' => '',
'criteriaIsBlacklisted' => 0,
'languageFullList' => $languageFullList,
);
$metaSeoLang = array(
'title' => 'title.sitemap.list',
'pagingMessage' => 'pager.results',
'pagingEmpty' => 'pager.noresults',
'sitemap_page_uid' => 'header.sitemap.page_uid',
'sitemap_page_url' => 'header.sitemap.page_url',
'sitemap_page_type' => 'header.sitemap.page_type',
'sitemap_page_depth' => 'header.sitemap.page_depth',
'sitemap_page_language' => 'header.sitemap.page_language',
'sitemap_page_is_blacklisted' => 'header.sitemap.page_is_blacklisted',
'page_tx_metaseo_is_exclude' => 'header.sitemap.page_tx_metaseo_is_exclude',
'sitemap_tstamp' => 'header.sitemap.tstamp',
'sitemap_crdate' => 'header.sitemap.crdate',
'labelSearchFulltext' => 'label.search.fulltext',
'emptySearchFulltext' => 'empty.search.fulltext',
'labelSearchPageUid' => 'label.search.page_uid',
'emptySearchPageUid' => 'empty.search.page_uid',
'labelSearchPageLanguage' => 'label.search.page_language',
'emptySearchPageLanguage' => 'empty.search.page_language',
'labelSearchPageDepth' => 'label.search.page_depth',
'emptySearchPageDepth' => 'empty.search.page_depth',
'labelSearchIsBlacklisted' => 'label.search.is_blacklisted',
'labelYes' => 'label.yes',
'labelNo' => 'label.no',
'buttonYes' => 'button.yes',
'buttonNo' => 'button.no',
'buttonDelete' => 'button.delete',
'buttonDeleteHint' => 'button.delete.hint',
'buttonBlacklist' => 'button.blacklist',
'buttonBlacklistHint' => 'button.blacklist.hint',
'buttonWhitelist' => 'button.whitelist',
'buttonWhitelistHint' => 'button.whitelist.hint',
'buttonDeleteAll' => 'button.delete_all',
'messageDeleteTitle' => 'message.delete.title',
'messageDeleteQuestion' => 'message.delete.question',
'messageDeleteAllTitle' => 'message.delete_all.title',
'messageDeleteAllQuestion' => 'message.delete_all.question',
'messageBlacklistTitle' => 'message.blacklist.title',
'messageBlacklistQuestion' => 'message.blacklist.question',
'messageWhitelistTitle' => 'message.whitelist.title',
'messageWhitelistQuestion' => 'message.whitelist.question',
'errorDeleteFailedMessage' => 'message.delete.failed_body',
'errorNoSelectedItemsBody' => 'message.no_selected_items',
'today' => 'today',
'yesterday' => 'yesterday',
'sitemapPageType' => array(
0 => 'sitemap.pagetype.0',
1 => 'sitemap.pagetype.1',
),
);
// translate list
$metaSeoLang = $this->translateList($metaSeoLang);
$metaSeoLang['title'] = sprintf($metaSeoLang['title'], $rootPage['title'], $rootPid);
$this->view->assign(
'JavaScript',
'Ext.namespace("MetaSeo.sitemap");
MetaSeo.sitemap.conf = ' . json_encode($metaSeoConf) . ';
MetaSeo.sitemap.conf.lang = ' . json_encode($metaSeoLang) . ';
'
);
}
}

View File

@@ -0,0 +1,85 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Dao;
use TYPO3\CMS\Core\DataHandling\DataHandler;
use TYPO3\CMS\Core\SingletonInterface;
class Dao implements SingletonInterface
{
/**
* DataHandler (TCE)
*
* @var \TYPO3\CMS\Core\DataHandling\DataHandler
*/
protected $dataHandler;
/**
* Check if field is in table (TCA)
*
* @param string $table Table
* @param string $field Field
*
* @return boolean
*/
protected function isFieldInTcaTable($table, $field)
{
return isset($GLOBALS['TCA'][$table]['columns'][$field]);
}
/**
* Return (cached) instance of t3lib_TCEmain
*
* @return \TYPO3\CMS\Core\DataHandling\DataHandler
*/
protected function getDataHandler()
{
$this->dataHandler->start(null, null);
return $this->dataHandler;
}
/**
* @return \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
*/
protected function getBackendUserAuthentication()
{
return $GLOBALS['BE_USER'];
}
/**
* @param DataHandler $dataHandler
*
* @return $this
*/
public function setDataHandler(DataHandler $dataHandler)
{
$this->dataHandler = $dataHandler;
return $this;
}
}

View File

@@ -0,0 +1,327 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Dao;
use Metaseo\Metaseo\DependencyInjection\Utility\HttpUtility;
use Metaseo\Metaseo\Exception\Ajax\AjaxException;
use Metaseo\Metaseo\Utility\DatabaseUtility;
use TYPO3\CMS\Backend\Tree\View\PageTreeView;
use TYPO3\CMS\Backend\Utility\BackendUtility;
class PageSeoDao extends Dao
{
/**
* @var PageTreeView
*/
protected $pageTreeView;
/**
* Return default tree
*
* @param array $page Root page
* @param integer $depth Depth
* @param integer $sysLanguage System language
* @param array $fieldList Field list
*
* @return array
*/
public function index(array $page, $depth, $sysLanguage, $fieldList = array())
{
$rootPid = $page['uid'];
$list = array();
$fieldList[] = 'pid';
$pageIdList = array();
// ###########################
// Build tree
// ############################
// Init tree
/** @var \TYPO3\CMS\Backend\Tree\View\PageTreeView $tree */
$tree = $this->pageTreeView;
foreach ($fieldList as $field) {
$tree->addField($field, true);
}
$tree->init(
'AND doktype IN (1,4) AND ' . $this->getBackendUserAuthentication()->getPagePermsClause(1)
);
$tree->tree[] = array(
'row' => $page,
'invertedDepth' => 0,
);
$tree->getTree($rootPid, $depth, '');
// Build tree list
foreach ($tree->tree as $row) {
$tmp = $row['row'];
$list[$tmp['uid']] = $tmp;
$pageIdList[$tmp['uid']] = $tmp['uid'];
}
// Calc depth
$rootLineRaw = array();
foreach ($list as $row) {
$rootLineRaw[$row['uid']] = $row['pid'];
}
$rootLineRaw[$rootPid] = null;
// overlay status "current"
$defaultOverlayStatus = 0;
if (!empty($sysLanguage)) {
// overlay status "only available from base"
$defaultOverlayStatus = 2;
}
unset($row);
foreach ($list as &$row) {
// Set field as main fields
foreach ($fieldList as $fieldName) {
$row['_overlay'][$fieldName] = $defaultOverlayStatus;
$row['_base'][$fieldName] = $row[$fieldName];
}
$row['_depth'] = $this->listCalcDepth($row['uid'], $rootLineRaw);
}
unset($row);
// ############################
// Language overlay
// ############################
if (!empty($sysLanguage) && !empty($pageIdList)) {
// Fetch all overlay rows for current page list
$overlayFieldList = array();
foreach ($fieldList as $fieldName) {
if ($this->isFieldInTcaTable('pages_language_overlay', $fieldName)) {
$overlayFieldList[$fieldName] = $fieldName;
}
}
// Build list of fields which we need to query
$queryFieldList = array(
'uid',
'pid',
'title',
);
$queryFieldList = array_merge($queryFieldList, $overlayFieldList);
$res = DatabaseUtility::connection()->exec_SELECTquery(
implode(',', $queryFieldList),
'pages_language_overlay',
'pid IN(' . implode(',', $pageIdList) . ') AND sys_language_uid = ' . (int)$sysLanguage
);
// update all overlay status field to "from base"
unset($row);
foreach ($list as &$row) {
foreach ($overlayFieldList as $fieldName) {
$row['_overlay'][$fieldName] = 0;
}
}
unset($row);
while ($overlayRow = DatabaseUtility::connection()->sql_fetch_assoc($res)) {
$pageOriginalId = $overlayRow['pid'];
// Don't use uid and pid
unset($overlayRow['uid'], $overlayRow['pid']);
// inject title
$fieldName = 'title';
if (!empty($overlayRow[$fieldName])) {
$list[$pageOriginalId][$fieldName] = $overlayRow[$fieldName];
}
// inject all other fields
foreach ($fieldList as $fieldName) {
if (!empty($overlayRow[$fieldName])) {
$list[$pageOriginalId][$fieldName] = $overlayRow[$fieldName];
// update overlay status field to "from overlay"
$list[$pageOriginalId]['_overlay'][$fieldName] = 1;
}
}
}
}
return $list;
}
/**
* Calculate the depth of a page
*
* @param integer $pageUid Page UID
* @param array $rootLineRaw Root line (raw list)
* @param integer $depth Current depth
*
* @return integer
*/
protected function listCalcDepth($pageUid, array $rootLineRaw, $depth = null)
{
if ($depth === null) {
$depth = 1;
}
if (empty($rootLineRaw[$pageUid])) {
// found root page
return $depth;
}
// we must be at least in the first depth
++$depth;
$pagePid = $rootLineRaw[$pageUid];
if (!empty($pagePid)) {
// recursive
$depth = $this->listCalcDepth($pagePid, $rootLineRaw, $depth);
}
return $depth;
}
/**
* Update field in page table
*
* @param integer $pid PID
* @param integer|NULL $sysLanguage System language id
* @param string $fieldName Field name
* @param string $fieldValue Field value
*
* @return array
*
* @throws AjaxException
*/
public function updatePageTableField($pid, $sysLanguage, $fieldName, $fieldValue)
{
$tableName = 'pages';
if (!empty($sysLanguage)) {
// check if field is in overlay
if ($this->isFieldInTcaTable('pages_language_overlay', $fieldName)) {
// Field is in pages language overlay
$tableName = 'pages_language_overlay';
}
}
switch ($tableName) {
case 'pages_language_overlay':
// Update field in pages overlay (also logs update event and clear cache for this page)
// check uid of pages language overlay
$query = 'SELECT uid
FROM pages_language_overlay
WHERE pid = ' . (int)$pid . '
AND sys_language_uid = ' . (int)$sysLanguage;
$overlayId = DatabaseUtility::getOne($query);
if (empty($overlayId)) {
// No access
throw new AjaxException(
'message.error.no_language_overlay_found',
'[0x4FBF3C05]',
HttpUtility::HTTP_STATUS_BAD_REQUEST
);
}
// ################
// UPDATE
// ################
$this->getDataHandler()->updateDB(
'pages_language_overlay',
(int)$overlayId,
array(
$fieldName => $fieldValue
)
);
break;
case 'pages':
// Update field in page (also logs update event and clear cache for this page)
$this->getDataHandler()->updateDB(
'pages',
(int)$pid,
array(
$fieldName => $fieldValue
)
);
break;
}
return array();
}
/**
* @param $pid
*
* @return array|NULL
*/
public function getPageById($pid)
{
return $this->getRecord('pages', $pid);
}
/**
* Gets record with uid = $uid from $table
* You can set $field to a list of fields (default is '*')
* Additional WHERE clauses can be added by $where (fx. ' AND blabla = 1')
* Will automatically check if records has been deleted and if so, not return anything.
* $table must be found in $GLOBALS['TCA']
*
* @param string $table Table name present in $GLOBALS['TCA']
* @param int $uid UID of record
* @param string $fields List of fields to select
* @param string $where Additional WHERE clause, eg. " AND blablabla = 0
* @param bool $useDeleteClause Use the deleteClause to check if a record is deleted (default TRUE)
*
* @return array|NULL Returns the row if found, otherwise NULL
*/
protected function getRecord($table, $uid, $fields = '*', $where = '', $useDeleteClause = true)
{
return BackendUtility::getRecord($table, $uid, $fields, $where, $useDeleteClause);
}
/**
* @param $pageTreeView
*
* @return $this
*/
public function setPageTreeView($pageTreeView)
{
$this->pageTreeView = $pageTreeView;
return $this;
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Dao;
use Metaseo\Metaseo\Utility\DatabaseUtility;
use TYPO3\CMS\Core\SingletonInterface;
class TemplateDao implements SingletonInterface
{
/**
* @param integer[] array of page IDs to be checked for templates
*
* @return array of PIDs which have a template which is not deleted or hidden.
*/
public function checkForTemplateByUidList($uidList)
{
$query = 'SELECT pid
FROM sys_template
WHERE pid IN (' . implode(',', $uidList) . ')
AND deleted = 0
AND hidden = 0';
return DatabaseUtility::getCol($query);
}
}

View File

@@ -0,0 +1,121 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\DependencyInjection\Utility;
use Metaseo\Metaseo\Utility\FrontendUtility as MetaseoFrontendUtility;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Frontend\Page\PageRepository;
class FrontendUtility implements SingletonInterface
{
/**
* @var PageRepository
*/
protected $pageRepository;
/**
* Init TSFE (for simulated pagetitle)
*
* @param array $page Page
* @param null|array $rootLine Rootline
* @param null|array $pageData Page data (recursive generated)
* @param null|array $rootlineFull Rootline full
* @param null|integer $sysLanguage System language
*
* @return void
*/
public function initTsfe(
array $page,
array $rootLine = null,
array $pageData = null,
array $rootlineFull = null,
$sysLanguage = null
) {
$pageUid = (int)$page['uid'];
if ($rootLine === null) {
$rootLine = $this->pageRepository->getRootLine($pageUid);
// save full rootline, we need it in TSFE
$rootlineFull = $rootLine;
}
// check if current page has a ts-setup-template
// if not, we go down the tree to the parent page
if (count($rootLine) >= 2 && !empty($this->templatePidList) && empty($this->templatePidList[$pageUid])) {
// go to parent page in rootline
reset($rootLine);
next($rootLine);
$prevPage = current($rootLine);
// strip current page from rootline
reset($rootLine);
$currPageIndex = key($rootLine);
unset($rootLine[$currPageIndex]);
MetaseoFrontendUtility::init(
$prevPage['uid'],
$rootLine,
$pageData,
$rootlineFull,
$sysLanguage
);
}
MetaseoFrontendUtility::init($page['uid'], $rootLine, $pageData, $rootlineFull, $sysLanguage);
}
/**
* @param array $conf
*
* @return string
*/
public function getTypoLinkUrl(array $conf)
{
return $this->getTSFE()->cObj->typolink_URL($conf);
}
/**
* @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
*/
protected function getTSFE()
{
return $GLOBALS['TSFE'];
}
/**
* @param PageRepository $pageRepository
*
* @return $this
*/
public function setPageRepository(PageRepository $pageRepository)
{
$this->pageRepository = $pageRepository;
return $this;
}
}

View File

@@ -0,0 +1,88 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\DependencyInjection\Utility;
use Exception;
use TYPO3\CMS\Core\SingletonInterface;
class HttpUtility implements SingletonInterface
{
/**
* Http Status Codes for Ajax
*
* @link https://dev.twitter.com/overview/api/response-codes
*/
const HTTP_STATUS_OK = 200;
const HTTP_STATUS_BAD_REQUEST = 400;
const HTTP_STATUS_UNAUTHORIZED = 401;
const HTTP_STATUS_FORBIDDEN = 403;
const HTTP_STATUS_NOT_FOUND = 404;
const HTTP_STATUS_NOT_ACCEPTABLE = 406;
const HTTP_STATUS_INTERNAL_SERVER_ERROR = 500;
const HTTP_STATUS_SERVICE_UNAVAILABLE = 503;
/**
* @param $httpStatusCode
*
* @return string
*
* @throws Exception
*/
public function getHttpStatusMessage($httpStatusCode)
{
switch ($httpStatusCode) {
case self::HTTP_STATUS_OK:
return 'OK';
case self::HTTP_STATUS_BAD_REQUEST:
return 'Bad Request';
case self::HTTP_STATUS_UNAUTHORIZED:
return 'Unauthorized';
case self::HTTP_STATUS_FORBIDDEN:
return 'Forbidden';
case self::HTTP_STATUS_NOT_FOUND:
return 'Not Found';
case self::HTTP_STATUS_NOT_ACCEPTABLE:
return 'Not Acceptable';
case self::HTTP_STATUS_INTERNAL_SERVER_ERROR:
return 'Internal Server Error';
case self::HTTP_STATUS_SERVICE_UNAVAILABLE:
return 'Service Unavailable';
default:
throw new Exception('Http status message is not available.');
}
}
/**
* @param $httpStatusCode
*/
public function sendHttpHeader($httpStatusCode)
{
if (!headers_sent()) {
header('HTTP/1.0 ' . $httpStatusCode . ' ' . $this->getHttpStatusMessage($httpStatusCode));
}
}
}

View File

@@ -0,0 +1,65 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Exception\Ajax;
use Exception;
class AjaxException extends Exception
{
/**
* @var string
*/
protected $message;
/**
* @var string
*/
protected $code;
/**
* @var int
*/
protected $httpStatus;
/**
* @param string $messageTranslationKey The error message translation KEY
* @param string $code Custom alphanumeric error code
* @param int $httpStatus http status code, e.g. 500 for internal server error.
*/
public function __construct($messageTranslationKey = '', $code = '', $httpStatus = 500)
{
parent::__construct();
$this->message = (string) $messageTranslationKey;
$this->code = (string) $code;
$this->httpStatus = (int) $httpStatus;
}
public function getHttpStatus()
{
return $this->httpStatus;
}
}

View File

@@ -0,0 +1,34 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Hook\Extension;
/**
* EXT:news hook for metatags
*/
class NewsExtension
{
}

View File

@@ -0,0 +1,91 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Hook\Extension;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Plugin\AbstractPlugin;
/**
* EXT:tt_news hook for metatags
*/
class TtnewsExtension
{
/**
* Extra item marker hook for metatag fetching
*
* @param array $markerArray Marker array
* @param array $row Current tt_news row
* @param array $lConf Local configuration
* @param AbstractPlugin $ttnewsObj Pi-object from tt_news
*
* @return array Marker array (not changed)
*/
public function extraItemMarkerProcessor(array $markerArray, array $row, array $lConf, AbstractPlugin $ttnewsObj)
{
$theCode = (string)strtoupper(trim($ttnewsObj->theCode));
$connector = GeneralUtility::makeInstance('Metaseo\\Metaseo\\Connector');
switch ($theCode) {
case 'SINGLE':
case 'SINGLE2':
// Title
if (!empty($row['title'])) {
$connector->setMetaTag('title', $row['title']);
}
// Description
if (!empty($row['short'])) {
$connector->setMetaTag('description', $row['short']);
}
// Keywords
if (!empty($row['keywords'])) {
$connector->setMetaTag('keywords', $row['keywords']);
}
// Short/Description
if (!empty($row['short'])) {
$connector->setMetaTag('description', $row['short']);
}
// Author
if (!empty($row['author'])) {
$connector->setMetaTag('author', $row['author']);
}
// E-Mail
if (!empty($row['author_email'])) {
$connector->setMetaTag('email', $row['author_email']);
}
break;
}
return $markerArray;
}
}

View File

@@ -0,0 +1,128 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Hook;
use Metaseo\Metaseo\Utility\FrontendUtility;
use Metaseo\Metaseo\Utility\GeneralUtility;
/**
* Http Header generator
*/
class HttpHook
{
/**
* Add HTTP Headers
*/
public function main()
{
// INIT
$tsSetup = $GLOBALS['TSFE']->tmpl->setup;
$headers = array();
// don't send any headers if headers are already sent
if (headers_sent()) {
return;
}
// Init caches
$cacheIdentification = sprintf(
'%s_%s_http',
$GLOBALS['TSFE']->id,
substr(sha1(FrontendUtility::getCurrentUrl()), 10, 30)
);
/** @var \TYPO3\CMS\Core\Cache\CacheManager $cacheManager */
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
'TYPO3\\CMS\\Extbase\\Object\\ObjectManager'
);
$cacheManager = $objectManager->get('TYPO3\\CMS\\Core\\Cache\\CacheManager');
$cache = $cacheManager->getCache('cache_pagesection');
if (!empty($GLOBALS['TSFE']->tmpl->loaded)) {
// ##################################
// Non-Cached page
// ##################################
if (!empty($tsSetup['plugin.']['metaseo.']['metaTags.'])) {
$tsSetupSeo = $tsSetup['plugin.']['metaseo.']['metaTags.'];
// ##################################
// W3C P3P Tags
// ##################################
$p3pCP = null;
$p3pPolicyUrl = null;
if (!empty($tsSetupSeo['p3pCP'])) {
$p3pCP = $tsSetupSeo['p3pCP'];
}
if (!empty($tsSetupSeo['p3pPolicyUrl'])) {
$p3pPolicyUrl = $tsSetupSeo['p3pPolicyUrl'];
}
if (!empty($p3pCP) || !empty($p3pPolicyUrl)) {
$p3pHeader = array();
if (!empty($p3pCP)) {
$p3pHeader[] = 'CP="' . $p3pCP . '"';
}
if (!empty($p3pPolicyUrl)) {
$p3pHeader[] = 'policyref="' . $p3pPolicyUrl . '"';
}
$headers['P3P'] = implode(' ', $p3pHeader);
}
}
// Store headers into cache
$cache->set($cacheIdentification, $headers, array('pageId_' . $GLOBALS['TSFE']->id));
} else {
// #####################################
// Cached page
// #####################################
// Fetched cached headers
$cachedHeaders = $cache->get($cacheIdentification);
if (!empty($cachedHeaders)) {
$headers = $cachedHeaders;
}
}
// Call hook
GeneralUtility::callHookAndSignal(__CLASS__, 'httpHeaderOutput', $this, $headers);
// #####################################
// Sender headers
// #####################################
if (!empty($headers['P3P'])) {
header('P3P: ' . $headers['P3P']);
}
}
}

View File

@@ -0,0 +1,290 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Hook;
use Metaseo\Metaseo\Utility\FrontendUtility;
use Metaseo\Metaseo\Utility\GeneralUtility;
use Metaseo\Metaseo\Utility\SitemapUtility;
use TYPO3\CMS\Core\SingletonInterface;
/**
* Sitemap Indexer
*/
abstract class SitemapIndexHook implements SingletonInterface
{
// ########################################################################
// Attributes
// ########################################################################
/**
* List of blacklisted page doktypes
*
* @var array
*/
protected $doktypeBlacklist = array();
/**
* List of blacklisted page types (Setup PAGE object typeNum)
*
* @var array
*/
protected $pageTypeBlacklist = array();
/**
* Page index status
*
* @var null|boolean
*/
protected $pageIndexFlag;
/**
* MetaSEO configuration
*
* @var array
*/
protected $conf = array();
/**
* Blacklist configuration
*
* @var array
*/
protected $blacklistConf = array();
/**
* File extension list
*
* @var array
*/
protected $fileExtList = array();
/**
* Sitemap entry expiration
*
* @var integer
*/
protected $indexExpiration;
/**
* Object manager
*
* @var \TYPO3\CMS\Extbase\Object\ObjectManager
*/
protected $objectManager;
// ########################################################################
// Methods
// ########################################################################
/**
* Constructor
*/
public function __construct()
{
/** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */
$this->objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
'TYPO3\\CMS\\Extbase\\Object\\ObjectManager'
);
$this->initConfiguration();
}
/**
* Init configuration
*/
protected function initConfiguration()
{
// Get configuration
if (!empty($GLOBALS['TSFE']->tmpl->setup['plugin.']['metaseo.'])) {
$this->conf = $GLOBALS['TSFE']->tmpl->setup['plugin.']['metaseo.'];
}
// Store blacklist configuration
if (!empty($this->conf['sitemap.']['index.']['blacklist.'])) {
$this->blacklistConf = $this->conf['sitemap.']['index.']['blacklist.'];
}
// Store blacklist configuration
if (!empty($this->conf['sitemap.']['index.']['fileExtension.'])) {
# File extensions can be a comma separated list
foreach ($this->conf['sitemap.']['index.']['fileExtension.'] as $fileExtListRaw) {
$fileExtList = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(',', $fileExtListRaw);
$this->fileExtList = array_merge($this->fileExtList, $fileExtList);
};
}
// Get expiration
$expirationInDays = 60;
if (!empty($this->conf['sitemap.']['expiration'])) {
$expirationInDays = abs($this->conf['sitemap.']['expiration']);
}
$this->indexExpiration = $_SERVER['REQUEST_TIME'] + ($expirationInDays * 24 * 60 * 60);
// Init blacklist for doktype (from table pages)
$this->doktypeBlacklist = SitemapUtility::getDoktypeBlacklist();
// Init blacklist for PAGE typenum
$this->pageTypeBlacklist = SitemapUtility::getPageTypeBlacklist();
}
/**
* Process/Clear link url
*
* @param string $linkUrl Link url
*
* @return string
*/
protected static function processLinkUrl($linkUrl)
{
static $absRefPrefix = null;
static $absRefPrefixLength = 0;
$ret = $linkUrl;
// Fetch abs ref prefix if available/set
if ($absRefPrefix === null) {
if (!empty($GLOBALS['TSFE']->tmpl->setup['config.']['absRefPrefix'])) {
$absRefPrefix = $GLOBALS['TSFE']->tmpl->setup['config.']['absRefPrefix'];
$absRefPrefixLength = strlen($absRefPrefix);
} else {
$absRefPrefix = false;
}
}
// remove abs ref prefix
if ($absRefPrefix !== false && strpos($ret, $absRefPrefix) === 0) {
$ret = substr($ret, $absRefPrefixLength);
}
return $ret;
}
/**
* Return page change frequency
*
* @param array $page Page data
*
* @return integer
*/
protected function getPageChangeFrequency(array $page)
{
$ret = 0;
if (!empty($page['tx_metaseo_change_frequency'])) {
$ret = (int)$page['tx_metaseo_change_frequency'];
} elseif (!empty($this->conf['sitemap.']['changeFrequency'])) {
$ret = (int)$this->conf['sitemap.']['changeFrequency'];
}
if (empty($pageChangeFrequency)) {
$ret = 0;
}
return $ret;
}
/**
* Check if sitemap indexing is enabled
*
* @param string $indexingType Indexing type (page or typolink)
*
* @return bool
*/
protected function checkIfSitemapIndexingIsEnabled($indexingType)
{
// check if sitemap is enabled in root
if (!GeneralUtility::getRootSettingValue('is_sitemap', true)
|| !GeneralUtility::getRootSettingValue('is_sitemap_' . $indexingType . '_indexer', true)
) {
return false;
}
// check current page
if (!$this->checkIfCurrentPageIsIndexable()) {
return false;
}
return true;
}
/**
* Check if current page is indexable
*
* Will do following checks:
* - REQUEST_METHOD (must be GET)
* - If there is a feuser session
* - Page type blacklisting
* - If page is static cacheable
* - If no_cache is not set
*
* (checks will be cached)
*
* @return bool
*/
protected function checkIfCurrentPageIsIndexable()
{
// check caching status
if ($this->pageIndexFlag !== null) {
return $this->pageIndexFlag;
}
// by default page is not cacheable
$this->pageIndexFlag = false;
// ############################
// Basic checks
// ############################
$cacheConf = array(
'allowNoStaticCachable' => (bool)$this->conf['sitemap.']['index.']['allowNoStaticCachable'],
'allowNoCache' => (bool)$this->conf['sitemap.']['index.']['allowNoCache']
);
if (!FrontendUtility::isCacheable($cacheConf)) {
return false;
}
// Check for type blacklisting (from typoscript PAGE object)
if (in_array($GLOBALS['TSFE']->type, $this->pageTypeBlacklist)) {
return false;
}
// Check for doktype blacklisting (from current page record)
if (in_array((int)$GLOBALS['TSFE']->page['doktype'], $this->doktypeBlacklist)) {
return false;
}
// all checks successful, page is cacheable
$this->pageIndexFlag = true;
return true;
}
}

View File

@@ -0,0 +1,294 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Hook;
use Metaseo\Metaseo\Utility\GeneralUtility;
use Metaseo\Metaseo\Utility\SitemapUtility;
/**
* Sitemap Indexer
*/
class SitemapIndexLinkHook extends SitemapIndexHook
{
// ########################################################################
// HOOKS
// ########################################################################
/**
* Hook: Link Parser
*
* @param array $pObj Object
*
* @return void
*/
public function hook_linkParse(array &$pObj)
{
if (!$this->checkIfSitemapIndexingIsEnabled('typolink')) {
return;
}
// Check
if (empty($pObj['finalTagParts']) || empty($pObj['conf']) || empty($pObj['finalTagParts']['url'])) {
// no valid link
return;
}
// Init link information
$linkConf = $pObj['conf'];
$linkUrl = $pObj['finalTagParts']['url'];
list($linkPageUid, $linkType) = $this->parseLinkConf($pObj);
$linkUrl = $this->processLinkUrl($linkUrl);
if ($linkType === null || empty($linkPageUid)) {
// no valid link
return;
}
// check blacklisting
if (GeneralUtility::checkUrlForBlacklisting($linkUrl, $this->blacklistConf)) {
return;
}
// ####################################
// Init
// ####################################
$addParameters = array();
if (!empty($linkConf['additionalParams'])) {
parse_str($linkConf['additionalParams'], $addParameters);
}
// #####################################
// Check if link is cacheable
// #####################################
$isValid = false;
// check if conf is valid
if (!empty($linkConf['useCacheHash'])) {
$isValid = true;
}
// check for typical typo3 params
$addParamsCache = $addParameters;
unset($addParamsCache['L']);
unset($addParamsCache['type']);
if (empty($addParamsCache)) {
$isValid = true;
}
if (!$isValid) {
// page is not cacheable, skip it
return;
}
// #####################################
// Rootline
// #####################################
$rootline = GeneralUtility::getRootLine($linkPageUid);
if (empty($rootline)) {
return;
}
// #####################################
// Page settings
// #####################################
// Fetch sysLanguage
if (isset($addParameters['L'])) {
$pageLanguage = (int)$addParameters['L'];
} else {
$pageLanguage = (int)GeneralUtility::getLanguageId();
}
// Index link
$pageData = $this->generateSitemapPageData($linkUrl, $linkPageUid, $rootline, $pageLanguage, $linkType);
if (!empty($pageData)) {
SitemapUtility::index($pageData);
}
}
// ########################################################################
// Methods
// ########################################################################
/**
* Generate sitemap page data
*
* @param string $linkUrl Link of current url
* @param integer $linkPageUid Link target page id
* @param array $rootline Rootline of link
* @param integer $pageLanguage Language id
* @param integer $linkType Link type
*
* @return array
* @internal param string $pageUrl Page url
*
*/
protected function generateSitemapPageData($linkUrl, $linkPageUid, array $rootline, $pageLanguage, $linkType)
{
$tstamp = $_SERVER['REQUEST_TIME'];
$rootPid = $rootline[0]['uid'];
// Get page data from rootline
$page = reset($rootline);
$ret = array(
'tstamp' => $tstamp,
'crdate' => $tstamp,
'page_rootpid' => $rootPid,
'page_uid' => $linkPageUid,
'page_language' => $pageLanguage,
'page_url' => $this->getPageUrl($linkUrl),
'page_depth' => count($rootline),
'page_change_frequency' => $this->getPageChangeFrequency($page),
'page_type' => $linkType,
'expire' => $this->indexExpiration,
);
// Call hook
GeneralUtility::callHookAndSignal(__CLASS__, 'sitemapIndexLink', $this, $ret);
return $ret;
}
/**
* Parse uid and type from generated link (from config array)
*
* @param array $conf Generated Link config array
*
* @return array
*/
protected function parseLinkConf(array $conf)
{
$uid = null;
$type = null;
// Check link type
switch ($conf['finalTagParts']['TYPE']) {
// ##############
// Page URL
// ##############
case 'page':
// TODO: Add support for more parameter checks
if (is_numeric($conf['conf']['parameter'])) {
$uid = $conf['conf']['parameter'];
}
$type = SitemapUtility::SITEMAP_TYPE_PAGE;
break;
// ##############
// File URL
// ##############
case 'file':
$fileUrl = $conf['finalTagParts']['url'];
if ($this->checkIfFileIsWhitelisted($fileUrl)) {
// File will be registered from the root page
// to prevent duplicate urls
$uid = GeneralUtility::getRootPid();
$type = SitemapUtility::SITEMAP_TYPE_FILE;
}
break;
}
return array($uid, $type);
}
/**
* Check if file is whitelisted
*
* Configuration specified in
* plugin.metaseo.sitemap.index.fileExtension
*
* @param string $url Url to file
*
* @return boolean
*/
protected function checkIfFileIsWhitelisted($url)
{
$ret = false;
// check for valid url
if (empty($url)) {
return false;
}
// parse url to extract only path
$urlParts = parse_url($url);
$filePath = $urlParts['path'];
// Extract last file extension
if (preg_match('/\.([^\.]+)$/', $filePath, $matches)) {
$fileExt = trim(strtolower($matches[1]));
// Check if file extension is whitelisted
foreach ($this->fileExtList as $allowedFileExt) {
if ($allowedFileExt === $fileExt) {
// File is whitelisted, not blacklisted
$ret = true;
break;
}
}
}
return $ret;
}
/**
* Get current page url
*
* @param string $linkUrl Link url
*
* @return null|string
*/
protected function getPageUrl($linkUrl)
{
$linkParts = parse_url($linkUrl);
// Remove left / (but only if not root page)
if ($linkParts['path'] === '/') {
// Link points to root page
$ret = '/';
} else {
// Link points to another page, strip left /
$ret = ltrim($linkParts['path'], '/');
}
// Add query
if (!empty($linkParts['query'])) {
$ret .= '?' . $linkParts['query'];
}
return $ret;
}
}

View File

@@ -0,0 +1,168 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Hook;
use Metaseo\Metaseo\Utility\FrontendUtility;
use Metaseo\Metaseo\Utility\GeneralUtility;
use Metaseo\Metaseo\Utility\SitemapUtility;
/**
* Sitemap Indexer
*/
class SitemapIndexPageHook extends SitemapIndexHook
{
/**
* Init configuration
*/
protected function initConfiguration()
{
parent::initConfiguration();
// Check custom index expiration (from connector)
/** @var \Metaseo\Metaseo\Connector $connector */
$connector = $this->objectManager->get('Metaseo\\Metaseo\\Connector');
$sitemapStore = $connector->getStore('sitemap');
// Set new expiration date
if (!empty($sitemapStore['expiration'])) {
$this->indexExpiration = $_SERVER['REQUEST_TIME'] + ($sitemapStore['expiration'] * 24 * 60 * 60);
}
}
// ########################################################################
// HOOKS
// ########################################################################
/**
* Hook: Index Page Content
*/
public function hook_indexContent()
{
$this->addPageToSitemapIndex();
$possibility = (int)GeneralUtility::getExtConf('sitemap_clearCachePossibility', 0);
if ($possibility > 0) {
$clearCacheChance = ceil(mt_rand(0, $possibility));
if ($clearCacheChance == 1) {
SitemapUtility::expire();
}
}
}
// ########################################################################
// Methods
// ########################################################################
/**
* Add Page to sitemap table
*
* @return void
*/
public function addPageToSitemapIndex()
{
if (!$this->checkIfSitemapIndexingIsEnabled('page')) {
return;
}
$pageUrl = $this->getPageUrl();
// check blacklisting
if (GeneralUtility::checkUrlForBlacklisting($pageUrl, $this->blacklistConf)) {
return;
}
// Index page
$pageData = $this->generateSitemapPageData($pageUrl);
if (!empty($pageData)) {
SitemapUtility::index($pageData);
}
}
/**
* Generate sitemap page data
*
* @param string $pageUrl Page url
*
* @return array
*/
protected function generateSitemapPageData($pageUrl)
{
$page = $GLOBALS['TSFE']->page;
$tstamp = $_SERVER['REQUEST_TIME'];
$ret = array(
'tstamp' => $tstamp,
'crdate' => $tstamp,
'page_rootpid' => GeneralUtility::getRootPid(),
'page_uid' => $GLOBALS['TSFE']->id,
'page_language' => GeneralUtility::getLanguageId(),
'page_url' => $pageUrl,
'page_depth' => count($GLOBALS['TSFE']->rootLine),
'page_change_frequency' => $this->getPageChangeFrequency($page),
'page_type' => SitemapUtility::SITEMAP_TYPE_PAGE,
'expire' => $this->indexExpiration,
);
// Call hook
GeneralUtility::callHookAndSignal(__CLASS__, 'sitemapIndexPage', $this, $ret);
return $ret;
}
/**
* Get current page url
*
* @return null|string
*/
protected function getPageUrl()
{
// Fetch chash
$pageHash = null;
if (!empty($GLOBALS['TSFE']->cHash)) {
$pageHash = $GLOBALS['TSFE']->cHash;
}
// Fetch pageUrl
if ($pageHash !== null) {
$ret = FrontendUtility::getCurrentUrl();
} else {
$linkConf = array(
'parameter' => $GLOBALS['TSFE']->id,
);
$ret = $GLOBALS['TSFE']->cObj->typoLink_URL($linkConf);
$ret = $this->processLinkUrl($ret);
}
return $ret;
}
}

View File

@@ -0,0 +1,154 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Hook\TCA;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Configuration\ConfigurationManager;
/**
* TCA Hook: Robots.txt default content
*/
class RobotsTxtDefault
{
/**
* TYPO3 Object manager
*
* @var \TYPO3\CMS\Extbase\Object\ObjectManager
*/
protected $objectManager;
/**
* TYPO3 configuration manager
*
* @var ConfigurationManager
*/
protected $configurationManager;
/**
* TYPO3 Content object renderer
*
* @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*/
protected $cObj;
/**
* Render default Robots.txt from TypoScript Setup
*
* @param array $data TCE Information array
*
* @return string
*/
public function main(array $data)
{
// ############################
// Init
// ############################
/** @var \TYPO3\CMS\Extbase\Object\ObjectManager objectManager */
$this->objectManager = GeneralUtility::makeInstance(
'TYPO3\\CMS\\Extbase\\Object\\ObjectManager'
);
/** @var ConfigurationManager configurationManager */
$this->configurationManager = $this->objectManager->get(
'TYPO3\\CMS\\Extbase\\Configuration\\ConfigurationManager'
);
/** @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer cObj */
$this->cObj = $this->objectManager->get('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
// ############################
// Init TSFE
// ############################
$rootPageId = $data['row']['pid'];
/** @var \TYPO3\CMS\Core\TimeTracker\NullTimeTracker $timeTracker */
$timeTracker = $this->objectManager->get('TYPO3\\CMS\\Core\\TimeTracker\\NullTimeTracker');
$GLOBALS['TT'] = $timeTracker;
$GLOBALS['TT']->start();
/** @var \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController $tsfeController */
$tsfeController = $this->objectManager->get(
'TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController',
$GLOBALS['TYPO3_CONF_VARS'],
$rootPageId,
0
);
$GLOBALS['TSFE'] = $tsfeController;
// ############################
// Render default robots.txt content
// ############################
// Fetch TypoScript setup
$tsSetup = $this->configurationManager->getConfiguration(
ConfigurationManager::CONFIGURATION_TYPE_FULL_TYPOSCRIPT,
'metaseo',
'plugin'
);
$content = '';
if (!empty($tsSetup['plugin.']['metaseo.']['robotsTxt.'])) {
$content = $this->cObj->cObjGetSingle(
$tsSetup['plugin.']['metaseo.']['robotsTxt.']['default'],
$tsSetup['plugin.']['metaseo.']['robotsTxt.']['default.']
);
}
$content = htmlspecialchars($content);
$content = nl2br($content);
/**
* instanciation of TypoScriptFrontendController instanciates PageRenderer which
* sets backPath to TYPO3_mainDir which is very bad in the Backend. Therefore,
* we must set it back to null to not get frontend-prefixed asset URLs. See #150.
*/
$this->cleanUpPageRendererBackPath();
return $content;
}
/**
* Sets backPath of PageRenderer back to null (for Backend)
*/
protected function cleanUpPageRendererBackPath()
{
$pageRenderer = $this->getPageRenderer();
$pageRenderer->setBackPath(null);
}
/**
* @return \TYPO3\CMS\Core\Page\PageRenderer
*/
protected function getPageRenderer()
{
return GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Page\\PageRenderer');
}
}

View File

@@ -0,0 +1,90 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Page;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Abstract page
*/
abstract class AbstractPage
{
// ########################################################################
// Attributes
// ########################################################################
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManager
* @inject
*/
protected $objectManager;
/**
* TypoScript Setup
*
* @var array
*/
protected $tsSetup = array();
// ########################################################################
// Methods
// ########################################################################
/**
* Constructor
*/
public function __construct()
{
// Init object manager
$this->objectManager = GeneralUtility::makeInstance(
'TYPO3\\CMS\\Extbase\\Object\\ObjectManager'
);
}
/**
* Main
*
* @return mixed
*/
abstract public function main();
/**
* Show error
*
* @param string $msg Message
*/
protected function showError($msg = null)
{
if ($msg === null) {
$msg = 'Sitemap is not available, please check your configuration';
}
header('HTTP/1.0 503 Service Unavailable');
$GLOBALS['TSFE']->pageErrorHandler(true, null, $msg);
exit;
}
}

View File

@@ -0,0 +1,59 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Page\Part;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Abstract part
*/
abstract class AbstractPart
{
// ########################################################################
// Attributes
// ########################################################################
/**
* @var \TYPO3\CMS\Extbase\Object\ObjectManager
* @inject
*/
protected $objectManager;
// ########################################################################
// Methods
// ########################################################################
/**
* Constructor
*/
public function __construct()
{
// Init object manager
$this->objectManager = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
}
}

View File

@@ -0,0 +1,235 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Page\Part;
use TYPO3\CMS\Core\Utility\GeneralUtility as Typo3GeneralUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Page Footer
*/
class FooterPart extends AbstractPart
{
/**
* Content object renderer
*
* @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*/
public $cObj;
/**
* Add Page Footer
*
* @param string $title Default page title (rendered by TYPO3)
*
* @return string Modified page title
*/
public function main($title)
{
// INIT
$ret = array();
$tsSetup = $GLOBALS['TSFE']->tmpl->setup;
$tsServices = array();
$beLoggedIn = isset($GLOBALS['BE_USER']->user['username']);
$disabledHeaderCode = false;
if (!empty($tsSetup['config.']['disableAllHeaderCode'])) {
$disabledHeaderCode = true;
}
if (!empty($tsSetup['plugin.']['metaseo.']['services.'])) {
$tsServices = $tsSetup['plugin.']['metaseo.']['services.'];
}
// Call hook
\Metaseo\Metaseo\Utility\GeneralUtility::callHookAndSignal(__CLASS__, 'pageFooterSetup', $this, $tsServices);
// #########################################
// GOOGLE ANALYTICS
// #########################################
if (!empty($tsServices['googleAnalytics'])) {
$gaConf = $tsServices['googleAnalytics.'];
$gaEnabled = true;
if ($disabledHeaderCode && empty($gaConf['enableIfHeaderIsDisabled'])) {
$gaEnabled = false;
}
if ($gaEnabled && !(empty($gaConf['showIfBeLogin']) && $beLoggedIn)) {
// Build Google Analytics service
$ret['ga'] = $this->buildGoogleAnalyticsCode($tsServices, $gaConf);
if (!empty($gaConf['trackDownloads']) && !empty($gaConf['trackDownloadsScript'])) {
$ret['ga.trackdownload'] = $this->serviceGoogleAnalyticsTrackDownloads($tsServices, $gaConf);
}
} elseif ($gaEnabled && $beLoggedIn) {
// Disable caching
$GLOBALS['TSFE']->set_no_cache('MetaSEO: Google Analytics code disabled, backend login detected');
// Backend login detected, disable cache because this page is viewed by BE-users
$ret['ga.disabled'] = '<!-- Google Analytics disabled, '
. 'Page cache disabled - Backend-Login detected -->';
}
}
// #########################################
// PIWIK
// #########################################
if (!empty($tsServices['piwik.'])
&& !empty($tsServices['piwik.']['url'])
&& !empty($tsServices['piwik.']['id'])
) {
$piwikConf = $tsServices['piwik.'];
$piwikEnabled = true;
if ($disabledHeaderCode && empty($piwikConf['enableIfHeaderIsDisabled'])) {
$piwikEnabled = false;
}
if ($piwikEnabled && !(empty($piwikConf['showIfBeLogin']) && $beLoggedIn)) {
// Build Piwik service
$ret['piwik'] = $this->buildPiwikCode($tsServices, $piwikConf);
} elseif ($piwikEnabled && $beLoggedIn) {
// Disable caching
$GLOBALS['TSFE']->set_no_cache('MetaSEO: Piwik code disabled, backend login detected');
// Backend login detected, disable cache because this page is viewed by BE-users
$ret['piwik.disabled'] = '<!-- Piwik disabled, Page cache disabled - Backend-Login detected -->';
}
}
// Call hook
\Metaseo\Metaseo\Utility\GeneralUtility::callHookAndSignal(__CLASS__, 'pageFooterOutput', $this, $ret);
return implode("\n", $ret);
}
/**
* Google analytics
*
* @param array $tsServices SetupTS of services
* @param array $gaConf Google Analytics configuration
*
* @return string
*/
public function buildGoogleAnalyticsCode(array $tsServices, array $gaConf)
{
$ret = array();
$gaCodeList = GeneralUtility::trimExplode(',', $tsServices['googleAnalytics']);
foreach ($gaCodeList as $gaCode) {
$customCode = '';
if (!empty($gaConf['customizationCode'])) {
$customCode .= "\n" . $this->cObj->cObjGetSingle(
$gaConf['customizationCode'],
$gaConf['customizationCode.']
);
}
$this->cObj->data['gaCode'] = $gaCode;
$this->cObj->data['gaIsAnonymize'] = (int)!empty($gaConf['anonymizeIp']);
$this->cObj->data['gaDomainName'] = $gaConf['domainName'];
$this->cObj->data['gaCustomizationCode'] = $customCode;
$this->cObj->data['gaUseUniversalAnalytics'] = (int)!empty($gaConf['universalAnalytics']);
// Build code
$ret[] = $this->cObj->cObjGetSingle($gaConf['template'], $gaConf['template.']);
}
// Build all GA codes
$ret = implode("\n", $ret);
return $ret;
}
/**
* Google analytics
*
* @param array $tsServices SetupTS of services
* @param array $gaConf Google Analytics configuration
*
* @return string
* @todo $tsServices is never used
*/
public function serviceGoogleAnalyticsTrackDownloads(array $tsServices, array $gaConf)
{
$jsFile = Typo3GeneralUtility::getFileAbsFileName($gaConf['trackDownloadsScript']);
$jsfile = preg_replace('/^' . preg_quote(PATH_site, '/') . '/i', '', $jsFile);
$ret = '<script type="text/javascript" src="' . htmlspecialchars($jsfile) . '"></script>';
return $ret;
}
/**
* Piwik
*
* @param array $tsServices SetupTS of services
* @param array $piwikConf Piwik configuration
*
* @return string
*/
public function buildPiwikCode(array $tsServices, array $piwikConf)
{
$ret = array();
$piwikCodeList = GeneralUtility::trimExplode(',', $piwikConf['id']);
foreach ($piwikCodeList as $piwikCode) {
$customCode = '';
if (!empty($piwikConf['customizationCode'])) {
$customCode .= "\n";
$customCode .= $this->cObj->cObjGetSingle(
$piwikConf['customizationCode'],
$piwikConf['customizationCode.']
);
}
// remove last slash
$piwikConf['url'] = rtrim($piwikConf['url'], '/');
$this->cObj->data['piwikUrl'] = $piwikConf['url'];
$this->cObj->data['piwikId'] = $piwikCode;
$this->cObj->data['piwikDomainName'] = $piwikConf['domainName'];
$this->cObj->data['piwikCookieDomainName'] = $piwikConf['cookieDomainName'];
$this->cObj->data['piwikDoNotTrack'] = $piwikConf['doNotTrack'];
$this->cObj->data['piwikCustomizationCode'] = $customCode;
// Build code
$ret[] = $this->cObj->cObjGetSingle($piwikConf['template'], $piwikConf['template.']);
}
// Build all piwik codes
$ret = implode("\n", $ret);
return $ret;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,417 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Page\Part;
use Metaseo\Metaseo\Utility\FrontendUtility;
use Metaseo\Metaseo\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility as Typo3GeneralUtility;
/**
* Page Title Changer
*/
class PagetitlePart extends AbstractPart
{
/**
* List of stdWrap manipulations
*
* @var array
*/
protected $stdWrapList = array();
/**
* Content object renderer
*
* @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*/
public $cObj;
/**
* TypoScript Setup
*
* @var array
*/
protected $tsSetup = array();
/**
* TypoScript Setup (subtree of plugin.metaseo)
*
* @var array
*/
protected $tsSetupSeo = array();
/**
* Page rootline
*
* @var array
*/
protected $rootLine = array();
/**
* Add SEO-Page Title
*
* @param string $title Default page title (rendered by TYPO3)
*
* @return string Modified page title
*/
public function main($title)
{
$ret = null;
// ############################
// Fetch from cache
// ############################
$pageTitleCachingEnabled = $this->checkIfPageTitleCachingEnabled();
if ($pageTitleCachingEnabled === true) {
$cacheIdentification = sprintf(
'%s_%s_title',
$GLOBALS['TSFE']->id,
substr(sha1(FrontendUtility::getCurrentUrl()), 10, 30)
);
/** @var \TYPO3\CMS\Core\Cache\CacheManager $cacheManager */
$objectManager = Typo3GeneralUtility::makeInstance(
'TYPO3\\CMS\\Extbase\\Object\\ObjectManager'
);
$cacheManager = $objectManager->get('TYPO3\\CMS\\Core\\Cache\\CacheManager');
$cache = $cacheManager->getCache('cache_pagesection');
$cacheTitle = $cache->get($cacheIdentification);
if (!empty($cacheTitle)) {
$ret = $cacheTitle;
}
}
// ############################
// Generate page title
// ############################
// Generate page title if not set
// also fallback
if (empty($ret)) {
$this->initialize();
$ret = $this->generatePageTitle($title);
// Cache page title (if page is not cacheable)
if ($pageTitleCachingEnabled === true && isset($cache) && isset($cacheIdentification)) {
$cache->set($cacheIdentification, $ret, array('pageId_' . $GLOBALS['TSFE']->id));
}
}
// ############################
// Output
// ############################
// Call hook
GeneralUtility::callHookAndSignal(__CLASS__, 'pageTitleOutput', $this, $ret);
return $ret;
}
/**
* Initialize
*/
protected function initialize()
{
$this->cObj = $GLOBALS['TSFE']->cObj;
$this->tsSetup = $GLOBALS['TSFE']->tmpl->setup;
$this->rootLine = GeneralUtility::getRootLine();
if (!empty($this->tsSetup['plugin.']['metaseo.'])) {
$this->tsSetupSeo = $this->tsSetup['plugin.']['metaseo.'];
// get stdwrap list
if (!empty($this->tsSetupSeo['stdWrap.'])) {
$this->stdWrapList = $this->tsSetupSeo['pageTitle.']['stdWrap.'];
}
} else {
$this->tsSetupSeo = array();
}
}
/**
* Check if page title caching is enabled
*
* @return bool
*/
protected function checkIfPageTitleCachingEnabled()
{
$cachingEnabled = !empty($GLOBALS['TSFE']->tmpl->setup['plugin.']['metaseo.']['pageTitle.']['caching']);
// Enable caching only if caching is enabled in SetupTS
// And if there is any USER_INT on the current page
//
// -> USER_INT will break Connector pagetitle setting
// because the plugin output is cached but not the whole
// page. so the Connector will not be called again
// and the default page title will be shown
// which is wrong
// -> if the page is fully cacheable we don't have anything
// to do
return $cachingEnabled && !FrontendUtility::isCacheable();
}
/**
* Add SEO-Page Title
*
* @param string $title Default page title (rendered by TYPO3)
*
* @return string Modified page title
* @todo: split up function (too long)
*/
public function generatePageTitle($title)
{
// INIT
$ret = $title;
$rawTitle = !empty($GLOBALS['TSFE']->altPageTitle) ?
$GLOBALS['TSFE']->altPageTitle : $GLOBALS['TSFE']->page['title'];
$currentPid = $GLOBALS['TSFE']->id;
$skipPrefixSuffix = false;
$applySitetitle = true;
$pageTitlePrefix = false;
$pageTitleSuffix = false;
$this->stdWrapList = array();
$sitetitle = $this->tsSetup['sitetitle'];
// Use browsertitle if available
if (!empty($GLOBALS['TSFE']->page['tx_metaseo_pagetitle_rel'])) {
$rawTitle = $GLOBALS['TSFE']->page['tx_metaseo_pagetitle_rel'];
}
// Call hook
GeneralUtility::callHookAndSignal(
__CLASS__,
'pageTitleSetup',
$this,
$this->tsSetupSeo
);
// get stdwrap list
if (!empty($this->tsSetupSeo['pageTitle.']['stdWrap.'])) {
$this->stdWrapList = $this->tsSetupSeo['pageTitle.']['stdWrap.'];
}
// Apply stdWrap before
if (!empty($this->stdWrapList['before.'])) {
$rawTitle = $this->cObj->stdWrap($rawTitle, $this->stdWrapList['before.']);
}
// #######################################################################
// RAW PAGE TITLE
// #######################################################################
if (!empty($GLOBALS['TSFE']->page['tx_metaseo_pagetitle'])) {
$ret = $GLOBALS['TSFE']->page['tx_metaseo_pagetitle'];
// Add template prefix/suffix
if (empty($this->tsSetupSeo['pageTitle.']['applySitetitleToPagetitle'])) {
$applySitetitle = false;
}
$skipPrefixSuffix = true;
}
// #######################################################################
// PAGE TITLE PREFIX/SUFFIX
// #######################################################################
if (!$skipPrefixSuffix) {
foreach ($this->rootLine as $page) {
switch ((int)$page['tx_metaseo_inheritance']) {
case 0:
// ###################################
// Normal
// ###################################
if (!empty($page['tx_metaseo_pagetitle_prefix'])) {
$pageTitlePrefix = $page['tx_metaseo_pagetitle_prefix'];
}
if (!empty($page['tx_metaseo_pagetitle_suffix'])) {
$pageTitleSuffix = $page['tx_metaseo_pagetitle_suffix'];
}
if ($pageTitlePrefix !== false || $pageTitleSuffix !== false) {
// pagetitle found - break foreach
break 2;
}
break;
case 1:
// ###################################
// Skip
// (don't inherit from this page)
// ###################################
if ((int)$page['uid'] != $currentPid) {
continue 2;
}
if (!empty($page['tx_metaseo_pagetitle_prefix'])) {
$pageTitlePrefix = $page['tx_metaseo_pagetitle_prefix'];
}
if (!empty($page['tx_metaseo_pagetitle_suffix'])) {
$pageTitleSuffix = $page['tx_metaseo_pagetitle_suffix'];
}
break 2;
break;
}
}
// #################
// Process settings from access point
// #################
$connector = $this->objectManager->get('Metaseo\\Metaseo\\Connector');
$store = $connector->getStore('pagetitle');
if (!empty($store)) {
if (isset($store['pagetitle.title'])) {
$rawTitle = $store['pagetitle.title'];
}
if (isset($store['pagetitle.prefix'])) {
$pageTitlePrefix = $store['pagetitle.prefix'];
}
if (isset($store['pagetitle.suffix'])) {
$pageTitleSuffix = $store['pagetitle.suffix'];
}
if (isset($store['pagetitle.absolute'])) {
$ret = $store['pagetitle.absolute'];
$rawTitle = $store['pagetitle.absolute'];
$pageTitlePrefix = false;
$pageTitleSuffix = false;
if (empty($this->tsSetupSeo['pageTitle.']['applySitetitleToPagetitle'])) {
$applySitetitle = false;
}
}
if (isset($store['pagetitle.sitetitle'])) {
$sitetitle = $store['pagetitle.sitetitle'];
}
}
// Apply prefix and suffix
if ($pageTitlePrefix !== false || $pageTitleSuffix !== false) {
$ret = $rawTitle;
if ($pageTitlePrefix !== false) {
$ret = $pageTitlePrefix . ' ' . $ret;
}
if ($pageTitleSuffix !== false) {
$ret .= ' ' . $pageTitleSuffix;
}
if (!empty($this->tsSetupSeo['pageTitle.']['applySitetitleToPrefixSuffix'])) {
$applySitetitle = true;
}
} else {
$ret = $rawTitle;
}
}
// #######################################################################
// APPLY SITETITLE (from setup)
// #######################################################################
if ($applySitetitle) {
$ret = $this->applySitetitleToPagetitle($sitetitle, $ret);
}
// Apply stdWrap after
if (!empty($this->stdWrapList['after.'])) {
$ret = $this->cObj->stdWrap($ret, $this->stdWrapList['after.']);
}
return $ret;
}
/**
* Apply sitetitle (from sys_template) to pagetitle
*
* @param string $sitetitle Sitetitle
* @param string $title Page title
*
* @return string
*/
protected function applySitetitleToPagetitle($sitetitle, $title)
{
$pageTitleGlue = ':';
$glueSpacerBefore = '';
$glueSpacerAfter = '';
$ret = $title;
// Overwrite sitetitle with the one from ts-setup (if available)
if (!empty($this->tsSetupSeo['pageTitle.']['sitetitle'])) {
$sitetitle = $this->tsSetupSeo['pageTitle.']['sitetitle'];
}
// Apply stdWrap after
if (!empty($this->stdWrapList['sitetitle.'])) {
$sitetitle = $this->cObj->stdWrap($sitetitle, $this->stdWrapList['sitetitle.']);
}
if (isset($this->tsSetupSeo['pageTitle.']['sitetitleGlue'])) {
$pageTitleGlue = $this->tsSetupSeo['pageTitle.']['sitetitleGlue'];
}
if (!empty($this->tsSetupSeo['pageTitle.']['sitetitleGlueSpaceBefore'])) {
$glueSpacerBefore = ' ';
}
if (!empty($this->tsSetupSeo['pageTitle.']['sitetitleGlueSpaceAfter'])) {
$glueSpacerAfter = ' ';
}
$sitetitlePosition = 0;
if (isset($this->tsSetupSeo['pageTitle.']['sitetitlePosition'])) {
$sitetitlePosition = (int)$this->tsSetupSeo['pageTitle.']['sitetitlePosition'];
} elseif (isset($this->tsSetup['config.']['pageTitleFirst'])) {
$sitetitlePosition = (int)$this->tsSetup['config.']['pageTitleFirst'];
}
// add overall pagetitle from template/ts-setup
if ($sitetitlePosition) {
// suffix
$ret .= $glueSpacerBefore . $pageTitleGlue . $glueSpacerAfter . $sitetitle;
return $ret;
} else {
// prefix (default)
$ret = $sitetitle . $glueSpacerBefore . $pageTitleGlue . $glueSpacerAfter . $ret;
return $ret;
}
}
}

View File

@@ -0,0 +1,225 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Page;
use Metaseo\Metaseo\Utility\GeneralUtility;
/**
* Robots txt Page
*/
class RobotsTxtPage extends AbstractPage
{
// ########################################################################
// Attributes
// ########################################################################
/**
* Content object renderer
*
* @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*/
public $cObj;
/**
* TypoScript Setup Seo
*
* @var array
*/
protected $tsSetupSeo = array();
/**
* Root page id
*
* @var integer
*/
protected $rootPid;
/**
* Language id
*
* @var integer
*/
protected $languageId;
/**
* Link to static sitemap
*
* @var boolean
*/
protected $linkToStaticSitemap;
/**
* Sitemap language lock
*
* @var boolean
*/
protected $sitemapLanguageLock;
// ########################################################################
// Methods
// ########################################################################
/**
* Fetch and build robots.txt
*/
public function main()
{
$ret = '';
$settings = GeneralUtility::getRootSetting();
// INIT
$this->tsSetup = $GLOBALS['TSFE']->tmpl->setup;
$this->cObj = $GLOBALS['TSFE']->cObj;
$this->rootPid = GeneralUtility::getRootPid();
$this->tsSetupSeo = null;
if (!empty($this->tsSetup['plugin.']['metaseo.']['robotsTxt.'])) {
$this->tsSetupSeo = $this->tsSetup['plugin.']['metaseo.']['robotsTxt.'];
}
// check if sitemap is enabled in root
if (!GeneralUtility::getRootSettingValue('is_robotstxt', true)) {
return true;
}
$this->linkToStaticSitemap = GeneralUtility::getRootSettingValue('is_robotstxt_sitemap_static', false);
// Language lock
$this->sitemapLanguageLock = GeneralUtility::getRootSettingValue('is_sitemap_language_lock', false);
$this->languageId = GeneralUtility::getLanguageId();
// ###############################
// Fetch robots.txt content
// ###############################
$settings['robotstxt'] = trim($settings['robotstxt']);
if (!empty($settings['robotstxt'])) {
// Custom Robots.txt
$ret .= $settings['robotstxt'];
} elseif ($this->tsSetupSeo) {
// Default robots.txt
$ret .= $this->cObj->cObjGetSingle($this->tsSetupSeo['default'], $this->tsSetupSeo['default.']);
}
// ###############################
// Fetch extra robots.txt content
// ###############################
// User additional
if (!empty($settings['robotstxt_additional'])) {
$ret .= "\n\n" . $settings['robotstxt_additional'];
}
// Setup additional
if ($this->tsSetupSeo) {
// Default robots.txt
$tmp = $this->cObj->cObjGetSingle($this->tsSetupSeo['extra'], $this->tsSetupSeo['extra.']);
if (!empty($tmp)) {
$ret .= "\n\n" . $tmp;
}
}
// ###############################
// Marker
// ###############################
if (!empty($this->tsSetupSeo['marker.'])) {
$ret = $this->applyMarker($ret);
}
// Call hook
GeneralUtility::callHookAndSignal(__CLASS__, 'robotsTxtOutput', $this, $ret);
return $ret;
}
/**
* Apply marker to robots.txt
*
* @param string $robotsTxt Content of robots.txt
*
* @return string
*/
protected function applyMarker($robotsTxt)
{
$ret = $robotsTxt;
$markerList = array();
$markerConfList = array();
foreach ($this->tsSetupSeo['marker.'] as $name => $data) {
if (strpos($name, '.') === false) {
$markerConfList[$name] = null;
}
}
if ($this->linkToStaticSitemap) {
// remove sitemap-marker because we link to static url
unset($markerConfList['sitemap']);
}
// Fetch marker content
foreach ($markerConfList as $name => $conf) {
$markerList['%' . $name . '%'] = $this->cObj->cObjGetSingle(
$this->tsSetupSeo['marker.'][$name],
$this->tsSetupSeo['marker.'][$name . '.']
);
}
// generate sitemap-static marker
if ($this->linkToStaticSitemap) {
if ($this->sitemapLanguageLock) {
$path = 'uploads/tx_metaseo/sitemap_xml/index-r' . (int)$this->rootPid . '-l'
. (int)$this->languageId . '.xml.gz';
} else {
$path = 'uploads/tx_metaseo/sitemap_xml/index-r' . (int)$this->rootPid . '.xml.gz';
}
$conf = array(
'parameter' => $path
);
$markerList['%sitemap%'] = $this->cObj->typolink_URL($conf);
}
// Fix sitemap-marker url (add prefix if needed)
$markerList['%sitemap%'] = GeneralUtility::fullUrl($markerList['%sitemap%']);
// Call hook
GeneralUtility::callHookAndSignal(__CLASS__, 'robotsTxtMarker', $this, $markerList);
// Apply marker list
if (!empty($markerList)) {
$ret = strtr($ret, $markerList);
return $ret;
}
return $ret;
}
}

View File

@@ -0,0 +1,80 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Page;
use Metaseo\Metaseo\Utility\GeneralUtility;
/**
* Sitemap txt page
*/
class SitemapTxtPage extends AbstractPage
{
// ########################################################################
// Attributes
// ########################################################################
// ########################################################################
// Methods
// ########################################################################
/**
* Build sitemap xml
*
* @return string
*/
public function main()
{
// INIT
$this->tsSetup = $GLOBALS['TSFE']->tmpl->setup['plugin.']['metaseo.']['sitemap.'];
// check if sitemap is enabled in root
if (!GeneralUtility::getRootSettingValue('is_sitemap', true)) {
$this->showError('Sitemap is not available, please check your configuration [control-center]');
}
$ret = $this->build();
return $ret;
}
/**
* Build sitemap index or specific page
*
* @return mixed
*/
protected function build()
{
/** @var \Metaseo\Metaseo\Sitemap\Generator\TxtGenerator $generator */
$generator = $this->objectManager->get('Metaseo\\Metaseo\\Sitemap\\Generator\\TxtGenerator');
$ret = $generator->sitemap();
return $ret;
}
}

View File

@@ -0,0 +1,87 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Page;
use Metaseo\Metaseo\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility as Typo3GeneralUtility;
/**
* Sitemap xml page
*/
class SitemapXmlPage extends AbstractPage
{
// ########################################################################
// Attributes
// ########################################################################
// ########################################################################
// Methods
// ########################################################################
/**
* Build sitemap xml
*
* @return string
*/
public function main()
{
// INIT
$this->tsSetup = $GLOBALS['TSFE']->tmpl->setup['plugin.']['metaseo.']['sitemap.'];
// check if sitemap is enabled in root
if (!GeneralUtility::getRootSettingValue('is_sitemap', true)) {
$this->showError('Sitemap is not available, please check your configuration [control-center]');
}
$ret = $this->build();
return $ret;
}
/**
* Build sitemap index or specific page
*
* @return mixed
*/
protected function build()
{
$page = Typo3GeneralUtility::_GP('page');
/** @var \Metaseo\Metaseo\Sitemap\Generator\XmlGenerator $generator */
$generator = $this->objectManager->get('Metaseo\\Metaseo\\Sitemap\\Generator\\XmlGenerator');
if (empty($page) || $page === 'index') {
$ret = $generator->sitemapIndex();
} else {
$ret = $generator->sitemap($page);
}
return $ret;
}
}

View File

@@ -0,0 +1,143 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Scheduler\Task;
use Metaseo\Metaseo\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility as Typo3GeneralUtility;
/**
* Scheduler Task Sitemap Base
*/
abstract class AbstractSitemapTask extends AbstractTask
{
// ########################################################################
// Attributes
// ########################################################################
/**
* Sitemap base directory
*
* @var string
*/
protected $sitemapDir;
// ########################################################################
// Methods
// ########################################################################
/**
* Execute task
*/
public function execute()
{
// Build sitemap
$this->initialize();
$rootPageList = $this->getRootPages();
$this->cleanupDirectory();
$this->initLanguages();
foreach ($rootPageList as $uid => $page) {
$this->initRootPage($uid);
if (GeneralUtility::getRootSettingValue('is_sitemap_language_lock', false, $uid)) {
foreach ($this->languageIdList as $languageId) {
$this->setRootPageLanguage($languageId);
$this->buildSitemap($uid, $languageId);
}
} else {
$this->buildSitemap($uid, null);
}
}
return true;
}
/**
* Cleanup sitemap directory
*/
protected function cleanupDirectory()
{
if (empty($this->sitemapDir)) {
throw new \Exception('Basedir not set');
}
$fullPath = PATH_site . '/' . $this->sitemapDir;
if (!is_dir($fullPath)) {
Typo3GeneralUtility::mkdir($fullPath);
}
foreach (new \DirectoryIterator($fullPath) as $file) {
if ($file->isFile() && !$file->isDot()) {
$fileName = $file->getFilename();
unlink($fullPath . '/' . $fileName);
}
}
}
/**
* Build sitemap
*
* @param integer $rootPageId Root page id
* @param integer $languageId Language id
*/
abstract protected function buildSitemap($rootPageId, $languageId);
// ########################################################################
// Abstract Methods
// ########################################################################
/**
* Generate sitemap link template
*
* @param string $template File link template
*
* @return string
*/
protected function generateSitemapLinkTemplate($template)
{
$ret = null;
// Set link template for index file
$linkConf = array(
'parameter' => $this->sitemapDir . '/' . $template,
);
if (strlen($GLOBALS['TSFE']->baseUrl) > 1) {
$ret = $GLOBALS['TSFE']->baseUrlWrap($GLOBALS['TSFE']->cObj->typoLink_URL($linkConf));
} elseif (strlen($GLOBALS['TSFE']->absRefPrefix) > 1) {
$ret = $GLOBALS['TSFE']->absRefPrefix . $GLOBALS['TSFE']->cObj->typoLink_URL($linkConf);
} else {
$ret = $GLOBALS['TSFE']->cObj->typoLink_URL($linkConf);
}
return $ret;
}
}

View File

@@ -0,0 +1,154 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Scheduler\Task;
use Metaseo\Metaseo\Utility\DatabaseUtility;
use Metaseo\Metaseo\Utility\FrontendUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Scheduler Task Sitemap Base
*/
abstract class AbstractTask extends \TYPO3\CMS\Scheduler\Task\AbstractTask
{
// ########################################################################
// Attributes
// ########################################################################
/**
* Backend Form Protection object
*
* @var \TYPO3\CMS\Extbase\Object\ObjectManager
* @inject
*/
protected $objectManager;
/**
* Language lock
*
* @var integer
*/
protected $languageLock;
/**
* Language list
*
* @var array
*/
protected $languageIdList;
// ########################################################################
// Methods
// ########################################################################
/**
* Initialize task
*/
protected function initialize()
{
$this->objectManager = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
}
/**
* Get list of root pages in current typo3
*
* @return array
*/
protected function getRootPages()
{
$query = 'SELECT uid
FROM pages
WHERE is_siteroot = 1
AND deleted = 0';
return DatabaseUtility::getColWithIndex($query);
}
/**
* Get list of root pages in current typo3
*
* @return array
*/
protected function initLanguages()
{
$this->languageIdList[0] = 0;
$query = 'SELECT uid
FROM sys_language
WHERE hidden = 0';
$langIdList = DatabaseUtility::getColWithIndex($query);
$this->languageIdList = $langIdList;
}
/**
* Set root page language
*
* @param integer $languageId
*/
protected function setRootPageLanguage($languageId)
{
$GLOBALS['TSFE']->tmpl->setup['config.']['sys_language_uid'] = $languageId;
$this->languageLock = $languageId;
}
/**
* Initialize root page (TSFE and stuff)
*
* @param integer $rootPageId $rootPageId
*/
protected function initRootPage($rootPageId)
{
FrontendUtility::init($rootPageId);
}
/**
* Write content to file
*
* @param string $file Filename/path
* @param string $content Content
*
* @throws \Exception
*/
protected function writeToFile($file, $content)
{
if (!function_exists('gzopen')) {
throw new \Exception('metaseo needs zlib support');
}
$fp = gzopen($file, 'w');
if ($fp) {
gzwrite($fp, $content);
gzclose($fp);
} else {
throw new \Exception('Could not open ' . $file . ' for writing');
}
}
}

View File

@@ -0,0 +1,50 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Scheduler\Task;
use Metaseo\Metaseo\Utility\SitemapUtility;
use TYPO3\CMS\Scheduler\Task\AbstractTask as Typo3AbstractTask;
/**
* Scheduler Task Garbage Collection
*/
class GarbageCollectionTask extends Typo3AbstractTask
{
/**
* Execute task
*
* @return boolean
*/
public function execute()
{
// Expire sitemap entries
SitemapUtility::expire();
return true;
}
}

View File

@@ -0,0 +1,76 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Scheduler\Task;
/**
* Scheduler Task Sitemap TXT
*/
class SitemapTxtTask extends AbstractSitemapTask
{
// ########################################################################
// Attributes
// ########################################################################
/**
* Sitemap base directory
*
* @var string
*/
protected $sitemapDir = 'uploads/tx_metaseo/sitemap_txt';
// ########################################################################
// Methods
// ########################################################################
/**
* Build sitemap
*
* @param integer $rootPageId Root page id
* @param integer $languageId Language id
*
* @return boolean
*/
protected function buildSitemap($rootPageId, $languageId)
{
if ($languageId !== null) {
// Language lock enabled
$sitemapFileName = 'sitemap-r%s-l%s.txt.gz';
} else {
$sitemapFileName = 'sitemap-r%s.txt.gz';
}
$generator = $this->objectManager->get('Metaseo\\Metaseo\\Sitemap\\Generator\\TxtGenerator');
$content = $generator->sitemap();
$fileName = sprintf($sitemapFileName, $rootPageId, $languageId);
$this->writeToFile(PATH_site . '/' . $this->sitemapDir . '/' . $fileName, $content);
return true;
}
}

View File

@@ -0,0 +1,94 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Scheduler\Task;
/**
* Scheduler Task Sitemap XML
*/
class SitemapXmlTask extends AbstractSitemapTask
{
// ########################################################################
// Attributes
// ########################################################################
/**
* Sitemap base directory
*
* @var string
*/
protected $sitemapDir = 'uploads/tx_metaseo/sitemap_xml';
// ########################################################################
// Methods
// ########################################################################
/**
* Build sitemap
*
* @param integer $rootPageId Root page id
* @param integer $languageId Language id
*
* @return boolean
*/
protected function buildSitemap($rootPageId, $languageId)
{
if ($languageId !== null) {
// Language lock enabled
$rootPageLinkTemplate = 'sitemap-r%s-l%s-p###PAGE###.xml.gz';
$sitemapIndexFileName = 'index-r%s-l%s.xml.gz';
$sitemapPageFileName = 'sitemap-r%s-l%s-p%s.xml.gz';
} else {
$rootPageLinkTemplate = 'sitemap-r%s-p###PAGE###.xml.gz';
$sitemapIndexFileName = 'index-r%s.xml.gz';
$sitemapPageFileName = 'sitemap-r%s-p%3$s.xml.gz';
}
// Init builder
$generator = $this->objectManager->get('Metaseo\\Metaseo\\Sitemap\\Generator\\XmlGenerator');
$fileName = sprintf($rootPageLinkTemplate, $rootPageId, $languageId);
$generator->indexPathTemplate = $this->generateSitemapLinkTemplate($fileName);
// Get list of pages
$pageCount = $generator->pageCount();
// Index
$content = $generator->sitemapIndex();
$fileName = sprintf($sitemapIndexFileName, $rootPageId, $languageId);
$this->writeToFile(PATH_site . '/' . $this->sitemapDir . '/' . $fileName, $content);
// Page
for ($i = 0; $i < $pageCount; $i++) {
$content = $generator->sitemap($i);
$fileName = sprintf($sitemapPageFileName, $rootPageId, $languageId, $i);
$this->writeToFile(PATH_site . '/' . $this->sitemapDir . '/' . $fileName, $content);
}
return true;
}
}

View File

@@ -0,0 +1,164 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Sitemap\Generator;
use Metaseo\Metaseo\Utility\GeneralUtility;
use Metaseo\Metaseo\Utility\SitemapUtility;
/**
* Sitemap abstract generator
*/
abstract class AbstractGenerator
{
// ########################################################################
// Attributes
// ########################################################################
/**
* Current root pid
*
* @var integer
*/
public $rootPid;
/**
* Sitemap pages
*
* @var array
*/
public $sitemapPages = array();
/**
* Page lookups
*
* @var array
*/
public $pages = array();
/**
* Extension setup configuration
*
* @var array
*/
public $tsSetup = array();
/**
* Page change frequency definition list
*
* @var array
*/
public $pageChangeFrequency = array(
1 => 'always',
2 => 'hourly',
3 => 'daily',
4 => 'weekly',
5 => 'monthly',
6 => 'yearly',
7 => 'never',
);
/**
* Link template for sitemap index
*
* Replacement marker ###PAGE### for page-uid
*
* @var string|boolean
*/
public $indexPathTemplate = false;
/**
* Extension configuration
*
* @var array
*/
protected $extConf = array();
// ########################################################################
// Methods
// ########################################################################
/**
* Fetch sitemap information and generate sitemap
*/
public function __construct()
{
// INIT
$this->rootPid = GeneralUtility::getRootPid();
$sysLanguageId = null;
$this->tsSetup = $GLOBALS['TSFE']->tmpl->setup['plugin.']['metaseo.']['sitemap.'];
// Language limit via setupTS
if (GeneralUtility::getRootSettingValue('is_sitemap_language_lock', false)) {
$sysLanguageId = GeneralUtility::getLanguageId();
}
// Fetch sitemap list/pages
$list = SitemapUtility::getList($this->rootPid, $sysLanguageId);
$this->sitemapPages = $list['tx_metaseo_sitemap'];
$this->pages = $list['pages'];
// Call hook
GeneralUtility::callHookAndSignal(__CLASS__, 'sitemapSetup', $this);
}
/**
* Return page count
*
* @return integer
*/
public function pageCount()
{
$pageLimit = GeneralUtility::getRootSettingValue('sitemap_page_limit', null);
if (empty($pageLimit)) {
$pageLimit = 1000;
}
$pageItems = count($this->sitemapPages);
$pageCount = ceil($pageItems / $pageLimit);
return $pageCount;
}
// ########################################################################
// Abstract methods
// ########################################################################
/**
* Create sitemap index
*
* @return string
*/
abstract public function sitemapIndex();
/**
* Create sitemap (for page)
*
* @param integer $page Page
*
* @return string
*/
abstract public function sitemap($page = null);
}

View File

@@ -0,0 +1,76 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Sitemap\Generator;
use Metaseo\Metaseo\Utility\GeneralUtility;
/**
* Sitemap TXT generator
*/
class TxtGenerator extends AbstractGenerator
{
// ########################################################################
// Methods
// ########################################################################
/**
* Create sitemap index
*
* @return string
*/
public function sitemapIndex()
{
return '';
}
/**
* Create sitemap (for page)
*
* @param integer $page Page
*
* @return string
*/
public function sitemap($page = null)
{
$ret = array();
foreach ($this->sitemapPages as $sitemapPage) {
if (empty($this->pages[$sitemapPage['page_uid']])) {
// invalid page
continue;
}
$ret[] = GeneralUtility::fullUrl($sitemapPage['page_url']);
}
// Call hook
GeneralUtility::callHookAndSignal(__CLASS__, 'sitemapTextOutput', $this, $ret);
return implode("\n", $ret);
}
}

View File

@@ -0,0 +1,259 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Sitemap\Generator;
use Metaseo\Metaseo\Utility\GeneralUtility;
/**
* Sitemap XML generator
*/
class XmlGenerator extends AbstractGenerator
{
// ########################################################################
// Methods
// ########################################################################
/**
* Create sitemap index
*
* @return string
*/
public function sitemapIndex()
{
$pageLimit = 10000;
if (isset($this->tsSetup['pageLimit']) && $this->tsSetup['pageLimit'] != '') {
$pageLimit = (int)$this->tsSetup['pageLimit'];
}
$sitemaps = array();
$pageItems = count($this->sitemapPages);
$pageCount = ceil($pageItems / $pageLimit);
$linkConf = array(
'parameter' => GeneralUtility::getCurrentPid() . ',' . $GLOBALS['TSFE']->type,
'additionalParams' => '',
'useCacheHash' => 1,
);
for ($i = 0; $i < $pageCount; $i++) {
if ($this->indexPathTemplate) {
$link = GeneralUtility::fullUrl(str_replace('###PAGE###', $i, $this->indexPathTemplate));
$sitemaps[] = $link;
} else {
$linkConf['additionalParams'] = '&page=' . ($i + 1);
$sitemaps[] = GeneralUtility::fullUrl($GLOBALS['TSFE']->cObj->typoLink_URL($linkConf));
}
}
$ret = '<?xml version="1.0" encoding="UTF-8"?>';
$ret .= '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" '
. 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"';
$ret .= ' xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 '
. 'http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">';
// Call hook
GeneralUtility::callHookAndSignal(__CLASS__, 'sitemapXmlIndexSitemapList', $this, $sitemaps);
foreach ($sitemaps as $sitemapPage) {
$ret .= '<sitemap><loc>' . htmlspecialchars($sitemapPage) . '</loc></sitemap>';
}
$ret .= '</sitemapindex>';
// Call hook
GeneralUtility::callHookAndSignal(__CLASS__, 'sitemapXmlIndexOutput', $this, $ret);
return $ret;
}
/**
* Create sitemap (for page)
*
* @param integer $page Page
*
* @return string
*/
public function sitemap($page = null)
{
$ret = '';
$pageLimit = 10000;
if (isset($this->tsSetup['pageLimit']) && $this->tsSetup['pageLimit'] != '') {
$pageLimit = (int)$this->tsSetup['pageLimit'];
}
$pageItems = count($this->sitemapPages);
$pageItemBegin = $pageLimit * ($page - 1);
if ($pageItemBegin <= $pageItems) {
$this->sitemapPages = array_slice($this->sitemapPages, $pageItemBegin, $pageLimit);
$ret = $this->createSitemapPage();
}
return $ret;
}
/**
* Create Sitemap Page
*
* @return string
*/
protected function createSitemapPage()
{
$ret = '<?xml version="1.0" encoding="UTF-8"?>';
$ret .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"';
$ret .= ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"';
$ret .= ' xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9';
$ret .= ' http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">';
$pagePriorityDefaultValue = (float)GeneralUtility::getRootSettingValue('sitemap_priorty', 0);
$pagePriorityDepthMultiplier = (float)GeneralUtility::getRootSettingValue(
'sitemap_priorty_depth_multiplier',
0
);
$pagePriorityDepthModificator = (float)GeneralUtility::getRootSettingValue(
'sitemap_priorty_depth_modificator',
0
);
if ($pagePriorityDefaultValue == 0) {
$pagePriorityDefaultValue = 1;
}
if ($pagePriorityDepthMultiplier == 0) {
$pagePriorityDepthMultiplier = 1;
}
if ($pagePriorityDepthModificator == 0) {
$pagePriorityDepthModificator = 1;
}
// #####################
// SetupTS conf
// #####################
foreach ($this->sitemapPages as $sitemapPage) {
if (empty($this->pages[$sitemapPage['page_uid']])) {
// invalid page
continue;
}
$page = $this->pages[$sitemapPage['page_uid']];
// #####################################
// Page priority
// #####################################
$pageDepth = $sitemapPage['page_depth'];
$pageDepthBase = 1;
if (!empty($sitemapPage['page_hash'])) {
// page has module-content - trade as subpage
++$pageDepth;
}
$pageDepth -= $pagePriorityDepthModificator;
if ($pageDepth > 0.1) {
$pageDepthBase = 1 / $pageDepth;
}
$pagePriority = $pagePriorityDefaultValue * ($pageDepthBase * $pagePriorityDepthMultiplier);
if (!empty($page['tx_metaseo_priority'])) {
$pagePriority = $page['tx_metaseo_priority'] / 100;
}
$pagePriority = number_format($pagePriority, 2);
if ($pagePriority > 1) {
$pagePriority = '1.00';
} elseif ($pagePriority <= 0) {
$pagePriority = '0.00';
}
// #####################################
// Page information
// #####################################
// page Url
$pageUrl = GeneralUtility::fullUrl($sitemapPage['page_url']);
// Page modification date
$pageModificationDate = date('c', $sitemapPage['tstamp']);
// Page change frequency
$pageChangeFrequency = null;
if (!empty($page['tx_metaseo_change_frequency'])) {
// from page
$pageChangeFrequency = (int)$page['tx_metaseo_change_frequency'];
} elseif (!empty($sitemapPage['page_change_frequency'])) {
// from sitemap settings
$pageChangeFrequency = (int)$sitemapPage['page_change_frequency'];
} elseif (!empty($this->tsSetup['changeFrequency'])) {
// default from SetupTS
$pageChangeFrequency = (int)$this->tsSetup['changeFrequency'];
}
// translate change frequency
if (!empty($pageChangeFrequency) && !empty($this->pageChangeFrequency[$pageChangeFrequency])) {
$pageChangeFrequency = $this->pageChangeFrequency[$pageChangeFrequency];
} else {
$pageChangeFrequency = null;
}
// #####################################
// Sitemal page output
// #####################################
$ret .= '<url>';
$ret .= '<loc>' . htmlspecialchars($pageUrl) . '</loc>';
$ret .= '<lastmod>' . $pageModificationDate . '</lastmod>';
if (!empty($pageChangeFrequency)) {
$ret .= '<changefreq>' . htmlspecialchars($pageChangeFrequency) . '</changefreq>';
}
$ret .= '<priority>' . $pagePriority . '</priority>';
$ret .= '</url>';
}
$ret .= '</urlset>';
// Call hook
GeneralUtility::callHookAndSignal(__CLASS__, 'sitemapXmlPageOutput', $this, $ret);
return $ret;
}
}

View File

@@ -0,0 +1,79 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Utility;
/**
* Backend utility
*/
class BackendUtility
{
/**
* Fetch list of root pages (is_siteroot) in TYPO3 (cached)
*
* @return array
*/
public static function getRootPageList()
{
static $cache = null;
if ($cache === null) {
$query = 'SELECT uid,
pid,
title
FROM pages
WHERE is_siteroot = 1
AND deleted = 0';
$cache = DatabaseUtility::getAllWithIndex($query, 'uid');
}
return $cache;
}
/**
* Fetch list of setting entries
*
* @return array
*/
public static function getRootPageSettingList()
{
static $cache = null;
if ($cache === null) {
$query = 'SELECT seosr.*
FROM tx_metaseo_setting_root seosr
INNER JOIN pages p
ON p.uid = seosr.pid
AND p.is_siteroot = 1
AND p.deleted = 0
WHERE seosr.deleted = 0';
$cache = DatabaseUtility::getAllWithIndex($query, 'pid');
}
return $cache;
}
}

View File

@@ -0,0 +1,122 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Utility;
/**
* Console utility
*/
class ConsoleUtility
{
/**
* Write output (without forcing newline)
*
* @param string $message Message text
* @param integer $padding Pad message
*/
public static function write($message = null, $padding = null)
{
if ($padding > 0) {
$message = str_pad($message, $padding, ' ');
}
self::stdOut($message);
}
/**
* Send output to STD_OUT
*
* @param string $message Message text
*/
public static function stdOut($message = null)
{
if (defined('TYPO3_cliMode')) {
file_put_contents('php://stdout', $message);
}
}
/**
* Write output (forcing newline)
*
* @param string $message Message text
*/
public static function writeLine($message = null)
{
self::stdOut($message . "\n");
}
/**
* Write error (without forcing newline)
*
* @param string $message Message text
* @param integer $padding Pad message
*/
public static function writeError($message = null, $padding = null)
{
if ($padding > 0) {
$message = str_pad($message, $padding, ' ');
}
self::stdError($message);
}
/**
* Send output to STD_ERR
*
* @param string $message Message text
*/
public static function stdError($message = null)
{
if (defined('TYPO3_cliMode')) {
file_put_contents('php://stderr', $message);
}
}
/**
* Write error (forcing newline)
*
* @param string $message Message
*/
public static function writeErrorLine($message = null)
{
$message .= "\n";
self::stdError($message);
}
/**
* Exit cli script with return code
*
* @param integer $exitCode Exit code (0 = success)
*/
public static function terminate($exitCode)
{
if (defined('TYPO3_cliMode')) {
exit($exitCode);
}
}
}

View File

@@ -0,0 +1,456 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Utility;
/**
* Database utility
*/
class DatabaseUtility
{
/**
* relation we know of that it exists and which we can use for database vendor determination
*/
const TYPO3_DEFAULT_TABLE = 'pages';
###########################################################################
# Query functions
###########################################################################
/**
* Get row
*
* @param string $query SQL query
*
* @return array
*/
public static function getRow($query)
{
$ret = null;
$res = self::query($query);
if ($res) {
if ($row = self::connection()->sql_fetch_assoc($res)) {
$ret = $row;
}
self::free($res);
}
return $ret;
}
/**
* Execute sql query
*
* @param string $query SQL query
*
* @return \mysqli_result
* @throws \Exception
*/
public static function query($query)
{
$res = self::connection()->sql_query($query);
if (!$res || self::connection()->sql_errno()) {
// SQL statement failed
$errorMsg = sprintf(
'SQL Error: %s [errno: %s]',
self::connection()->sql_error(),
self::connection()->sql_errno()
);
if (defined('TYPO3_cliMode')) {
throw new \Exception($errorMsg);
} else {
debug('SQL-QUERY: ' . $query, $errorMsg, __LINE__, __FILE__);
}
$res = null;
}
return $res;
}
/**
* Get current database connection
*
* @return \TYPO3\CMS\Core\Database\DatabaseConnection
*/
public static function connection()
{
return $GLOBALS['TYPO3_DB'];
}
/**
* Free sql result
*
* @param boolean|\mysqli_result|object $res SQL result
*/
public static function free($res)
{
if ($res && $res !== true) {
self::connection()->sql_free_result($res);
}
}
/**
* Get All
*
* @param string $query SQL query
*
* @return array
*/
public static function getAll($query)
{
$ret = array();
$res = self::query($query);
if ($res) {
while ($row = self::connection()->sql_fetch_assoc($res)) {
$ret[] = $row;
}
self::free($res);
}
return $ret;
}
/**
* Get All with index (first value)
*
* @param string $query SQL query
* @param string $indexCol Index column name
*
* @return array
*/
public static function getAllWithIndex($query, $indexCol = null)
{
$ret = array();
$res = self::query($query);
if ($res) {
while ($row = self::connection()->sql_fetch_assoc($res)) {
if ($indexCol === null) {
// use first key as index
$index = reset($row);
} else {
$index = $row[$indexCol];
}
$ret[$index] = $row;
}
self::free($res);
}
return $ret;
}
/**
* Get List
*
* @param string $query SQL query
*
* @return array
*/
public static function getList($query)
{
$ret = array();
$res = self::query($query);
if ($res) {
while ($row = self::connection()->sql_fetch_row($res)) {
$ret[$row[0]] = $row[1];
}
self::free($res);
}
return $ret;
}
/**
* Get column
*
* @param string $query SQL query
*
* @return array
*/
public static function getCol($query)
{
$ret = array();
$res = self::query($query);
if ($res) {
while ($row = self::connection()->sql_fetch_row($res)) {
$ret[] = $row[0];
}
self::free($res);
}
return $ret;
}
/**
* Get column
*
* @param string $query SQL query
*
* @return array
*/
public static function getColWithIndex($query)
{
$ret = array();
$res = self::query($query);
if ($res) {
while ($row = self::connection()->sql_fetch_row($res)) {
$ret[$row[0]] = $row[0];
}
self::free($res);
}
return $ret;
}
/**
* Get count (from query)
*
* @param string $query SQL query
*
* @return integer
*/
public static function getCount($query)
{
$query = 'SELECT COUNT(*) FROM (' . $query . ') tmp';
return self::getOne($query);
}
###########################################################################
# Quote functions
###########################################################################
/**
* Get one
*
* @param string $query SQL query
*
* @return mixed
*/
public static function getOne($query)
{
$ret = null;
$res = self::query($query);
if ($res) {
if ($row = self::connection()->sql_fetch_assoc($res)) {
$ret = reset($row);
}
self::free($res);
}
return $ret;
}
/**
* Exec query (INSERT)
*
* @param string $query SQL query
*
* @return integer Last insert id
*/
public static function execInsert($query)
{
$ret = false;
$res = self::query($query);
if ($res) {
$ret = self::connection()->sql_insert_id();
self::free($res);
}
return $ret;
}
/**
* Exec query (DELETE, UPDATE etc)
*
* @param string $query SQL query
*
* @return integer Affected rows
*/
public static function exec($query)
{
$ret = false;
$res = self::query($query);
if ($res) {
$ret = self::connection()->sql_affected_rows();
self::free($res);
}
return $ret;
}
###########################################################################
# Helper functions
###########################################################################
/**
* Add condition to query
*
* @param array|string $condition Condition
*
* @return string
*/
public static function addCondition($condition)
{
$ret = ' ';
if (!empty($condition)) {
if (is_array($condition)) {
$ret .= ' AND (( ' . implode(" )\nAND (", $condition) . ' ))';
} else {
$ret .= ' AND ( ' . $condition . ' )';
}
}
return $ret;
}
/**
* Create condition 'field IN (1,2,3,4)'
*
* @param string $field SQL field
* @param array $values Values
* @param boolean $required Required
*
* @return string
*/
public static function conditionIn($field, array $values, $required = true)
{
return self::buildConditionIn($field, $values, $required, false);
}
/**
* Create condition 'field NOT IN (1,2,3,4)'
*
* @param string $field SQL field
* @param array $values Values
* @param boolean $required Required
*
* @return string
*/
public static function conditionNotIn($field, array $values, $required = true)
{
return self::buildConditionIn($field, $values, $required, true);
}
/**
* Create condition 'field [NOT] IN (1,2,3,4)'
*
* @param string $field SQL field
* @param array $values Values
* @param boolean $required Required
* @param boolean $negate use true for a NOT IN clause, use false for an IN clause (default)
*
* @return string
*/
protected static function buildConditionIn($field, array $values, $required = true, $negate = false)
{
if (empty($values)) {
return $required ? '1=0' : '1=1';
}
$not = $negate ? ' NOT' : '';
$quotedValues = self::quoteArray($values);
return $field . $not . ' IN (' . implode(',', $quotedValues) . ')';
}
/**
* Quote array with values
*
* @param array $valueList Values
* @param string $table Table
*
* @return array
*/
public static function quoteArray(array $valueList, $table = null)
{
$ret = array();
foreach ($valueList as $k => $v) {
$ret[$k] = self::quote($v, $table);
}
return $ret;
}
###########################################################################
# SQL wrapper functions
###########################################################################
/**
* Quote value
*
* @param string $value Value
* @param string $table Table
*
* @return string
*/
public static function quote($value, $table = null)
{
if ($table === null) {
$table = self::TYPO3_DEFAULT_TABLE;
}
if ($value === null) {
return 'NULL';
}
return self::connection()->fullQuoteStr($value, $table);
}
/**
* Build condition
*
* @param array $where Where condition
*
* @return string
*/
public static function buildCondition(array $where)
{
$ret = ' ';
if (!empty($where)) {
$ret = ' ( ' . implode(' ) AND ( ', $where) . ' ) ';
}
return $ret;
}
}

View File

@@ -0,0 +1,124 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Utility;
use ReflectionMethod;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility as Typo3ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility as Typo3GeneralUtility;
class ExtensionManagementUtility
{
const AJAX_METHOD_NAME_SUFFIX = 'Action';
const AJAX_METHOD_DELIMITER = '::';
/**
* Registers all public methods of a specified class with method name suffix 'Action' as ajax actions
* The ajax method names have the form <ajaxPrefix>::<ajaxMethod> (with 'Action' removed from the method)
* or <ajaxMethod> for empty/unspecified <ajaxPrefix>
*
* @param string $qualifiedClassName
* @param string $ajaxPrefix
*/
public static function registerAjaxClass($qualifiedClassName, $ajaxPrefix = '')
{
if (!empty($ajaxPrefix)) {
$ajaxPrefix = $ajaxPrefix . self::AJAX_METHOD_DELIMITER;
}
self::removeBeginningBackslash($qualifiedClassName);
$reflectionClass = self::getReflectionClass($qualifiedClassName);
$methods = $reflectionClass->getMethods(ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method) {
$methodName = $method->getName();
if (self::isAjaxMethod($methodName)) {
$ajaxMethodName = self::extractAjaxMethod($methodName);
Typo3ExtensionManagementUtility::registerAjaxHandler(
$ajaxPrefix . $ajaxMethodName,
$qualifiedClassName . '->' . $methodName
);
}
}
}
/**
* @param array $qualifiedClassNames
*/
public static function registerAjaxClasses(array $qualifiedClassNames)
{
foreach ($qualifiedClassNames as $ajaxPrefix => $qualifiedClassName) {
self::registerAjaxClass($qualifiedClassName, $ajaxPrefix);
}
}
/**
* @param string $methodName
*
* @return bool
*/
protected static function isAjaxMethod($methodName)
{
$suffixLength = strlen(self::AJAX_METHOD_NAME_SUFFIX);
return strlen($methodName) > $suffixLength
&& self::AJAX_METHOD_NAME_SUFFIX === substr($methodName, -1 * $suffixLength);
}
/**
* @param string $methodName
*
* @return string
*/
protected static function extractAjaxMethod($methodName)
{
$suffixLength = strlen(self::AJAX_METHOD_NAME_SUFFIX);
return substr(
$methodName,
0,
strlen($methodName) - $suffixLength
);
}
/**
* @param $qualifiedClassName
*/
protected static function removeBeginningBackslash(&$qualifiedClassName)
{
if ($qualifiedClassName[0] === '\\') {
$qualifiedClassName = substr($qualifiedClassName, 1);
}
}
/**
* @param $qualifiedClassName
*
* @return \ReflectionClass
*/
protected static function getReflectionClass($qualifiedClassName)
{
return Typo3GeneralUtility::makeInstance('ReflectionClass', $qualifiedClassName);
}
}

View File

@@ -0,0 +1,212 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Utility;
use TYPO3\CMS\Core\Utility\GeneralUtility as Typo3GeneralUtility;
/**
* General utility
*/
class FrontendUtility
{
/**
* Init TSFE with all needed classes eg. for backend usage ($GLOBALS['TSFE'])
*
* @param integer $pageUid PageUID
* @param null|array $rootLine Rootline
* @param null|array $pageData Page data array
* @param null|array $rootlineFull Full rootline
* @param null|integer $sysLanguage Sys language uid
*/
public static function init(
$pageUid,
$rootLine = null,
$pageData = null,
$rootlineFull = null,
$sysLanguage = null
) {
static $cacheTSFE = array();
static $lastTsSetupPid = null;
/** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */
$objectManager = Typo3GeneralUtility::makeInstance(
'TYPO3\\CMS\\Extbase\\Object\\ObjectManager'
);
// Fetch page if needed
if ($pageData === null) {
/** @var \TYPO3\CMS\Frontend\Page\PageRepository $sysPageObj */
$sysPageObj = $objectManager->get('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
$sysPageObj->sys_language_uid = $sysLanguage;
$pageData = $sysPageObj->getPage_noCheck($pageUid);
}
// create time tracker if needed
if (empty($GLOBALS['TT'])) {
/** @var \TYPO3\CMS\Core\TimeTracker\NullTimeTracker $timeTracker */
$timeTracker = $objectManager->get('TYPO3\\CMS\\Core\\TimeTracker\\NullTimeTracker');
$GLOBALS['TT'] = $timeTracker;
$GLOBALS['TT']->start();
}
if ($rootLine === null) {
/** @var \TYPO3\CMS\Frontend\Page\PageRepository $sysPageObj */
$sysPageObj = $objectManager->get('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
$sysPageObj->sys_language_uid = $sysLanguage;
$rootLine = $sysPageObj->getRootLine($pageUid);
// save full rootline, we need it in TSFE
$rootlineFull = $rootLine;
}
// Only setup tsfe if current instance must be changed
if ($lastTsSetupPid !== $pageUid) {
// Cache TSFE if possible to prevent reinit (is still slow but we need the TSFE)
if (empty($cacheTSFE[$pageUid])) {
/** @var \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController $tsfeController */
$tsfeController = $objectManager->get(
'TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController',
$GLOBALS['TYPO3_CONF_VARS'],
$pageUid,
0
);
$tsfeController->sys_language_uid = $sysLanguage;
/** @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer $cObjRenderer */
$cObjRenderer = $objectManager->get('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
/** @var \TYPO3\CMS\Core\TypoScript\ExtendedTemplateService $TSObj */
$TSObj = $objectManager->get('TYPO3\\CMS\\Core\\TypoScript\\ExtendedTemplateService');
$TSObj->tt_track = 0;
$TSObj->init();
$TSObj->runThroughTemplates($rootLine);
$TSObj->generateConfig();
$_GET['id'] = $pageUid;
// Init TSFE
$GLOBALS['TSFE'] = $tsfeController;
$GLOBALS['TSFE']->cObj = $cObjRenderer;
$GLOBALS['TSFE']->initFEuser();
$GLOBALS['TSFE']->determineId();
if (empty($GLOBALS['TSFE']->tmpl)) {
$GLOBALS['TSFE']->tmpl = new \stdClass();
}
$GLOBALS['TSFE']->tmpl->setup = $TSObj->setup;
$GLOBALS['TSFE']->initTemplate();
$GLOBALS['TSFE']->getConfigArray();
$GLOBALS['TSFE']->baseUrl = $GLOBALS['TSFE']->config['config']['baseURL'];
$cacheTSFE[$pageUid] = $GLOBALS['TSFE'];
}
$GLOBALS['TSFE'] = $cacheTSFE[$pageUid];
$lastTsSetupPid = $pageUid;
}
$GLOBALS['TSFE']->page = $pageData;
$GLOBALS['TSFE']->rootLine = $rootlineFull;
$GLOBALS['TSFE']->cObj->data = $pageData;
}
/**
* Check current page for blacklisting
*
* @param array $blacklist Blacklist configuration
*
* @return bool
*/
public static function checkPageForBlacklist(array $blacklist)
{
return GeneralUtility::checkUrlForBlacklisting(self::getCurrentUrl(), $blacklist);
}
/**
* Check if frontend page is cacheable
*
* @param array|null $conf Configuration
* @return bool
*/
public static function isCacheable($conf = null)
{
$TSFE = self::getTsfe();
if ($_SERVER['REQUEST_METHOD'] !== 'GET' || !empty($TSFE->fe_user->user['uid'])) {
return false;
}
// don't parse if page is not cacheable
if (empty($conf['allowNoStaticCachable']) && !$TSFE->isStaticCacheble()) {
return false;
}
// Skip no_cache-pages
if (empty($conf['allowNoCache']) && !empty($TSFE->no_cache)) {
return false;
}
return true;
}
/**
* Return current URL
*
* @return null|string
*/
public static function getCurrentUrl()
{
$ret = null;
$TSFE = self::getTsfe();
if (!empty($TSFE->anchorPrefix)) {
$ret = (string)$TSFE->anchorPrefix;
} else {
$ret = (string)$TSFE->siteScript;
}
return $ret;
}
/**
* Get TSFE
*
* @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
*/
public static function getTsfe()
{
return $GLOBALS['TSFE'];
}
}

View File

@@ -0,0 +1,463 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Utility;
/**
* General utility
*/
class GeneralUtility
{
// ########################################################################
// Attributes
// ########################################################################
/**
* Page Select
*
* @var \TYPO3\CMS\Frontend\Page\PageRepository
*/
protected static $sysPageObj;
/**
* Rootline cache
*
* @var array
*/
protected static $rootlineCache = array();
// ########################################################################
// Public methods
// ########################################################################
/**
* Get current language id
*
* @return integer
*/
public static function getLanguageId()
{
$ret = 0;
if (!empty($GLOBALS['TSFE']->tmpl->setup['config.']['sys_language_uid'])) {
$ret = (int)$GLOBALS['TSFE']->tmpl->setup['config.']['sys_language_uid'];
}
return $ret;
}
/**
* Get current pid
*
* @return integer
*/
public static function getCurrentPid()
{
return $GLOBALS['TSFE']->id;
}
/**
* Check if there is any mountpoint in rootline
*
* @param integer|null $uid Page UID
*
* @return boolean
*/
public static function isMountpointInRootLine($uid = null)
{
$ret = false;
// Performance check, there must be an MP-GET value
if (\TYPO3\CMS\Core\Utility\GeneralUtility::_GET('MP')) {
// Possible mount point detected, let's check the rootline
foreach (self::getRootLine($uid) as $page) {
if (!empty($page['_MOUNT_OL'])) {
// Mountpoint detected in rootline
$ret = true;
}
}
}
return $ret;
}
/**
* Get current root line
*
* @param integer|null $uid Page UID
*
* @return array
*/
public static function getRootLine($uid = null)
{
if ($uid === null) {
#################
# Current rootline
#################
if (empty(self::$rootlineCache['__CURRENT__'])) {
// Current rootline
$rootline = $GLOBALS['TSFE']->tmpl->rootLine;
// Filter rootline by siteroot
$rootline = self::filterRootlineBySiteroot((array)$rootline);
self::$rootlineCache['__CURRENT__'] = $rootline;
}
$ret = self::$rootlineCache['__CURRENT__'];
} else {
#################
# Other rootline
#################
if (empty(self::$rootlineCache[$uid])) {
// Fetch full rootline to TYPO3 root (0)
$rootline = self::getSysPageObj()->getRootLine($uid);
// Filter rootline by siteroot
$rootline = self::filterRootlineBySiteroot((array)$rootline);
self::$rootlineCache[$uid] = $rootline;
}
$ret = self::$rootlineCache[$uid];
}
return $ret;
}
/**
* Filter rootline to get the real one up to siteroot page
*
* @param $rootline
*
* @return array
*/
protected static function filterRootlineBySiteroot(array $rootline)
{
$ret = array();
// Make sure sorting is right (first root, last page)
ksort($rootline, SORT_NUMERIC);
//reverse rootline
$rootline = array_reverse($rootline);
foreach ($rootline as $page) {
$ret[] = $page;
if (!empty($page['is_siteroot'])) {
break;
}
}
$ret = array_reverse($ret);
return $ret;
}
/**
* Get sys page object
*
* @return \TYPO3\CMS\Frontend\Page\PageRepository
*/
protected static function getSysPageObj()
{
if (self::$sysPageObj === null) {
/** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
'TYPO3\\CMS\\Extbase\\Object\\ObjectManager'
);
/** @var \TYPO3\CMS\Frontend\Page\PageRepository $sysPageObj */
$sysPageObj = $objectManager->get('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
self::$sysPageObj = $sysPageObj;
}
return self::$sysPageObj;
}
/**
* Get domain
*
* @return array
*/
public static function getSysDomain()
{
static $ret = null;
if ($ret !== null) {
return $ret;
}
$host = \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('HTTP_HOST');
$rootPid = self::getRootPid();
$query = 'SELECT *
FROM sys_domain
WHERE pid = ' . (int)$rootPid . '
AND domainName = ' . DatabaseUtility::quote($host, 'sys_domain') . '
AND hidden = 0';
$ret = DatabaseUtility::getRow($query);
return $ret;
}
/**
* Get current root pid
*
* @param integer|null $uid Page UID
*
* @return integer
*/
public static function getRootPid($uid = null)
{
static $cache = array();
$ret = null;
if ($uid === null) {
#################
# Current root PID
#################
$rootline = self::getRootLine();
if (!empty($rootline[0])) {
$ret = $rootline[0]['uid'];
}
} else {
#################
# Other root PID
#################
if (!isset($cache[$uid])) {
$cache[$uid] = null;
$rootline = self::getRootLine($uid);
if (!empty($rootline[0])) {
$cache[$uid] = $rootline[0]['uid'];
}
}
$ret = $cache[$uid];
}
return $ret;
}
/**
* Get root setting value
*
* @param string $name Name of configuration
* @param mixed|NULL $defaultValue Default value
* @param integer|NULL $rootPid Root Page Id
*
* @return array
*/
public static function getRootSettingValue($name, $defaultValue = null, $rootPid = null)
{
$setting = self::getRootSetting($rootPid);
if (isset($setting[$name])) {
$ret = $setting[$name];
} else {
$ret = $defaultValue;
}
return $ret;
}
/**
* Get root setting row
*
* @param integer $rootPid Root Page Id
*
* @return array
*/
public static function getRootSetting($rootPid = null)
{
static $ret = null;
if ($ret !== null) {
return $ret;
}
if ($rootPid === null) {
$rootPid = self::getRootPid();
}
$query = 'SELECT *
FROM tx_metaseo_setting_root
WHERE pid = ' . (int)$rootPid . '
AND deleted = 0
LIMIT 1';
$ret = DatabaseUtility::getRow($query);
return $ret;
}
/**
* Get extension configuration
*
* @param string $name Name of config
* @param boolean $default Default value
*
* @return mixed
*/
public static function getExtConf($name, $default = null)
{
static $conf = null;
$ret = $default;
if ($conf === null) {
// Load ext conf
$conf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['metaseo']);
if (!is_array($conf)) {
$conf = array();
}
}
if (isset($conf[$name])) {
$ret = $conf[$name];
}
return $ret;
}
/**
* Call hook and signal
*
* @param string $class Name of the class containing the signal
* @param string $name Name of hook
* @param mixed $obj Reference to be passed along (typically "$this"
* - being a reference to the calling object) (REFERENCE!)
* @param mixed|NULL $args Args
*
* @return mixed
*/
public static function callHookAndSignal($class, $name, $obj, &$args = null)
{
static $hookConf = null;
static $signalSlotDispatcher = null;
// Fetch hooks config for metaseo, minimize array lookups
if ($hookConf === null) {
$hookConf = array();
if (isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks'])
&& is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks'])
) {
$hookConf = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks'];
}
}
// Call hooks
if (!empty($hookConf[$name]) && is_array($hookConf[$name])) {
foreach ($hookConf[$name] as $_funcRef) {
if ($_funcRef) {
\TYPO3\CMS\Core\Utility\GeneralUtility::callUserFunction($_funcRef, $args, $obj);
}
}
}
// Call signal
if ($signalSlotDispatcher === null) {
/** @var \TYPO3\CMS\Extbase\Object\ObjectManager $objectManager */
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
'TYPO3\\CMS\\Extbase\\Object\\ObjectManager'
);
/** @var \TYPO3\CMS\Extbase\SignalSlot\Dispatcher $signalSlotDispatcher */
$signalSlotDispatcher = $objectManager->get('TYPO3\\CMS\\Extbase\\SignalSlot\\Dispatcher');
}
$signalSlotDispatcher->dispatch($class, $name, array($args, $obj));
}
/**
* Generate full url
*
* Makes sure the url is absolute (http://....)
*
* @param string $url URL
* @param string $domain Domain
*
* @return string
*/
public static function fullUrl($url, $domain = null)
{
if (!preg_match('/^https?:\/\//i', $url)) {
// Fix for root page link
if ($url === '/') {
$url = '';
}
// remove first /
if (strpos($url, '/') === 0) {
$url = substr($url, 1);
}
if ($domain !== null) {
// specified domain
$url = 'http://' . $domain . '/' . $url;
} else {
// domain from env
$url = \TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . $url;
}
}
// Fix url stuff
$url = str_replace('?&', '?', $url);
return $url;
}
// ########################################################################
// Protected methods
// ########################################################################
/**
* Check if url is blacklisted
*
* @param string $url URL
* @param array $blacklistConf Blacklist configuration (list of regexp)
*
* @return bool
*/
public static function checkUrlForBlacklisting($url, array $blacklistConf)
{
// check for valid url
if (empty($url)) {
return true;
}
$blacklistConf = (array)$blacklistConf;
foreach ($blacklistConf as $blacklistRegExp) {
if (preg_match($blacklistRegExp, $url)) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,126 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Utility;
use TYPO3\CMS\Core\Utility\GeneralUtility as Typo3GeneralUtility;
/**
* Root page utility
*/
class RootPageUtility
{
/**
* Domain cache
*
* array(
* rootPid => domainName
* );
*
* @var array
*/
protected static $domainCache = array();
/**
* Get sitemap index url
*
* @param integer $rootPid Root PID
*
* @return string
*/
public static function getSitemapIndexUrl($rootPid)
{
return self::getFrontendUrl($rootPid, SitemapUtility::PAGE_TYPE_SITEMAP_XML);
}
/**
* Build a frontend url
*
* @param integer $rootPid Root Page ID
* @param integer $typeNum Type num
*
* @return string
*/
public static function getFrontendUrl($rootPid, $typeNum)
{
$domain = self::getDomain($rootPid);
if (!empty($domain)) {
$domain = 'http://' . $domain . '/';
} else {
$domain = Typo3GeneralUtility::getIndpEnv('TYPO3_SITE_URL');
}
// "build", TODO: use typolink to use TYPO3 internals
$url = $domain . 'index.php?id=' . (int)$rootPid . '&type=' . (int)$typeNum;
return $url;
}
/**
* Get domain
*
* @param integer $rootPid Root PID
*
* @return null|string
*/
public static function getDomain($rootPid)
{
// Use cached one if exists
if (isset(self::$domainCache[$rootPid])) {
return self::$domainCache[$rootPid];
}
// Fetch domain name
$query = 'SELECT domainName
FROM sys_domain
WHERE pid = ' . (int)$rootPid . '
AND hidden = 0
ORDER BY forced DESC,
sorting
LIMIT 1';
$ret = DatabaseUtility::getOne($query);
// Remove possible slash at the end
$ret = rtrim($ret, '/');
// Cache entry
self::$domainCache[$rootPid] = $ret;
return $ret;
}
/**
* Get robots.txt url
*
* @param integer $rootPid Root PID
*
* @return string
*/
public static function getRobotsTxtUrl($rootPid)
{
return self::getFrontendUrl($rootPid, SitemapUtility::PAGE_TYPE_ROBOTS_TXT);
}
}

View File

@@ -0,0 +1,298 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* (c) 2013 Markus Blaschke (TEQneers GmbH & Co. KG) <blaschke@teqneers.de> (tq_seo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Utility;
use TYPO3\CMS\Core\Utility\GeneralUtility as Typo3GeneralUtility;
use TYPO3\CMS\Frontend\Page\PageRepository;
/**
* Sitemap utility
*/
class SitemapUtility
{
const SITEMAP_TYPE_PAGE = 0;
const SITEMAP_TYPE_FILE = 1;
/* apply changes in Configuration/TypoScript/setup.txt */
const PAGE_TYPE_SITEMAP_TXT = 841131; // sitemap.txt (EXT:metaseo)
const PAGE_TYPE_SITEMAP_XML = 841132; // sitemap.xml (EXT:metaseo)
const PAGE_TYPE_ROBOTS_TXT = 841133; // robots.txt (EXT:metaseo)
// ########################################################################
// Attributes
// ########################################################################
/**
* List of blacklisted doktypes (from table pages)
* @var array
*/
protected static $doktypeBlacklist = array(
PageRepository::DOKTYPE_BE_USER_SECTION, // Backend Section (TYPO3 CMS)
PageRepository::DOKTYPE_SPACER, // Menu separator (TYPO3 CMS)
PageRepository::DOKTYPE_SYSFOLDER, // Folder (TYPO3 CMS)
PageRepository::DOKTYPE_RECYCLER, // Recycler (TYPO3 CMS)
);
/**
* List of blacklisted rendering PAGE typenum (typoscript object)
*
* @var array
*/
protected static $pagetypeBlacklist = array(
self::PAGE_TYPE_SITEMAP_TXT, // sitemap.txt (EXT:metaseo)
self::PAGE_TYPE_SITEMAP_XML, // sitemap.xml (EXT:metaseo)
self::PAGE_TYPE_ROBOTS_TXT, // robots.txt (EXT:metaseo)
);
// ########################################################################
// Public methods
// ########################################################################
/**
* Insert into sitemap
*
* @param array $pageData page information
*/
public static function index(array $pageData)
{
static $cache = array();
// do not index empty urls
if (empty($pageData['page_url'])) {
return;
}
// Trim url
$pageData['page_url'] = trim($pageData['page_url']);
// calc page hash
$pageData['page_hash'] = md5($pageData['page_url']);
$pageHash = $pageData['page_hash'];
// set default type if not set
if (!isset($pageData['page_type'])) {
$pageData['page_type'] = self::SITEMAP_TYPE_PAGE;
}
// Escape/Quote data
unset($pageDataValue);
foreach ($pageData as &$pageDataValue) {
if ($pageDataValue === null) {
$pageDataValue = 'NULL';
} elseif (is_int($pageDataValue) || is_numeric($pageDataValue)) {
// Don't quote numeric/integers
$pageDataValue = (int)$pageDataValue;
} else {
// String
$pageDataValue = DatabaseUtility::quote($pageDataValue, 'tx_metaseo_sitemap');
}
}
unset($pageDataValue);
// only process each page once to keep sql-statements at a normal level
if (empty($cache[$pageHash])) {
// $pageData is already quoted
// TODO: INSERT INTO ... ON DUPLICATE KEY UPDATE?
$query = 'SELECT uid
FROM tx_metaseo_sitemap
WHERE page_uid = ' . $pageData['page_uid'] . '
AND page_language = ' . $pageData['page_language'] . '
AND page_hash = ' . $pageData['page_hash'] . '
AND page_type = ' . $pageData['page_type'];
$sitemapUid = DatabaseUtility::getOne($query);
if (!empty($sitemapUid)) {
$query = 'UPDATE tx_metaseo_sitemap
SET tstamp = ' . $pageData['tstamp'] . ',
page_rootpid = ' . $pageData['page_rootpid'] . ',
page_language = ' . $pageData['page_language'] . ',
page_url = ' . $pageData['page_url'] . ',
page_depth = ' . $pageData['page_depth'] . ',
page_change_frequency = ' . $pageData['page_change_frequency'] . ',
page_type = ' . $pageData['page_type'] . ',
expire = ' . $pageData['expire'] . '
WHERE uid = ' . (int)$sitemapUid;
DatabaseUtility::exec($query);
} else {
// #####################################
// INSERT
// #####################################
DatabaseUtility::connection()->exec_INSERTquery(
'tx_metaseo_sitemap',
$pageData,
array_keys($pageData)
);
}
$cache[$pageHash] = 1;
}
}
/**
* Clear outdated and invalid pages from sitemap table
*/
public static function expire()
{
// #####################
// Delete expired entries
// #####################
$query = 'DELETE FROM tx_metaseo_sitemap
WHERE is_blacklisted = 0
AND expire <= ' . (int)time();
DatabaseUtility::exec($query);
// #####################
// Deleted or
// excluded pages
// #####################
$query = 'SELECT ts.uid
FROM tx_metaseo_sitemap ts
LEFT JOIN pages p
ON p.uid = ts.page_uid
AND p.deleted = 0
AND p.hidden = 0
AND p.tx_metaseo_is_exclude = 0
AND ' . DatabaseUtility::conditionNotIn('p.doktype', self::getDoktypeBlacklist()) . '
WHERE p.uid IS NULL';
$deletedSitemapPages = DatabaseUtility::getColWithIndex($query);
// delete pages
if (!empty($deletedSitemapPages)) {
$query = 'DELETE FROM tx_metaseo_sitemap
WHERE uid IN (' . implode(',', $deletedSitemapPages) . ')
AND is_blacklisted = 0';
DatabaseUtility::exec($query);
}
}
/**
* Get list of blacklisted doktypes (from table pages)
*
* @return array
*/
public static function getDoktypeBlacklist()
{
return self::$doktypeBlacklist;
}
/**
* Get list of blacklisted PAGE typenum (typoscript object)
*
* @return array
*/
public static function getPageTypeBlacklist()
{
$ret = self::$pagetypeBlacklist;
// Fetch from SetupTS (comma separated list)
if (isset($GLOBALS['TSFE']->tmpl->setup['plugin.']['metaseo.']['sitemap.']['index.']['pageTypeBlacklist'])
&& strlen(
$GLOBALS['TSFE']
->tmpl
->setup['plugin.']['metaseo.']['sitemap.']['index.']['pageTypeBlacklist']
) >= 1
) {
$pageTypeBlacklist = $GLOBALS['TSFE']->tmpl
->setup['plugin.']['metaseo.']['sitemap.']['index.']['pageTypeBlacklist'];
$pageTypeBlacklist = Typo3GeneralUtility::trimExplode(',', $pageTypeBlacklist);
$ret = array_merge($ret, $pageTypeBlacklist);
}
return $ret;
}
/**
* Return list of sitemap pages
*
* @param integer $rootPid Root page id of tree
* @param integer $languageId Limit to language id
*
* @return boolean|array
*/
public static function getList($rootPid, $languageId = null)
{
$sitemapList = array();
$pageList = array();
$typo3Pids = array();
$query = 'SELECT ts.*
FROM tx_metaseo_sitemap ts
INNER JOIN pages p
ON p.uid = ts.page_uid
AND p.deleted = 0
AND p.hidden = 0
AND p.tx_metaseo_is_exclude = 0
AND ' . DatabaseUtility::conditionNotIn('p.doktype', self::getDoktypeBlacklist()) . '
WHERE ts.page_rootpid = ' . (int)$rootPid . '
AND ts.is_blacklisted = 0';
if ($languageId !== null) {
$query .= ' AND ts.page_language = ' . (int)$languageId;
}
$query .= ' ORDER BY
ts.page_depth ASC,
p.pid ASC,
p.sorting ASC';
$resultRows = DatabaseUtility::getAll($query);
if (!$resultRows) {
return false;
}
foreach ($resultRows as $row) {
$sitemapList[] = $row;
$sitemapPageId = $row['page_uid'];
$typo3Pids[$sitemapPageId] = (int)$sitemapPageId;
}
if (!empty($typo3Pids)) {
$query = 'SELECT *
FROM pages
WHERE ' . DatabaseUtility::conditionIn('uid', $typo3Pids);
$pageList = DatabaseUtility::getAllWithIndex($query, 'uid');
if (empty($pageList)) {
return false;
}
}
$ret = array(
'tx_metaseo_sitemap' => $sitemapList,
'pages' => $pageList
);
return $ret;
}
}

View File

@@ -0,0 +1,365 @@
<?php
/*
* Copyright notice
*
* (c) 2015 Markus Blaschke <typo3@markus-blaschke.de> (metaseo)
* All rights reserved
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
*/
namespace Metaseo\Metaseo\Utility;
use TYPO3\CMS\Core\Utility\GeneralUtility as Typo3GeneralUtility;
class TypoScript implements \Iterator
{
###########################################################################
## Attributes
###########################################################################
/**
* TYPO3 TypoScript Data
*
* @var array
*/
protected $tsData;
/**
* TYPO3 TypoScript Data Type
*
* @var string
*/
protected $tsType;
/**
* Iterator position
*
* @var mixed
*/
protected $iteratorPosition = false;
/**
* cObj
* @var \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*/
protected $cObj;
###########################################################################
## Constructor
###########################################################################
/**
* Constructor
*
* @param NULL|array $conf TypoScript node configuration
* @param NULL|string $type TypoScript node type
*/
public function __construct($conf = null, $type = null)
{
if ($conf !== null) {
$this->tsData = $conf;
}
if ($type !== null) {
$this->tsType = $type;
}
}
###########################################################################
## Iterator methods
###########################################################################
/**
* Rewind iterator position
*/
public function rewind()
{
reset($this->tsData);
$this->iteratorNextNode();
}
/**
* Check if current node is a valid node
*
* @return boolean
*/
public function valid()
{
return $this->iteratorPosition && array_key_exists($this->iteratorPosition, $this->tsData);
}
/**
* Return current iterator key
*
* @return string TypoScript path-node-key
*/
public function key()
{
return substr($this->iteratorPosition, 0, -1);
}
/**
* Return current iterator node
*
* @return TypoScript
*/
public function current()
{
$nodePath = substr($this->iteratorPosition, 0, -1);
return $this->getNode($nodePath);
}
/**
* Get TypoScript subnode
*
* @param string $tsNodePath TypoScript node-path
*
* @return TypoScript TypoScript subnode-object
*/
public function getNode($tsNodePath)
{
$ret = null;
// extract TypoScript-path information
$nodeSections = explode('.', $tsNodePath);
$nodeValueType = end($nodeSections);
$nodeValueName = end($nodeSections) . '.';
// remove last node from sections because we already got the node name
unset($nodeSections[key($nodeSections)]);
// walk though array to find node
$nodeData = $this->tsData;
if (!empty($nodeSections) && is_array($nodeSections)) {
foreach ($nodeSections as $sectionName) {
$sectionName .= '.';
if (is_array($nodeData) && array_key_exists($sectionName, $nodeData)) {
$nodeData = $nodeData[$sectionName];
} else {
break;
}
}
}
// Fetch TypoScript configuration data
$tsData = array();
if (is_array($nodeData) && array_key_exists($nodeValueName, $nodeData)) {
$tsData = $nodeData[$nodeValueName];
}
// Fetch TypoScript configuration type
$tsType = null;
if (is_array($nodeData) && array_key_exists($nodeValueType, $nodeData)) {
$tsType = $nodeData[$nodeValueType];
}
// Clone object and set values
$ret = clone $this;
$ret->tsData = $tsData;
$ret->tsType = $tsType;
$ret->iteratorPosition = false;
return $ret;
}
/**
* Next iterator node
*/
public function next()
{
next($this->tsData);
$this->iteratorNextNode();
}
###########################################################################
## Public methods
###########################################################################
/**
* Search next iterator node
*/
public function iteratorNextNode()
{
// INIT
$iteratorPosition = null;
$this->iteratorPosition = false;
$nextNode = false;
do {
if ($nextNode) {
next($this->tsData);
}
$currentNode = current($this->tsData);
if ($currentNode !== false) {
// get key
$iteratorPosition = key($this->tsData);
// check if node is subnode or value
if (substr($iteratorPosition, -1) == '.') {
// next subnode fond
$this->iteratorPosition = $iteratorPosition;
break;
}
} else {
$iteratorPosition = false;
$this->iteratorPosition = false;
}
$nextNode = true;
} while ($iteratorPosition !== false);
}
/**
* Get value from node
*
* @param string $tsNodePath TypoScript node-path
* @param mixed $defaultValue Default value
*
* @return mixed Node value (or default value)
*/
public function getValue($tsNodePath, $defaultValue = null)
{
$ret = $defaultValue;
// extract TypoScript-path information
$nodeFound = true;
$nodeSections = explode('.', $tsNodePath);
$nodeValueName = end($nodeSections);
// remove last node from sections because we already got the node name
unset($nodeSections[key($nodeSections)]);
// walk though array to find node
$nodeData = $this->tsData;
if (!empty($nodeSections) && is_array($nodeSections)) {
foreach ($nodeSections as $sectionName) {
$sectionName .= '.';
if (is_array($nodeData) && array_key_exists($sectionName, $nodeData)) {
$nodeData = $nodeData[$sectionName];
} else {
$nodeFound = false;
break;
}
}
}
// check if we got the value of the node
if ($nodeFound && is_array($nodeData) && array_key_exists($nodeValueName, $nodeData)) {
$ret = $nodeData[$nodeValueName];
}
return $ret;
}
/**
* Convert TypoScript to original array
*
* @return array
*/
public function toArray()
{
return $this->tsData;
}
/**
* Check if TypoScript is empty/not set
*
* @return boolean
*/
public function isEmpty()
{
return empty($this->tsData);
}
/**
* Render TypoScript Config
*
* @return mixed Result of cObj
*/
public function render()
{
return $this->getCObj()->cObjGetSingle($this->tsType, $this->tsData);
}
/**
* StdWrap with TypoScript Configuration
*
* @param mixed $value Value for stdWrap
*
* @return mixed Result of stdWrap
*/
public function stdWrap($value = null)
{
return $this->getCObj()->stdWrap($value, $this->tsData);
}
###########################################################################
## Protected methods
###########################################################################
/**
* Return instance of \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*
* @return \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer
*/
protected function getCObj()
{
if ($this->cObj === null) {
$this->cObj = Typo3GeneralUtility::makeInstance(
'TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer'
);
}
return $this->cObj;
}
###########################################################################
## Private methods
###########################################################################
###########################################################################
## Accessors
###########################################################################
public function setTypoScript(Array $conf)
{
$this->tsData = $conf;
return $this;
}
public function getTypoScriptType()
{
return $this->tsType;
}
public function setTypoScriptType($value)
{
$this->tsType = (string)$value;
return $this;
}
}