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,29 @@
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
charset = utf-8
trim_trailing_whitespace = true
[*]
indent_style = space
indent_size = 4
[*.php]
indent_style = space
[{setup,constants,ext_conf_template}.txt]
indent_style = space
[*.json]
indent_style = space
indent_size = 2
[*.html]
indent_style = tab
[*.rst]
indent_style = tab
[Makefile]
indent_style = tab

10
typo3conf/ext/metaseo/.gitignore vendored Normal file
View File

@@ -0,0 +1,10 @@
.settings/
.buildpath
*.kdev4
.project
.remote_password_hash
.remote_server
.remote_username
tmp
*~
.idea

View File

@@ -0,0 +1,34 @@
# MetaSEO - Changelog
## MetaSEO 2.0
- Added TYPO3 7.x support
- Implemented Signals
- Implemented blacklist of PAGE typeNum in SetupTS
- Implemented blacklist for index/noindex robots metatag
- Implemented blacklist for canonical url
- Implemented canonical url support for mounted pages, pointing to real page instead of mount path (disabled by default)
- Implemented expiry date for sitemap entries (customizable with SetupTS or Connector)
- Implemented pagetitle caching (if there is any USER_INT on the current page)
- Removed own caching solution, using TYPO3 caching framework now
- Fixed many bugs and issues
- Fixed coding style (added .editorconfig)
- Refactored whole extension
## Beta features
- If you have any issues with cached pagetitle: set `plugin.metaseo.pageTitle.caching = 0` to disable this feature.
### Migrate from 1.x to 2.x
- TypoScript Constant `plugin.metaseo.metaTags.useCanonical` changed to `plugin.metaseo.metaTags.canonicalUrl`
- TypoScript Setup `plugin.metaseo.metaTags.useCanonical` changed to `plugin.metaseo.metaTags.canonicalUrl`
- Names of Hooks changed, now camelCase
## MetaSEO 1.0 (2014-04-20)
- Version 1.0.0
- Fork of metaseo
- Fixed several bugs and improved codebase
- Fixed and improved manual (now reStructuredText)

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;
}
}

View File

@@ -0,0 +1,32 @@
<?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\Configuration\TCA;
/**
* This File is include()d by TYPO3's ExtensionUtility. We'll get an exception when we remove it.
* At some time we should find out what this file is actually good for.
*/

View File

@@ -0,0 +1,259 @@
<?php
defined('TYPO3_MODE') or exit();
$tempColumns = array(
'tx_metaseo_pagetitle' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_pagetitle',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
'tx_metaseo_pagetitle_rel' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_pagetitle_rel',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
'tx_metaseo_pagetitle_prefix' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_pagetitle_prefix',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
'tx_metaseo_pagetitle_suffix' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_pagetitle_suffix',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
'tx_metaseo_inheritance' => array(
'exclude' => 1,
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_inheritance',
'config' => array(
'type' => 'select',
'items' => array(
array(
'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_inheritance.I.0',
0
),
array(
'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_inheritance.I.1',
1
),
),
'size' => 1,
'maxitems' => 1
)
),
'tx_metaseo_is_exclude' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_is_exclude',
'exclude' => 1,
'config' => array(
'type' => 'check'
)
),
'tx_metaseo_canonicalurl' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_canonicalurl',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
'wizards' => array(
'_PADDING' => 2,
'link' => array(
'type' => 'popup',
'title' => 'Link',
'icon' => 'link_popup.gif',
'module' => array(
'name' => 'wizard_element_browser',
'urlParameters' => array(
'mode' => 'wizard',
'act' => 'url'
)
),
'params' => array(
'blindLinkOptions' => 'mail',
),
'JSopenParams' => 'height=300,width=500,status=0,menubar=0,scrollbars=1'
),
),
)
),
'tx_metaseo_priority' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_priority',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'int',
)
),
'tx_metaseo_change_frequency' => array(
'exclude' => 1,
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_change_frequency',
'config' => array(
'type' => 'select',
'items' => array(
array(
'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.tx_metaseo_change_frequency.I.0',
0
),
array(
'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.tx_metaseo_change_frequency.I.1',
1
),
array(
'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.tx_metaseo_change_frequency.I.2',
2
),
array(
'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.tx_metaseo_change_frequency.I.3',
3
),
array(
'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.tx_metaseo_change_frequency.I.4',
4
),
array(
'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.tx_metaseo_change_frequency.I.5',
5
),
array(
'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.tx_metaseo_change_frequency.I.6',
6
),
array(
'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.tx_metaseo_change_frequency.I.7',
7
),
),
'size' => 1,
'maxitems' => 1
)
),
'tx_metaseo_geo_lat' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_geo_lat',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
'tx_metaseo_geo_long' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_geo_long',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
'tx_metaseo_geo_place' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_geo_place',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
'tx_metaseo_geo_region' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tx_metaseo_geo_region',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('pages', $tempColumns, 1);
// TCA Palettes
$GLOBALS['TCA']['pages']['palettes']['tx_metaseo_pagetitle'] = array(
'showitem' => 'tx_metaseo_pagetitle,--linebreak--,tx_metaseo_pagetitle_prefix,'
. 'tx_metaseo_pagetitle_suffix,--linebreak--,tx_metaseo_inheritance',
'canNotCollapse' => 1
);
$GLOBALS['TCA']['pages']['palettes']['tx_metaseo_crawler'] = array(
'showitem' => 'tx_metaseo_is_exclude,--linebreak--,tx_metaseo_canonicalurl',
'canNotCollapse' => 1
);
$GLOBALS['TCA']['pages']['palettes']['tx_metaseo_sitemap'] = array(
'showitem' => 'tx_metaseo_priority,--linebreak--,tx_metaseo_change_frequency',
'canNotCollapse' => 1
);
$GLOBALS['TCA']['pages']['palettes']['tx_metaseo_geo'] = array(
'showitem' => 'tx_metaseo_geo_lat,--linebreak--,tx_metaseo_geo_long,--linebreak--,'
. 'tx_metaseo_geo_place,--linebreak--,tx_metaseo_geo_region',
'canNotCollapse' => 1
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
'pages',
'tx_metaseo_pagetitle_rel',
'1,4,7,3',
'after:title'
);
// Put it for standard page
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
'pages',
'--div--;LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tab.seo;,--palette--;'
. 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.palette.pagetitle;tx_metaseo_pagetitle,'
. '--palette--;LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.palette.geo;tx_metaseo_geo,'
. '--palette--;LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.palette.crawler;'
. 'tx_metaseo_crawler,--palette--;LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.palette.sitemap;tx_metaseo_sitemap',
'1,4,7,3',
'after:author_email'
);

View File

@@ -0,0 +1,115 @@
<?php
defined('TYPO3_MODE') or exit();
$tempColumns = array(
'tx_metaseo_pagetitle' => array(
'exclude' => 1,
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages_language_overlay.tx_metaseo_pagetitle',
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
'tx_metaseo_pagetitle_rel' => array(
'exclude' => 1,
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages_language_overlay.tx_metaseo_pagetitle_rel',
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
'tx_metaseo_pagetitle_prefix' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.tx_metaseo_pagetitle_prefix',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
'tx_metaseo_pagetitle_suffix' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.tx_metaseo_pagetitle_suffix',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
)
),
'tx_metaseo_canonicalurl' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'pages.tx_metaseo_canonicalurl',
'exclude' => 1,
'config' => array(
'type' => 'input',
'size' => '30',
'max' => '255',
'checkbox' => '',
'eval' => 'trim',
'wizards' => array(
'_PADDING' => 2,
'link' => array(
'type' => 'popup',
'title' => 'Link',
'icon' => 'link_popup.gif',
'module' => array(
'name' => 'wizard_element_browser',
'urlParameters' => array(
'mode' => 'wizard',
'act' => 'url'
)
),
'params' => array(
'blindLinkOptions' => 'mail',
),
'JSopenParams' => 'height=300,width=500,status=0,menubar=0,scrollbars=1'
),
),
)
),
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addTCAcolumns('pages_language_overlay', $tempColumns, 1);
// TCA Palettes
$GLOBALS['TCA']['pages_language_overlay']['palettes']['tx_metaseo_pagetitle'] = array(
'showitem' => 'tx_metaseo_pagetitle,--linebreak--,tx_metaseo_pagetitle_prefix,tx_metaseo_pagetitle_suffix',
'canNotCollapse' => 1
);
$GLOBALS['TCA']['pages_language_overlay']['palettes']['tx_metaseo_crawler'] = array(
'showitem' => 'tx_metaseo_canonicalurl',
'canNotCollapse' => 1
);
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
'pages_language_overlay',
'tx_metaseo_pagetitle_rel',
'',
'after:title'
);
// Put it for standard page overlay
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addToAllTCAtypes(
'pages_language_overlay',
'--div--;LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.tab.seo;,--palette--;'
. 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.palette.pagetitle;tx_metaseo_pagetitle,'
. '--palette--;LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:pages.palette.crawler;'
. 'tx_metaseo_crawler',
'',
'after:author_email'
);

View File

@@ -0,0 +1,154 @@
<?php
return array(
'ctrl' => array(
'title' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:tx_metaseo_setting_root',
'label' => 'uid',
'adminOnly' => true,
'iconfile' => 'page',
'hideTable' => true,
'dividers2tabs' => true,
),
'interface' => array(
'always_description' => true,
'showRecordFieldList' => 'is_robotstxt,robotstxt',
),
'columns' => array(
'is_sitemap' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.is_sitemap',
'config' => array(
'type' => 'check',
),
),
'is_sitemap_page_indexer' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.is_sitemap_page_indexer',
'config' => array(
'type' => 'check',
),
),
'is_sitemap_typolink_indexer' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.is_sitemap_typolink_indexer',
'config' => array(
'type' => 'check',
),
),
'is_sitemap_language_lock' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.is_sitemap_language_lock',
'config' => array(
'type' => 'check',
),
),
'sitemap_page_limit' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.sitemap_page_limit',
'config' => array(
'type' => 'input',
'size' => '10',
'max' => '10',
'eval' => 'int',
'range' => array(
'upper' => '1000000',
'lower' => '0',
),
),
),
'sitemap_priorty' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.sitemap_priorty',
'config' => array(
'type' => 'input',
'size' => '6',
'max' => '6',
'eval' => 'tx_metaseo_backend_validation_float',
),
),
'sitemap_priorty_depth_multiplier' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.sitemap_priorty_depth_multiplier',
'config' => array(
'type' => 'input',
'size' => '6',
'max' => '6',
'eval' => 'tx_metaseo_backend_validation_float',
),
),
'sitemap_priorty_depth_modificator' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.sitemap_priorty_depth_modificator',
'config' => array(
'type' => 'input',
'size' => '6',
'max' => '6',
'eval' => 'tx_metaseo_backend_validation_float',
),
),
'is_robotstxt' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.is_robotstxt',
'config' => array(
'type' => 'check',
),
),
'is_robotstxt_sitemap_static' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.is_robotstxt_sitemap_static',
'config' => array(
'type' => 'check',
),
),
'robotstxt' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.robotstxt',
'config' => array(
'type' => 'text',
'cols' => '30',
'rows' => '20',
),
),
'robotstxt_default' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.robotstxt_default',
'config' => array(
'type' => 'user',
'userFunc' => 'Metaseo\Metaseo\Hook\TCA\RobotsTxtDefault->main'
),
),
'robotstxt_additional' => array(
'label' => 'LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.robotstxt_additional',
'config' => array(
'type' => 'text',
'cols' => '30',
'rows' => '20',
),
),
),
'types' => array(
'0' => array(
'showitem' => '--div--;LLL:EXT:metaseo/Resources/Private/Language/TCA/locallang.xlf:'
. 'tx_metaseo_setting_root.tab.sitemap,is_sitemap;;pallette_sitemap,is_sitemap_language_lock,'
. 'sitemap_page_limit,sitemap_priorty,sitemap_priorty_depth_multiplier,'
. 'sitemap_priorty_depth_modificator,--div--;LLL:EXT:'
. 'metaseo/Resources/Private/Language/TCA/locallang.xlf:tx_metaseo_setting_root.tab.robotstxt,'
. 'is_robotstxt;;pallette_robotstxt',
'canNotCollapse' => '1'
),
),
'palettes' => array(
'pallette_sitemap' => array(
'showitem' => 'is_sitemap_page_indexer,is_sitemap_typolink_indexer',
'canNotCollapse' => '1'
),
'pallette_robotstxt' => array(
'showitem' => 'is_robotstxt_sitemap_static,--linebreak--,robotstxt,robotstxt_default,'
. '--linebreak--,robotstxt_additional',
'canNotCollapse' => '1'
),
),
);

