Commit f81b1679 authored by Tino Goratsch's avatar Tino Goratsch

Merge commit 'f3ddbb82' as 'ACP3/Modules/ACP3/Seo'

parents cd5c8f3b f3ddbb82
<?php
namespace ACP3\Modules\ACP3\Seo;
use ACP3\Core;
/**
* Class Cache
* @package ACP3\Modules\ACP3\Seo
*/
class Cache extends Core\Modules\AbstractCacheStorage
{
/**
* @var \ACP3\Modules\ACP3\Seo\Model
*/
protected $seoModel;
/**
* @param \ACP3\Core\Cache $cache
* @param \ACP3\Modules\ACP3\Seo\Model $seoModel
*/
public function __construct(
Core\Cache $cache,
Model $seoModel)
{
parent::__construct($cache);
$this->seoModel = $seoModel;
}
/**
* Gibt den Cache der URI-Aliase zurück
*
* @return array
*/
public function getCache()
{
if ($this->cache->contains('seo') === false) {
$this->setCache();
}
return $this->cache->fetch('seo');
}
/**
* Setzt den Cache für die URI-Aliase
*
* @return boolean
*/
public function setCache()
{
$aliases = $this->seoModel->getAllMetaTags();
$c_aliases = count($aliases);
$data = [];
for ($i = 0; $i < $c_aliases; ++$i) {
$data[$aliases[$i]['uri']] = [
'alias' => $aliases[$i]['alias'],
'keywords' => $aliases[$i]['keywords'],
'description' => $aliases[$i]['description'],
'robots' => $aliases[$i]['robots']
];
}
return $this->cache->save('seo', $data);
}
}
\ No newline at end of file
<?php
namespace ACP3\Modules\ACP3\Seo\Controller\Admin;
use ACP3\Core;
use ACP3\Modules\ACP3\Seo;
/**
* Class Index
* @package ACP3\Modules\ACP3\Seo\Controller\Admin
*/
class Index extends Core\Modules\Controller\Admin
{
/**
* @var \ACP3\Core\Helpers\Secure
*/
protected $secureHelper;
/**
* @var \ACP3\Modules\ACP3\Seo\Cache
*/
protected $seoCache;
/**
* @var \ACP3\Modules\ACP3\Seo\Model
*/
protected $seoModel;
/**
* @var \ACP3\Modules\ACP3\Seo\Validator
*/
protected $seoValidator;
/**
* @param \ACP3\Core\Context\Admin $context
* @param \ACP3\Core\Helpers\Secure $secureHelper
* @param \ACP3\Modules\ACP3\Seo\Cache $seoCache
* @param \ACP3\Modules\ACP3\Seo\Model $seoModel
* @param \ACP3\Modules\ACP3\Seo\Validator $seoValidator
*/
public function __construct(
Core\Context\Admin $context,
Core\Helpers\Secure $secureHelper,
Seo\Cache $seoCache,
Seo\Model $seoModel,
Seo\Validator $seoValidator)
{
parent::__construct($context);
$this->secureHelper = $secureHelper;
$this->seoCache = $seoCache;
$this->seoModel = $seoModel;
$this->seoValidator = $seoValidator;
}
public function actionCreate()
{
if (empty($_POST) === false) {
$this->_createPost($_POST);
}
$this->view->assign('SEO_FORM_FIELDS', $this->seo->formFields());
$this->view->assign('form', array_merge(['uri' => ''], $_POST));
$this->secureHelper->generateFormToken($this->request->query);
}
public function actionDelete()
{
$items = $this->_deleteItem();
if ($this->request->action === 'confirmed') {
$bool = false;
foreach ($items as $item) {
$bool = $this->seoModel->delete($item);
}
$this->seoCache->setCache();
$this->redirectMessages()->setMessage($bool, $this->lang->t('system', $bool !== false ? 'delete_success' : 'delete_error'));
} elseif (is_string($items)) {
throw new Core\Exceptions\ResultNotExists();
}
}
public function actionEdit()
{
$seo = $this->seoModel->getOneById((int)$this->request->id);
if (empty($seo) === false) {
$this->breadcrumb->setTitlePostfix($seo['alias']);
if (empty($_POST) === false) {
$this->_editPost($_POST, $seo['uri']);
}
$this->view->assign('SEO_FORM_FIELDS', $this->seo->formFields($seo['uri']));
$this->view->assign('form', array_merge(['uri' => $seo['uri']], $_POST));
$this->secureHelper->generateFormToken($this->request->query);
} else {
throw new Core\Exceptions\ResultNotExists();
}
}
public function actionIndex()
{
$seo = $this->seoModel->getAllInAcp();
if (count($seo) > 0) {
$canDelete = $this->acl->hasPermission('admin/seo/index/delete');
$config = [
'element' => '#acp-table',
'sort_col' => $canDelete === true ? 1 : 0,
'sort_dir' => 'desc',
'hide_col_sort' => $canDelete === true ? 0 : '',
'records_per_page' => $this->auth->entries
];
$this->view->assign('datatable_config', $config);
$this->view->assign('seo', $seo);
$this->view->assign('can_delete', $canDelete);
}
}
/**
* @param array $formData
*/
protected function _createPost(array $formData)
{
try {
$this->seoValidator->validate($formData);
$bool = $this->seo->insertUriAlias(
$formData['uri'],
$formData['alias'],
$formData['seo_keywords'],
$formData['seo_description'],
(int)$formData['seo_robots']
);
$this->secureHelper->unsetFormToken($this->request->query);
$this->redirectMessages()->setMessage($bool, $this->lang->t('system', $bool !== false ? 'create_success' : 'create_error'));
} catch (Core\Exceptions\InvalidFormToken $e) {
$this->redirectMessages()->setMessage(false, $e->getMessage());
} catch (Core\Exceptions\ValidationFailed $e) {
$this->view->assign('error_msg', $this->get('core.helpers.alerts')->errorBox($e->getMessage()));
}
}
/**
* @param array $formData
* @param $path
*/
protected function _editPost(array $formData, $path)
{
try {
$this->seoValidator->validate($formData, $path);
$updateValues = [
'uri' => $formData['uri'],
'alias' => $formData['alias'],
'keywords' => Core\Functions::strEncode($formData['seo_keywords']),
'description' => Core\Functions::strEncode($formData['seo_description']),
'robots' => (int)$formData['seo_robots']
];
$bool = $this->seoModel->update($updateValues, $this->request->id);
$this->seoCache->setCache();
$this->secureHelper->unsetFormToken($this->request->query);
$this->redirectMessages()->setMessage($bool, $this->lang->t('system', $bool !== false ? 'edit_success' : 'edit_error'));
} catch (Core\Exceptions\InvalidFormToken $e) {
$this->redirectMessages()->setMessage(false, $e->getMessage());
} catch (Core\Exceptions\ValidationFailed $e) {
$this->view->assign('error_msg', $this->get('core.helpers.alerts')->errorBox($e->getMessage()));
}
}
public function actionSettings()
{
if (empty($_POST) === false) {
$this->_settingsPost($_POST);
}
$seoSettings = $this->config->getSettings('seo');
// Robots
$lang_robots = [
$this->lang->t('seo', 'robots_index_follow'),
$this->lang->t('seo', 'robots_index_nofollow'),
$this->lang->t('seo', 'robots_noindex_follow'),
$this->lang->t('seo', 'robots_noindex_nofollow')
];
$this->view->assign('robots', $this->get('core.helpers.forms')->selectGenerator('robots', [1, 2, 3, 4], $lang_robots, $seoSettings['robots']));
// Sef-URIs
$lang_modRewrite = [$this->lang->t('system', 'yes'), $this->lang->t('system', 'no')];
$this->view->assign('mod_rewrite', $this->get('core.helpers.forms')->selectGenerator('mod_rewrite', [1, 0], $lang_modRewrite, $seoSettings['mod_rewrite'], 'checked'));
$this->view->assign('form', array_merge($seoSettings, $_POST));
$this->secureHelper->generateFormToken($this->request->query);
}
/**
* @param array $formData
*/
protected function _settingsPost(array $formData)
{
try {
$this->seoValidator->validateSettings($formData);
// Config aktualisieren
$data = [
'meta_description' => Core\Functions::strEncode($formData['meta_description']),
'meta_keywords' => Core\Functions::strEncode($formData['meta_keywords']),
'mod_rewrite' => (int)$formData['mod_rewrite'],
'robots' => (int)$formData['robots'],
'title' => Core\Functions::strEncode($formData['title']),
];
$bool = $this->config->setSettings($data, 'seo');
$this->secureHelper->unsetFormToken($this->request->query);
$this->redirectMessages()->setMessage($bool, $this->lang->t('system', $bool !== false ? 'settings_success' : 'settings_error'));
} catch (Core\Exceptions\InvalidFormToken $e) {
$this->redirectMessages()->setMessage(false, $e->getMessage());
} catch (Core\Exceptions\ValidationFailed $e) {
$this->view->assign('error_msg', $this->get('core.helpers.alerts')->errorBox($e->getMessage()));
}
}
}
\ No newline at end of file
<?php
namespace ACP3\Modules\ACP3\Seo;
use ACP3\Core\Modules;
/**
* Class Installer
* @package ACP3\Modules\ACP3\Seo
*/
class Installer extends Modules\AbstractInstaller
{
const MODULE_NAME = 'seo';
const SCHEMA_VERSION = 4;
/**
* @inheritdoc
*/
public function removeResources()
{
return true;
}
/**
* @inheritdoc
*/
public function createTables()
{
return [
"CREATE TABLE IF NOT EXISTS `{pre}seo` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`uri` varchar(255) NOT NULL,
`alias` varchar(100) NOT NULL,
`keywords` varchar(255) NOT NULL,
`description` varchar(255) NOT NULL,
`robots` TINYINT(1) UNSIGNED NOT NULL,
PRIMARY KEY (`id`), UNIQUE(`uri`), INDEX (`alias`)
) {engine} {charset};"
];
}
/**
* @inheritdoc
*/
public function removeTables()
{
return [];
}
/**
* @inheritdoc
*/
public function settings()
{
return [
'meta_description' => '',
'meta_keywords' => '',
'mod_rewrite' => false,
'robots' => 1,
'title' => ''
];
}
/**
* @inheritdoc
*/
public function removeSettings()
{
return true;
}
/**
* @inheritdoc
*/
public function removeFromModulesTable()
{
return true;
}
/**
* @inheritdoc
*/
public function schemaUpdates()
{
return [
2 => [
'DELETE FROM `{pre}settings` WHERE `module_id` = ' . $this->getModuleId() . ' AND `name` LIKE "seo_%";',
'UPDATE `{pre}settings` SET `module_id` = ' . $this->getModuleId(). ' WHERE `module_id` = (SELECT `id` FROM `{pre}modules` WHERE `name` = "system") AND `name` LIKE "seo_%";'
],
3 => [
"INSERT INTO `{pre}acl_resources` (`id`, `module_id`, `area`, `controller`, `page`, `params`, `privilege_id`) VALUES('', " . $this->getModuleId() . ", 'admin', 'index', 'settings', '', 7);",
],
4 => [
'UPDATE `{pre}settings` SET `name` = SUBSTRING(`name`, 5) WHERE `module_id` = ' . $this->getModuleId() .' AND `name` LIKE "seo_%";',
]
];
}
}
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<language>
<info>
<name>Deutsch (Deutschland)</name>
<direction>ltr</direction>
</info>
<keys>
<item key="admin_index_create">Neuen URL-Rewrite erstellen</item>
<item key="admin_index_delete">URL-Rewrites löschen</item>
<item key="admin_index_edit">URL-Rewrite bearbeiten</item>
<item key="admin_index_settings">Einstellungen</item>
<item key="alias">Alias</item>
<item key="alias_description">Bitte nur Kleinbuchstaben von a-z, Ziffern und den Bindestrich verwenden.</item>
<item key="alias_unallowed_characters_or_exists">Entweder haben Sie für den URI-Alias unerlaubte Zeichen eingegeben oder es existiert bereits einer mit diesem Namen.</item>
<item key="description">Beschreibung</item>
<item key="keywords">Schlüsselwörter</item>
<item key="keywords_separate_with_commas">Bitte mit Kommata trennen.</item>
<item key="mod_description">Dieses Modul ist für die Verwaltung von URL-Rewrites, Schlüsselwörtern, Beschreibungen und den Robots-Einstellungen zuständig.</item>
<item key="mod_rewrite">mod_rewrite verwenden</item>
<item key="mod_rewrite_description">Bitte nur aktivieren, wenn Sie den Apache Webserver verwenden.</item>
<item key="robots">Robots</item>
<item key="robots_use_system_default">Systemstandard verwenden (%s)</item>
<item key="robots_index_follow">index, follow</item>
<item key="robots_index_nofollow">index, nofollow</item>
<item key="robots_noindex_follow">noindex, follow</item>
<item key="robots_noindex_nofollow">noindex, nofollow</item>
<item key="select_mod_rewrite">Bitte geben Sie an, ob die suchmaschinenfreundlichen URIs verwendet werden sollen, oder nicht.</item>
<item key="select_robots">Bitte wählen Sie aus, wie die Website von Suchmaschinen-Crawlern indexiert werden soll.</item>
<item key="seo">SEO</item>
<item key="uri">Pfad</item>
</keys>
</language>
<?xml version="1.0" encoding="UTF-8"?>
<language>
<info>
<name>English (United States)</name>
<direction>ltr</direction>
</info>
<keys>
<item key="admin_index_create">Create a new URL-Rewrite</item>
<item key="admin_index_delete">Delete URL-Rewrites</item>
<item key="admin_index_edit">Edit URL-Rewrite</item>
<item key="admin_index_settings">Settings</item>
<item key="alias">Alias</item>
<item key="alias_description">Please use only lower case letters, numbers and the hyphen.</item>
<item key="alias_unallowed_characters_or_exists">Either you have typed in unallowed characters or there is already an URI-Alias with the given name.</item>
<item key="description">Description</item>
<item key="keywords">Keywords</item>
<item key="keywords_separate_with_commas">Please seperate with commas.</item>
<item key="mod_description">This module is responsible for managing the url rewrites, keywords, descriptions and the robots settings.</item>
<item key="mod_rewrite">Use mod_rewrite</item>
<item key="mod_rewrite_description">Only enable this if you are using the Apache web server.</item>
<item key="robots">Robots</item>
<item key="robots_use_system_default">Use system default (%s)</item>
<item key="robots_index_follow">index, follow</item>
<item key="robots_index_nofollow">index, nofollow</item>
<item key="robots_noindex_follow">noindex, follow</item>
<item key="robots_noindex_nofollow">noindex, nofollow</item>
<item key="select_mod_rewrite">Please select whether search engine friendly URIs should be used or not.</item>
<item key="select_robots">Please select how your website should be indexed by the seach engine crawlers.</item>
<item key="seo">SEO</item>
<item key="uri">Path</item>
</keys>
</language>
<?php
namespace ACP3\Modules\ACP3\Seo;
use ACP3\Core;
/**
* Class Model
* @package ACP3\Modules\ACP3\System
*/
class Model extends Core\Model
{
const TABLE_NAME = 'seo';
/**
* @param $path
* @return bool
*/
public function uriAliasExists($path)
{
return $this->db->fetchColumn('SELECT COUNT(*) FROM ' . $this->db->getPrefix() . static::TABLE_NAME . ' WHERE uri = ?', [$path]) > 0;
}
/**
* @param $alias
* @param string $path
* @return bool
*/
public function uriAliasExistsByAlias($alias, $path = '')
{
return $this->db->fetchColumn('SELECT COUNT(*) FROM ' . $this->db->getPrefix() . static::TABLE_NAME . ' WHERE alias = ? AND uri != ?', [$alias, $path]) > 0;
}
/**
* @return array
*/
public function getAllInAcp()
{
return $this->db->fetchAll('SELECT * FROM ' . $this->db->getPrefix() . static::TABLE_NAME);
}
/**
* @param $id
* @return array
*/
public function getOneById($id)
{
return $this->db->fetchAssoc('SELECT * FROM ' . $this->db->getPrefix() . static::TABLE_NAME . ' WHERE id = ?', [(int)$id]);
}
/**
* @return array
*/
public function getAllMetaTags()
{
return $this->db->fetchAll('SELECT * FROM ' . $this->db->getPrefix() . static::TABLE_NAME . ' WHERE alias != "" OR keywords != "" OR description != "" OR robots != 0');
}
/**
* @param $alias
*
* @return bool|string
*/
public function getUriByAlias($alias)
{
return $this->db->fetchColumn('SELECT uri FROM ' . $this->db->getPrefix() . 'seo WHERE alias = ?', [$alias]);
}
}
{extends file="asset:layout.tpl"}
{block CONTENT}
{if isset($error_msg)}
{$error_msg}
{/if}
<form action="{$REQUEST_URI}" method="post" accept-charset="UTF-8" class="form-horizontal" data-ajax-form="true" data-ajax-form-loading-text="{lang t="system|loading_please_wait"}">
<div class="form-group">
<label for="uri" class="col-sm-2 control-label">{lang t="seo|uri"}</label>
<div class="col-sm-10">
<input class="form-control" type="text" name="uri" id="uri" value="{$form.uri}" maxlength="120" required>
</div>
</div>
{include file="asset:seo/seo_fields.tpl" seo=$SEO_FORM_FIELDS}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" name="submit" class="btn btn-primary">{lang t="system|submit"}</button>
<a href="{uri args="acp/seo"}" class="btn btn-default">{lang t="system|cancel"}</a>
{$form_token}
</div>
</div>
</form>
{javascripts}
{include_js module="system" file="forms"}
{/javascripts}
{/block}
\ No newline at end of file
{extends file="asset:seo/admin/index.create.tpl"}
\ No newline at end of file
{extends file="asset:layout.tpl"}
{block CONTENT}
<form action="{uri args="acp/seo/index/delete"}" method="post">
<nav id="adm-list" class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex2-collapse">
<span class="sr-only">{lang t="system|toggle_navigation"}</span>
<span class="icon-bar"></span> <span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<span class="navbar-brand">{lang t="system|overview"}</span>
</div>
<div class="collapse navbar-collapse navbar-ex2-collapse">
<div class="navbar-text pull-right">
{check_access mode="link" path="acp/seo/index/create" class="glyphicon glyphicon-plus text-success"}
{check_access mode="link" path="acp/seo/index/settings" class="glyphicon glyphicon-cog"}
{if isset($seo)}
{check_access mode="button" path="acp/seo/index/delete" class="glyphicon glyphicon-remove text-danger" lang="system|delete_marked"}
{/if}
</div>
</div>
</nav>
{redirect_message}
{if isset($seo)}
<table id="acp-table" class="table table-striped table-hover">
<thead>
<tr>
{if $can_delete === true}
<th style="width:3%"><input type="checkbox" id="mark-all" value="1" {mark name="entries"}></th>
{/if}
<th>{lang t="seo|uri"}</th>
<th>{lang t="seo|alias"}</th>
<th>{lang t="seo|keywords"}</th>
<th>{lang t="seo|description"}</th>
<th>{lang t="seo|robots"}</th>
<th style="width:5%">{lang t="system|id"}</th>
</tr>
</thead>
<tbody>
{foreach $seo as $row}
<tr>
{if $can_delete === true}
<td><input type="checkbox" name="entries[]" value="{$row.id}"></td>
{/if}
<td>{check_access mode="link" path="acp/seo/index/edit/id_`$row.id`" title=$row.uri}</td>
<td>{$row.alias}</td>
<td>{$row.keywords}</td>
<td>{$row.description}</td>
<td>{$row.robots|robots}</td>
<td>{$row.id}</td>
</tr>
{/foreach}
</tbody>
</table>
{if $can_delete === true}
{include file="asset:system/mark.tpl"}
{/if}
{include file="asset:system/datatable.tpl" dt=$datatable_config}
{else}
<div class="alert alert-warning text-center">
<strong>{lang t="system|no_entries"}</strong>
</div>
{/if}
</form>
{/block}
\ No newline at end of file
{extends file="asset:layout.tpl"}
{block CONTENT}
{if isset($error_msg)}
{$error_msg}
{/if}
<form action="{$REQUEST_URI}" method="post" accept-charset="UTF-8" class="form-horizontal" data-ajax-form="true" data-ajax-form-loading-text="{lang t="system|loading_please_wait"}">
<div class="form-group">
<label for="title" class="col-sm-2 control-label">{lang t="system|title"}</label>
<div class="col-sm-10">
<input class="form-control" type="text" name="title" id="title" value="{$form.title}" maxlength="120">
</div>
</div>
<div class="form-group">
<label for="meta-description" class="col-sm-2 control-label">{lang t="seo|description"}</label>
<div class="col-sm-10">
<input class="form-control" type="text" name="meta_description" id="meta-description" value="{$form.meta_description}" maxlength="120">
</div>
</div>
<div class="form-group">
<label for="meta-keywords" class="col-sm-2 control-label">{lang t="seo|keywords"}</label>
<div class="col-sm-10">
<textarea class="form-control" name="meta_keywords" id="meta-keywords" cols="50" rows="6">{$form.meta_keywords}</textarea>
<p class="help-block">{lang t="seo|keywords_separate_with_commas"}</p>
</div>
</div>
<div class="form-group">
<label for="robots" class="col-sm-2 control-label">{lang t="seo|robots"}</label>
<div class="col-sm-10">
<select class="form-control" name="robots" id="robots">
{foreach $robots as $row}
<option value="{$row.value}"{$row.selected}>{$row.lang}</option>
{/foreach}
</select>
</div>
</div>
<div class="form-group">
<label for="{$mod_rewrite.0.id}" class="col-sm-2 control-label">{lang t="seo|mod_rewrite"}</label>
<div class="col-sm-10">
<div class="btn-group" data-toggle="buttons">
{foreach $mod_rewrite as $row}
<label for="{$row.id}" class="btn btn-default{if !empty($row.checked)} active{/if}">
<input type="radio" name="mod_rewrite" id="{$row.id}" value="{$row.value}"{$row.checked}>
{$row.lang}
</label>
{/foreach}
</div>
<p class="help-block">{lang t="seo|mod_rewrite_description"}</p>
</div>
</div>
<div class="form-group">