View File

@@ -0,0 +1,172 @@
###
# This are the default TS-constants for metaseo
##
plugin.metaseo {
# cat=plugin.metaseo.metaTags/page/01; type=string; label= Meta Description: Short description of your webpage.
metaTags.description =
# cat=plugin.metaseo.metaTags/page/02; type=string; label= Meta Keywords: Comma separated list of keywords.
metaTags.keywords =
# cat=plugin.metaseo.metaTags/page/03; type=string; label= Meta Copyright info: Copyright information (eg. "Me Myself and I, %YEAR%. All rights reserved.", %YEAR% will be substituted with the current year).
metaTags.copyright =
# cat=plugin.metaseo.metaTags/page/04; type=string; label= Meta Reply-to email: Enter the e-mail adress for contact issues
metaTags.email =
# cat=plugin.metaseo.metaTags/page/05; type=string; label= Meta Author: Enter name of author.
metaTags.author =
# cat=plugin.metaseo.metaTags/page/06; type=string; label= Meta Publisher: Enter name of publisher.
metaTags.publisher =
# cat=plugin.metaseo.metaTags/page/08; type=string; label= Distribution
metaTags.distribution =
# cat=plugin.metaseo.metaTags/page/08; type=options[,General,Mature,14 years,Restricted]; label= Rating
metaTags.rating =
# cat=plugin.metaseo.metaTags/page/10; type=int+; label= Revisit after: Number of days between search engine visits.
metaTags.revisit =
# cat=plugin.metaseo.metaTags/page/14; type=string; label= Geo Position Latitude: Latitude of webpage
metaTags.geoPositionLatitude =
# cat=plugin.metaseo.metaTags/page/15; type=string; label= Geo Position Longitude: Longitude of webpage
metaTags.geoPositionLongitude =
# cat=plugin.metaseo.metaTags/page/16; type=string; label= Geo Region: Region of webpage (eg. DE-BW)
metaTags.geoRegion =
# cat=plugin.metaseo.metaTags/page/17; type=string; label= Geo Placename: Placename of webpage (eg. Stuttgart)
metaTags.geoPlacename =
# cat=plugin.metaseo.metaTags/page/19; type=string; label= PICS-Label: Platform for Internet Content Selection Label, see http://www.w3.org/PICS/
metaTags.picsLabel =
# cat=plugin.metaseo.metaTags/enable/20; type=boolean; label= Publish LastUpdate-Time: Should the crawler be informed about the time a page was last updated.
metaTags.useLastUpdate = 1
# cat=plugin.metaseo.metaTags/enable/22; type=boolean; label= Canonical Tag: Autogenerate Canonical-Metatag if possible.
metaTags.canonicalUrl = 1
# cat=plugin.metaseo.metaTags/enable/23; type=boolean; label= Canonical Tag (Strict mode): Enable strict mode (all wrong GET-parameters will generate a canonical-tag to the self without GET-params).
metaTags.canonicalUrl.strict = 1
# cat=plugin.metaseo.metaTags/enable/23; type=boolean; label= Canonical Tag (No MP mode): Link all mount point links to origin pages.
metaTags.canonicalUrl.noMP = 0
# cat=plugin.metaseo.metaTags/enable/24; type=boolean; label= OpenGraph Tags: Enable generation of OpenGraph Tags
metaTags.opengraph = 1
# cat=plugin.metaseo.metaTags/enable/25; type=boolean; label= Publish Page Expire Time: Anounce Expire Tag (TYPO3's enddate in content elements).
metaTags.useExpire = 1
# cat=plugin.metaseo.metaTags/page/26; type=string; label= P3P Compact Policy: W3C P3P Compact Policy String.
metaTags.p3pCP =
# cat=plugin.metaseo.metaTags/page/27; type=string; label= P3P Policy Url: URL to your W3C P3P Policy file.
metaTags.p3pPolicyUrl =
# cat=plugin.metaseo.metaTags/enable/28; type=boolean; label= Link generation: Automatic generate index, up, prev und next links (metatags).
metaTags.linkGeneration = 1
# cat=plugin.metaseo.metaTags/enable/29; type=boolean; label= Meta Description: Enable Dublin Core (DC.) metatags
metaTags.enableDC = 1
# cat=plugin.metaseo.crawler/page/01; type=boolean; label= Crawler Robots-Tag: Enable robot-metatag
metaTags.robotsEnable = 1
# cat=plugin.metaseo.crawler/page/02; type=boolean; label= Crawler Index: Should the crawler (eg. Google) index the page and subpages
metaTags.robotsIndex = 1
# cat=plugin.metaseo.crawler/page/03; type=boolean; label= Crawler Follow: Should the crawler (eg. Google) follow links
metaTags.robotsFollow = 1
# cat=plugin.metaseo.crawler/page/04; type=boolean; label= Crawler Archive: Should the crawler (eg. Google) put the content of the page into the archive (eg. Google Cache)
metaTags.robotsArchive = 1
# cat=plugin.metaseo.crawler/page/05; type=boolean; label= Crawler Snippet: Should the crawler (eg. Google) show the snippet in the search result
metaTags.robotsSnippet = 1
# cat=plugin.metaseo.crawler/page/06; type=boolean; label= Crawler Noimageindex: Should the crawler (eg. Google) not index images
metaTags.robotsNoImageindex = 0
# cat=plugin.metaseo.crawler/page/07; type=boolean; label= Crawler Notranslate: Should the crawler (eg. Google) not translate content
metaTags.robotsNoTranslate = 0
# cat=plugin.metaseo.crawler/page/08; type=boolean; label= Crawler ODP: Should the crawler (eg. Google) use the description from the OpenDirectoryProject
metaTags.robotsOdp = 1
# cat=plugin.metaseo.crawler/page/09; type=boolean; label= Crawler YDir: Should the crawler (eg. Google) use the description from the Yahoo Directory
metaTags.robotsYdir = 1
# cat=plugin.metaseo.userAgent/ie/1; type=options[,Highest Version=edge,10.x=10,9.x=9,8.x=8,7.x=7,6.x=6,5.x=5]; label= IE Compatibility Mode: Compatibility mode for Microsoft Internet Explorer.
userAgent.ieCompatibilityMode =
# cat=plugin.metaseo.services/enable/01; type=boolean; label= Enable Services if header is disabled: If config.disableAllHeaderCode = 1 then services are automatically disabled (eg. for ajax calls) to prevent duplicate hits in google analytics/piwik (and/or javascript issues)
services.enableIfHeaderIsDisabled = 0
# cat=plugin.metaseo.services/page/02; type=string; label= Google Crawler Verification: Verification code for google webmaster tools
metaTags.googleVerification =
# cat=plugin.metaseo.services/page/03; type=string; label= MSN Crawler Verification: Verification code for msn webmaster tools
metaTags.msnVerification =
# cat=plugin.metaseo.services/page/04; type=string; label= Yahoo! Crawler Verification: Verification code for yahoo! webmaster tools
metaTags.yahooVerification =
# cat=plugin.metaseo.services/page/05; type=string; label= Web Of Trust Verification: Verification code for Web of trust (mywot.com)
metaTags.wotVerification =
# cat=plugin.metaseo.services/page/06; type=string; label= Google Analytics: Code for google analytics (eg. UA-12345456-1) (multiple codes, comma separated)
services.googleAnalytics =
# cat=plugin.metaseo.services/page/07; type=string; label= Google Analytics Download & Click Domain Name: "auto", "none", single domain support: "example.com", subdomain support: ".example.com"
services.googleAnalytics.domainName =
# cat=plugin.metaseo.services/page/08; type=boolean; label= Google Analytics Anonymize IP: Enable anonymize IP
services.googleAnalytics.anonymizeIp = 0
# cat=plugin.metaseo.services/page/09; type=boolean; label= Google Analytics Track Downloads: Track downloads (with javascript) (BETA!)
services.googleAnalytics.trackDownloads = 0
# cat=plugin.metaseo.services/page/11; type=string; label= Piwik URL: Url to your piwik installation (eg. www.example.com/piwik/ - don't use http:// or https:// as prefix!)
services.piwik.url =
# cat=plugin.metaseo.services/page/12; type=string; label= Piwik Id: Id of your website (multiple ids, comma separated)
services.piwik.id =
# cat=plugin.metaseo.services/page/13; type=string; label= Piwik Download & Click Domain Name: single domain support: "example.com", subdomain support: ".example.com"
services.piwik.domainName =
# cat=plugin.metaseo.services/page/14; type=string; label= Piwik Cookie Domain Name: single domain support: "example.com", subdomain support: ".example.com"
services.piwik.cookieDomainName =
# cat=plugin.metaseo.services/page/15; type=boolean; label= Piwik DoNotTrack: Opt Out users with Mozilla's DoNotTrack browser setting
services.piwik.doNotTrack = 1
# cat=plugin.metaseo.social/page/1; type=string; label= Google+ Direct Connect: Your Google+ Profile Page ID (see https://developers.google.com/+/plugins/badge/)
social.googleplus.profilePageId =
# cat=plugin.metaseo.pageTitle/enable/01; type=boolean; label= Apply Tmpl-Sitetitle to absolute <title>: This enables the addition of the template-sitetitle to the rendered page-title (in absolute <title>-mode)
pageTitle.applySitetitleToPagetitle = 0
# cat=plugin.metaseo.pageTitle/enable/02; type=boolean; label= Apply Tmpl-Sitetitle to prefix/suffix: This enables the addition of the template-sitetitle to the rendered page-title (in pagetitle-prefix/suffix-mode)
pageTitle.applySitetitleToPrefixSuffix = 1
# cat=plugin.metaseo.pageTitle/enable/03; type=string; label= Sitetitle glue: String between title and sitetitle (from template)
pageTitle.sitetitleGlue = :
# cat=plugin.metaseo.pageTitle/enable/04; type=boolean; label= Sitetitle glue spacer (before): Add spacer between title and glue (from template)
pageTitle.sitetitleGlueSpaceBefore = 0
# cat=plugin.metaseo.pageTitle/enable/05; type=boolean; label= Sitetitle glue spacer (after): Add spacer between glue and sitetitle (from template)
pageTitle.sitetitleGlueSpaceAfter = 1
# cat=plugin.metaseo.pageTitle/enable/06; type=options[Sitetitle-Pagetitle=0, Pagetitle-Sitetitle=1]; label= Sitetitle position: Position of template-sitetitle in title
pageTitle.sitetitlePosition = 0
# cat=plugin.metaseo.pageTitle/enable/07; type=string; label= Sitetitle : Overwrite the template sitetitle with a custom one
pageTitle.sitetitle =
# cat=plugin.metaseo.sitemap/page/02; type=int+; label= Default page priority (0-100)
sitemap.pagePriority =
# cat=plugin.metaseo.sitemap/page/03; type=options[,Always=1,Hourly=2,Daily=3,Weekly=4,Monthly=5,Yearly=6,Never (archive)=7]; label= Default change frequency: Default change frequency for sitemap cache (will be cached!)
sitemap.changeFrequency =
# cat=plugin.metaseo.sitemap/page/04; type=int+; label= Default expiration: Sitemap entry expiration in days
sitemap.expiration = 60
# cat=plugin.metaseo.sitemap/index/01; type=boolean; label= Index not static cacheable pages: Allow to index not static cacheable pages
sitemap.index.allowNoStaticCachable = 0
# cat=plugin.metaseo.sitemap/index/01; type=boolean; label= Index no_cache pages: Allow to index no_cache pages
sitemap.index.allowNoCache = 0
}

View File

@@ -0,0 +1,593 @@
###
# This is the default TS-setup for metaseo
#
# (see Section Reference in the manual for more options & parameters)
#
###
## title tag changer
config.titleTagFunction = Metaseo\Metaseo\Page\Part\PagetitlePart->main
page {
# MetaSEO: Metatags
headerData.84113002 = USER
headerData.84113002 {
userFunc = Metaseo\Metaseo\Page\Part\MetatagPart->main
}
# MetaSEO: Pager Footer
84113002 = USER
84113002 {
userFunc = Metaseo\Metaseo\Page\Part\FooterPart->main
}
}
# TypoScript added by extension "metaseo"
plugin.metaseo =
plugin.metaseo {
# Page title generator
pageTitle =
pageTitle {
# Caching of page title
caching = 1
applySitetitleToPagetitle = {$plugin.metaseo.pageTitle.applySitetitleToPagetitle}
applySitetitleToPrefixSuffix = {$plugin.metaseo.pageTitle.applySitetitleToPrefixSuffix}
sitetitleGlue = {$plugin.metaseo.pageTitle.sitetitleGlue}
sitetitleGlueSpaceBefore = {$plugin.metaseo.pageTitle.sitetitleGlueSpaceBefore}
sitetitleGlueSpaceAfter = {$plugin.metaseo.pageTitle.sitetitleGlueSpaceAfter}
sitetitlePosition = {$plugin.metaseo.pageTitle.sitetitlePosition}
sitetitle = {$plugin.metaseo.pageTitle.sitetitle}
# list of stdWraps for advanced page title manipulations
stdWrap =
stdWrap {
# stdWrap for raw page title (before processing)
before =
before {
}
# stdWrap for sitetitle (the title from the template, not from the page)
sitetitle =
sitetitle {
}
# stdWrap for processed page title (after processing)
after =
after {
}
}
}
# Page metatag generator
metaTags =
metaTags {
enableDC = {$plugin.metaseo.metaTags.enableDC}
description = {$plugin.metaseo.metaTags.description}
keywords = {$plugin.metaseo.metaTags.keywords}
copyright = {$plugin.metaseo.metaTags.copyright}
email = {$plugin.metaseo.metaTags.email}
author = {$plugin.metaseo.metaTags.author}
publisher = {$plugin.metaseo.metaTags.publisher}
language = {$plugin.metaseo.metaTags.language}
distribution = {$plugin.metaseo.metaTags.distribution}
rating = {$plugin.metaseo.metaTags.rating}
revisit = {$plugin.metaseo.metaTags.revisit}
p3pCP = {$plugin.metaseo.metaTags.p3pCP}
p3pPolicyUrl = {$plugin.metaseo.metaTags.p3pPolicyUrl}
linkGeneration = {$plugin.metaseo.metaTags.linkGeneration}
robotsEnable = {$plugin.metaseo.metaTags.robotsEnable}
robotsIndex = {$plugin.metaseo.metaTags.robotsIndex}
robotsIndex {
# blacklist (RegExp, eg /typo3/)
blacklist {
}
}
robotsFollow = {$plugin.metaseo.metaTags.robotsFollow}
robotsArchive = {$plugin.metaseo.metaTags.robotsArchive}
robotsSnippet = {$plugin.metaseo.metaTags.robotsSnippet}
robotsNoImageindex = {$plugin.metaseo.metaTags.robotsNoImageindex}
robotsNoTranslate = {$plugin.metaseo.metaTags.robotsNoTranslate}
robotsOdp = {$plugin.metaseo.metaTags.robotsOdp}
robotsYdir = {$plugin.metaseo.metaTags.robotsYdir}
geoPositionLatitude = {$plugin.metaseo.metaTags.geoPositionLatitude}
geoPositionLongitude = {$plugin.metaseo.metaTags.geoPositionLongitude}
geoRegion = {$plugin.metaseo.metaTags.geoRegion}
geoPlacename = {$plugin.metaseo.metaTags.geoPlacename}
googleVerification = {$plugin.metaseo.metaTags.googleVerification}
msnVerification = {$plugin.metaseo.metaTags.msnVerification}
yahooVerification = {$plugin.metaseo.metaTags.yahooVerification}
wotVerification = {$plugin.metaseo.metaTags.wotVerification}
picsLabel = {$plugin.metaseo.metaTags.picsLabel}
useLastUpdate = {$plugin.metaseo.metaTags.useLastUpdate}
# canonical tag generator settings
canonicalUrl = {$plugin.metaseo.metaTags.canonicalUrl}
canonicalUrl {
strict = {$plugin.metaseo.metaTags.canonicalUrl.strict}
noMP = {$plugin.metaseo.metaTags.canonicalUrl.noMP}
# Default typolink configuration for canonical link
typolink {
}
# blacklist (RegExp, eg /typo3/)
blacklist {
}
}
# OpenGraph metatags
opengraph = {$plugin.metaseo.metaTags.opengraph}
opengraph {
site_name = TEXT
site_name {
data = TSFE:tmpl|sitetitle
}
title = TEXT
title {
field = title
}
type = article
admins =
email = {$plugin.metaseo.metaTags.email}
phone_number =
fax_number =
latitude = {$plugin.metaseo.metaTags.geoPositionLatitude}
longitude = {$plugin.metaseo.metaTags.geoPositionLongitude}
street-address =
locality = {$plugin.metaseo.metaTags.geoPlacename}
region = {$plugin.metaseo.metaTags.geoRegion}
postal-code =
country-name =
}
useExpire = {$plugin.metaseo.metaTags.useExpire}
ieCompatibilityMode = {$plugin.metaseo.userAgent.ieCompatibilityMode}
# basic configuration for metatag information
conf =
conf {
description_page.field = description
keywords_page.field = keywords
title_page.field = title
author_page.field = author
email_page.field = author_email
tx_metaseo_geo_lat.field = tx_metaseo_geo_lat
tx_metaseo_geo_long.field = tx_metaseo_geo_long
tx_metaseo_geo_place.field = tx_metaseo_geo_place
tx_metaseo_geo_region.field = tx_metaseo_geo_region
lastUpdate_page = TEXT
lastUpdate_page {
data = page:lastUpdated
stdWrap.ifEmpty.data = register : SYS_LASTCHANGED
date = c
}
}
# section links (start, up, next, prev)
sectionLinks =
sectionLinks {
prev = HMENU
prev {
special = browse
special {
items = prev
prev.fields.title =
}
1 = TMENU
1.NO {
wrapItemAndSub = {field:uid}
wrapItemAndSub.insertData = 1
doNotLinkIt = 1
}
}
next = HMENU
next {
special = browse
special {
items = next
next.fields.title =
}
1 = TMENU
1.NO {
wrapItemAndSub = {field:uid}
wrapItemAndSub.insertData = 1
doNotLinkIt = 1
}
}
}
# list of stdWraps for advanced metatag manipulations
stdWrap =
stdWrap {
# stdWrap for title
title =
title {
}
# stdWrap for description
description =
description {
}
# stdWrap for keywords
keywords =
keywords {
}
# stdWrap for copyright
copyright =
copyright {
}
# stdWrap for language
language =
language {
}
# stdWrap for email
email =
email {
}
# stdWrap for author
author =
author {
}
# stdWrap for publisher
publisher =
publisher {
}
# stdWrap for distribution
distribution =
distribution {
}
# stdWrap for rating
rating =
rating {
}
# stdWrap for lastUpdate
lastUpdate =
lastUpdate {
}
}
}
# Advanced services (google analytics, piwik ...)
services =
services {
# Google Analytics configuration
googleAnalytics = {$plugin.metaseo.services.googleAnalytics}
googleAnalytics {
# show google analytics if user is logged in be (default is disable, we don't want to track be-users)
showIfBeLogin = 0
anonymizeIp = {$plugin.metaseo.services.googleAnalytics.anonymizeIp}
domainName = {$plugin.metaseo.services.googleAnalytics.domainName}
trackDownloads = {$plugin.metaseo.services.googleAnalytics.trackDownloads}
trackDownloadsScript = EXT:metaseo/Resources/Public/Frontend/JavaScript/GoogleAnalyticsTrackDownload.js
customizationCode =
enableIfHeaderIsDisabled = {$plugin.metaseo.services.enableIfHeaderIsDisabled}
## google analytics template code
template = COA
template {
10 = FLUIDTEMPLATE
10 {
file = EXT:metaseo/Resources/Private/Templates/PageParts/ServiceGoogleAnalytics.html
variables {
gaCode = TEXT
gaCode.field = gaCode
gaCustomizationCode = TEXT
gaCustomizationCode.field = gaCustomizationCode
gaIsAnonymize = TEXT
gaIsAnonymize.field = gaIsAnonymize
gaDomainName = TEXT
gaDomainName.field = gaDomainName
gaUseUniversalAnalytics = TEXT
gaUseUniversalAnalytics.field = gaUseUniversalAnalytics
}
}
}
}
# Piwik configuration
piwik =
piwik {
# show piwik if user is logged in be (default is disable, we don't want to track be-users)
showIfBeLogin = 0
url = {$plugin.metaseo.services.piwik.url}
id = {$plugin.metaseo.services.piwik.id}
domainName = {$plugin.metaseo.services.piwik.domainName}
cookieDomainName = {$plugin.metaseo.services.piwik.cookieDomainName}
doNotTrack = {$plugin.metaseo.services.piwik.doNotTrack}
customizationCode =
enableIfHeaderIsDisabled = {$plugin.metaseo.services.enableIfHeaderIsDisabled}
## piwik template code
template = COA
template {
10 = FLUIDTEMPLATE
10 {
file = EXT:metaseo/Resources/Private/Templates/PageParts/ServicePiwik.html
variables {
piwikUrl = TEXT
piwikUrl.field = piwikUrl
piwikId = TEXT
piwikId.field = piwikId
piwikCustomizationCode = TEXT
piwikCustomizationCode.field = piwikCustomizationCode
piwikDomainName = TEXT
piwikDomainName.field = piwikDomainName
piwikCookieDomainName = TEXT
piwikCookieDomainName.field = piwikCookieDomainName
piwikDoNotTrack = TEXT
piwikDoNotTrack.field = piwikDoNotTrack
}
}
}
}
}
# Social services (Google+,...)
social =
social {
googlePlus =
googlePlus {
profilePageId = {$plugin.metaseo.social.googleplus.profilePageId}
}
}
# Sitemap indexer and generator
sitemap =
sitemap {
pagePriority = {$plugin.metaseo.sitemap.pagePriority}
changeFrequency = {$plugin.metaseo.sitemap.changeFrequency}
expiration = {$plugin.metaseo.sitemap.expiration}
# indexer settings
index {
# blacklist (RegExp, eg /typo3/)
blacklist {
}
# Blacklist for SetupTS PAGE object typeNums
pageTypeBlacklist =
allowNoStaticCachable = {$plugin.metaseo.sitemap.index.allowNoStaticCachable}
allowNoCache = {$plugin.metaseo.sitemap.index.allowNoCache}
# Whitelist of allowed file extensions
fileExtension {
# PDF
1 = pdf
# Microsoft Office
2 = doc,docx,xls,xlsx,ppt,pptx
# OpenOffice
3 = odt,odp,ods,odg
}
}
}
# Robots.txt configuration
robotsTxt =
robotsTxt {
# Default robots.txt if no config is found
default = COA
default {
10 = TEXT
10 {
value (
User-agent: *
Disallow: /fileadmin/_temp_/
Disallow: /t3lib/
Disallow: /typo3/
Disallow: /typo3_src/
Disallow: /typo3conf/
Disallow: /clear.gif
Allow: /typo3/sysext/frontend/Resources/Public/*
)
}
90 = TEXT
90 {
value (
Sitemap: %sitemap%
)
}
}
# Extra robots.txt, will added even if robots.txt is found
extra = COA
extra {
}
# Robots.txt marker (search/replace, eg. %name%)
marker =
marker {
sitemap = TEXT
sitemap {
typolink {
parameter.data = leveluid:0
parameter.wrap = |,841132
returnLast = url
}
}
}
}
}
# MetaSEO TXT Sitemap
metaSeoSitemapTxt = PAGE
metaSeoSitemapTxt {
typeNum = 841131
config {
linkVars < config.linkVars
linkVars := removeFromList(type)
}
10 = USER_INT
10 {
userFunc = Metaseo\Metaseo\Page\SitemapTxtPage->main
}
config {
disableAllHeaderCode = 1
additionalHeaders = Content-type:text/plain;charset=UTF-8
xhtml_cleaning = 0
## disable static documents and stuff
simulateStaticDocuments = 0
tx_realurl_enable = 0
tx_cooluri_enable = 0
sourceopt.enabled = 0
## disable indexed search
index_enable = 0
## disable features
insertDmailerBoundaries = 0
admPanel = 0
stat = 0
jumpurl_enable = 0
debug = 0
message_preview = #
}
}
# MetaSEO XML Sitemap
metaSeoSitemapXml = PAGE
metaSeoSitemapXml {
typeNum = 841132
config {
linkVars < config.linkVars
linkVars := removeFromList(type)
}
10 = USER_INT
10 {
userFunc = Metaseo\Metaseo\Page\SitemapXmlPage->main
}
config {
disableAllHeaderCode = 1
additionalHeaders = Content-type:application/xml;charset=UTF-8
xhtml_cleaning = 0
## disable static documents and stuff
simulateStaticDocuments = 0
tx_realurl_enable = 0
tx_cooluri_enable = 0
sourceopt.enabled = 0
## disable indexed search
index_enable = 0
## disable features
insertDmailerBoundaries = 0
admPanel = 0
stat = 0
jumpurl_enable = 0
debug = 0
message_preview = <!-- -->
}
}
# MetaSEO Robots.txt
metaSeoRobotsTxt = PAGE
metaSeoRobotsTxt {
typeNum = 841133
10 = USER_INT
10 {
userFunc = Metaseo\Metaseo\Page\RobotsTxtPage->main
}
config {
disableAllHeaderCode = 1
additionalHeaders = Content-type:text/plain;charset=UTF-8
xhtml_cleaning = 0
## disable static documents and stuff
simulateStaticDocuments = 0
tx_realurl_enable = 0
tx_cooluri_enable = 0
sourceopt.enabled = 0
## disable indexed search
index_enable = 0
## disable features
insertDmailerBoundaries = 0
admPanel = 0
stat = 0
jumpurl_enable = 0
debug = 0
message_preview = #
}
}
#####
# Ext: news
####
plugin.tx_news.settings.detail.registerProperties := addToList(keywords,title,teaser,authoremail)

View File

@@ -0,0 +1,251 @@
.. ==================================================
.. FOR YOUR INFORMATION
.. --------------------------------------------------
.. -*- coding: utf-8 -*- with BOM.
.. include:: ../Includes.txt
.. _admin-manual:
Administrator Manual
====================
Installation
------------
- Install Extension via Extension Manager.
- Include “static extension template” (Template → Info/Modify → Edit the whole template record → “Include static (from extensions):” and select “MetaSEO”)
- *Optional:* If you want to import your settings from the predecessor "tq_seo" install the "metaseo_tqseo_import" extension and run the importer.
- Modify your metatags via constants editor
Indexed Sitemap
---------------
The sitemap will automatically collect all cacheable sites and provides a XML- and plaintext-output that's why it is “indexed”.
The XML-Sitemap (eg. for Google) is available with: index.php?type=841132
The TXT-Sitemap is available with: index.php?type=841131
If you have more than one tree in your TYPO3 you will have to add the root-PID to your Sitemap, e.g.:
- Tree #1 with PID 123: index.php?id=123&type=841132
- Tree #2 with PID 234: index.php?id=234&type=841132
If you have also enabled “sitemap_ObeySysLanguage” in the extension configuration you also have to add the language-id for your Sitemap - eg. for separated language-domain e.g. example.com (only english pages) and example.de (only german pages).
The sitemap will index ALL cacheable pages with full extension support (like tt_news and all other “clean” extensions).
If your extension doesn't use cHash or use no_cache the output WILL NOT be included in the sitemap (and also will not be indexed by index_search).
The sitemap indexes all generate “typolinks” (BETA).
**Warning:**
The MetaSEO Sitemap relies on the TYPO3 caching system. If an extension (or configuration e.g. RealURL configuration) breaks the caching system and makes TSFE non-cacheable (TSFE->no_cache) the sites will NOT be INDEXED!
Make sure no extension will set no_cache and the cHash of your link is valid. This is the only way to get just valid URLs into your sitemap.
This sitemap supports both, pibase and extbase extensions without problems. However the developer must take care of the cHash-handling.
Robots.txt
----------
The robots.txt can be generated with type 841133, e.g.:
index.php?type=841133
If possible and enabled the robots.txt builder will automatically add the link to the sitemap generator or the static sitemap files (will require TYPO3 scheduler task to generate the static sitemap).
Scheduler Tasks
---------------
============================================= =============================================================== ======================
Scheduler Task Description Frequency
============================================= =============================================================== ======================
MetaSEO Cleanup This task cleans up old database entries in the One run per day
tx_metaseo_sitemap table.
MetaSEO sitemap.txt builder This task builds a real sitemap.txt file in the One run per day
upload directory.
- Directory: uploads/tx_metaseo/sitemap_txt/
- Sitemap: sitemap-r{ROOTPID}.txt.gz
If language domain support is active:
- Sitemap: sitemap-r{ROOTPID}-l{LANG}.txt.gz
{ROOTPID} is the Page-UID from the root pages in
your TYPO3 installations.
{LANG} is the language id (only active if language
domains are active).
Hint: These files are already gzipped.
MetaSEO sitemap.xml builder This task builds a real sitemap.xml files in the One run per day
upload directory.
- Directory: uploads/tx_metaseo/sitemap_xml/
- Sitemap-Index: index-r{ROOTPID}.xml.gz
- Sitemap-Page: sitemap-r{ROOTPID}-p{PAGE}.xml.gz
If language domain support is active:
- Sitemap-Index: index-r{ROOTPID}-l{LANG}.xml.gz
- Sitemap-Page: sitemap-r{ROOTPID}-l{LANG}-p{PAGE}.xml.gz
{ROOTPID} is the Page-UID from the root pages in your
TYPO3 installations.
{PAGE} is the current page of the sitemap.
{LANG} is the language id (only active if language
domains are active).
The index will refer to all page sitemaps so you only
have to reference to the sitemap index.
Hint: These files are already gzipped.
============================================= =============================================================== ======================
RealURL Configuration
---------------------
If you want to activate a “real” sitemap.xml feature (eg. http://example.com/sitemap.xml), configure realurl like this:
::
<?php
$TYPO3_CONF_VARS['EXTCONF']['realurl']['_DEFAULT'] = array(
'init' => array(
// ...
),
'preVars' => array(
// ...
),
'fixedPostVars' => array(
// ...
),
'postVarSets' => array(
'_DEFAULT' => array(
// TT-NEWS (example configuration)
'date' => array(
array(
'GETvar' => 'tx_ttnews[year]' ,
),
array(
'GETvar' => 'tx_ttnews[month]' ,
'valueMap' => array(
'january' => '01',
'february' => '02',
'march' => '03',
'april' => '04',
'may' => '05',
'june' => '06',
'july' => '07',
'august' => '08',
'september' => '09',
'october' => '10',
'november' => '11',
'december' => '12',
),
),
array(
'GETvar' => 'tx_ttnews[day]',
),
),
// news pagebrowser
'browse' => array(
array(
'GETvar' => 'tx_ttnews[pointer]',
),
),
// news categories
'news-category' => array (
array(
'GETvar' => 'tx_ttnews[cat]',
'lookUpTable' => array(
'table' => 'tt_news_cat',
'id_field' => 'uid',
'alias_field' => 'title',
'addWhereClause' => ' AND NOT deleted',
'useUniqueCache' => 1,
'useUniqueCache_conf' => array(
'strtolower' => 1,
'spaceCharacter' => '-',
),
),
),
),
// news articles
'article' => array(
array(
'GETvar' => 'tx_ttnews[tt_news]',
'lookUpTable' => array(
'table' => 'tt_news',
'id_field' => 'uid',
'alias_field' => 'title',
'addWhereClause' => ' AND NOT deleted',
'useUniqueCache' => 1,
'useUniqueCache_conf' => array(
'strtolower' => 1,
'spaceCharacter' => '-',
),
),
),
),
// ... other extensions ...
),
),
'fileName' => array(
'defaultToHTMLsuffixOnPrev' => 1,
'index' => array(
// ...
'sitemap.xml' => array(
'keyValues' => array(
'type' => 841132,
),
),
'sitemap.txt' => array(
'keyValues' => array(
'type' => 841131,
),
),
'robots.txt' => array(
'keyValues' => array(
'type' => 841133,
),
),
'_DEFAULT' => array(
'keyValues' => array(
'type' => 0,
)
),
),
),
'pagePath' => array(
'type' => 'user',
'userFunc' => 'EXT:realurl/class.tx_realurl_advanced.php:&tx_realurl_advanced->main',
'spaceCharacter' => '-',
'segTitleFieldList' => 'tx_realurl_pathsegment,alias,nav_title,title',
'languageGetVar' => 'L',
'expireDays' => 30,
'rootpage_id' => 1,
),
);

View File

@@ -0,0 +1,60 @@
.. ==================================================
.. FOR YOUR INFORMATION
.. --------------------------------------------------
.. -*- coding: utf-8 -*- with BOM.
.. include:: ../Includes.txt
.. _backend-modules:
Backend Modules
===============
SEO Page Module (Website -> SEO)
--------------------------------
.. figure:: ../Images/Introduction/ModuleSeoMetatags.png
:scale: 80%
:alt: Backend Module - SEO Metatags
The SEO page module provides an overview for all seo relevant information (including possibility to edit this information on click).
============================== ==========================================================
Module Description
============================== ==========================================================
Metatags Overview for all relevant metatags
Geo position Overview for geo positioning
SearchEngines Overview for all relevant search engine settings
including sitemap stuff
URL Handling Overview for all relevant url handling stuff including
RealURL support and possibility to simulate the url.
Pagetitle Overview for all relevant pagetitle information and
possibility to simulate the pagetitle.
Pagetitle simulator (Slow!) Simulates the pagetitle generation for the current
selected tree.
============================== ==========================================================
SEO Control Center (SEO -> Control Center)
------------------------------------------
.. figure:: ../Images/Introduction/ModuleSeoControlCenter.png
:scale: 80%
:alt: Backend Module - SEO Control Center
The SEO control center lists all your root-pages in your TYPO3 installation. For each root page you can control specific sitemap and robots.txt settings.
SEO Sitemap (SEO -> Sitemap)
----------------------------
.. figure:: ../Images/Introduction/ModuleSeoSitemap.png
:scale: 80%
:alt: Backend Module - SEO Sitemap
The SEO sitemap module provides access to the indexed sitemap list.

View File

@@ -0,0 +1,23 @@
.. ==================================================
.. FOR YOUR INFORMATION
.. --------------------------------------------------
.. -*- coding: utf-8 -*- with BOM.
.. include:: ../Includes.txt
.. _changelog:
Changelog
=========
============= ==============================================================================
Version Changes
============= ==============================================================================
1.0.0 **Fork of Fork of predecessor "tq_seo"**
- Major improvements of features and codebase
- Fixed several major and minor bugs
- Fixed manual (now reStructuredText)
- Fixed sitemap url generation in TYPO3 scheduler
============= ==============================================================================

View File

@@ -0,0 +1,282 @@
.. ==================================================
.. FOR YOUR INFORMATION
.. --------------------------------------------------
.. -*- coding: utf-8 -*- with BOM.
.. include:: ../Includes.txt
.. _constants:
Constants
=========
MetaTags
--------
============================== ========================================================== =================
Constant Description Default
============================== ========================================================== =================
Last Update time Publish the update time of the current page *enabled*
Detect Language Publish the current TYPO3-FE-language as metatag *enabled*
Canonical Tag Publish canonical link if possible *enabled*
(TYPO3-cache is enabled and cHash is valid)
or if user entered canonical tag into page options. *disabled*
Canonical Tag (Strict mode) Enable strict mode (all wrong GET-parameters will *enabled*
generate a canonical-tag to the self without GET-params).
e.g. /index.php?id=123&foo=bar would generate a
Canonical-Tag pointing to /index.php?id=123
if the cHash is wrong or caching is disabled
Canonical Tag (No MP mode) Prevent canonical links to contain mountpoint information. *disabled*
Useful if some pages would count as duplicate content
because of mountpoints.
Publish Page Expire Time Publish expire date from the “End Date” of the page. *enabled*
Currently only used for Google.
Link generation Automatic generate index and up/next/prev-links. *enabled*
Enable Dublin Core (DC.) tags Enable/Disable output of dublin core (DC) metatags *enabled*
Description Default description of your pages.
Overwritten by description of page
Keywords Default list of keywords
Overwritten by keywords of page
Copyright info Copyright information of your page
Reply-to email E-Mail address for contact
Author Default author
Overwritten by author of page
Publisher Publisher of the website
Language Overwrite language detection
Rating Rating of the website
Distribution Distribution of your website
Revisit after Number of days between search engine visits
Geo Location Geo location of your web page with latitude,
longitude, region and placename
PICS-label Platform for Internet Content Selection
- http://www.w3.org/PICS/labels.html
P3P Compact Policy Your P3P Compact Policy.
More information about P3P:
- http://www.w3.org/P3P/
- http://www.w3.org/TR/P3P/
- https://en.wikipedia.org/wiki/P3P
- http://www.p3pwriter.com/LRN_111.asp
P3P Policy Url Link (full URL) to your P3P Policy File
============================== ========================================================== =================
Some metatags also have markers which could be build in, following metatags supports markers:
- Title
- Description
- Keywords
- Copyright
- Publisher
Following Markers are available:
============================== ========================================================== =================
Marker Description Example value
============================== ========================================================== =================
%YEAR% Replacement for the current year 2014
============================== ========================================================== =================
UserAgent
---------
============================== ========================================================== =================
Constant Description Default
============================== ========================================================== =================
IE Compatibility Mode Compatibility mode for Microsoft Internet Explorer
============================== ========================================================== =================
Crawler
-------
============================== ========================================================== =================
Constant Description Default
============================== ========================================================== =================
Crawler Robots-Tag Enable crawler "robot"-tag (and all other settings below) *enabled*
Index Should the crawler index your website? *enabled*
Follow Should the crawler follow links on your website? *enabled*
Archive Is the crawler allowed to archive the page *enabled*
(e.g. Google cache)
Snippet Should the crawler use the snippet/description *enabled*
in search results
ODP Should the crawler use the OpenDirectoryProject to *enabled*
display the description in search results
YDir Should the crawler use the YahooDirectory to *enabled*
display the description in search results
============================== ========================================================== =================
Services
--------
============================== =============================================================== =================
Constant Description Default
============================== =============================================================== =================
Crawler Verification Verification code for Google, MSN and Yahoo
webmaster tools and Web of trust
Google Analytics The google analytics code for using on your site
Multiple GA Codes possible, comma separated
(Will not be shown in frontend if BE-user is logged in,
can be re-enabled in BE-Login-Mode:
plugin.metaseo.services.googleAnalytics.showIfBeLogin = 1)
GA Cookie Domain Name If you want to limit the current google analytics to
one domain (or subdomain) set the domain name here, eg.:
- “auto” (default in google analytics)
- “none”
- single domain (eg. “example.com”)
- subdomain (eg. “.example.com”)
GA Anonymize IP Anonymize the last part of the IP *disabled*
(may be required in some countries)
GA Track Downloads Try to track downloads with google analytics. *disabled*
See res/ga-track-download.js for more details
Currently supported files:
- doc,docx,xls,ppt,odt,ods,pdf,zip,tar,gz,txt,vsd,vxd,
rar,exe,wma,mov,avi,ogg,ogm,mkv,wmv,mp3,webm
Piwik URL Url to your Piwik installation
(without http:// and https://)
Piwik ID Tracking id of your website in your piwik
Multiple Piwik IDs possible, comma separated
Piwik Download & Click Domain Specifies which domains are internal domains:
- single domain (eg. “example.com”)
- subdomain (eg. “.example.com”)
For more information visit:
- https://developer.piwik.org/api-reference/tracking-javascript
Piwik Cookie Domain Name Specifies the domain name for the tracking cookie:
- single domain (eg. “example.com”)
- subdomain (eg. “.example.com”)
For more information visit:
- https://developer.piwik.org/api-reference/tracking-javascript
Piwik DoNotTrack Opt out users with Mozilla's DoNotTrack *enabled*
browser setting
============================== =============================================================== =================
Social
------
============================== ========================================================== =================
Constant Description Default
============================== ========================================================== =================
Google+ Direct Connect Your Google+ profile page ID
see https://developers.google.com/+/web/badge/
============================== ========================================================== =================
PageTitle
---------
========================================= ========================================================== ======================
Constant Description Default
========================================= ========================================================== ======================
Apply tmpl-sitetitle to absolute <title> There is a prefix/suffix for your pagetitle defined *disabled*
in your root template settings.
If you use the SEO-Absolute-Pagetitle settings you
can disable this suffix/prefix here.
Apply tmpl-sitetitle to prefix/suffix There is a prefix/suffix for your pagetitle defined *enabled*
in your root template settings.
If you use the SEO-Pagetitle-Suffix/Prefix settings you
can disable this suffix/prefix here.
Sitetitle glue Glue between Pagetitle (from Page) and :
Sitetitle (from template)
Sitetitle glue spacer (before) Add spacer before glue string *disabled*
Sitetitle glue spacer (after) Add spacer after glue string *enabled*
Sitetitle position Position of Sitetitle (from template) Sitetitle-Pagetitle
Possible options: (0)
Sitetitle-Pagetitle (eg. Example Company: About us)
Pagetitle-Sitetitle (eg. About us: Example Company)
Sitetitle Overwrite the template sitetitle with a custom one
========================================= ========================================================== ======================
Sitemap
-------
================================= ========================================================== =================
Constant Description Default
================================= ========================================================== =================
Enable Enables output (if set on root-pid of tree) and *enabled*
indexing for the whole subtree
Page limit Limit pages on sitemap-xml-pages *10000*
Limit to current language Limit output of the sitemap to the current language. *disabled*
This will enable multi-language-domain sitemaps. eg:
- www.example.com (FE-Language is english) will output
only english pages
- www.example.de (FE-Language is german) will output
only german pages
This option was ported from the extension configuration
and will replace this configuration.
Default change frequency Default change frequency for sitemap cache
(will be cached!)
Page priority Default page priority if the page has no own 1
priority set
Page priority will be calculated by:
( [page priority] [priority modificator] ) *
( 1/[page depth] * [page multiplier] )
Page priority depth multiplier Page depth multiplier, see formula in page priority 1
Page priority depth modificator Page depth modificator, see formula in page priority 1
================================= ========================================================== =================

View File

@@ -0,0 +1,291 @@
.. ==================================================
.. FOR YOUR INFORMATION
.. --------------------------------------------------
.. -*- coding: utf-8 -*- with BOM.
.. include:: ../Includes.txt
.. _developer-manual:
Developer Manual
================
TypoScript Setup
----------------
Advanced manipulations (stdWrap support)
----------------------------------------
If you want to modify some things you can use stdWraps
MetaTags
^^^^^^^^
============================================= ========================================================== ======================
TypoScript Node Description Type
============================================= ========================================================== ======================
plugin.metaseo.metaTags.stdWrap.title Manipulation for title *stdWrap*
plugin.metaseo.metaTags.stdWrap.description Manipulation for description *stdWrap*
plugin.metaseo.metaTags.stdWrap.keywords Manipulation for keywords *stdWrap*
plugin.metaseo.metaTags.stdWrap.copyright Manipulation for copyright *stdWrap*
plugin.metaseo.metaTags.stdWrap.language Manipulation for language *stdWrap*
plugin.metaseo.metaTags.stdWrap.email Manipulation for email *stdWrap*
plugin.metaseo.metaTags.stdWrap.author Manipulation for author *stdWrap*
plugin.metaseo.metaTags.stdWrap.publisher Manipulation for publisher *stdWrap*
plugin.metaseo.metaTags.stdWrap.distribution Manipulation for distribution *stdWrap*
plugin.metaseo.metaTags.stdWrap.rating Manipulation for rating *stdWrap*
plugin.metaseo.metaTags.stdWrap.lastUpdate Manipulation for last update (date) *stdWrap*
============================================= ========================================================== ======================
PageTitle
^^^^^^^^^
============================================= ========================================================== ======================
TypoScript Node Description Type
============================================= ========================================================== ======================
plugin.metaseo.pageTitle.caching Enables caching of page title. *boolean*
If the page is fully cacheable you don't have to enable
this option.
If you use USER_INTs and one USER plugin changes page
title (eg. via Connector) than this is not working
because the output of the USER plugin is cached and
the Connector not called again with the second hit.
The caching fixes that issue.
plugin.metaseo.pageTitle.stdWrap.before Manipulation of the raw page title *stdWrap*
(before MetaSEO processing)
plugin.metaseo.pageTitle.stdWrap.after Manipulation of the processed page title *stdWrap*
(after MetaSEO processing)
plugin.metaseo.pageTitle.stdWrap.sitetitle Manipulation of the sitetitle *stdWrap*
(from the TS-Setup-Template)
============================================= ========================================================== ======================
Google Analyitics / Piwik customizations
----------------------------------------
Customization codes (fast/simple)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can add additional javascript code to the default Google Analytics and/or Piwik integration.
========================================================== ========================================================== ======================
TypoScript Node Description Type
========================================================== ========================================================== ======================
plugin.metaseo.services.googleAnalytics.customizationCode Customization code for Google Analytics TS-Content Object
(*TEXT*, *COA*, ...)
plugin.metaseo.services.piwik.customizationCode Customization code for Piwik TS-Content Object
(*TEXT*, *COA*, ...)
========================================================== ========================================================== ======================
Example for Google Analytics in TypoScript-Setup:
::
plugin.metaseo.services.googleAnalytics.customizationCode = COA
plugin.metaseo.services.googleAnalytics.customizationCode {
10 = TEXT
10.value (
_gaq.push(['_setClientInfo', false]);
_gaq.push(['_setAllowHash', false]);
_gaq.push(['_setDetectFlash', false]);
_gaq.push(['_setDetectTitle', false]);
)
}
Template customization (advanced)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The Google Analytics and Piwik integration is done by using a FLUIDTEMPLATE object in TypoScript. If you don't like the integration and want to modify the integration feel free to use your own templates and pass your own variables to FLUIDTEMPLATE.
========================================================== ========================================================== ======================
TypoScript Node Description Type
========================================================== ========================================================== ======================
plugin.metaseo.services.googleAnalytics.template Template rendering object for Google Analytics *COA*
(contains a FLUIDTEMPLATE)
plugin.metaseo.services.piwik.template Template rendering object for Piwik *COA*
(contains a FLUIDTEMPLATE)
========================================================== ========================================================== ======================
It's quite easy, for more information read:
- https://docs.typo3.org/typo3cms/TyposcriptReference/ContentObjects/Fluidtemplate/Index.html
- https://typo3.org/documentation/article/the-fluidtemplate-cobject
Example for your own Google Analytics Template:
::
## Google Analytics template
plugin.metaseo.services.googleAnalytics.template.10.file = fileadmin/templates/service-ga.html
## if you need some variables you also can set these:
plugin.metaseo.services.googleAnalytics.template.10.variables {
myOwnStuff = TEXT
myOwnStuff.value = foobar
}
Sitemap
-------
========================================================== ========================================================== ======================
TypoScript Node Description Type
========================================================== ========================================================== ======================
plugin.metaseo.sitemap.index.blacklist List of Regular Expression for blacklisting URLs while List
indexing, eg.
10 = /typo3/
20 = /foobar/
30 = /imprint/i
40 = /[a-z]/
plugin.metaseo.sitemap.index.pageTypeBlacklist List of blacklisted page typeNums (SetupTS PAGE objects) String, comma separated
plugin.metaseo.sitemap.index.fileExtension List of allowed file extensions for indexing List
Default:
1 = pdf
2 = doc,docx,xls,xlsx,ppt,pptx
3 = odt,odp,ods,odg
========================================================== ========================================================== ======================
Hooks
-----
All hooks are also available as Extbase Signal. Please use signals instead of hooks.
::
<?php
// ----------------------------------------------------------------------------
// Example of MetaSEO Hooks
//
// Example integrations (eg. in localconf.php or ext_localconf.php):
//
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['metatagSetup'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_metatagSetup';
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['metatagOutput'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_metatagOutput';
//
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['pageTitleSetup'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_pagetitleSetup';
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['pageTitleOutput'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_pagetitleOutput';
//
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['pageFooterSetup'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_pagefooterSetup';
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['pageFooterOutput'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_pagefooterOutput';
//
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['sitemapIndexPage'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_sitemapIndexPage';
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['sitemapIndexLink'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_sitemapIndexLink';
//
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['sitemapSetup'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_sitemapSetup';
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['sitemapTextOutput'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_sitemapTextOutput';
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['sitemapXmlIndexSitemapList'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_sitemapXmlIndexSitemapList';
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['sitemapXmlIndexOutput'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_sitemapXmlIndexOutput';
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['sitemapXmlPageOutput'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_sitemapXmlPageOutput';
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['sitemapClear'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_sitemapClear';
//
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['robotsTxtMarker'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_robotsTxtMarker';
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['robotsTxtOutput'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_robotsTxtOutput';
//
// $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['metaseo']['hooks']['httpHeaderOutput'][] = 'EXT:metaseo/examples/hooks.php:user_metaseo_hook->hook_httpHeaderOutput';
// ----------------------------------------------------------------------------
class user_metaseo_hook {
public function hook_metatagSetup(&$args, $obj) {
// Hook for metatag setup
}
public function hook_metatagOutput(&$args, $obj) {
// Hook for metatag output
}
// ------------------------------------------------------------------------
public function hook_pagetitleSetup(&$args, $obj) {
// Hook for pagetitle setup
}
public function hook_pagetitleOutput(&$args, $obj) {
// Hook for pagetitle output
}
// ------------------------------------------------------------------------
public function hook_pagefooterSetup(&$args, $obj) {
// Hook for page footer setup
}
public function hook_pagefooterOutput(&$args, $obj) {
// Hook for page footer output
}
// ------------------------------------------------------------------------
public function hook_sitemapIndexPage(&$args) {
// Hook for sitemap page indexer
}
public function hook_sitemapIndexLink(&$args) {
// Hook for sitemap link indexer
}
// ------------------------------------------------------------------------
public function hook_sitemapSetup(&$args, $obj) {
// Hook for sitemap setup
}
public function hook_sitemapTextOutput(&$args, $obj) {
// Hook for xml text output
}
public function hook_sitemapXmlIndexOutput(&$args, $obj) {
// Hook for xml index-page output
}
public function hook_sitemapXmlIndexSitemapList(&$args, $obj) {
// Hook for manipulation sitemap.xml index page sitemap list
}
public function hook_sitemapXmlPageOutput(&$args, $obj) {
// Hook for xml page output
}
public function hook_sitemapClear(&$args, $obj) {
// Hook for sitemap clearing (truncating via clear-cache hook)
}
// ------------------------------------------------------------------------
public function hook_robotsTxtMarker(&$args, $obj) {
// Hook for robots.txt marker list
}
public function hook_robotsTxtOutput(&$args, $obj) {
// Hook for robots.txt output
}
// ------------------------------------------------------------------------
public function hook_httpHeaderOutput($args, $obj) {
// Hook for http header output
}
// ------------------------------------------------------------------------
}

View File

@@ -0,0 +1,82 @@
.. ==================================================
.. FOR YOUR INFORMATION
.. --------------------------------------------------
.. -*- coding: utf-8 -*- with BOM.
.. include:: ../Includes.txt
.. _faq-manual:
Frequently Asked Questions (FAQ)
================================
General
-------
| **Problem:**
| Is this extension multi-language and/or multi-tree ready?
| **Solution:**
| Check it out, there should be no problems at all with multi-language multi-tree installations of TYPO3 CMS.
|
| **Problem:**
| In my TYPO3 the feature XYZ of this extension doesn't work. What's wrong?
| **Solution:**
| The metaseo-Extension has been written carefully. We want to deliver correct pages and extensions with the power of TYPO3's caching system (and those extensions are the fastest). For some features (e.g. sitemap, canonical-tag) we have to trust in the caching-system it's the only way to make sure that we don't deliver wrong information to search engines. If our extension doesn't work correctly, something could also be wrong with the configuration of your TYPO3 the configuration variables, setupTS or a conflict or a problem with other extensions.
Indexed Sitemap
---------------
| **Problem:**
| When I want to open my sitemap I get an error "The page is not configured! [type=841131|841132|841133][]. This means that there is no TypoScript object of type PAGE with typeNum=841131|841132|841133 configured."
| **Solution:**
| Make sure you have configured MetaSEO "Include static" as described in the installation manual.
|
| **Problem:**
| The sitemap is empty.
| **Solution:**
| Check if the “tx_metaseo_sitemap” database-table was created! We're using MySQL's InnoDB table engine so you have to make sure that your MySQL server comes with InnoDB-support (if your hoster does not provide InnoDB you should look out for another hoster!).
|
| **Problem:**
| My sitemap is still empty, but the database is ok.
| **Solution:**
| Maybe you disabled the whole TYPO3 cache (config.no_cache=1 or something else)? Enable the cache this will also speed up your TYPO3 instance.
|
| **Problem:**
| The pages which my extension created are not available in the sitemap!
| **Solution:**
| You have to make sure that all generated pages are cacheable. The extension must be able to pass a valid cHash-token!
|
| **Problem:**
| In the sitemap-database are thousands of pages but there is only one site in my XML-Sitemap.
| **Solution:**
| That's correct. MetaSEO always uses “Sitemap Groups” (as defined in http://www.sitemaps.org/protocol.html#index), each group can contain about 50.000 pages/URLs so if we have more than 50.000 URLs we have to use sitemap groups. Visit the URL defined in the LOC-tag and you will see that the sub-sitemap will contain all your stored URLs.
|
| **Problem:**
| The generated pages from my extension still are not included in the sitemap!
| **Solution:**
| Have you enabled RealURL? Please check the RealURL configuration if you have specified values that are not passed with your URL. All variables that are not passed with the URL will result in a NO-CACHE.
|
| **Problem:**
| The sitemap is still not working! No page is indexed and the table tx_metaseo_sitemap is empty!
| **Solution:**
| Double check your installation and disable all third party extensions. Make sure that no extension disables the TYPO3-cache! RealUrl (if properly configured) and TemplaVoila are working perfectly together with MetaSEO sitemap but some old extensions might break the TYPO3 caching system and you will not notice it. Our sitemap indexer relies on the indexing system to make sure that only valid urls are stored and delivered to search engines like google.
|
| **Problem:**
| I want to limit each sitemap to its domain (eg. example.com for english pages, example.de for german pages). Is this possible?
| **Solution:**
| Yes, just enable the “Enable language-domain support” in seo control center in your website/rootpage settings (replaces the old extension configuration sitemap_ObeySysLanguage and TypoScript constants setting).
|
| **Problem:**
| My tt_news entries are not indexed, what's wrong?
| **Solution:**
| You're using realurl? Then check your realurl_conf.php. Errors (or misconfiguration) in the realurl-configuration will produce uncacheable sites (and you will not notice it). The most common issue is the configuration of the parameter “tx_ttnews[swords]” in the postVarSets-area. Remove it, you don't need it.
Others
------
| **Problem:**
| I want to customize my Google Analytics and/or Piwik integration.
| **Solution:**
| You can modify the code of the Google Analytics and Piwik integration with TypoScript. Feel free to use plugin.metaseo.services.googleAnalytics.customizationCode (STDWRAP) or plugin.metaseo.services.piwik.customizationCode (STDWRAP). Also you can modify the FLUIDTEMPLATE and assign custom variables.

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,21 @@
.. ==================================================
.. FOR YOUR INFORMATION
.. --------------------------------------------------
.. -*- coding: utf-8 -*- with BOM.
.. This is 'Includes.txt'. It is included at the very top of each and
every ReST source file in this documentation project (= manual).
.. ==================================================
.. DEFINE SOME TEXT ROLES
.. --------------------------------------------------
.. role:: typoscript(code)
.. role:: ts(typoscript)
:class: typoscript
.. role:: php(code)
.. highlight:: php

View File

@@ -0,0 +1,67 @@
.. ==================================================
.. FOR YOUR INFORMATION
.. --------------------------------------------------
.. -*- coding: utf-8 -*- with BOM.
.. include:: Includes.txt
.. _start:
=============================================================
MetaSEO
=============================================================
.. only:: html
:Classification:
metaseo
:Version:
|release|
:Language:
en
:Description:
Search Engine Optimization (SEO),
Indexed Google-Sitemap (TXT- and XML-Sitemap) for all Extensions (pibase, extbase),
Metatags, Canonical-URL, Pagetitle manipulations, Crawler verification,
Piwik and Google Analytics support and some more... multi-language- and multi-tree-support
:Keywords:
metatag,metatags,seo,sitemap,google,searchengine,tqseo,tq_seo,metaseo,pagetitle
:Copyright:
2014
:Author:
Markus Blaschke
:Email:
typo3@markus-blaschke.de
:License:
This document is published under the Open Content License
available from http://www.opencontent.org/opl.shtml
:Rendered:
|today|
The content of this document is related to TYPO3,
a GNU/GPL CMS/Framework available from `typo3.org <https://typo3.org>`_.
**Table of Contents**
.. toctree::
:maxdepth: 5
:glob:
Introduction/Index
Constants/Index
BackendModules/Index
AdministratorManual/Index
DeveloperManual/Index
FaqManual/Index
ChangeLog/Index

View File

@@ -0,0 +1,142 @@
.. ==================================================
.. FOR YOUR INFORMATION
.. --------------------------------------------------
.. -*- coding: utf-8 -*- with BOM.
.. include:: ../Includes.txt
What does it do?
================
This extensions handles multiple page metatags and pagetitle manipulations in TYPO3. It's a replacement and major improvement for the “metatags” and this extension is the successor of the popular "tq_seo" extension.
The following features are supported:
- Indexed XML sitemap for Google and other search engines (with support for ALL extensions, pibase and extbase, not only tt_news)
- Real sitemap builder via TYPO3 scheduler
- Metatags
- Manipulation of Metatags via stdWrap (Beta)
- Automatic fetching metatags from tt_news (single-display module)
- Pagetitle manipulations
- Manipulation of pagetitle via stdWrap (Beta)
- Multi-language and/or multi-tree TYPO3 installations
Backend modules:
- SEO page module
- SEO control center module
- SEO sitemap module
The following metatags are supported:
- Language (auto-detected)
- Description
- Keyword
- Copyright information
- Reply-To E-Mail-Address
- Author and publisher
- Rating and distribution
- Revisit
- Geo-location information
- Searchengine crawler instructions
- Google Analytics (with anonymized IP and download link tracking, asynchronous implementation since 4.0)
- Piwik integration (asynchronous implementation since 4.0)
- Google, MSN, Yahoo and WebOfTrust Verification
- Google+ Direct Connect
- Canonical URL (Custom URL or autogenerated to current page)
- IE Compatibility-Mode
- Google Expire Date
- Index, up, prev und next link-metatags
- P3P-HTTP-Headers
- OpenGraph (WIP)
- Blacklist for sitemap, CanonicalURL and searchengine index/noindex switching
The following pagetitle transformations are supported:
- Prefix and suffix (inheritable)
- Absolute pagetitle without any prefix and suffix
- Sitetitle glue options
- Sitetitle positon
Screenshots
-----------
Backend Modules
^^^^^^^^^^^^^^^
.. figure:: ../Images/Introduction/ModuleSeoMetatags.png
:scale: 80%
:alt: Backend Module - SEO Metatags
Backend Module "SEO Metatags"
.. figure:: ../Images/Introduction/ModuleSeoControlCenter.png
:scale: 80%
:alt: Backend Module - SEO Control Center
Backend Module "SEO Control Center"
.. figure:: ../Images/Introduction/ModuleSeoSitemap.png
:scale: 80%
:alt: Backend Module - SEO Sitemap
Backend Module "SEO Sitemap"
Constants
^^^^^^^^^
.. figure:: ../Images/Introduction/ConstantsMetatags.png
:scale: 80%
:alt: Constants Editor - Metatags
Constants Editor of metatags
.. figure:: ../Images/Introduction/ConstantsPagetitle.png
:scale: 80%
:alt: Constants Editor - Pagetitle
Constants Editor of pagetitle settings
.. figure:: ../Images/Introduction/ConstantsCrawler.png
:scale: 80%
:alt: Constants Editor - Crawler
Constants Editor of crawler (google) settings
.. figure:: ../Images/Introduction/ConstantsServices.png
:scale: 80%
:alt: Constants Editor - Services
Constants Editor of services settings
Found a bug?
------------
Just send me a mail to typo3@markus-blaschke.de
or just enter the bug into the bugtracker at https://github.com/mblaschke/TYPO3-metaseo
Thanks to...
------------
- TEQneers GmbH & Co. KG for sponsoring the predecessor "tq_seo"
- jweiland.net especially Wolfgang Wagner for all the tutorials
- Pierre Arlt
- Riccardo De Contardi
- Rico Sonntag
- Ralle Büchnitz
- Manfred Egger
- Carsten Hager
- Thomas Deuling
- Thomas Mayer
- Florian Duffner
- Georg Tiefenbrunn
- Arne-Kolja Bachstein
- all other contributors and bug reporters
- famfamfam for these cool silk icons http://www.famfamfam.com/lab/icons/silk/

View File

@@ -0,0 +1,24 @@
# This is the project specific Settings.yml file.
# Place Sphinx specific build information here.
# Settings given here will replace the settings of 'conf.py'.
---
conf.py:
copyright: 2014
project: MetaSEO
version: 1.0
release: 1.0.0
html_theme_options:
github_repository: mblaschke/TYPO3-metaseo
github_branch: develop
latex_documents:
- - Index
- metaseo.tex
- MetaSEO
- Markus Blaschke
- manual
latex_elements:
papersize: a4paper
pointsize: 10pt
preamble: \usepackage{typo3}
...

View File

@@ -0,0 +1,156 @@
# You can set these variables from the command line.
SPHINXOPTS = -c . -a -E -w ./_not_versioned/warnings.txt
SPHINXBUILD = sphinx-build
PAPER = a4
BUILDDIR = build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) ..
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) ..
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " pdf to make PDF using rst2pdf"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Projectname.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Projectname.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Projectname"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Projectname"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
pdf:
$(SPHINXBUILD) -b pdf $(ALLSPHINXOPTS) $(BUILDDIR)/pdf
@echo
@echo "Build finished. The PDF is in $(BUILDDIR)/pdf."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View File

@@ -0,0 +1,7 @@
# this is file .gitignore
# ignore everything in this directory
*
# but do not ignore this this file
!.gitignore

View File

@@ -0,0 +1,7 @@
# this is file .gitignore
# ignore everything in this directory
*
# but do not ignore this this file
!.gitignore

View File

@@ -0,0 +1,423 @@
# -*- coding: utf-8 -*-
#
# MetaSEO Import from tq_seo documentation build configuration file, created by
# TYPO3 extension sphinx on Tue, 01 Apr 2014 17:53:40 +0200.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- PHP highlighting configuration --------------------------------------------
from sphinx.highlighting import lexers
if lexers:
from pygments.lexers.web import PhpLexer
lexers['php'] = PhpLexer(startinline=True)
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo', 'sphinx.ext.ifconfig']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['../_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'Index'
# General information about the project.
project = u'MetaSEO Import from tq_seo'
copyright = u'2014, Markus Blaschke'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
release = '1.0.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
today_fmt = '%Y-%m-%d %H:%M'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_make']
exclude_trees = ['_make']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['../_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'metaseo_tqseo_importdoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
'preamble': '\\usepackage{typo3}'
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('Index', 'metaseo_tqseo_import.tex', u'MetaSEO Import from tq_seo',
u'Markus Blaschke', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for rst2pdf output ------------------------------------------------
# Grouping the document tree into PDF files. List of tuples
# (source start file, target name, title, author, options).
#
# If there is more than one author, separate them with \\.
# For example: r'Guido van Rossum\\Fred L. Drake, Jr., editor'
#
# The options element is a dictionary that lets you override
# this config per-document.
# For example,
# ('index', u'MyProject', u'My Project', u'Author Name',
# dict(pdf_compressed = True))
# would mean that specific document would be compressed
# regardless of the global pdf_compressed setting.
pdf_documents = [
('Index', 'metaseo_tqseo_import', u'MetaSEO Import from tq_seo',
u'Markus Blaschke'),
]
# A comma-separated list of custom stylesheets. Example:
pdf_stylesheets = ['sphinx','kerning','a4']
# A list of folders to search for stylesheets. Example:
pdf_style_path = ['.', '_styles']
# Create a compressed PDF
# Use True/False or 1/0
# Example: compressed=True
#pdf_compressed = False
# A colon-separated list of folders to search for fonts. Example:
# pdf_font_path = ['/usr/share/fonts', '/usr/share/texmf-dist/fonts/']
# Language to be used for hyphenation support
#pdf_language = "en_US"
# Mode for literal blocks wider than the frame. Can be
# overflow, shrink or truncate
#pdf_fit_mode = "shrink"
# Section level that forces a break page.
# For example: 1 means top-level sections start in a new page
# 0 means disabled
#pdf_break_level = 0
# When a section starts in a new page, force it to be 'even', 'odd',
# or just use 'any'
#pdf_breakside = 'any'
# Insert footnotes where they are defined instead of
# at the end.
#pdf_inline_footnotes = True
# verbosity level. 0 1 or 2
#pdf_verbosity = 0
# If false, no index is generated.
#pdf_use_index = True
# If false, no modindex is generated.
#pdf_use_modindex = True
# If false, no coverpage is generated.
#pdf_use_coverpage = True
# Name of the cover page template to use
#pdf_cover_template = 'sphinxcover.tmpl'
# Documents to append as an appendix to all manuals.
#pdf_appendices = []
# Enable experimental feature to split table cells. Use it
# if you get "DelayedTable too big" errors
#pdf_splittables = False
# Set the default DPI for images
#pdf_default_dpi = 72
# Enable rst2pdf extension modules (default is only vectorpdf)
# you need vectorpdf if you want to use sphinx's graphviz support
#pdf_extensions = ['vectorpdf']
# Page template name for "regular" pages
#pdf_page_template = 'cutePage'
# Show Table Of Contents at the beginning?
#pdf_use_toc = True
# How many levels deep should the table of contents be?
pdf_toc_depth = 9999
# Add section number to section references
pdf_use_numbered_links = False
# Background images fitting mode
pdf_fit_background_mode = 'scale'
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('Index', 'metaseo_tqseo_import', u'MetaSEO Import from tq_seo',
[u'Markus Blaschke'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('Index', 'metaseo_tqseo_import', u'MetaSEO Import from tq_seo',
u'Markus Blaschke', 'MetaSEO Import from tq_seo', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
#=================================================
#
# TYPO3 codeblock BEGIN:
#
# Insert this codeblock at the end of your Sphinx
# builder configuration file 'conf.py'.
# This may enable TYPO3 specific features like
# TYPO3 themes. It makes Yaml settings files work.
#
#-------------------------------------------------
if 1 and "TYPO3 specific":
try:
t3DocTeam
except NameError:
t3DocTeam = {}
try:
import t3sphinx
html_theme_path.insert(0, t3sphinx.themes_dir)
html_theme = 'typo3sphinx'
except:
html_theme = 'default'
t3DocTeam['conf_py_file'] = None
try:
t3DocTeam['conf_py_file'] = __file__
except:
import inspect
t3DocTeam['conf_py_file'] = inspect.getfile(
inspect.currentframe())
t3DocTeam['conf_py_package_dir'] = os.path.abspath(os.path.dirname(
t3DocTeam['conf_py_file']))
t3DocTeam['relpath_to_master_doc'] = '..'
t3DocTeam['relpath_to_logdir'] = '_not_versioned'
t3DocTeam['path_to_logdir'] = os.path.join(
t3DocTeam['conf_py_package_dir'],
t3DocTeam['relpath_to_logdir'])
t3DocTeam['pathToYamlSettings'] = os.path.join(
t3DocTeam['conf_py_package_dir'],
t3DocTeam['relpath_to_master_doc'], 'Settings.yml')
try:
t3DocTeam['pathToGlobalYamlSettings'] = \
t3sphinx.pathToGlobalYamlSettings
except:
t3DocTeam['pathToGlobalYamlSettings'] = None
if not t3DocTeam['pathToGlobalYamlSettings']:
t3DocTeam['pathToGlobalYamlSettings'] = os.path.join(
t3DocTeam['conf_py_package_dir'], 'GlobalSettings.yml')
try:
__function = t3sphinx.yamlsettings.processYamlSettings
except:
__function = None
if not __function:
try:
import yamlsettings
__function = yamlsettings.processYamlSettings
except:
__function = None
if __function:
__function(globals(), t3DocTeam)
#-------------------------------------------------
#
# TYPO3 codeblock END.
#
#=================================================

View File

@@ -0,0 +1,22 @@
@echo off
echo.
echo.
echo Building single file HTML version in build/singlehtml ...
call make.bat singlehtml
echo.
echo.
echo Building HTML version in build/html ...
call make.bat html
echo.
echo.
echo Starting build/html/Index.html in browser ...
start build\html\Index.html
echo.
echo.
echo Finished.
pause

View File

@@ -0,0 +1,194 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXOPTS%" == "" (
set SPHINXOPTS=-c . -a -E -w ./_not_versioned/warnings.txt
)
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=/home/mblaschke/public_html/t3intro/typo3temp/tx_sphinx/sphinx-doc/bin/sphinx-build
)
set PAPER=a4
set BUILDDIR=build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% ..
set I18NSPHINXOPTS=%SPHINXOPTS% ..
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Projectname.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Projectname.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

View File

@@ -0,0 +1,3 @@
This directory is only used by developers to run a syntax check for the rst files.
The conf.py is not used for production purposes. Instead, use /Documentation/Settings.yml

View File

@@ -0,0 +1,7 @@
# this is file .gitignore
# ignore everything in this directory
*
# but do not ignore this this file
!.gitignore

View File

@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program 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.
This program 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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@@ -0,0 +1,82 @@
# MetaSEO - Search Engine Optimization for TYPO3
![stable v1.0.8](https://img.shields.io/badge/stable-v1.0.8-green.svg?style=flat)
![development v2.0.0](https://img.shields.io/badge/development-v2.0.0-red.svg?style=flat)
![License GPL3](https://img.shields.io/badge/license-GPL3-blue.svg?style=flat)
[![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/mblaschke/typo3-metaseo.svg)](https://isitmaintained.com/project/mblaschke/typo3-metaseo "Average time to resolve an issue")
[![Percentage of issues still open](https://isitmaintained.com/badge/open/mblaschke/typo3-metaseo.svg)](https://isitmaintained.com/project/mblaschke/typo3-metaseo "Percentage of issues still open")
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/19914ab4-1f0f-4be0-9215-410fba880af2/big.png)](https://insight.sensiolabs.com/projects/19914ab4-1f0f-4be0-9215-410fba880af2)
This extension provides an indexed google/xml-sitemap, enhanced metatag-support and pagetitle-manipulations for TYPO3 CMS.
It's a replacement for the "metatag"-extension and the successor of "tq_seo".
* Manual: https://docs.typo3.org/typo3cms/extensions/metaseo/
* Git: https://github.com/mblaschke/TYPO3-metaseo
* Support: https://github.com/mblaschke/TYPO3-metaseo/issues
## Version status
* Version **1.x**:
+ Branch **master**
+ TYPO3 Version: 6.2.x
+ Composer: dev-master
* Version **2.x**:
+ Branch **develop**
+ TYPO3 Version: 6.2.x - 7.4.x
+ Composer: dev-develop
For version specific information see [Changelog for MetaSEO](CHANGELOG.md)
## Composer Support
MetaSEO (stable) is available **from TYPO3 TER** and also available with composer ::
{
"repositories": [
{ "type": "composer", "url": "https://composer.typo3.org/" }
],
.......
"require": {
"typo3/cms": "6.2.*",
"typo3-ter/metaseo": "*"
}
}
Or (unstable, don't blame me for bugs - but feel free to report bugs) directly **from Github** ::
{
"repositories": [
{ "type": "composer", "url": "https://composer.typo3.org/" },
{ "type": "vcs", "url": "https://github.com/mblaschke/TYPO3-metaseo.git" },
],
.......
"require": {
"typo3/cms": "6.2.*",
"mblaschke/metaseo": "dev-master"
}
}
## Found a bug? Got problems?
Please send us following information for easier bug hunting:
* MetaSEO version
* TYPO3 version
* PHP version
* Hoster and/or Linux distribution
## Contribution
If you want to contribute make sure you have an Editorconfig-Plugin installed in your IDE.
See [.editorconfig](.editorconfig) for indentation.
This TYPO3 Extension is using [PSR-2](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md) as coding style.

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<xliff version="1.0">
<file source-language="en" target-language="de" datatype="plaintext" original="messages" date="2014-11-08T14:45:21Z"
product-name="metaseo">
<header/>
<body>
<trans-unit id="mlang_tabs_tab" xml:space="preserve" approved="yes">
<source>Control Center</source>
<target>Kontrollzentrum</target>
</trans-unit>
<trans-unit id="mlang_labels_tabdescr" xml:space="preserve" approved="yes">
<source>MetaSEO Control center, sitemap configuration and rootpage settings</source>
<target>MetaSEO-Kontrollzentrum, Sitemap- und Rootpage-Einstellungen</target>
</trans-unit>
</body>
</file>
</xliff>

Some files were not shown because too many files have changed in this diff Show More