primo commit

This commit is contained in:
2024-12-17 17:34:10 +01:00
commit e650f8df99
16435 changed files with 2451012 additions and 0 deletions

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_accessibility</name>
<author>Joomla! Project</author>
<creationDate>2020-02-15</creationDate>
<copyright>(C) 2020 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>4.0.0</version>
<description>PLG_SYSTEM_ACCESSIBILITY_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\System\Accessibility</namespace>
<files>
<folder plugin="accessibility">services</folder>
<folder>src</folder>
</files>
<languages folder="admin">
<language tag="en-GB">language/en-GB/plg_system_accessibility.ini</language>
<language tag="en-GB">language/en-GB/plg_system_accessibility.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="section"
type="list"
label="PLG_SYSTEM_ACCESSIBILITY_SECTION"
default="administrator"
validate="options"
>
<option value="site">PLG_SYSTEM_ACCESSIBILITY_SECTION_SITE</option>
<option value="administrator">PLG_SYSTEM_ACCESSIBILITY_SECTION_ADMIN</option>
<option value="both">PLG_SYSTEM_ACCESSIBILITY_SECTION_BOTH</option>
</field>
<field
name="useEmojis"
type="list"
label="PLG_SYSTEM_ACCESSIBILITY_EMOJIS"
default="true"
validate="options"
>
<option value="true">PLG_SYSTEM_ACCESSIBILITY_EMOJIS_TRUE</option>
<option value="false">PLG_SYSTEM_ACCESSIBILITY_EMOJIS_FALSE</option>
</field>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,46 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.accessibility
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\System\Accessibility\Extension\Accessibility;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.4.0
*/
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Accessibility(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('system', 'accessibility')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};

View File

@ -0,0 +1,114 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.accessibility
*
* @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Accessibility\Extension;
use Joomla\CMS\Plugin\CMSPlugin;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* System plugin to add additional accessibility features to the administrator interface.
*
* @since 4.0.0
*/
final class Accessibility extends CMSPlugin
{
/**
* Add the javascript for the accessibility menu
*
* @return void
*
* @since 4.0.0
*/
public function onBeforeCompileHead()
{
$section = $this->params->get('section', 'administrator');
if ($section !== 'both' && $this->getApplication()->isClient($section) !== true) {
return;
}
// Get the document object.
$document = $this->getApplication()->getDocument();
if ($document->getType() !== 'html') {
return;
}
// Are we in a modal?
if ($this->getApplication()->getInput()->get('tmpl', '', 'cmd') === 'component') {
return;
}
// Load language file.
$this->loadLanguage();
// Determine if it is an LTR or RTL language
$direction = $this->getApplication()->getLanguage()->isRtl() ? 'right' : 'left';
// Detect the current active language
$lang = $this->getApplication()->getLanguage()->getTag();
/**
* Add strings for translations in Javascript.
* Reference https://ranbuch.github.io/accessibility/
*/
$document->addScriptOptions(
'accessibility-options',
[
'labels' => [
'menuTitle' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_MENU_TITLE'),
'increaseText' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_INCREASE_TEXT'),
'decreaseText' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_DECREASE_TEXT'),
'increaseTextSpacing' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_INCREASE_SPACING'),
'decreaseTextSpacing' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_DECREASE_SPACING'),
'invertColors' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_INVERT_COLORS'),
'grayHues' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_GREY'),
'underlineLinks' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_UNDERLINE'),
'bigCursor' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_CURSOR'),
'readingGuide' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_READING'),
'textToSpeech' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_TTS'),
'speechToText' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_STT'),
'resetTitle' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_RESET'),
'closeTitle' => $this->getApplication()->getLanguage()->_('PLG_SYSTEM_ACCESSIBILITY_CLOSE'),
],
'icon' => [
'position' => [
$direction => [
'size' => '0',
'units' => 'px',
],
],
'useEmojis' => $this->params->get('useEmojis', 'true') === 'true',
],
'hotkeys' => [
'enabled' => true,
'helpTitles' => true,
],
'textToSpeechLang' => [$lang],
'speechToTextLang' => [$lang],
]
);
$document->getWebAssetManager()
->useScript('accessibility')
->addInlineScript(
'window.addEventListener("load", function() {'
. 'new Accessibility(Joomla.getOptions("accessibility-options") || {});'
. '});',
['name' => 'inline.plg.system.accessibility'],
['type' => 'module'],
['accessibility']
);
}
}

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_actionlogs</name>
<author>Joomla! Project</author>
<creationDate>2018-05</creationDate>
<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.9.0</version>
<description>PLG_SYSTEM_ACTIONLOGS_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\System\ActionLogs</namespace>
<files>
<folder>forms</folder>
<folder plugin="actionlogs">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_system_actionlogs.ini</language>
<language tag="en-GB">language/en-GB/plg_system_actionlogs.sys.ini</language>
</languages>
</extension>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fieldset name="actionlogs" label="PLG_SYSTEM_ACTIONLOGS_OPTIONS" addfieldprefix="Joomla\Component\Actionlogs\Administrator\Field">
<fields name="actionlogs">
<field
name="actionlogsNotify"
type="radio"
label="PLG_SYSTEM_ACTIONLOGS_NOTIFICATIONS"
layout="joomla.form.field.radio.switcher"
default="0"
filter="integer"
required="true"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="actionlogsExtensions"
type="userlogtype"
label="PLG_SYSTEM_ACTIONLOGS_EXTENSIONS_NOTIFICATIONS"
multiple="true"
validate="options"
layout="joomla.form.field.list-fancy-select"
showon="actionlogsNotify:1"
default="com_content"
/>
</fields>
</fieldset>
</form>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<form>
<fields name="params">
<fieldset name="information" label="PLG_SYSTEM_ACTIONLOGS_OPTIONS">
<field addfieldprefix="Joomla\Component\Actionlogs\Administrator\Field"
name="Information"
type="plugininfo"
label="PLG_SYSTEM_ACTIONLOGS_INFO_LABEL"
description="PLG_SYSTEM_ACTIONLOGS_INFO_DESC"
/>
</fieldset>
</fields>
</form>

View File

@ -0,0 +1,50 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.actionlogs
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\System\ActionLogs\Extension\ActionLogs;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.4.0
*/
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new ActionLogs(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('system', 'actionlogs')
);
$plugin->setApplication(Factory::getApplication());
$plugin->setDatabase($container->get(DatabaseInterface::class));
$plugin->setUserFactory($container->get(UserFactoryInterface::class));
return $plugin;
}
);
}
};

View File

@ -0,0 +1,407 @@
<?php
/**
* @package Joomla.Plugins
* @subpackage System.actionlogs
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\ActionLogs\Extension;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Form\Form;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\UserFactoryAwareTrait;
use Joomla\Component\Actionlogs\Administrator\Helper\ActionlogsHelper;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Database\Exception\ExecutionFailureException;
use Joomla\Database\ParameterType;
use Joomla\Event\DispatcherInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla! Users Actions Logging Plugin.
*
* @since 3.9.0
*/
final class ActionLogs extends CMSPlugin
{
use DatabaseAwareTrait;
use UserFactoryAwareTrait;
/**
* Constructor.
*
* @param DispatcherInterface $dispatcher The dispatcher
* @param array $config An optional associative array of configuration settings
*
* @since 3.9.0
*/
public function __construct(DispatcherInterface $dispatcher, array $config)
{
parent::__construct($dispatcher, $config);
// Import actionlog plugin group so that these plugins will be triggered for events
PluginHelper::importPlugin('actionlog');
}
/**
* Adds additional fields to the user editing form for logs e-mail notifications
*
* @param Form $form The form to be altered.
* @param mixed $data The associated data for the form.
*
* @return boolean
*
* @since 3.9.0
*
* @throws \Exception
*/
public function onContentPrepareForm(Form $form, $data)
{
$formName = $form->getName();
$allowedFormNames = [
'com_users.profile',
'com_users.user',
];
if (!\in_array($formName, $allowedFormNames, true)) {
return true;
}
/**
* We only allow users who have Super User permission to change this setting for themselves or for other
* users who have the same Super User permission
*/
$user = $this->getApplication()->getIdentity();
if (!$user || !$user->authorise('core.admin')) {
return true;
}
// Load plugin language files.
$this->loadLanguage();
// If we are on the save command, no data is passed to $data variable, we need to get it directly from request
$jformData = $this->getApplication()->getInput()->get('jform', [], 'array');
if ($jformData && !$data) {
$data = $jformData;
}
if (\is_array($data)) {
$data = (object) $data;
}
if (empty($data->id) || !$this->getUserFactory()->loadUserById($data->id)->authorise('core.admin')) {
return true;
}
Form::addFormPath(JPATH_PLUGINS . '/' . $this->_type . '/' . $this->_name . '/forms');
if ((!PluginHelper::isEnabled('actionlog', 'joomla')) && ($this->getApplication()->isClient('administrator'))) {
$form->loadFile('information', false);
return true;
}
if (!PluginHelper::isEnabled('actionlog', 'joomla')) {
return true;
}
$form->loadFile('actionlogs', false);
return true;
}
/**
* Runs on content preparation
*
* @param string $context The context for the data
* @param object $data An object containing the data for the form.
*
* @return boolean
*
* @since 3.9.0
*/
public function onContentPrepareData($context, $data)
{
if (!\in_array($context, ['com_users.profile', 'com_users.user'])) {
return true;
}
if (\is_array($data)) {
$data = (object) $data;
}
if (empty($data->id) || !$this->getUserFactory()->loadUserById($data->id)->authorise('core.admin')) {
return true;
}
$db = $this->getDatabase();
$id = (int) $data->id;
$query = $db->getQuery(true)
->select($db->quoteName(['notify', 'extensions']))
->from($db->quoteName('#__action_logs_users'))
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $id, ParameterType::INTEGER);
try {
$values = $db->setQuery($query)->loadObject();
} catch (ExecutionFailureException $e) {
return false;
}
if (!$values) {
return true;
}
// Load plugin language files.
$this->loadLanguage();
$data->actionlogs = new \stdClass();
$data->actionlogs->actionlogsNotify = $values->notify;
$data->actionlogs->actionlogsExtensions = $values->extensions;
if (!HTMLHelper::isRegistered('users.actionlogsNotify')) {
HTMLHelper::register('users.actionlogsNotify', [__CLASS__, 'renderActionlogsNotify']);
}
if (!HTMLHelper::isRegistered('users.actionlogsExtensions')) {
HTMLHelper::register('users.actionlogsExtensions', [__CLASS__, 'renderActionlogsExtensions']);
}
return true;
}
/**
* Utility method to act on a user after it has been saved.
*
* @param array $user Holds the new user data.
* @param boolean $isNew True if a new user is stored.
* @param boolean $success True if user was successfully stored in the database.
* @param string $msg Message.
*
* @return void
*
* @since 3.9.0
*/
public function onUserAfterSave($user, $isNew, $success, $msg): void
{
if (!$success) {
return;
}
// Clear access rights in case user groups were changed.
$userObject = $this->getUserFactory()->loadUserById($user['id']);
$userObject->clearAccessRights();
$authorised = $userObject->authorise('core.admin');
$userid = (int) $user['id'];
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select('COUNT(*)')
->from($db->quoteName('#__action_logs_users'))
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $userid, ParameterType::INTEGER);
try {
$exists = (bool) $db->setQuery($query)->loadResult();
} catch (ExecutionFailureException $e) {
return;
}
$query->clear();
// If preferences don't exist, insert.
if (!$exists && $authorised && isset($user['actionlogs'])) {
$notify = (int) $user['actionlogs']['actionlogsNotify'];
$values = [':userid', ':notify'];
$bind = [$userid, $notify];
$columns = ['user_id', 'notify'];
$query->bind($values, $bind, ParameterType::INTEGER);
if (isset($user['actionlogs']['actionlogsExtensions'])) {
$values[] = ':extension';
$columns[] = 'extensions';
$extension = json_encode($user['actionlogs']['actionlogsExtensions']);
$query->bind(':extension', $extension);
}
$query->insert($db->quoteName('#__action_logs_users'))
->columns($db->quoteName($columns))
->values(implode(',', $values));
} elseif ($exists && $authorised && isset($user['actionlogs'])) {
// Update preferences.
$notify = (int) $user['actionlogs']['actionlogsNotify'];
$values = [$db->quoteName('notify') . ' = :notify'];
$query->bind(':notify', $notify, ParameterType::INTEGER);
if (isset($user['actionlogs']['actionlogsExtensions'])) {
$values[] = $db->quoteName('extensions') . ' = :extension';
$extension = json_encode($user['actionlogs']['actionlogsExtensions']);
$query->bind(':extension', $extension);
}
$query->update($db->quoteName('#__action_logs_users'))
->set($values)
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $userid, ParameterType::INTEGER);
} elseif ($exists && !$authorised) {
// Remove preferences if user is not authorised.
$query->delete($db->quoteName('#__action_logs_users'))
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $userid, ParameterType::INTEGER);
} else {
return;
}
try {
$db->setQuery($query)->execute();
} catch (ExecutionFailureException $e) {
// Do nothing.
}
}
/**
* Removes user preferences
*
* Method is called after user data is deleted from the database
*
* @param array $user Holds the user data
* @param boolean $success True if user was successfully stored in the database
* @param string $msg Message
*
* @return void
*
* @since 3.9.0
*/
public function onUserAfterDelete($user, $success, $msg): void
{
if (!$success) {
return;
}
$db = $this->getDatabase();
$userid = (int) $user['id'];
$query = $db->getQuery(true)
->delete($db->quoteName('#__action_logs_users'))
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $userid, ParameterType::INTEGER);
try {
$db->setQuery($query)->execute();
} catch (ExecutionFailureException $e) {
// Do nothing.
}
}
/**
* Method to render a value.
*
* @param integer|string $value The value (0 or 1).
*
* @return string The rendered value.
*
* @since 3.9.16
*/
public static function renderActionlogsNotify($value)
{
return Text::_($value ? 'JYES' : 'JNO');
}
/**
* Method to render a list of extensions.
*
* @param array|string $extensions Array of extensions or an empty string if none selected.
*
* @return string The rendered value.
*
* @since 3.9.16
*/
public static function renderActionlogsExtensions($extensions)
{
// No extensions selected.
if (!$extensions) {
return Text::_('JNONE');
}
foreach ($extensions as &$extension) {
// Load extension language files and translate extension name.
ActionlogsHelper::loadTranslationFiles($extension);
$extension = Text::_($extension);
}
return implode(', ', $extensions);
}
/**
* On Saving extensions logging method
* Method is called when an extension is being saved
*
* @param string $context The extension
* @param \Joomla\CMS\Table\Table $table DataBase Table object
* @param boolean $isNew If the extension is new or not
*
* @return void
*
* @since 5.1.0
*/
public function onExtensionAfterSave($context, $table, $isNew): void
{
if ($context !== 'com_config.component' || $table->name !== 'com_actionlogs') {
return;
}
$params = ComponentHelper::getParams('com_actionlogs');
$globalExt = (array) $params->get('loggable_extensions', []);
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName(['user_id', 'notify', 'extensions']))
->from($db->quoteName('#__action_logs_users'));
try {
$values = $db->setQuery($query)->loadObjectList();
} catch (ExecutionFailureException $e) {
return;
}
foreach ($values as $item) {
$userExt = substr($item->extensions, 2);
$userExt = substr($userExt, 0, -2);
$user = explode('","', $userExt);
$common = array_intersect($globalExt, $user);
$extension = json_encode(array_values($common));
$query->clear()
->update($db->quoteName('#__action_logs_users'))
->set($db->quoteName('extensions') . ' = :extension')
->where($db->quoteName('user_id') . ' = :userid')
->bind(':userid', $item->user_id, ParameterType::INTEGER)
->bind(':extension', $extension);
try {
$db->setQuery($query)->execute();
} catch (ExecutionFailureException $e) {
// Do nothing.
}
}
}
}

59
plugins/system/cache/cache.xml vendored Normal file
View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_cache</name>
<author>Joomla! Project</author>
<creationDate>2007-02</creationDate>
<copyright>(C) 2007 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_CACHE_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\System\Cache</namespace>
<files>
<folder plugin="cache">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_system_cache.ini</language>
<language tag="en-GB">language/en-GB/plg_system_cache.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="browsercache"
type="radio"
layout="joomla.form.field.radio.switcher"
label="PLG_CACHE_FIELD_BROWSERCACHE_LABEL"
default="0"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="exclude_menu_items"
type="menuitem"
label="PLG_CACHE_FIELD_EXCLUDE_MENU_ITEMS_LABEL"
multiple="multiple"
filter="intarray"
layout="joomla.form.field.groupedlist-fancy-select"
/>
</fieldset>
<fieldset name="advanced">
<field
name="exclude"
type="textarea"
label="PLG_CACHE_FIELD_EXCLUDE_LABEL"
description="PLG_CACHE_FIELD_EXCLUDE_DESC"
rows="15"
filter="raw"
/>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,52 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.cache
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Profiler\Profiler;
use Joomla\CMS\Router\SiteRouter;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\System\Cache\Extension\Cache;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
* @since 4.2.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = PluginHelper::getPlugin('system', 'cache');
$dispatcher = $container->get(DispatcherInterface::class);
$documentFactory = $container->get('document.factory');
$cacheControllerFactory = $container->get(CacheControllerFactoryInterface::class);
$profiler = (\defined('JDEBUG') && JDEBUG) ? Profiler::getInstance('Application') : null;
$router = $container->has(SiteRouter::class) ? $container->get(SiteRouter::class) : null;
$plugin = new Cache($dispatcher, (array) $plugin, $documentFactory, $cacheControllerFactory, $profiler, $router);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};

View File

@ -0,0 +1,383 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.cache
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Cache\Extension;
use Joomla\CMS\Cache\CacheController;
use Joomla\CMS\Cache\CacheControllerFactoryInterface;
use Joomla\CMS\Document\FactoryInterface as DocumentFactoryInterface;
use Joomla\CMS\Event\Application\AfterRespondEvent;
use Joomla\CMS\Event\PageCache\GetKeyEvent;
use Joomla\CMS\Event\PageCache\IsExcludedEvent;
use Joomla\CMS\Event\PageCache\SetCachingEvent;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Profiler\Profiler;
use Joomla\CMS\Router\SiteRouter;
use Joomla\CMS\Uri\Uri;
use Joomla\Event\DispatcherInterface;
use Joomla\Event\Event;
use Joomla\Event\Priority;
use Joomla\Event\SubscriberInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla! Page Cache Plugin.
*
* @since 1.5
*/
final class Cache extends CMSPlugin implements SubscriberInterface
{
/**
* Cache instance.
*
* @var CacheController
* @since 1.5
*/
private $cache;
/**
* The application's document factory interface
*
* @var DocumentFactoryInterface
* @since 4.2.0
*/
private $documentFactory;
/**
* Cache controller factory interface
*
* @var CacheControllerFactoryInterface
* @since 4.2.0
*/
private $cacheControllerFactory;
/**
* The application profiler, used when Debug Site is set to Yes in Global Configuration.
*
* @var Profiler|null
* @since 4.2.0
*/
private $profiler;
/**
* The frontend router, injected by the service provider.
*
* @var SiteRouter|null
* @since 4.2.0
*/
private $router;
/**
* Constructor
*
* @param DispatcherInterface $dispatcher The object to observe
* @param array $config An optional associative
* array of configuration
* settings. Recognized key
* values include 'name',
* 'group', 'params',
* 'language'
* (this list is not meant
* to be comprehensive).
* @param DocumentFactoryInterface $documentFactory The application's
* document factory
* @param CacheControllerFactoryInterface $cacheControllerFactory Cache controller factory
* @param Profiler|null $profiler The application profiler
* @param SiteRouter|null $router The frontend router
*
* @since 4.2.0
*/
public function __construct(
DispatcherInterface $dispatcher,
array $config,
DocumentFactoryInterface $documentFactory,
CacheControllerFactoryInterface $cacheControllerFactory,
?Profiler $profiler,
?SiteRouter $router
) {
parent::__construct($dispatcher, $config);
$this->documentFactory = $documentFactory;
$this->cacheControllerFactory = $cacheControllerFactory;
$this->profiler = $profiler;
$this->router = $router;
}
/**
* Returns an array of CMS events this plugin will listen to and the respective handlers.
*
* @return array
*
* @since 4.2.0
*/
public static function getSubscribedEvents(): array
{
/**
* Note that onAfterRender and onAfterRespond must be the last handlers to run for this
* plugin to operate as expected. These handlers put pages into cache. We must make sure
* that a. the page SHOULD be cached and b. we are caching the complete page, as it's
* output to the browser.
*/
return [
'onAfterRoute' => 'onAfterRoute',
'onAfterRender' => ['onAfterRender', Priority::LOW],
'onAfterRespond' => ['onAfterRespond', Priority::LOW],
];
}
/**
* Returns a cached page if the current URL exists in the cache.
*
* @param Event $event The Joomla event being handled
*
* @return void
*
* @since 4.0.0
*/
public function onAfterRoute(Event $event)
{
if (!$this->appStateSupportsCaching()) {
return;
}
// Import "pagecache" plugins
$dispatcher = $this->getDispatcher();
PluginHelper::importPlugin('pagecache', null, true, $dispatcher);
// If any onPageCacheSetCaching listener return false, do not use the cache.
$results = $dispatcher->dispatch('onPageCacheSetCaching', new SetCachingEvent('onPageCacheSetCaching'))
->getArgument('result', []);
$this->getCacheController()->setCaching(!\in_array(false, $results, true));
$data = $this->getCacheController()->get($this->getCacheKey());
if ($data === false) {
// No cached data.
return;
}
// Set the page content from the cache and output it to the browser.
$this->getApplication()->setBody($data);
echo $this->getApplication()->toString((bool) $this->getApplication()->get('gzip'));
// Mark afterCache in debug and run debug onAfterRespond events, e.g. show Joomla Debug Console if debug is active.
if (JDEBUG) {
// Create a document instance and load it into the application.
$document = $this->documentFactory
->createDocument($this->getApplication()->getInput()->get('format', 'html'));
$this->getApplication()->loadDocument($document);
if ($this->profiler) {
$this->profiler->mark('afterCache');
}
$this->getDispatcher()->dispatch('onAfterRespond', new AfterRespondEvent(
'onAfterRespond',
[
'subject' => $this->getApplication(),
]
));
}
// Closes the application.
$this->getApplication()->close();
}
/**
* Does the current application state allow for caching?
*
* The following conditions must be met:
* * This is the frontend application. This plugin does not apply to other applications.
* * This is a GET request. This plugin does not apply to POST, PUT etc.
* * There is no currently logged in user (pages might have userspecific content).
* * The message queue is empty.
*
* The first two tests are cached to make early returns possible; these conditions cannot change
* throughout the lifetime of the request.
*
* The other two tests MUST NOT be cached because autologin plugins may fire anytime within
* the application lifetime logging in a user and messages can be generated anytime within the
* application's lifetime.
*
* @return boolean
* @since 4.2.0
*/
private function appStateSupportsCaching(): bool
{
static $isSite = null;
static $isGET = null;
if ($isSite === null) {
$isSite = $this->getApplication()->isClient('site');
$isGET = $this->getApplication()->getInput()->getMethod() === 'GET';
}
// Boolean shortcircuit evaluation means this returns fast false when $isSite is false.
return $isSite
&& $isGET
&& $this->getApplication()->getIdentity()->guest
&& empty($this->getApplication()->getMessageQueue());
}
/**
* Get the cache controller
*
* @return CacheController
* @since 4.2.0
*/
private function getCacheController(): CacheController
{
if (!empty($this->cache)) {
return $this->cache;
}
// Set the cache options.
$options = [
'defaultgroup' => 'page',
'browsercache' => $this->params->get('browsercache', 0),
'caching' => false,
];
// Instantiate cache with previous options.
$this->cache = $this->cacheControllerFactory->createCacheController('page', $options);
return $this->cache;
}
/**
* Get a cache key for the current page based on the url and possible other factors.
*
* @return string
*
* @since 3.7
*/
private function getCacheKey(): string
{
static $key;
if (!$key) {
$parts = $this->getDispatcher()->dispatch('onPageCacheGetKey', new GetKeyEvent('onPageCacheGetKey'))
->getArgument('result', []);
$parts[] = Uri::getInstance()->toString();
$key = md5(serialize($parts));
}
return $key;
}
/**
* After Render Event. Check whether the current page is excluded from cache.
*
* @param Event $event The CMS event we are handling.
*
* @return void
*
* @since 3.9.12
*/
public function onAfterRender(Event $event)
{
if (!$this->appStateSupportsCaching() || $this->getCacheController()->getCaching() === false) {
return;
}
if ($this->isExcluded() === true) {
$this->getCacheController()->setCaching(false);
return;
}
// Disable compression before caching the page.
$this->getApplication()->set('gzip', false);
}
/**
* Check if the page is excluded from the cache or not.
*
* @return boolean True if the page is excluded else false
*
* @since 3.5
*/
private function isExcluded(): bool
{
// Check if menu items have been excluded.
$excludedMenuItems = $this->params->get('exclude_menu_items', []);
if ($excludedMenuItems) {
// Get the current menu item.
$active = $this->getApplication()->getMenu()->getActive();
if ($active && $active->id && \in_array((int) $active->id, (array) $excludedMenuItems)) {
return true;
}
}
// Check if regular expressions are being used.
$exclusions = $this->params->get('exclude', '');
if ($exclusions) {
// Convert the exclusions into a normalised array
$exclusions = str_replace(["\r\n", "\r"], "\n", $exclusions);
$exclusions = explode("\n", $exclusions);
$exclusions = array_map('trim', $exclusions);
$filterExpression = function ($x) {
return $x !== '';
};
$exclusions = array_filter($exclusions, $filterExpression);
// Gets the internal (non-SEF) and the external (possibly SEF) URIs.
$internalUrl = '/index.php?'
. Uri::getInstance()->buildQuery($this->router->getVars());
$externalUrl = Uri::getInstance()->toString();
// Loop through each pattern.
if ($exclusions) {
foreach ($exclusions as $exclusion) {
// Test both external and internal URI
if (preg_match('#' . $exclusion . '#i', $externalUrl . ' ' . $internalUrl, $match)) {
return true;
}
}
}
}
// If any onPageCacheIsExcluded listener return true, exclude.
$results = $this->getDispatcher()->dispatch('onPageCacheIsExcluded', new IsExcludedEvent('onPageCacheIsExcluded'))
->getArgument('result', []);
return \in_array(true, $results, true);
}
/**
* After Respond Event. Stores page in cache.
*
* @param Event $event The application event we are handling.
*
* @return void
*
* @since 1.5
*/
public function onAfterRespond(Event $event)
{
if (!$this->appStateSupportsCaching() || $this->getCacheController()->getCaching() === false) {
return;
}
// Saves current page in cache.
$this->getCacheController()->store($this->getApplication()->getBody(), $this->getCacheKey());
}
}

View File

@ -0,0 +1,125 @@
<?php
/**
* @package Conditional Content
* @version 5.2.2
*
* @author Peter van Westen <info@regularlabs.com>
* @link https://regularlabs.com
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
* @license GNU General Public License version 2 or later
*/
defined('_JEXEC') or die;
use Joomla\CMS\Factory as JFactory;
use Joomla\CMS\Language\Text as JText;
use RegularLabs\Library\Document as RL_Document;
use RegularLabs\Library\Extension as RL_Extension;
use RegularLabs\Library\Html as RL_Html;
use RegularLabs\Library\SystemPlugin as RL_SystemPlugin;
use RegularLabs\Plugin\System\ConditionalContent\Params;
use RegularLabs\Plugin\System\ConditionalContent\Protect;
use RegularLabs\Plugin\System\ConditionalContent\Replace;
// Do not instantiate plugin on install pages
// to prevent installation/update breaking because of potential breaking changes
if (
in_array(JFactory::getApplication()->input->getCmd('option'), ['com_installer', 'com_regularlabsmanager'])
&& JFactory::getApplication()->input->getCmd('action') != ''
)
{
return;
}
if ( ! is_file(JPATH_LIBRARIES . '/regularlabs/regularlabs.xml')
|| ! class_exists('RegularLabs\Library\Parameters')
|| ! class_exists('RegularLabs\Library\DownloadKey')
|| ! class_exists('RegularLabs\Library\SystemPlugin')
)
{
JFactory::getApplication()->getLanguage()->load('plg_system_conditionalcontent', __DIR__);
JFactory::getApplication()->enqueueMessage(
JText::sprintf('AA_EXTENSION_CAN_NOT_FUNCTION', JText::_('CONDITIONALCONTENT'))
. ' ' . JText::_('AA_REGULAR_LABS_LIBRARY_NOT_INSTALLED'),
'error'
);
return;
}
if ( ! RL_Document::isJoomlaVersion(4, 'CONDITIONALCONTENT'))
{
RL_Extension::disable('conditionalcontent', 'plugin');
RL_Document::adminError(
JText::sprintf('RL_PLUGIN_HAS_BEEN_DISABLED', JText::_('CONDITIONALCONTENT'))
);
return;
}
if (true)
{
class PlgSystemConditionalContent extends RL_SystemPlugin
{
public $_lang_prefix = 'COC';
public $_can_disable_by_url = false;
public $_jversion = 4;
public $_enable_in_admin = true;
public function __construct(&$subject, $config = [])
{
parent::__construct($subject, $config);
$params = Params::get();
$this->_enable_in_admin = $params->enable_admin;
}
public function processArticle(
&$string,
$area = 'article',
$context = '',
$article = null,
$page = 0
)
{
Replace::replaceTags($string, $area, $context, $article);
}
/**
* @param object $module
* @param array $params
*/
protected function handleOnAfterRenderModule(&$module, &$params): void
{
if ( ! isset($module->content))
{
return;
}
Replace::replaceTags($module->content, 'module');
}
protected function changeDocumentBuffer(&$buffer)
{
return Replace::replaceTags($buffer, 'component');
}
protected function changeFinalHtmlOutput(&$html)
{
// only do stuff in body
[$pre, $body, $post] = RL_Html::getBody($html);
Replace::replaceTags($body, 'body');
$html = $pre . $body . $post;
return true;
}
protected function cleanFinalHtmlOutput(&$html)
{
Protect::unprotectTags($html);
//RL_Protect::removeInlineComments($html, 'ConditionalContent');
}
}
}

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<extension version="4" type="plugin" group="system" method="upgrade">
<name>PLG_SYSTEM_CONDITIONALCONTENT</name>
<description>PLG_SYSTEM_CONDITIONALCONTENT_DESC</description>
<version>5.2.2</version>
<creationDate>November 2024</creationDate>
<author>Regular Labs (Peter van Westen)</author>
<authorEmail>info@regularlabs.com</authorEmail>
<authorUrl>https://regularlabs.com</authorUrl>
<copyright>Copyright © 2024 Regular Labs - All Rights Reserved</copyright>
<license>GNU General Public License version 2 or later</license>
<namespace path="src">RegularLabs\Plugin\System\ConditionalContent</namespace>
<files>
<file plugin="conditionalcontent">conditionalcontent.php</file>
<folder>language</folder>
<folder>src</folder>
</files>
<media folder="media" destination="conditionalcontent">
<folder>js</folder>
</media>
<config>
<fields name="params" addfieldprefix="RegularLabs\Library\Form\Field">
<fieldset name="basic">
<field name="@load_script_descriptions" type="LoadMedia" filetype="script" file="regularlabs.admin-form-descriptions"/>
<field name="@load_language_regularlabs" type="LoadLanguage" extension="plg_system_regularlabs"/>
<field name="@jcompatibility" type="JCompatibility" extension="CONDITIONALCONTENT"/>
<field name="@license" type="License" extension="CONDITIONALCONTENT"/>
<field name="@version" type="Version" extension="CONDITIONALCONTENT"/>
<field name="@header" type="Header" label="CONDITIONALCONTENT" description="CONDITIONALCONTENT_DESC" url="https://regularlabs.com/conditionalcontent"/>
</fieldset>
<fieldset name="RL_SETTINGS_EDITOR_BUTTON">
<field name="button_text" type="Text" class="font-monospace rl-w-20em" default="Conditional Content" label="RL_BUTTON_TEXT" description="RL_BUTTON_TEXT_DESC"/>
<field name="enable_frontend" type="Radio" class="btn-group rl-btn-group btn-group-md btn-group-yesno" default="1" label="RL_ENABLE_IN_FRONTEND" description="RL_ENABLE_IN_FRONTEND_DESC">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field name="use_editors" type="Radio" class="btn-group rl-btn-group btn-group-md btn-group-yesno" default="0" label="COC_USE_EDITORS" description="COC_USE_EDITORS_DESC">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
<fieldset name="RL_TAG_SYNTAX">
<field name="tag_show" type="Text" class="font-monospace rl-w-20em" default="show" label="COC_SHOW_TAG" description="COC_TAG_DESC"/>
<field name="tag_hide" type="Text" class="font-monospace rl-w-20em" default="hide" label="COC_HIDE_TAG" description="COC_TAG_DESC"/>
<field name="tag_characters" type="List" class="font-monospace w-auto" default="{.}" label="RL_TAG_CHARACTERS" description="RL_TAG_CHARACTERS_DESC">
<option value="{.}">{...}</option>
<option value="[.]">[...]</option>
<option value="«.»">«...»</option>
<option value="{{.}}">{{...}}</option>
<option value="[[.]]">[[...]]</option>
<option value="[:.:]">[:...:]</option>
<option value="[%.%]">[%...%]</option>
</field>
</fieldset>
<fieldset name="advanced">
<field name="trim" type="Radio" class="btn-group rl-btn-group btn-group-md btn-group-yesno" default="0" label="RL_STRIP_SURROUNDING_TAGS" description="RL_STRIP_SURROUNDING_TAGS_DESC">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field name="@note__disabled_components" type="OnlyPro" label="RL_DISABLE_ON_COMPONENTS" description="RL_DISABLE_ON_COMPONENTS_DESC"/>
<field name="enable_admin" type="Radio" class="btn-group rl-btn-group btn-group-md btn-group-yesno" default="0" label="RL_ENABLE_IN_ADMIN" description="RL_ENABLE_IN_ADMIN_DESC">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field name="place_comments" type="Radio" class="btn-group rl-btn-group btn-group-md btn-group-yesno" default="1" label="RL_PLACE_HTML_COMMENTS" description="RL_PLACE_HTML_COMMENTS_DESC">
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] لا يمكن تشغيله."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="مُنتج Regular Labs Library غير مُمكن."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="مُنتج Regular Labs Library غير مُثبت."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
; COC_CONDITIONS="Conditions"
COC_CONTENT="المحتوى"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="الكلمة التي ستستخدم في العلامات.<br><br><strong>ملاحظة:</strong> إذا قمت بتغيير هذه الكلمة, فإن جميع العلامات الموجودة لن تعمل بعد الآن."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] لا يمكن تشغيله."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="مُنتج Regular Labs Library غير مُمكن."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="مُنتج Regular Labs Library غير مُثبت."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
; COC_CONDITIONS="Conditions"
COC_CONTENT="Content"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="الكلمة التي ستستخدم في العلامات.<br><br><strong>ملاحظة:</strong> إذا قمت بتغيير هذه الكلمة, فإن جميع العلامات الموجودة لن تعمل بعد الآن."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - ограничете съдържание на база Вашите условия в Джумла!"
CONDITIONALCONTENT="условно съдържание"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] не може да функционира."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Добавката Regular Labs Library не е включена."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Добавката Regular Labs Library не е инсталирана."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
; COC_CONDITIONS="Conditions"
COC_CONTENT="Content"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
; COC_TAG_DESC="The word to be used in the tags.<br><br><strong>Note:</strong> If you change this, all existing tags will not work anymore."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - ограничете съдържание на база Вашите условия в Джумла!"
CONDITIONALCONTENT="условно съдържание"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] no pot funcionar."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="El plugin Regular Labs Library no está activat."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="El plugin Regular Labs Library no està instal·lat."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
; COC_CONDITIONS="Conditions"
COC_CONTENT="Contingut"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
COC_CONTENTS="Continguts"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="La paraula a emprar als tags.<br><br><strong>Nota:</strong> Si la canvieu, tots els tags existents deixaràn de funcionar."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] δεν ήταν δυνατόν να λειτουργήσει."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Το πρόσθετο Regular Labs Library δεν είναι ενεργό."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Η βιβλιοθήκη Regular Labs δεν είναι εγκατεστημένη."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
; COC_CONDITIONS="Conditions"
COC_CONTENT="Προσαρμοσμένο Περιεχόμενο"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="Η λέξη που θα χρησιμοποιείται στις ετικέτες.<br><br><strong>Σημείωση:</strong> Εάν αλλάξετε αυτό, όλες οι υπάρχοντες ετικέτες δεν θα δουλεύουν."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,44 @@
;; @package Conditional Content
;; @version 5.2.2
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link https://regularlabs.com
;; @copyright Copyright © 2024 Regular Labs All Rights Reserved
;; @license GNU General Public License version 2 or later
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
CONDITIONALCONTENT="Conditional Content"
CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot; something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot; something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] cannot function."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Regular Labs Library plugin is not enabled."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Regular Labs Library plugin is not installed."
COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
COC_ALTERNATIVE_CONTENT="Alternative Content"
COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when the conditions are NOT met.<br><br>Don't worry, you can change this later too."
COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
COC_BUTTON_INLINE="Use Inline Rules"
COC_CONDITION_TYPE="Use Condition"
COC_CONDITIONS="Conditions"
COC_CONTENT="Content"
COC_CONTENT_DESC="Enter the content you want to show/hide when the conditions are met.<br><br>Don't worry, you can change this later too."
COC_CONTENTS="Contents"
COC_HIDE_TAG="Hide Tag"
COC_INLINE_RULES="Inline Rules"
COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="The word to be used in the tags.<br><br><strong>Note:</strong> If you change this, all existing tags will not work anymore."
COC_TAG_TYPE="Show or Hide"
COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
COC_USE_EDITORS="Use Editors"
COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."
CON_CONSIDER_CONDITION_SET="You are using multiple inline Condition Rules. Consider creating a Condition Set instead.<br><br>Condition Sets allow you to group multiple Condition Rules into one and are reusable."
CON_MORE_IN_CONDITION_SET="There are more Condition Rules and settings available when you create a Condition Set instead."
CON_MORE_IN_PRO="There are a lot more Condition Rules available in [[%1:start link%]]the Pro version of Conditional Content[[%2:end link%]]."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 5.2.2
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link https://regularlabs.com
;; @copyright Copyright © 2024 Regular Labs All Rights Reserved
;; @license GNU General Public License version 2 or later
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] تابغ نمی تواند عمل کند"
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="پلاگین Regular Labs Library فعال نمی باشد"
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="پلاگین Regular Labs Library نصب نمی باشد"
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
COC_CONDITIONS="شرایط"
COC_CONTENT="محتواي"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="کلمه ای که از آن در تگ ها استفاده شود .<br><br><strong>توجه :</strong> اگر این متن را تغییر دهید تمامی برچسب ها کار نخواهند کرد .."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] nem működik."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="A Regular Labs keretrendszer beépülőmodul nincs engedélyezve."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Nincs telepítve a Regular Labs Library beépülőmodul."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
COC_CONDITIONS="feltételek"
COC_CONTENT="Tartalom"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
; COC_TAG_DESC="The word to be used in the tags.<br><br><strong>Note:</strong> If you change this, all existing tags will not work anymore."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,44 @@
;; @package Conditional Content
;; @version 5.2.2
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link https://regularlabs.com
;; @copyright Copyright © 2024 Regular Labs All Rights Reserved
;; @license GNU General Public License version 2 or later
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - Limita il contenuto Joomla! in base alle tue condizioni."
CONDITIONALCONTENT="Conditional Content"
CONDITIONALCONTENT_DESC="Con Conditional Content puoi limitare il tuo contenuto (una parte) in base alle tue condizioni.<br><br>Inserendo i tag attorno ai contenuti, puoi limitare il contenuto a/per chiunque o qualunque cosa desideri. La sintassi è semplice:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot; something=&quot;else&quot;}Il Tuo Contenuto...{/show}</span><br>O:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot; something=&quot;else&quot;}Il Tuo Contenuto...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] non può funzionare."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Il plugin Regular Labs Library non è abilitato."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Il plugin Regular Labs Library non è installato."
COC_ALL_DESC="Il contenuto verrà visualizzato/nascosto se <strong>TUTTE</strong> le condizioni seguenti sono soddisfatte."
COC_ALTERNATIVE_CONTENT="Contenuto Alternativo"
COC_ALTERNATIVE_CONTENT_DESC="Inserisci il contenuto che desideri mostrare/nascondere quando le condizioni NON sono soddisfatte.<br><br>Non ti preoccupare, puoi cambiarlo anche in seguito."
COC_ANY_DESC="Il contenuto verrà visualizzato/nascosto se viene soddisfatta <strong>QUALSIASI</strong>(una o più) condizioni di seguito.<br>I gruppi di condizione in cui è selezionato 'Ignora' verranno ignorati."
; COC_BUTTON_INLINE="Use Inline Rules"
; COC_CONDITION_TYPE="Use Condition"
COC_CONDITIONS="Condizioni"
COC_CONTENT="Contenuto"
COC_CONTENT_DESC="Inserisci il contenuto che vuoi mostrare/nascondere quando le condizioni sono soddisfatte.<br><br>Non ti preoccupare, puoi cambiarlo anche in seguito."
COC_CONTENTS="Contenuti"
COC_HIDE_TAG="Nascondi Tag"
; COC_INLINE_RULES="Inline Rules"
COC_MATCHING_METHOD_DESC="Dovrebbero essere soddisfatte tutte o eventuali condizioni?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
COC_SHOW_TAG="Mostra Tag"
COC_TAG_DESC="La parola utilizzata nei tags.<br><br><strong>Nota:</strong>Se modifichi questo parametro, tutti i tags esistenti non funzioneranno più."
COC_TAG_TYPE="Mostra o Nascondi"
COC_TAG_TYPE_DESC="Seleziona se desideri che il contenuto venga visualizzato o nascosto in base alle condizioni specificate."
COC_USE_ALTERNATIVE_CONTENT="Usa Contenuto Alternativo"
COC_USE_ALTERNATIVE_CONTENT_DESC="Selezionare per utilizzare un contenuto alternativo che si desidera mostrare/nascondere quando le condizioni sottostanti NON sono soddisfatte."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."
; CON_CONSIDER_CONDITION_SET="You are using multiple inline Condition Rules. Consider creating a Condition Set instead.<br><br>Condition Sets allow you to group multiple Condition Rules into one and are reusable."
; CON_MORE_IN_CONDITION_SET="There are more Condition Rules and settings available when you create a Condition Set instead."
; CON_MORE_IN_PRO="There are a lot more Condition Rules available in [[%1:start link%]]the Pro version of Conditional Content[[%2:end link%]]."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 5.2.2
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link https://regularlabs.com
;; @copyright Copyright © 2024 Regular Labs All Rights Reserved
;; @license GNU General Public License version 2 or later
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - Limita il contenuto Joomla! in base alle tue condizioni."
CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] は機能しません。"
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Regular Labs Library プラグインが有効になっていません。"
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Regular Labs フレームワークプラグインがインストールされていません。"
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
COC_CONDITIONS="条件"
COC_CONTENT="コンテンツ"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="タグに使用される単語です。<br><br><strong>注意:</strong> これを変更すると、全ての既存タグが動作しなくなります。"
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] negali funkcionuoti."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Regular Labs Library įskiepis nėra įgalintas."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Regular Labs Library įskiepis nėra įdiegtas."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
; COC_CONDITIONS="Conditions"
COC_CONTENT="Turinys"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="Žodis, naudojamas žymei.<br><br><strong>Pastaba:</strong> Jei pakeisite šį žodį, visas esamos žymės daugiau nebeveiks."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] vil ikke fungere."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Regular Labs Rammeverk programtillegg er ikke aktivert."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Regular Labs Plugin er ikke installert."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
COC_CONDITIONS="Betingelse"
COC_CONTENT="Innhold"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="Ord som skal anvendes i kodene.<br><br><strong>OBS!:</strong> Hvis du endrer dette, vil ingen nåværende koder virke."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] kan niet functioneren."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Regular Labs bibliotheek plugin is niet geactiveerd"
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Regular Labs bibliotheek plugin is niet geïnstalleerd"
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
; COC_CONDITIONS="Conditions"
COC_CONTENT="Inhoud"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="Het woord om te gebruiken in de tags.<br><br><strong>Let op:</strong> Als u dit wijzigt, zullen alle bestaande tags niet meer werken."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] nu poate functiona."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Regular Labs Library plugin neactivat."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Regular Labs Library plugin neinstalat."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
COC_CONDITIONS="Conditii"
COC_CONTENT="Continut"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="Cuvantul utilizat in tag.<br><br><strong>Nota:</strong> Daca-l schimbati, toate tagurile existente nu vor mai functiona."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] nemôže fungovať."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Regular Labs Library doplnok nie je aktivovaný/povolený."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Regular Labs Library doplnok nie je nainštalovaný."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
; COC_CONDITIONS="Conditions"
COC_CONTENT="Polia obsahu"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="Slovo použité v Značkách.<br><br><strong>Poznámka:</strong> Ak toto zmeníte, všetky existujúce značky už viac nebudú fungovať."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] ne more delovati."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Regular Labs Library vtičnik ni omogočen."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Regular Labs Library vtičnik ni nameščen."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
; COC_CONDITIONS="Conditions"
COC_CONTENT="Vsebina"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="Beseda, ki se uporabljajo v oznake.<br><br><strong>Opomba:</strong> Če spremenite to, vse obstoječe oznake ne bodo več delovale."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="ไม่สามารถใช้งาน [[%1:extension name%]] ได้."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Regular Labs Library plugin ยังไม่ได้เปิดใช้งาน."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Regular Labs Library plugin ยังไม่ได้ถูกติดตั้ง."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
COC_CONDITIONS="เงื่อนไข"
COC_CONTENT="เนื้อหา"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="ข้อความสำหรับใช้ในแท็กป้ายกำกับ.<br><br><strong>หมายเหตุ:</strong> หากคุณเปลี่ยนแปลงแก้ไขส่วนนี้, แท็กป้ายกำกับทั้งหมดที่เคยมีอยู่จะไม่สามารถใช้งานได้อีกต่อไป."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] không thể hoạt động."
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Plugin Regular Labs Library không được bật."
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Plugin Regular Labs Library không được cài đặt."
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
COC_CONDITIONS="Điều kiện"
COC_CONTENT="Nội dung"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
; COC_TAG_DESC="The word to be used in the tags.<br><br><strong>Note:</strong> If you change this, all existing tags will not work anymore."
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,38 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"
; CONDITIONALCONTENT_DESC="With Conditional Content you can restrict (parts of) your content based on your conditions.<br><br>By placing tags around your content, you can restrict the content to/from whoever or whenever you want. The syntax simply looks like:<br><span class=&quot;rl-code rl-code-block&quot;>{show usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/show}</span><br>Or:<br><span class=&quot;rl-code rl-code-block&quot;>{hide usergroup=&quot;Registered&quot;something=&quot;else&quot;}Your content...{/hide}</span>"
COC_EXTENSION_CAN_NOT_FUNCTION="[[%1:extension name%]] 無法動作。"
COC_REGULAR_LABS_LIBRARY_NOT_ENABLED="Regular Labs Library 外掛未啟用。"
COC_REGULAR_LABS_LIBRARY_NOT_INSTALLED="Regular Labs Library 外掛未安裝。"
; COC_ALL_DESC="The content will be shown/hidden if <strong>ALL</strong> of below conditions are met."
; COC_ALTERNATIVE_CONTENT="Alternative Content"
; COC_ALTERNATIVE_CONTENT_DESC="Enter the content you want to show/hide when below conditions are NOT met.<br><br>Don't worry, you can change this later too."
; COC_ANY_DESC="The content will be shown/hidden if <strong>ANY</strong> (one or more) of below conditions are met.<br>Condition groups where 'Ignore' is selected will be ignored."
; COC_CONDITIONS="Conditions"
COC_CONTENT="內容"
; COC_CONTENT_DESC="Enter the content you want to show/hide when below conditions are met.<br><br>Don't worry, you can change this later too."
; COC_CONTENTS="Contents"
; COC_HIDE_TAG="Hide Tag"
; COC_MATCHING_METHOD_DESC="Should all or any conditions be met?<br><br><strong>[[%1:all%]]</strong><br>[[%2:all description%]]<br><br><strong>[[%3:any%]]</strong><br>[[%4:any description%]]"
; COC_SHOW_TAG="Show Tag"
COC_TAG_DESC="標籤中所用的單字。<br><br><strong>請注意:</strong> 如果您變更此,所有現有標籤將不再動作。"
; COC_TAG_TYPE="Show or Hide"
; COC_TAG_TYPE_DESC="Select whether you want the content to be shown or hidden according to the specified conditions."
; COC_USE_ALTERNATIVE_CONTENT="Use Alternative Content"
; COC_USE_ALTERNATIVE_CONTENT_DESC="Select to use an alternative content that you want to show/hide when below conditions are NOT met."
; COC_USE_EDITORS="Use Editors"
; COC_USE_EDITORS_DESC="Enable to use the Joomla editor for the content and alternative content fields in the editor button popup."

View File

@ -0,0 +1,13 @@
;; @package Conditional Content
;; @version 3.1.0
;;
;; @author Peter van Westen <info@regularlabs.com>
;; @link http://regularlabs.com
;; @copyright Copyright © 2022 Regular Labs All Rights Reserved
;; @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
;;
;; @translate Want to help with translations? See: https://regularlabs.com/translate
; PLG_SYSTEM_CONDITIONALCONTENT="System - Regular Labs - Conditional Content"
; PLG_SYSTEM_CONDITIONALCONTENT_DESC="Conditional Content - restrict content based on your conditions in Joomla!"
; CONDITIONALCONTENT="Conditional Content"

View File

@ -0,0 +1,26 @@
<?php
/**
* @package Conditional Content
* @version 4.0.0
*
* @author Peter van Westen <info@regularlabs.com>
* @link http://regularlabs.com
* @copyright Copyright © 2022 Regular Labs All Rights Reserved
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
*/
defined('_JEXEC') or die;
require_once __DIR__ . '/script.install.helper.php';
class PlgSystemConditionalContentInstallerScript extends PlgSystemConditionalContentInstallerScriptHelper
{
public $alias = 'conditionalcontent';
public $extension_type = 'plugin';
public $name = 'CONDITIONALCONTENT';
public function uninstall($adapter)
{
$this->uninstallPlugin($this->extname, 'editors-xtd');
}
}

View File

@ -0,0 +1,26 @@
<?php
/**
* @package Conditional Content
* @version 2.7.1
*
* @author Peter van Westen <info@regularlabs.com>
* @link http://www.regularlabs.com
* @copyright Copyright © 2020 Regular Labs All Rights Reserved
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
*/
namespace RegularLabs\Plugin\System\ConditionalContent;
defined('_JEXEC') or die;
class Clean
{
/**
* Just in case you can't figure the method name out: this cleans the left-over junk
*/
public static function cleanLeftoverJunk(&$string)
{
Protect::unprotectTags($string);
//RL_Protect::removeInlineComments($string, 'ConditionalContent');
}
}

View File

@ -0,0 +1,72 @@
<?php
/**
* @package Conditional Content
* @version 2.7.1
*
* @author Peter van Westen <info@regularlabs.com>
* @link http://www.regularlabs.com
* @copyright Copyright © 2020 Regular Labs All Rights Reserved
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
*/
namespace RegularLabs\Plugin\System\ConditionalContent;
defined('_JEXEC') or die;
use Joomla\CMS\Factory as JFactory;
use RegularLabs\Library\Article as RL_Article;
use RegularLabs\Library\Document as RL_Document;
use RegularLabs\Library\Html as RL_Html;
/**
* Plugin that replaces stuff
*/
class Helper
{
public function onContentPrepare($context, &$article, &$params)
{
$area = isset($article->created_by) ? 'article' : 'other';
$context = (($params instanceof \JRegistry) && $params->get('rl_search')) ? 'com_search.' . $params->get('readmore_limit') : $context;
RL_Article::process($article, $context, $this, 'replaceTags', [$area, $context]);
}
public function onAfterDispatch()
{
if ( ! $buffer = RL_Document::getBuffer())
{
return;
}
if ( ! Replace::replaceTags($buffer, 'component'))
{
return;
}
RL_Document::setBuffer($buffer);
}
public function onAfterRender()
{
$html = JFactory::getApplication()->getBody();
if ($html == '')
{
return;
}
// only do stuff in body
list($pre, $body, $post) = RL_Html::getBody($html);
Replace::replaceTags($body, 'body');
$html = $pre . $body . $post;
Clean::cleanLeftoverJunk($html);
JFactory::getApplication()->setBody($html);
}
public function replaceTags(&$string, $area = 'article', $context = '')
{
Replace::replaceTags($string, $area, $context);
}
}

View File

@ -0,0 +1,146 @@
<?php
/**
* @package Conditional Content
* @version 5.2.2
*
* @author Peter van Westen <info@regularlabs.com>
* @link https://regularlabs.com
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
* @license GNU General Public License version 2 or later
*/
namespace RegularLabs\Plugin\System\ConditionalContent;
defined('_JEXEC') or die;
use RegularLabs\Library\Parameters as RL_Parameters;
use RegularLabs\Library\PluginTag as RL_PluginTag;
use RegularLabs\Library\RegEx as RL_RegEx;
class Params
{
protected static $params = null;
protected static $regexes = [];
public static function get()
{
if ( ! is_null(self::$params))
{
return self::$params;
}
$params = RL_Parameters::getPlugin('conditionalcontent');
$params->tag_show = RL_PluginTag::clean($params->tag_show);
$params->tag_hide = RL_PluginTag::clean($params->tag_hide);
self::$params = $params;
return self::$params;
}
public static function getRegex()
{
if (isset(self::$regexes['main']))
{
return self::$regexes['main'];
}
$params = self::get();
// Tag character start and end
[$tag_start, $tag_end] = Params::getTagCharacters();
$pre = RL_PluginTag::getRegexSurroundingTagsPre();
$post = RL_PluginTag::getRegexSurroundingTagsPost();
$inside_tag = RL_PluginTag::getRegexInsideTag($tag_start, $tag_end);
$spaces = RL_PluginTag::getRegexSpaces();
$tag_start = RL_RegEx::quote($tag_start);
$tag_end = RL_RegEx::quote($tag_end);
self::$regexes['main'] =
'(?<start_pre>' . $pre . ')'
. $tag_start . '(?<tag>' . RL_RegEx::quote($params->tag_show) . '|' . RL_RegEx::quote($params->tag_hide) . ')'
. '(?<data>(?:(?:' . $spaces . '|<)' . $inside_tag . ')?)' . $tag_end
. '(?<start_post>' . $post . ')'
. '(?<content>.*?)'
. '(?<end_pre>' . $pre . ')'
. $tag_start . '/\2' . $tag_end
. '(?<end_post>' . $post . ')';
return self::$regexes['main'];
}
public static function getRegexElse($type = 'show')
{
if (isset(self::$regexes[$type]))
{
return self::$regexes[$type];
}
$params = self::get();
// Tag character start and end
[$tag_start, $tag_end] = Params::getTagCharacters();
$pre = RL_PluginTag::getRegexSurroundingTagsPre();
$post = RL_PluginTag::getRegexSurroundingTagsPost();
$inside_tag = RL_PluginTag::getRegexInsideTag($tag_start, $tag_end);
$spaces = RL_PluginTag::getRegexSpaces();
$tag_start = RL_RegEx::quote($tag_start);
$tag_end = RL_RegEx::quote($tag_end);
$type = $type === 'hide' ? $params->tag_hide : $params->tag_show;
self::$regexes[$type] =
'(?<else_pre>' . $pre . ')'
. $tag_start . RL_RegEx::quote($type) . '-else'
. '(?<data>(?:(?:' . $spaces . '|<)' . $inside_tag . ')?)' . $tag_end
. '(?<else_post>' . $post . ')';
return self::$regexes[$type];
}
public static function getTagCharacters()
{
$params = self::get();
if ( ! isset($params->tag_character_start))
{
self::setTagCharacters();
}
return [$params->tag_character_start, $params->tag_character_end];
}
public static function getTags($only_start_tags = false)
{
$params = self::get();
[$tag_start, $tag_end] = self::getTagCharacters();
$tags = [
[
$tag_start . $params->tag_show,
$tag_start . $params->tag_hide,
],
[
$tag_start . '/' . $params->tag_show . $tag_end,
$tag_start . '/' . $params->tag_hide . $tag_end,
],
];
return $only_start_tags ? $tags[0] : $tags;
}
public static function setTagCharacters()
{
$params = self::get();
[self::$params->tag_character_start, self::$params->tag_character_end] = explode('.', $params->tag_characters);
}
}

View File

@ -0,0 +1,402 @@
<?php
/**
* @package Conditional Content
* @version 2.7.1
*
* @author Peter van Westen <info@regularlabs.com>
* @link http://www.regularlabs.com
* @copyright Copyright © 2020 Regular Labs All Rights Reserved
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
*/
/*
* This class is used as template (extend) for most Regular Labs plugins
* This class is not placed in the Regular Labs Library as a re-usable class because
* it also needs to be working when the Regular Labs Library is not installed
*/
namespace RegularLabs\Plugin\System\ConditionalContent;
defined('_JEXEC') or die;
if (is_file(JPATH_LIBRARIES . '/regularlabs/autoload.php'))
{
require_once JPATH_LIBRARIES . '/regularlabs/autoload.php';
}
use Joomla\CMS\Factory as JFactory;
use Joomla\CMS\Installer\Installer as JInstaller;
use Joomla\CMS\Language\Text as JText;
use Joomla\CMS\Plugin\CMSPlugin as JPlugin;
use Joomla\CMS\Plugin\PluginHelper as JPluginHelper;
use ReflectionMethod;
use RegularLabs\Library\Document as RL_Document;
use RegularLabs\Library\Language as RL_Language;
use RegularLabs\Library\Protect as RL_Protect;
class Plugin extends JPlugin
{
public $_alias = '';
public $_title = '';
public $_lang_prefix = '';
public $_has_tags = false;
public $_enable_in_frontend = true;
public $_enable_in_admin = false;
public $_can_disable_by_url = true;
public $_disable_on_components = false;
public $_protected_formats = [];
public $_page_types = [];
private $_init = false;
private $_pass = null;
private $_helper = null;
protected function run()
{
if ( ! $this->passChecks())
{
return false;
}
if ( ! $this->getHelper())
{
return false;
}
$caller = debug_backtrace()[1];
if (empty($caller))
{
return false;
}
$event = $caller['function'];
if ( ! method_exists($this->_helper, $event))
{
return false;
}
$reflect = new ReflectionMethod($this->_helper, $event);
$parameters = $reflect->getParameters();
$arguments = [];
// Check if arguments should be passed as reference or not
foreach ($parameters as $count => $parameter)
{
if ($parameter->isPassedByReference())
{
$arguments[] = &$caller['args'][$count];
continue;
}
$arguments[] = $caller['args'][$count];
}
// Work-around for K2 stuff :(
if ($event == 'onContentPrepare'
&& empty($arguments[1]->id)
&& strpos($arguments[0], 'com_k2') === 0
)
{
return false;
}
return call_user_func_array([$this->_helper, $event], $arguments);
}
/**
* Create the helper object
*
* @return object|null The plugins helper object
*/
private function getHelper()
{
// Already initialized, so return
if ($this->_init)
{
return $this->_helper;
}
$this->_init = true;
RL_Language::load('plg_' . $this->_type . '_' . $this->_name);
$this->init();
$this->_helper = new Helper;
return $this->_helper;
}
private function passChecks()
{
if ( ! is_null($this->_pass))
{
return $this->_pass;
}
$this->_pass = false;
if ( ! $this->isFrameworkEnabled())
{
return false;
}
if ( ! self::passPageTypes())
{
return false;
}
// allow in frontend?
if ( ! $this->_enable_in_frontend
&& ! RL_Document::isAdmin())
{
return false;
}
// allow in admin?
if ( ! $this->_enable_in_admin
&& RL_Document::isAdmin()
&& ( ! isset(Params::get()->enable_admin) || ! Params::get()->enable_admin))
{
return false;
}
// disabled by url?
if ($this->_can_disable_by_url
&& RL_Protect::isDisabledByUrl($this->_alias))
{
return false;
}
// disabled by component?
if ($this->_disable_on_components
&& RL_Protect::isRestrictedComponent(isset(Params::get()->disabled_components) ? Params::get()->disabled_components : [], 'component'))
{
return false;
}
// restricted page?
if (RL_Protect::isRestrictedPage($this->_has_tags, $this->_protected_formats))
{
return false;
}
if ( ! $this->extraChecks())
{
return false;
}
$this->_pass = true;
return true;
}
public function passPageTypes()
{
if (empty($this->_page_types))
{
return true;
}
if (in_array('*', $this->_page_types))
{
return true;
}
if (empty(JFactory::$document))
{
return true;
}
if (RL_Document::isFeed())
{
return in_array('feed', $this->_page_types);
}
if (RL_Document::isPDF())
{
return in_array('pdf', $this->_page_types);
}
$page_type = JFactory::getDocument()->getType();
if (in_array($page_type, $this->_page_types))
{
return true;
}
return false;
}
public function extraChecks()
{
$input = JFactory::getApplication()->input;
// Disable on Gridbox edit form: option=com_gridbox&view=gridbox
if ($input->get('option') == 'com_gridbox' && $input->get('view') == 'gridbox')
{
return false;
}
// Disable on SP PageBuilder edit form: option=com_sppagebuilder&view=form
if ($input->get('option') == 'com_sppagebuilder' && $input->get('view') == 'form')
{
return false;
}
return true;
}
public function init()
{
return;
}
/**
* Check if the Regular Labs Library is enabled
*
* @return bool
*/
private function isFrameworkEnabled()
{
if ( ! defined('REGULAR_LABS_LIBRARY_ENABLED'))
{
$this->setIsFrameworkEnabled();
}
if ( ! REGULAR_LABS_LIBRARY_ENABLED)
{
$this->throwError('REGULAR_LABS_LIBRARY_NOT_ENABLED');
}
return REGULAR_LABS_LIBRARY_ENABLED;
}
/**
* Set the define with whether the Regular Labs Library is enabled
*/
private function setIsFrameworkEnabled()
{
// Return false if Regular Labs Library is not installed
if ( ! $this->isFrameworkInstalled())
{
define('REGULAR_LABS_LIBRARY_ENABLED', false);
return;
}
if ( ! JPluginHelper::isEnabled('system', 'regularlabs'))
{
$this->throwError('REGULAR_LABS_LIBRARY_NOT_ENABLED');
define('REGULAR_LABS_LIBRARY_ENABLED', false);
return;
}
define('REGULAR_LABS_LIBRARY_ENABLED', true);
}
/**
* Check if the Regular Labs Library is installed
*
* @return bool
*/
private function isFrameworkInstalled()
{
if ( ! defined('REGULAR_LABS_LIBRARY_INSTALLED'))
{
$this->setIsFrameworkInstalled();
}
switch (REGULAR_LABS_LIBRARY_INSTALLED)
{
case 'outdated':
$this->throwError('REGULAR_LABS_LIBRARY_OUTDATED');
return false;
case 'no':
$this->throwError('REGULAR_LABS_LIBRARY_NOT_INSTALLED');
return false;
case 'yes':
default:
return true;
}
}
/**
* set the define with whether the Regular Labs Library is installed
*/
private function setIsFrameworkInstalled()
{
if (
! is_file(JPATH_PLUGINS . '/system/regularlabs/regularlabs.xml')
|| ! is_file(JPATH_LIBRARIES . '/regularlabs/autoload.php')
)
{
define('REGULAR_LABS_LIBRARY_INSTALLED', 'no');
return;
}
$plugin = JInstaller::parseXMLInstallFile(JPATH_PLUGINS . '/system/regularlabs/regularlabs.xml');
$library = JInstaller::parseXMLInstallFile(JPATH_LIBRARIES . '/regularlabs/regularlabs.xml');
if (empty($plugin) || empty($library))
{
define('REGULAR_LABS_LIBRARY_INSTALLED', 'no');
return;
}
if (version_compare($plugin['version'], '20.7.20564', '<')
|| version_compare($library['version'], '20.7.20564', '<'))
{
define('REGULAR_LABS_LIBRARY_INSTALLED', 'outdated');
return;
}
define('REGULAR_LABS_LIBRARY_INSTALLED', 'yes');
}
/**
* Place an error in the message queue
*/
private function throwError($error)
{
// Return if page is not an admin page or the admin login page
if (
! JFactory::getApplication()->isClient('administrator')
|| JFactory::getUser()->get('guest')
)
{
return;
}
// load the admin language file
JFactory::getLanguage()->load('plg_' . $this->_type . '_' . $this->_name, JPATH_PLUGINS . '/' . $this->_type . '/' . $this->_name);
$text = JText::sprintf($this->_lang_prefix . '_' . $error, JText::_($this->_title));
$text = JText::_($text) . ' ' . JText::sprintf($this->_lang_prefix . '_EXTENSION_CAN_NOT_FUNCTION', JText::_($this->_title));
// Check if message is not already in queue
$messagequeue = JFactory::getApplication()->getMessageQueue();
foreach ($messagequeue as $message)
{
if ($message['message'] == $text)
{
return;
}
}
JFactory::getApplication()->enqueueMessage($text, 'error');
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* @package Conditional Content
* @version 5.2.2
*
* @author Peter van Westen <info@regularlabs.com>
* @link https://regularlabs.com
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
* @license GNU General Public License version 2 or later
*/
namespace RegularLabs\Plugin\System\ConditionalContent;
defined('_JEXEC') or die;
use RegularLabs\Library\Protect as RL_Protect;
class Protect
{
static $name = 'ConditionalContent';
public static function _(&$string)
{
RL_Protect::protectHtmlCommentTags($string);
RL_Protect::protectFields($string, Params::getTags(true));
RL_Protect::protectSourcerer($string);
}
public static function protectTags(&$string)
{
RL_Protect::protectTags($string, Params::getTags(true));
}
public static function unprotectTags(&$string)
{
RL_Protect::unprotectTags($string, Params::getTags(true));
}
/**
* Wrap the comment in comment tags
*
* @param string $comment
*
* @return string
*/
public static function wrapInCommentTags($comment)
{
return RL_Protect::wrapInCommentTags(self::$name, $comment);
}
}

View File

@ -0,0 +1,230 @@
<?php
/**
* @package Conditional Content
* @version 5.2.2
*
* @author Peter van Westen <info@regularlabs.com>
* @link https://regularlabs.com
* @copyright Copyright © 2024 Regular Labs All Rights Reserved
* @license GNU General Public License version 2 or later
*/
namespace RegularLabs\Plugin\System\ConditionalContent;
defined('_JEXEC') or die;
use RegularLabs\Component\Conditions\Administrator\Api\Conditions as Api_Conditions;
use RegularLabs\Library\Html as RL_Html;
use RegularLabs\Library\PluginTag as RL_PluginTag;
use RegularLabs\Library\Protect as RL_Protect;
use RegularLabs\Library\RegEx as RL_RegEx;
use RegularLabs\Library\StringHelper as RL_String;
class Replace
{
static $article;
public static function replaceTags(&$string, $area = 'article', $context = '', $article = null)
{
self::$article = $article;
if ( ! is_string($string) || $string == '')
{
return false;
}
if ( ! RL_String::contains($string, Params::getTags(true)))
{
return false;
}
// Check if tags are in the text snippet used for the search component
if (str_starts_with($context, 'com_search.'))
{
$limit = explode('.', $context, 2);
$limit = (int) array_pop($limit);
$string_check = substr($string, 0, $limit);
if ( ! RL_String::contains($string_check, Params::getTags(true)))
{
return false;
}
}
$params = Params::get();
$regex = Params::getRegex();
// allow in component?
if (RL_Protect::isRestrictedComponent($params->disabled_components ?? [], $area))
{
Protect::_($string);
$string = RL_RegEx::replace($regex, '\2', $string);
RL_Protect::unprotect($string);
return true;
}
Protect::_($string);
[$start_tags, $end_tags] = Params::getTags();
[$pre_string, $string, $post_string] = RL_Html::getContentContainingSearches(
$string,
$start_tags,
$end_tags
);
RL_RegEx::matchAll($regex, $string, $matches);
foreach ($matches as $match)
{
self::replaceTag($string, $match);
}
$string = $pre_string . $string . $post_string;
RL_Protect::unprotect($string);
return true;
}
private static function getContent($match)
{
$params = Params::get();
$parts = self::getParts($match);
foreach ($parts as $part)
{
$attributes = self::getTagValues($part->data);
unset($attributes->trim);
$has_access = self::hasAccess($attributes);
$has_access = $match['tag'] == $params->tag_hide ? ! $has_access : $has_access;
if ($has_access)
{
return $part->content;
}
}
return '';
}
private static function getParts($data)
{
$params = Params::get();
$regex = Params::getRegexElse($data['tag'] == $params->tag_hide ? 'hide' : 'show');
RL_RegEx::matchAll($regex, $data['content'], $matches, null, PREG_OFFSET_CAPTURE);
if (empty($matches) || empty($matches[0]))
{
return [
(object) [
'data' => $data['data'],
'content' => $data['content'],
],
];
}
$parts = [
(object) [
'data' => $data['data'],
'content' => substr($data['content'], 0, $matches[0][0][1]),
],
];
foreach ($matches[0] as $i => $match)
{
$offset = $match[1] + strlen($match[0]);
$next_pos = isset($matches[0][$i + 1])
? $matches[0][$i + 1][1]
: strlen($data['content']);
$length = $next_pos - $offset;
$parts[] = (object) [
'data' => $matches['data'][$i][0],
'content' => substr($data['content'], $offset, $length),
];
}
return $parts;
}
private static function getTagValues($string)
{
$string = html_entity_decode($string);
return RL_PluginTag::getAttributesFromString($string, null, [], false);
}
private static function hasAccess($attributes)
{
if (empty($attributes))
{
return true;
}
$conditions = [
'menu__menu_item',
'menu__home_page',
'date__date',
'visitor__access_level',
'visitor__user_group',
'visitor__language',
'agent__device',
'other__condition',
];
return (new Api_Conditions(self::$article))
->setConditionByAttributes($attributes)
->pass($conditions);
}
private static function replaceTag(&$string, $match)
{
$params = Params::get();
$content = self::getContent($match);
$attributes = self::getTagValues($match['data']);
$trim = $attributes->trim ?? $params->trim;
if ($trim)
{
$tags = RL_Html::cleanSurroundingTags([
'start_pre' => $match['start_pre'],
'start_post' => $match['start_post'],
], ['p', 'span', 'div']);
$match = [...$match, ...$tags];
$tags = RL_Html::cleanSurroundingTags([
'end_pre' => $match['end_pre'],
'end_post' => $match['end_post'],
], ['p', 'span', 'div']);
$match = [...$match, ...$tags];
$tags = RL_Html::cleanSurroundingTags([
'start_pre' => $match['start_pre'],
'end_post' => $match['end_post'],
], ['p', 'span', 'div']);
$match = [...$match, ...$tags];
}
if ($params->place_comments)
{
$content = Protect::wrapInCommentTags($content);
}
$replace = $match['start_pre'] . $match['start_post'] . $content . $match['end_pre'] . $match['end_post'];
$string = str_replace($match[0], $replace, $string);
}
}

View File

@ -0,0 +1,262 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_debug</name>
<author>Joomla! Project</author>
<creationDate>2006-12</creationDate>
<copyright>(C) 2006 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_DEBUG_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\System\Debug</namespace>
<files>
<folder plugin="debug">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_system_debug.ini</language>
<language tag="en-GB">language/en-GB/plg_system_debug.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="refresh_assets"
type="radio"
label="PLG_DEBUG_FIELD_REFRESH_ASSETS_LABEL"
description="PLG_DEBUG_FIELD_REFRESH_ASSETS_DESC"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="filter_groups"
type="usergrouplist"
label="PLG_DEBUG_FIELD_ALLOWED_GROUPS_LABEL"
multiple="true"
layout="joomla.form.field.list-fancy-select"
filter="intarray"
/>
<field
name="memory"
type="radio"
label="PLG_DEBUG_FIELD_MEMORY_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="request"
type="radio"
label="PLG_DEBUG_FIELD_REQUEST_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="session"
type="radio"
label="PLG_DEBUG_FIELD_SESSION_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="profile"
type="radio"
label="PLG_DEBUG_FIELD_PROFILING_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="queries"
type="radio"
label="PLG_DEBUG_FIELD_QUERIES_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="query_traces"
type="radio"
label="PLG_DEBUG_FIELD_QUERY_TRACES_LABEL"
layout="joomla.form.field.radio.switcher"
default="0"
showon="queries:1"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="query_profiles"
type="radio"
label="PLG_DEBUG_FIELD_QUERY_PROFILES_LABEL"
layout="joomla.form.field.radio.switcher"
default="0"
showon="queries:1"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="query_explains"
type="radio"
label="PLG_DEBUG_FIELD_QUERY_EXPLAINS_LABEL"
layout="joomla.form.field.radio.switcher"
default="0"
showon="queries:1"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="track_request_history"
type="radio"
label="PLG_DEBUG_FIELD_TRACK_REQUEST_HISTORY_LABEL"
description="PLG_DEBUG_FIELD_TRACK_REQUEST_HISTORY_DESC"
layout="joomla.form.field.radio.switcher"
default="0"
filter="integer"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
</fieldset>
<fieldset
name="language"
label="PLG_DEBUG_LANGUAGE_FIELDSET_LABEL"
>
<field
name="language_errorfiles"
type="radio"
label="PLG_DEBUG_FIELD_LANGUAGE_ERRORFILES_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="language_files"
type="radio"
label="PLG_DEBUG_FIELD_LANGUAGE_FILES_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="language_strings"
type="radio"
label="PLG_DEBUG_FIELD_LANGUAGE_STRING_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="strip-first"
type="radio"
label="PLG_DEBUG_FIELD_STRIP_FIRST_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="strip-prefix"
type="textarea"
label="PLG_DEBUG_FIELD_STRIP_PREFIX_LABEL"
description="PLG_DEBUG_FIELD_STRIP_PREFIX_DESC"
cols="30"
rows="4"
/>
<field
name="strip-suffix"
type="textarea"
label="PLG_DEBUG_FIELD_STRIP_SUFFIX_LABEL"
description="PLG_DEBUG_FIELD_STRIP_SUFFIX_DESC"
cols="30"
rows="4"
/>
</fieldset>
<fieldset
name="logging"
label="PLG_DEBUG_LOGGING_FIELDSET_LABEL"
>
<field
name="logs"
type="radio"
label="PLG_DEBUG_FIELD_LOGS_LABEL"
layout="joomla.form.field.radio.switcher"
default="1"
>
<option value="0">JHIDE</option>
<option value="1">JSHOW</option>
</field>
<field
name="log-deprecated-core"
type="radio"
label="PLG_DEBUG_FIELD_LOG_DEPRECATED_CORE_LABEL"
layout="joomla.form.field.radio.switcher"
default="0"
filter="integer"
showon="logs:1"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,46 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.debug
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\System\Debug\Extension\Debug;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.4.0
*/
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
return new Debug(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('system', 'debug'),
Factory::getApplication(),
$container->get(DatabaseInterface::class)
);
}
);
}
};

View File

@ -0,0 +1,113 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\Renderable;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* AbstractDataCollector
*
* @since 4.0.0
*/
abstract class AbstractDataCollector extends DataCollector implements Renderable
{
/**
* Parameters.
*
* @var Registry
* @since 4.0.0
*/
protected $params;
/**
* The default formatter.
*
* @var DataFormatter
* @since 4.0.0
*/
public static $defaultDataFormatter;
/**
* AbstractDataCollector constructor.
*
* @param Registry $params Parameters.
*
* @since 4.0.0
*/
public function __construct(Registry $params)
{
$this->params = $params;
}
/**
* Get a data formatter.
*
* @since 4.0.0
* @return DataFormatter
*/
public function getDataFormatter(): DataFormatter
{
if ($this->dataFormater === null) {
$this->dataFormater = self::getDefaultDataFormatter();
}
return $this->dataFormater;
}
/**
* Returns the default data formatter
*
* @since 4.0.0
* @return DataFormatter
*/
public static function getDefaultDataFormatter(): DataFormatter
{
if (self::$defaultDataFormatter === null) {
self::$defaultDataFormatter = new DataFormatter();
}
return self::$defaultDataFormatter;
}
/**
* Strip the Joomla! root path.
*
* @param string $path The path.
*
* @return string
*
* @since 4.0.0
*/
public function formatPath($path): string
{
return $this->getDataFormatter()->formatPath($path);
}
/**
* Format a string from back trace.
*
* @param array $call The array to format
*
* @return string
*
* @since 4.0.0
*/
public function formatCallerInfo(array $call): string
{
return $this->getDataFormatter()->formatCallerInfo($call);
}
}

View File

@ -0,0 +1,217 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug\DataCollector;
use DebugBar\DataCollector\AssetProvider;
use Joomla\CMS\Application\AdministratorApplication;
use Joomla\CMS\Application\SiteApplication;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\User\User;
use Joomla\Plugin\System\Debug\AbstractDataCollector;
use Joomla\Registry\Registry;
use Psr\Http\Message\ResponseInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* InfoDataCollector
*
* @since 4.0.0
*/
class InfoCollector extends AbstractDataCollector implements AssetProvider
{
/**
* Collector name.
*
* @var string
* @since 4.0.0
*/
private $name = 'info';
/**
* Request ID.
*
* @var string
* @since 4.0.0
*/
private $requestId;
/**
* InfoDataCollector constructor.
*
* @param Registry $params Parameters
* @param string $requestId Request ID
*
* @since 4.0.0
*/
public function __construct(Registry $params, $requestId)
{
$this->requestId = $requestId;
parent::__construct($params);
}
/**
* Returns the unique name of the collector
*
* @since 4.0.0
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* Returns a hash where keys are control names and their values
* an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()}
*
* @since 4.0.0
* @return array
*/
public function getWidgets(): array
{
return [
'info' => [
'icon' => 'info-circle',
'title' => 'J! Info',
'widget' => 'PhpDebugBar.Widgets.InfoWidget',
'map' => $this->name,
'default' => '{}',
],
];
}
/**
* Returns an array with the following keys:
* - base_path
* - base_url
* - css: an array of filenames
* - js: an array of filenames
*
* @since 4.0.0
* @return array
*/
public function getAssets(): array
{
return [
'js' => Uri::root(true) . '/media/plg_system_debug/widgets/info/widget.min.js',
'css' => Uri::root(true) . '/media/plg_system_debug/widgets/info/widget.min.css',
];
}
/**
* Called by the DebugBar when data needs to be collected
*
* @since 4.0.0
*
* @return array Collected data
*/
public function collect(): array
{
/** @type SiteApplication|AdministratorApplication $application */
$application = Factory::getApplication();
$model = $application->bootComponent('com_admin')
->getMVCFactory()->createModel('Sysinfo', 'Administrator');
return [
'phpVersion' => PHP_VERSION,
'joomlaVersion' => JVERSION,
'requestId' => $this->requestId,
'identity' => $this->getIdentityInfo($application->getIdentity()),
'response' => $this->getResponseInfo($application->getResponse()),
'template' => $this->getTemplateInfo($application->getTemplate(true)),
'database' => $this->getDatabaseInfo($model->getInfo()),
];
}
/**
* Get Identity info.
*
* @param User $identity The identity.
*
* @since 4.0.0
*
* @return array
*/
private function getIdentityInfo(User $identity): array
{
if (!$identity->id) {
return ['type' => 'guest'];
}
return [
'type' => 'user',
'id' => $identity->id,
'name' => $identity->name,
'username' => $identity->username,
];
}
/**
* Get response info.
*
* @param ResponseInterface $response The response.
*
* @since 4.0.0
*
* @return array
*/
private function getResponseInfo(ResponseInterface $response): array
{
return [
'status_code' => $response->getStatusCode(),
];
}
/**
* Get template info.
*
* @param object $template The template.
*
* @since 4.0.0
*
* @return array
*/
private function getTemplateInfo($template): array
{
return [
'template' => $template->template ?? '',
'home' => $template->home ?? '',
'id' => $template->id ?? '',
];
}
/**
* Get database info.
*
* @param array $info General information.
*
* @since 4.0.0
*
* @return array
*/
private function getDatabaseInfo(array $info): array
{
return [
'dbserver' => $info['dbserver'] ?? '',
'dbversion' => $info['dbversion'] ?? '',
'dbcollation' => $info['dbcollation'] ?? '',
'dbconnectioncollation' => $info['dbconnectioncollation'] ?? '',
'dbconnectionencryption' => $info['dbconnectionencryption'] ?? '',
'dbconnencryptsupported' => $info['dbconnencryptsupported'] ?? '',
];
}
}

View File

@ -0,0 +1,153 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug\DataCollector;
use DebugBar\DataCollector\AssetProvider;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\Plugin\System\Debug\AbstractDataCollector;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* LanguageErrorsDataCollector
*
* @since 4.0.0
*/
class LanguageErrorsCollector extends AbstractDataCollector implements AssetProvider
{
/**
* Collector name.
*
* @var string
* @since 4.0.0
*/
private $name = 'languageErrors';
/**
* The count.
*
* @var integer
* @since 4.0.0
*/
private $count = 0;
/**
* Called by the DebugBar when data needs to be collected
*
* @since 4.0.0
*
* @return array Collected data
*/
public function collect(): array
{
return [
'data' => [
'files' => $this->getData(),
'jroot' => JPATH_ROOT,
'xdebugLink' => $this->getXdebugLinkTemplate(),
],
'count' => $this->getCount(),
];
}
/**
* Returns the unique name of the collector
*
* @since 4.0.0
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* Returns a hash where keys are control names and their values
* an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()}
*
* @since 4.0.0
*
* @return array
*/
public function getWidgets(): array
{
return [
'errors' => [
'icon' => 'warning',
'widget' => 'PhpDebugBar.Widgets.languageErrorsWidget',
'map' => $this->name . '.data',
'default' => '',
],
'errors:badge' => [
'map' => $this->name . '.count',
'default' => 'null',
],
];
}
/**
* Returns an array with the following keys:
* - base_path
* - base_url
* - css: an array of filenames
* - js: an array of filenames
*
* @since 4.0.0
* @return array
*/
public function getAssets()
{
return [
'js' => Uri::root(true) . '/media/plg_system_debug/widgets/languageErrors/widget.min.js',
'css' => Uri::root(true) . '/media/plg_system_debug/widgets/languageErrors/widget.min.css',
];
}
/**
* Collect data.
*
* @return array
*
* @since 4.0.0
*/
private function getData(): array
{
$errorFiles = Factory::getLanguage()->getErrorFiles();
$errors = [];
if (\count($errorFiles)) {
foreach ($errorFiles as $file => $lines) {
foreach ($lines as $line) {
$errors[] = [$file, $line];
$this->count++;
}
}
}
return $errors;
}
/**
* Get a count value.
*
* @return int
*
* @since 4.0.0
*/
private function getCount(): int
{
return $this->count;
}
}

View File

@ -0,0 +1,130 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug\DataCollector;
use DebugBar\DataCollector\AssetProvider;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\Plugin\System\Debug\AbstractDataCollector;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* LanguageFilesDataCollector
*
* @since 4.0.0
*/
class LanguageFilesCollector extends AbstractDataCollector implements AssetProvider
{
/**
* Collector name.
*
* @var string
* @since 4.0.0
*/
private $name = 'languageFiles';
/**
* The count.
*
* @var integer
* @since 4.0.0
*/
private $count = 0;
/**
* Called by the DebugBar when data needs to be collected
*
* @since 4.0.0
*
* @return array Collected data
*/
public function collect(): array
{
$paths = Factory::getLanguage()->getPaths();
$loaded = [];
foreach ($paths as $extension => $files) {
$loaded[$extension] = [];
foreach ($files as $file => $status) {
$loaded[$extension][$file] = $status;
if ($status) {
$this->count++;
}
}
}
return [
'loaded' => $loaded,
'xdebugLink' => $this->getXdebugLinkTemplate(),
'jroot' => JPATH_ROOT,
'count' => $this->count,
];
}
/**
* Returns the unique name of the collector
*
* @since 4.0.0
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* Returns a hash where keys are control names and their values
* an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()}
*
* @since 4.0.0
*
* @return array
*/
public function getWidgets(): array
{
return [
'loaded' => [
'icon' => 'language',
'widget' => 'PhpDebugBar.Widgets.languageFilesWidget',
'map' => $this->name,
'default' => '[]',
],
'loaded:badge' => [
'map' => $this->name . '.count',
'default' => 'null',
],
];
}
/**
* Returns an array with the following keys:
* - base_path
* - base_url
* - css: an array of filenames
* - js: an array of filenames
*
* @since 4.0.0
* @return array
*/
public function getAssets(): array
{
return [
'js' => Uri::root(true) . '/media/plg_system_debug/widgets/languageFiles/widget.min.js',
'css' => Uri::root(true) . '/media/plg_system_debug/widgets/languageFiles/widget.min.css',
];
}
}

View File

@ -0,0 +1,189 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug\DataCollector;
use DebugBar\DataCollector\AssetProvider;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Language;
use Joomla\CMS\Uri\Uri;
use Joomla\Plugin\System\Debug\AbstractDataCollector;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* LanguageStringsDataCollector
*
* @since 4.0.0
*/
class LanguageStringsCollector extends AbstractDataCollector implements AssetProvider
{
/**
* Collector name.
*
* @var string
* @since 4.0.0
*/
private $name = 'languageStrings';
/**
* Called by the DebugBar when data needs to be collected
*
* @since 4.0.0
*
* @return array Collected data
*/
public function collect(): array
{
return [
'data' => $this->getData(),
'count' => $this->getCount(),
];
}
/**
* Returns the unique name of the collector
*
* @since 4.0.0
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* Returns a hash where keys are control names and their values
* an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()}
*
* @since 4.0.0
*
* @return array
*/
public function getWidgets(): array
{
return [
'untranslated' => [
'icon' => 'question-circle',
'widget' => 'PhpDebugBar.Widgets.languageStringsWidget',
'map' => $this->name . '.data',
'default' => '',
],
'untranslated:badge' => [
'map' => $this->name . '.count',
'default' => 'null',
],
];
}
/**
* Returns an array with the following keys:
* - base_path
* - base_url
* - css: an array of filenames
* - js: an array of filenames
*
* @since 4.0.0
* @return array
*/
public function getAssets(): array
{
return [
'js' => Uri::root(true) . '/media/plg_system_debug/widgets/languageStrings/widget.min.js',
'css' => Uri::root(true) . '/media/plg_system_debug/widgets/languageStrings/widget.min.css',
];
}
/**
* Collect data.
*
* @return array
*
* @since 4.0.0
*/
private function getData(): array
{
$orphans = Factory::getLanguage()->getOrphans();
$data = [];
foreach ($orphans as $orphan => $occurrences) {
$data[$orphan] = [];
foreach ($occurrences as $occurrence) {
$item = [];
$item['string'] = $occurrence['string'] ?? 'n/a';
$item['trace'] = [];
$item['caller'] = '';
if (isset($occurrence['trace'])) {
$cnt = 0;
$trace = [];
$callerLocation = '';
array_shift($occurrence['trace']);
foreach ($occurrence['trace'] as $i => $stack) {
$class = $stack['class'] ?? '';
$file = $stack['file'] ?? '';
$line = $stack['line'] ?? '';
$caller = $this->formatCallerInfo($stack);
$location = $file && $line ? "$file:$line" : 'same';
$isCaller = 0;
if (!$callerLocation && $class !== Language::class && !strpos($file, 'Text.php')) {
$callerLocation = $location;
$isCaller = 1;
}
$trace[] = [
\count($occurrence['trace']) - $cnt,
$isCaller,
$caller,
$file,
$line,
];
$cnt++;
}
$item['trace'] = $trace;
$item['caller'] = $callerLocation;
}
$data[$orphan][] = $item;
}
}
return [
'orphans' => $data,
'jroot' => JPATH_ROOT,
'xdebugLink' => $this->getXdebugLinkTemplate(),
];
}
/**
* Get a count value.
*
* @return integer
*
* @since 4.0.0
*/
private function getCount(): int
{
return \count(Factory::getLanguage()->getOrphans());
}
}

View File

@ -0,0 +1,151 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug\DataCollector;
use Joomla\Plugin\System\Debug\AbstractDataCollector;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Collects info about the request duration as well as providing
* a way to log duration of any operations
*
* @since 4.4.0
*/
class MemoryCollector extends AbstractDataCollector
{
/**
* @var boolean
* @since 4.4.0
*/
protected $realUsage = false;
/**
* @var float
* @since 4.4.0
*/
protected $peakUsage = 0;
/**
* @param Registry $params Parameters.
* @param float $peakUsage
* @param boolean $realUsage
*
* @since 4.4.0
*/
public function __construct(Registry $params, $peakUsage = null, $realUsage = null)
{
parent::__construct($params);
if ($peakUsage !== null) {
$this->peakUsage = $peakUsage;
}
if ($realUsage !== null) {
$this->realUsage = $realUsage;
}
}
/**
* Returns whether total allocated memory page size is used instead of actual used memory size
* by the application. See $real_usage parameter on memory_get_peak_usage for details.
*
* @return boolean
*
* @since 4.4.0
*/
public function getRealUsage()
{
return $this->realUsage;
}
/**
* Sets whether total allocated memory page size is used instead of actual used memory size
* by the application. See $real_usage parameter on memory_get_peak_usage for details.
*
* @param boolean $realUsage
*
* @since 4.4.0
*/
public function setRealUsage($realUsage)
{
$this->realUsage = $realUsage;
}
/**
* Returns the peak memory usage
*
* @return integer
*
* @since 4.4.0
*/
public function getPeakUsage()
{
return $this->peakUsage;
}
/**
* Updates the peak memory usage value
*
* @since 4.4.0
*/
public function updatePeakUsage()
{
if ($this->peakUsage === null) {
$this->peakUsage = memory_get_peak_usage($this->realUsage);
}
}
/**
* @return array
*
* @since 4.4.0
*/
public function collect()
{
$this->updatePeakUsage();
return [
'peak_usage' => $this->peakUsage,
'peak_usage_str' => $this->getDataFormatter()->formatBytes($this->peakUsage, 3),
];
}
/**
* @return string
*
* @since 4.4.0
*/
public function getName()
{
return 'memory';
}
/**
* @return array
*
* @since 4.4.0
*/
public function getWidgets()
{
return [
'memory' => [
'icon' => 'cogs',
'tooltip' => 'Memory Usage',
'map' => 'memory.peak_usage_str',
'default' => "'0B'",
],
];
}
}

View File

@ -0,0 +1,342 @@
<?php
/**
* This file is part of the DebugBar package.
*
* @copyright (c) 2013 Maxime Bouroumeau-Fuseau
* @license For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Joomla\Plugin\System\Debug\DataCollector;
use DebugBar\DebugBarException;
use Joomla\CMS\Profiler\Profiler;
use Joomla\Plugin\System\Debug\AbstractDataCollector;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Collects info about the request duration as well as providing
* a way to log duration of any operations
*
* @since version
*/
class ProfileCollector extends AbstractDataCollector
{
/**
* Request start time.
*
* @var float
* @since 4.0.0
*/
protected $requestStartTime;
/**
* Request end time.
*
* @var float
* @since 4.0.0
*/
protected $requestEndTime;
/**
* Started measures.
*
* @var array
* @since 4.0.0
*/
protected $startedMeasures = [];
/**
* Measures.
*
* @var array
* @since 4.0.0
*/
protected $measures = [];
/**
* Constructor.
*
* @param Registry $params Parameters.
*
* @since 4.0.0
*/
public function __construct(Registry $params)
{
if (isset($_SERVER['REQUEST_TIME_FLOAT'])) {
$this->requestStartTime = $_SERVER['REQUEST_TIME_FLOAT'];
} else {
$this->requestStartTime = microtime(true);
}
parent::__construct($params);
}
/**
* Starts a measure.
*
* @param string $name Internal name, used to stop the measure
* @param string|null $label Public name
* @param string|null $collector The source of the collector
*
* @return void
*
* @since 4.0.0
*/
public function startMeasure($name, $label = null, $collector = null)
{
$start = microtime(true);
$this->startedMeasures[$name] = [
'label' => $label ?: $name,
'start' => $start,
'collector' => $collector,
];
}
/**
* Check a measure exists
*
* @param string $name Group name.
*
* @return bool
*
* @since 4.0.0
*/
public function hasStartedMeasure($name): bool
{
return isset($this->startedMeasures[$name]);
}
/**
* Stops a measure.
*
* @param string $name Measurement name.
* @param array $params Parameters
*
* @return void
*
* @since 4.0.0
*
* @throws DebugBarException
*/
public function stopMeasure($name, array $params = [])
{
$end = microtime(true);
if (!$this->hasStartedMeasure($name)) {
throw new DebugBarException("Failed stopping measure '$name' because it hasn't been started");
}
$this->addMeasure($this->startedMeasures[$name]['label'], $this->startedMeasures[$name]['start'], $end, $params, $this->startedMeasures[$name]['collector']);
unset($this->startedMeasures[$name]);
}
/**
* Adds a measure
*
* @param string $label A label.
* @param float $start Start of request.
* @param float $end End of request.
* @param array $params Parameters.
* @param string|null $collector A collector.
*
* @return void
*
* @since 4.0.0
*/
public function addMeasure($label, $start, $end, array $params = [], $collector = null)
{
$this->measures[] = [
'label' => $label,
'start' => $start,
'relative_start' => $start - $this->requestStartTime,
'end' => $end,
'relative_end' => $end - $this->requestEndTime,
'duration' => $end - $start,
'duration_str' => $this->getDataFormatter()->formatDuration($end - $start),
'params' => $params,
'collector' => $collector,
];
}
/**
* Utility function to measure the execution of a Closure
*
* @param string $label A label.
* @param \Closure $closure A closure.
* @param string|null $collector A collector.
*
* @return void
*
* @since 4.0.0
*/
public function measure($label, \Closure $closure, $collector = null)
{
$name = spl_object_hash($closure);
$this->startMeasure($name, $label, $collector);
$result = $closure();
$params = \is_array($result) ? $result : [];
$this->stopMeasure($name, $params);
}
/**
* Returns an array of all measures
*
* @return array
*
* @since 4.0.0
*/
public function getMeasures(): array
{
return $this->measures;
}
/**
* Returns the request start time
*
* @return float
*
* @since 4.0.0
*/
public function getRequestStartTime(): float
{
return $this->requestStartTime;
}
/**
* Returns the request end time
*
* @return float
*
* @since 4.0.0
*/
public function getRequestEndTime(): float
{
return $this->requestEndTime;
}
/**
* Returns the duration of a request
*
* @return float
*
* @since 4.0.0
*/
public function getRequestDuration(): float
{
if ($this->requestEndTime !== null) {
return $this->requestEndTime - $this->requestStartTime;
}
return microtime(true) - $this->requestStartTime;
}
/**
* Sets request end time.
*
* @param float $time Request end time.
*
* @return $this
*
* @since 4.4.0
*/
public function setRequestEndTime($time): self
{
$this->requestEndTime = $time;
return $this;
}
/**
* Called by the DebugBar when data needs to be collected
*
* @return array Collected data
*
* @since 4.0.0
*/
public function collect(): array
{
$this->requestEndTime = $this->requestEndTime ?? microtime(true);
$start = $this->requestStartTime;
$marks = Profiler::getInstance('Application')->getMarks();
foreach ($marks as $mark) {
$mem = $this->getDataFormatter()->formatBytes(abs($mark->memory) * 1048576);
$label = $mark->label . " ($mem)";
$end = $start + $mark->time / 1000;
$this->addMeasure($label, $start, $end);
$start = $end;
}
foreach (array_keys($this->startedMeasures) as $name) {
$this->stopMeasure($name);
}
usort(
$this->measures,
function ($a, $b) {
if ($a['start'] === $b['start']) {
return 0;
}
return $a['start'] < $b['start'] ? -1 : 1;
}
);
return [
'start' => $this->requestStartTime,
'end' => $this->requestEndTime,
'duration' => $this->getRequestDuration(),
'duration_str' => $this->getDataFormatter()->formatDuration($this->getRequestDuration()),
'measures' => array_values($this->measures),
'rawMarks' => $marks,
];
}
/**
* Returns the unique name of the collector
*
* @return string
*
* @since 4.0.0
*/
public function getName(): string
{
return 'profile';
}
/**
* Returns a hash where keys are control names and their values
* an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()}
*
* @return array
*
* @since 4.0.0
*/
public function getWidgets(): array
{
return [
'profileTime' => [
'icon' => 'clock-o',
'tooltip' => 'Request Duration',
'map' => 'profile.duration_str',
'default' => "'0ms'",
],
'profile' => [
'icon' => 'clock-o',
'widget' => 'PhpDebugBar.Widgets.TimelineWidget',
'map' => 'profile',
'default' => '{}',
],
];
}
}

View File

@ -0,0 +1,258 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug\DataCollector;
use DebugBar\DataCollector\AssetProvider;
use Joomla\CMS\Uri\Uri;
use Joomla\Database\Monitor\DebugMonitor;
use Joomla\Plugin\System\Debug\AbstractDataCollector;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* QueryDataCollector
*
* @since 4.0.0
*/
class QueryCollector extends AbstractDataCollector implements AssetProvider
{
/**
* Collector name.
*
* @var string
* @since 4.0.0
*/
private $name = 'queries';
/**
* The query monitor.
*
* @var DebugMonitor
* @since 4.0.0
*/
private $queryMonitor;
/**
* Profile data.
*
* @var array
* @since 4.0.0
*/
private $profiles;
/**
* Explain data.
*
* @var array
* @since 4.0.0
*/
private $explains;
/**
* Accumulated Duration.
*
* @var integer
* @since 4.0.0
*/
private $accumulatedDuration = 0;
/**
* Accumulated Memory.
*
* @var integer
* @since 4.0.0
*/
private $accumulatedMemory = 0;
/**
* Constructor.
*
* @param Registry $params Parameters.
* @param DebugMonitor $queryMonitor Query monitor.
* @param array $profiles Profile data.
* @param array $explains Explain data
*
* @since 4.0.0
*/
public function __construct(Registry $params, DebugMonitor $queryMonitor, array $profiles, array $explains)
{
$this->queryMonitor = $queryMonitor;
parent::__construct($params);
$this->profiles = $profiles;
$this->explains = $explains;
}
/**
* Called by the DebugBar when data needs to be collected
*
* @since 4.0.0
*
* @return array Collected data
*/
public function collect(): array
{
$statements = $this->getStatements();
return [
'data' => [
'statements' => $statements,
'nb_statements' => \count($statements),
'accumulated_duration_str' => $this->getDataFormatter()->formatDuration($this->accumulatedDuration),
'memory_usage_str' => $this->getDataFormatter()->formatBytes($this->accumulatedMemory),
'xdebug_link' => $this->getXdebugLinkTemplate(),
'root_path' => JPATH_ROOT,
],
'count' => \count($this->queryMonitor->getLogs()),
];
}
/**
* Returns the unique name of the collector
*
* @since 4.0.0
*
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* Returns a hash where keys are control names and their values
* an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()}
*
* @since 4.0.0
*
* @return array
*/
public function getWidgets(): array
{
return [
'queries' => [
'icon' => 'database',
'widget' => 'PhpDebugBar.Widgets.SQLQueriesWidget',
'map' => $this->name . '.data',
'default' => '[]',
],
'queries:badge' => [
'map' => $this->name . '.count',
'default' => 'null',
],
];
}
/**
* Assets for the collector.
*
* @since 4.0.0
*
* @return array
*/
public function getAssets(): array
{
return [
'css' => Uri::root(true) . '/media/plg_system_debug/widgets/sqlqueries/widget.min.css',
'js' => Uri::root(true) . '/media/plg_system_debug/widgets/sqlqueries/widget.min.js',
];
}
/**
* Prepare the executed statements data.
*
* @since 4.0.0
*
* @return array
*/
private function getStatements(): array
{
$statements = [];
$logs = $this->queryMonitor->getLogs();
$boundParams = $this->queryMonitor->getBoundParams();
$timings = $this->queryMonitor->getTimings();
$memoryLogs = $this->queryMonitor->getMemoryLogs();
$stacks = $this->queryMonitor->getCallStacks();
$collectStacks = $this->params->get('query_traces');
foreach ($logs as $id => $item) {
$queryTime = 0;
$queryMemory = 0;
if ($timings && isset($timings[$id * 2 + 1])) {
// Compute the query time.
$queryTime = ($timings[$id * 2 + 1] - $timings[$id * 2]);
$this->accumulatedDuration += $queryTime;
}
if ($memoryLogs && isset($memoryLogs[$id * 2 + 1])) {
// Compute the query memory usage.
$queryMemory = ($memoryLogs[$id * 2 + 1] - $memoryLogs[$id * 2]);
$this->accumulatedMemory += $queryMemory;
}
$trace = [];
$callerLocation = '';
if (isset($stacks[$id])) {
$cnt = 0;
foreach ($stacks[$id] as $i => $stack) {
$class = $stack['class'] ?? '';
$file = $stack['file'] ?? '';
$line = $stack['line'] ?? '';
$caller = $this->formatCallerInfo($stack);
$location = $file && $line ? "$file:$line" : 'same';
$isCaller = 0;
if (\Joomla\Database\DatabaseDriver::class === $class && false === strpos($file, 'DatabaseDriver.php')) {
$callerLocation = $location;
$isCaller = 1;
}
if ($collectStacks) {
$trace[] = [\count($stacks[$id]) - $cnt, $isCaller, $caller, $file, $line];
}
$cnt++;
}
}
$explain = $this->explains[$id] ?? [];
$explainColumns = [];
// Extract column labels for Explain table
if ($explain) {
$explainColumns = array_keys(reset($explain));
}
$statements[] = [
'sql' => $item,
'params' => $boundParams[$id] ?? [],
'duration_str' => $this->getDataFormatter()->formatDuration($queryTime),
'memory_str' => $this->getDataFormatter()->formatBytes($queryMemory),
'caller' => $callerLocation,
'callstack' => $trace,
'explain' => $explain,
'explain_col' => $explainColumns,
'profile' => $this->profiles[$id] ?? [],
];
}
return $statements;
}
}

View File

@ -0,0 +1,67 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug\DataCollector;
use Joomla\Plugin\System\Debug\Extension\Debug;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Collects info about the request content while redacting potentially secret content
*
* @since 4.2.4
*/
class RequestDataCollector extends \DebugBar\DataCollector\RequestDataCollector
{
/**
* Called by the DebugBar when data needs to be collected
*
* @since 4.2.4
*
* @return array
*/
public function collect()
{
$vars = ['_GET', '_POST', '_SESSION', '_COOKIE', '_SERVER'];
$returnData = [];
foreach ($vars as $var) {
if (isset($GLOBALS[$var])) {
$key = "$" . $var;
$data = $GLOBALS[$var];
// Replace Joomla session data from session data, it will be collected by SessionCollector
if ($var === '_SESSION' && !empty($data['joomla'])) {
$data['joomla'] = '***redacted***';
}
array_walk_recursive($data, static function (&$value, $key) {
if (!preg_match(Debug::PROTECTED_COLLECTOR_KEYS, $key)) {
return;
}
$value = '***redacted***';
});
if ($this->isHtmlVarDumperUsed()) {
$returnData[$key] = $this->getVarDumper()->renderVar($data);
} else {
$returnData[$key] = $this->getDataFormatter()->formatVar($data);
}
}
}
return $returnData;
}
}

View File

@ -0,0 +1,125 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug\DataCollector;
use Joomla\CMS\Factory;
use Joomla\Plugin\System\Debug\AbstractDataCollector;
use Joomla\Plugin\System\Debug\Extension\Debug;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* SessionDataCollector
*
* @since 4.0.0
*/
class SessionCollector extends AbstractDataCollector
{
/**
* Collector name.
*
* @var string
* @since 4.0.0
*/
private $name = 'session';
/**
* Collected data.
*
* @var array
* @since 4.4.0
*/
protected $sessionData;
/**
* Constructor.
*
* @param Registry $params Parameters.
* @param bool $collect Collect the session data.
*
* @since 4.4.0
*/
public function __construct($params, $collect = false)
{
parent::__construct($params);
if ($collect) {
$this->collect();
}
}
/**
* Called by the DebugBar when data needs to be collected
*
* @param bool $overwrite Overwrite the previously collected session data.
*
* @return array Collected data
*
* @since 4.0.0
*/
public function collect($overwrite = false)
{
if ($this->sessionData === null || $overwrite) {
$this->sessionData = [];
$data = Factory::getApplication()->getSession()->all();
// redact value of potentially secret keys
array_walk_recursive($data, static function (&$value, $key) {
if (!preg_match(Debug::PROTECTED_COLLECTOR_KEYS, $key)) {
return;
}
$value = '***redacted***';
});
foreach ($data as $key => $value) {
$this->sessionData[$key] = $this->getDataFormatter()->formatVar($value);
}
}
return ['data' => $this->sessionData];
}
/**
* Returns the unique name of the collector
*
* @since 4.0.0
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Returns a hash where keys are control names and their values
* an array of options as defined in {@see \DebugBar\JavascriptRenderer::addControl()}
*
* @since 4.0.0
*
* @return array
*/
public function getWidgets()
{
return [
'session' => [
'icon' => 'key',
'widget' => 'PhpDebugBar.Widgets.VariableListWidget',
'map' => $this->name . '.data',
'default' => '[]',
],
];
}
}

View File

@ -0,0 +1,62 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug\DataCollector;
use DebugBar\DataCollector\DataCollectorInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\User\UserFactoryInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* User collector that stores the user id of the person making the request allowing us to filter on it after storage
*
* @since 4.2.4
*/
class UserCollector implements DataCollectorInterface
{
/**
* Collector name.
*
* @var string
* @since 4.2.4
*/
private $name = 'juser';
/**
* Called by the DebugBar when data needs to be collected
*
* @since 4.2.4
*
* @return array Collected data
*/
public function collect()
{
$user = Factory::getApplication()->getIdentity()
?: Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById(0);
return ['user_id' => $user->id];
}
/**
* Returns the unique name of the collector
*
* @since 4.2.4
*
* @return string
*/
public function getName()
{
return $this->name;
}
}

View File

@ -0,0 +1,93 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug;
use DebugBar\DataFormatter\DataFormatter as DebugBarDataFormatter;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* DataFormatter
*
* @since 4.0.0
*/
class DataFormatter extends DebugBarDataFormatter
{
/**
* Strip the root path.
*
* @param string $path The path.
* @param string $replacement The replacement
*
* @return string
*
* @since 4.0.0
*/
public function formatPath($path, $replacement = ''): string
{
return str_replace(JPATH_ROOT, $replacement, $path);
}
/**
* Format a string from back trace.
*
* @param array $call The array to format
*
* @return string
*
* @since 4.0.0
*/
public function formatCallerInfo(array $call): string
{
$string = '';
if (isset($call['class'])) {
// If entry has Class/Method print it.
$string .= htmlspecialchars($call['class'] . $call['type'] . $call['function']) . '()';
} elseif (isset($call['args'][0]) && \is_array($call['args'][0])) {
$string .= htmlspecialchars($call['function']) . ' (';
foreach ($call['args'][0] as $arg) {
// Check if the arguments can be used as string
if (\is_object($arg) && !method_exists($arg, '__toString')) {
$arg = \get_class($arg);
}
// Keep only the size of array
if (\is_array($arg)) {
$arg = 'Array(count=' . \count($arg) . ')';
}
$string .= htmlspecialchars($arg) . ', ';
}
$string = rtrim($string, ', ') . ')';
} elseif (isset($call['args'][0])) {
$string .= htmlspecialchars($call['function']) . '(';
if (\is_scalar($call['args'][0])) {
$string .= $call['args'][0];
} elseif (\is_object($call['args'][0])) {
$string .= \get_class($call['args'][0]);
} else {
$string .= \gettype($call['args'][0]);
}
$string .= ')';
} else {
// It's a function.
$string .= htmlspecialchars($call['function']) . '()';
}
return $string;
}
}

View File

@ -0,0 +1,711 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.debug
*
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug\Extension;
use DebugBar\DataCollector\MessagesCollector;
use DebugBar\DebugBar;
use DebugBar\OpenHandler;
use Joomla\Application\ApplicationEvents;
use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\CMS\Document\HtmlDocument;
use Joomla\CMS\Event\Plugin\AjaxEvent;
use Joomla\CMS\Log\Log;
use Joomla\CMS\Log\LogEntry;
use Joomla\CMS\Log\Logger\InMemoryLogger;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Profiler\Profiler;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Uri\Uri;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Database\DatabaseInterface;
use Joomla\Database\Event\ConnectionEvent;
use Joomla\Event\DispatcherInterface;
use Joomla\Event\Priority;
use Joomla\Event\SubscriberInterface;
use Joomla\Plugin\System\Debug\DataCollector\InfoCollector;
use Joomla\Plugin\System\Debug\DataCollector\LanguageErrorsCollector;
use Joomla\Plugin\System\Debug\DataCollector\LanguageFilesCollector;
use Joomla\Plugin\System\Debug\DataCollector\LanguageStringsCollector;
use Joomla\Plugin\System\Debug\DataCollector\MemoryCollector;
use Joomla\Plugin\System\Debug\DataCollector\ProfileCollector;
use Joomla\Plugin\System\Debug\DataCollector\QueryCollector;
use Joomla\Plugin\System\Debug\DataCollector\RequestDataCollector;
use Joomla\Plugin\System\Debug\DataCollector\SessionCollector;
use Joomla\Plugin\System\Debug\DataCollector\UserCollector;
use Joomla\Plugin\System\Debug\JavascriptRenderer;
use Joomla\Plugin\System\Debug\JoomlaHttpDriver;
use Joomla\Plugin\System\Debug\Storage\FileStorage;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla! Debug plugin.
*
* @since 1.5
*/
final class Debug extends CMSPlugin implements SubscriberInterface
{
use DatabaseAwareTrait;
/**
* List of protected keys that will be redacted in multiple data collected
*
* @since 4.2.4
*/
public const PROTECTED_COLLECTOR_KEYS = "/password|passwd|pwd|secret|token|server_auth|_pass|smtppass|otpKey|otep/i";
/**
* True if debug lang is on.
*
* @var boolean
* @since 3.0
*/
private $debugLang;
/**
* Holds log entries handled by the plugin.
*
* @var LogEntry[]
* @since 3.1
*/
private $logEntries = [];
/**
* Holds all SHOW PROFILE FOR QUERY n, indexed by n-1.
*
* @var array
* @since 3.1.2
*/
private $sqlShowProfileEach = [];
/**
* Holds all EXPLAIN EXTENDED for all queries.
*
* @var array
* @since 3.1.2
*/
private $explains = [];
/**
* @var DebugBar
* @since 4.0.0
*/
private $debugBar;
/**
* The query monitor.
*
* @var \Joomla\Database\Monitor\DebugMonitor
* @since 4.0.0
*/
private $queryMonitor;
/**
* AJAX marker
*
* @var bool
* @since 4.0.0
*/
protected $isAjax = false;
/**
* Whether displaying a logs is enabled
*
* @var bool
* @since 4.0.0
*/
protected $showLogs = false;
/**
* The time spent in onAfterDisconnect()
*
* @var float
* @since 4.4.0
*/
protected $timeInOnAfterDisconnect = 0;
/**
* @return array
*
* @since 4.1.3
*/
public static function getSubscribedEvents(): array
{
return [
'onBeforeCompileHead' => 'onBeforeCompileHead',
'onAjaxDebug' => 'onAjaxDebug',
'onBeforeRespond' => 'onBeforeRespond',
'onAfterRespond' => [
'onAfterRespond',
Priority::MIN,
],
ApplicationEvents::AFTER_RESPOND => [
'onAfterRespond',
Priority::MIN,
],
'onAfterDisconnect' => 'onAfterDisconnect',
];
}
/**
* @param DispatcherInterface $dispatcher The object to observe -- event dispatcher.
* @param array $config An optional associative array of configuration settings.
* @param CMSApplicationInterface $app The app
* @param DatabaseInterface $db The db
*
* @since 1.5
*/
public function __construct(DispatcherInterface $dispatcher, array $config, CMSApplicationInterface $app, DatabaseInterface $db)
{
parent::__construct($dispatcher, $config);
$this->setApplication($app);
$this->setDatabase($db);
$this->debugLang = $this->getApplication()->get('debug_lang');
// Skip the plugin if debug is off
if (!$this->debugLang && !$this->getApplication()->get('debug')) {
return;
}
$this->getApplication()->set('gzip', false);
ob_start();
ob_implicit_flush(false);
/** @var \Joomla\Database\Monitor\DebugMonitor */
$this->queryMonitor = $this->getDatabase()->getMonitor();
if (!$this->params->get('queries', 1)) {
// Remove the database driver monitor
$this->getDatabase()->setMonitor(null);
}
$this->debugBar = new DebugBar();
// Check whether we want to track the request history for future use.
if ($this->params->get('track_request_history', false)) {
$storagePath = JPATH_CACHE . '/plg_system_debug_' . $this->getApplication()->getName();
$this->debugBar->setStorage(new FileStorage($storagePath));
}
$this->debugBar->setHttpDriver(new JoomlaHttpDriver($this->getApplication()));
$this->isAjax = $this->getApplication()->getInput()->get('option') === 'com_ajax'
&& $this->getApplication()->getInput()->get('plugin') === 'debug' && $this->getApplication()->getInput()->get('group') === 'system';
$this->showLogs = (bool) $this->params->get('logs', true);
// Log deprecated class aliases
if ($this->showLogs && $this->getApplication()->get('log_deprecated')) {
foreach (\JLoader::getDeprecatedAliases() as $deprecation) {
Log::add(
\sprintf(
'%1$s has been aliased to %2$s and the former class name is deprecated. The alias will be removed in %3$s.',
$deprecation['old'],
$deprecation['new'],
$deprecation['version']
),
Log::WARNING,
'deprecation-notes'
);
}
}
}
/**
* Add an assets for debugger.
*
* @return void
*
* @since 4.0.0
*/
public function onBeforeCompileHead()
{
// Only if debugging or language debug is enabled.
if ((JDEBUG || $this->debugLang) && $this->isAuthorisedDisplayDebug() && $this->getApplication()->getDocument() instanceof HtmlDocument) {
// Use our own jQuery and fontawesome instead of the debug bar shipped version
$assetManager = $this->getApplication()->getDocument()->getWebAssetManager();
$assetManager->registerAndUseStyle(
'plg.system.debug',
'plg_system_debug/debug.css',
[],
[],
['fontawesome']
);
$assetManager->registerAndUseScript(
'plg.system.debug',
'plg_system_debug/debug.min.js',
[],
['defer' => true],
['jquery']
);
}
// Disable asset media version if needed.
if (JDEBUG && (int) $this->params->get('refresh_assets', 1) === 0) {
$this->getApplication()->getDocument()->setMediaVersion('');
}
}
/**
* Show the debug info.
*
* @return void
*
* @since 1.6
*/
public function onAfterRespond()
{
$endTime = microtime(true) - $this->timeInOnAfterDisconnect;
$endMemory = memory_get_peak_usage(false);
// Do not collect data if debugging or language debug is not enabled.
if ((!JDEBUG && !$this->debugLang) || $this->isAjax) {
return;
}
// User has to be authorised to see the debug information.
if (!$this->isAuthorisedDisplayDebug()) {
return;
}
// Load language.
$this->loadLanguage();
$this->debugBar->addCollector(new InfoCollector($this->params, $this->debugBar->getCurrentRequestId()));
$this->debugBar->addCollector(new UserCollector());
if (JDEBUG) {
if ($this->params->get('memory', 1)) {
$this->debugBar->addCollector(new MemoryCollector($this->params, $endMemory));
}
if ($this->params->get('request', 1)) {
$this->debugBar->addCollector(new RequestDataCollector());
}
if ($this->params->get('session', 1)) {
$this->debugBar->addCollector(new SessionCollector($this->params, true));
}
if ($this->params->get('profile', 1)) {
$this->debugBar->addCollector((new ProfileCollector($this->params))->setRequestEndTime($endTime));
}
if ($this->params->get('queries', 1)) {
// Remember session form token for possible future usage.
$formToken = Session::getFormToken();
// Close session to collect possible session-related queries.
$this->getApplication()->getSession()->close();
// Call $db->disconnect() here to trigger the onAfterDisconnect() method here in this class!
$this->getDatabase()->disconnect();
$this->debugBar->addCollector(new QueryCollector($this->params, $this->queryMonitor, $this->sqlShowProfileEach, $this->explains));
}
if ($this->showLogs) {
$this->collectLogs();
}
}
if ($this->debugLang) {
$this->debugBar->addCollector(new LanguageFilesCollector($this->params));
$this->debugBar->addCollector(new LanguageStringsCollector($this->params));
$this->debugBar->addCollector(new LanguageErrorsCollector($this->params));
}
// Only render for HTML output.
if (!($this->getApplication()->getDocument() instanceof HtmlDocument)) {
$this->debugBar->stackData();
return;
}
$debugBarRenderer = new JavascriptRenderer($this->debugBar, Uri::root(true) . '/media/vendor/debugbar/');
$openHandlerUrl = Uri::base(true) . '/index.php?option=com_ajax&plugin=debug&group=system&format=raw&action=openhandler';
$openHandlerUrl .= '&' . ($formToken ?? Session::getFormToken()) . '=1';
$debugBarRenderer->setOpenHandlerUrl($openHandlerUrl);
/**
* @todo disable highlightjs from the DebugBar, import it through NPM
* and deliver it through Joomla's API
* Also every DebugBar script and stylesheet needs to use Joomla's API
* $debugBarRenderer->disableVendor('highlightjs');
*/
// Capture output.
$contents = ob_get_contents();
if ($contents) {
ob_end_clean();
}
// No debug for Safari and Chrome redirection.
if (
strpos($contents, '<html><head><meta http-equiv="refresh" content="0;') === 0
&& strpos(strtolower($_SERVER['HTTP_USER_AGENT'] ?? ''), 'webkit') !== false
) {
$this->debugBar->stackData();
echo $contents;
return;
}
echo str_replace('</body>', $debugBarRenderer->renderHead() . $debugBarRenderer->render() . '</body>', $contents);
}
/**
* AJAX handler
*
* @param AjaxEvent $event
*
* @return void
*
* @since 4.0.0
*/
public function onAjaxDebug(AjaxEvent $event)
{
// Do not render if debugging or language debug is not enabled.
if (!JDEBUG && !$this->debugLang) {
return;
}
// User has to be authorised to see the debug information.
if (!$this->isAuthorisedDisplayDebug() || !Session::checkToken('request')) {
return;
}
switch ($this->getApplication()->getInput()->get('action')) {
case 'openhandler':
$handler = new OpenHandler($this->debugBar);
$result = $handler->handle($this->getApplication()->getInput()->request->getArray(), false, false);
$event->addResult($result);
}
}
/**
* Method to check if the current user is allowed to see the debug information or not.
*
* @return boolean True if access is allowed.
*
* @since 3.0
*/
private function isAuthorisedDisplayDebug(): bool
{
static $result;
if ($result !== null) {
return $result;
}
// If the user is not allowed to view the output then end here.
$filterGroups = (array) $this->params->get('filter_groups', []);
if (!empty($filterGroups)) {
$userGroups = $this->getApplication()->getIdentity()->get('groups');
if (!array_intersect($filterGroups, $userGroups)) {
$result = false;
return false;
}
}
$result = true;
return true;
}
/**
* Disconnect handler for database to collect profiling and explain information.
*
* @param ConnectionEvent $event Event object
*
* @return void
*
* @since 4.0.0
*/
public function onAfterDisconnect(ConnectionEvent $event)
{
if (!JDEBUG) {
return;
}
$startTime = microtime(true);
$db = $event->getDriver();
// Remove the monitor to avoid monitoring the following queries
$db->setMonitor(null);
if ($this->params->get('query_profiles') && $db->getServerType() === 'mysql') {
try {
// Check if profiling is enabled.
$db->setQuery("SHOW VARIABLES LIKE 'have_profiling'");
$hasProfiling = $db->loadResult();
if ($hasProfiling) {
// Run a SHOW PROFILE query.
$db->setQuery('SHOW PROFILES');
$sqlShowProfiles = $db->loadAssocList();
if ($sqlShowProfiles) {
foreach ($sqlShowProfiles as $qn) {
// Run SHOW PROFILE FOR QUERY for each query where a profile is available (max 100).
$db->setQuery('SHOW PROFILE FOR QUERY ' . (int) $qn['Query_ID']);
$this->sqlShowProfileEach[$qn['Query_ID'] - 1] = $db->loadAssocList();
}
}
} else {
$this->sqlShowProfileEach[0] = [['Error' => 'MySql have_profiling = off']];
}
} catch (\Exception $e) {
$this->sqlShowProfileEach[0] = [['Error' => $e->getMessage()]];
}
}
if ($this->params->get('query_explains') && \in_array($db->getServerType(), ['mysql', 'postgresql'], true)) {
$logs = $this->queryMonitor->getLogs();
$boundParams = $this->queryMonitor->getBoundParams();
foreach ($logs as $k => $query) {
$dbVersion56 = $db->getServerType() === 'mysql' && version_compare($db->getVersion(), '5.6', '>=');
$dbVersion80 = $db->getServerType() === 'mysql' && version_compare($db->getVersion(), '8.0', '>=');
if ($dbVersion80) {
$dbVersion56 = false;
}
if ((stripos($query, 'select') === 0) || ($dbVersion56 && ((stripos($query, 'delete') === 0) || (stripos($query, 'update') === 0)))) {
try {
$queryInstance = $db->getQuery(true);
$queryInstance->setQuery('EXPLAIN ' . ($dbVersion56 ? 'EXTENDED ' : '') . $query);
if ($boundParams[$k]) {
foreach ($boundParams[$k] as $key => $obj) {
$queryInstance->bind($key, $obj->value, $obj->dataType, $obj->length, $obj->driverOptions);
}
}
$this->explains[$k] = $db->setQuery($queryInstance)->loadAssocList();
} catch (\Exception $e) {
$this->explains[$k] = [['error' => $e->getMessage()]];
}
}
}
}
$this->timeInOnAfterDisconnect = microtime(true) - $startTime;
}
/**
* Store log messages so they can be displayed later.
* This function is passed log entries by JLogLoggerCallback.
*
* @param LogEntry $entry A log entry.
*
* @return void
*
* @since 3.1
*
* @deprecated 4.3 will be removed in 6.0
* Use \Joomla\CMS\Log\Log::add(LogEntry $entry) instead
*/
public function logger(LogEntry $entry)
{
if (!$this->showLogs) {
return;
}
$this->logEntries[] = $entry;
}
/**
* Collect log messages.
*
* @return void
*
* @since 4.0.0
*/
private function collectLogs()
{
$loggerOptions = ['group' => 'default'];
$logger = new InMemoryLogger($loggerOptions);
$logEntries = $logger->getCollectedEntries();
if (!$this->logEntries && !$logEntries) {
return;
}
if ($this->logEntries) {
$logEntries = array_merge($logEntries, $this->logEntries);
}
$logDeprecated = $this->getApplication()->get('log_deprecated', 0);
$logDeprecatedCore = $this->params->get('log-deprecated-core', 0);
$this->debugBar->addCollector(new MessagesCollector('log'));
if ($logDeprecated) {
$this->debugBar->addCollector(new MessagesCollector('deprecated'));
$this->debugBar->addCollector(new MessagesCollector('deprecation-notes'));
}
if ($logDeprecatedCore) {
$this->debugBar->addCollector(new MessagesCollector('deprecated-core'));
}
foreach ($logEntries as $entry) {
switch ($entry->category) {
case 'deprecation-notes':
if ($logDeprecated) {
$this->debugBar[$entry->category]->addMessage($entry->message);
}
break;
case 'deprecated':
if (!$logDeprecated && !$logDeprecatedCore) {
break;
}
$file = '';
$line = '';
// Find the caller, skip Log methods and trigger_error function
foreach ($entry->callStack as $stackEntry) {
if (
!empty($stackEntry['class'])
&& ($stackEntry['class'] === 'Joomla\CMS\Log\LogEntry' || $stackEntry['class'] === 'Joomla\CMS\Log\Log')
) {
continue;
}
if (
empty($stackEntry['class']) && !empty($stackEntry['function'])
&& $stackEntry['function'] === 'trigger_error'
) {
continue;
}
$file = $stackEntry['file'] ?? '';
$line = $stackEntry['line'] ?? '';
break;
}
$category = $entry->category;
$relative = $file ? str_replace(JPATH_ROOT, '', $file) : '';
if ($relative && 0 === strpos($relative, '/libraries/src')) {
if (!$logDeprecatedCore) {
break;
}
$category .= '-core';
} elseif (!$logDeprecated) {
break;
}
$message = [
'message' => $entry->message,
'caller' => $file . ':' . $line,
// @todo 'stack' => $entry->callStack;
];
$this->debugBar[$category]->addMessage($message, 'warning');
break;
case 'databasequery':
// Should be collected by its own collector
break;
default:
switch ($entry->priority) {
case Log::EMERGENCY:
case Log::ALERT:
case Log::CRITICAL:
case Log::ERROR:
$level = 'error';
break;
case Log::WARNING:
$level = 'warning';
break;
default:
$level = 'info';
}
$this->debugBar['log']->addMessage($entry->category . ' - ' . $entry->message, $level);
break;
}
}
}
/**
* Add server timing headers when profile is activated.
*
* @return void
*
* @since 4.1.0
*/
public function onBeforeRespond(): void
{
if (!JDEBUG || !$this->params->get('profile', 1)) {
return;
}
$metrics = '';
$moduleTime = 0;
$accessTime = 0;
foreach (Profiler::getInstance('Application')->getMarks() as $index => $mark) {
// Ignore the before mark as the after one contains the timing of the action
if (stripos($mark->label, 'before') !== false) {
continue;
}
// Collect the module render time
if (strpos($mark->label, 'mod_') !== false) {
$moduleTime += $mark->time;
continue;
}
// Collect the access render time
if (strpos($mark->label, 'Access:') !== false) {
$accessTime += $mark->time;
continue;
}
$desc = str_ireplace('after', '', $mark->label);
$name = preg_replace('/[^\da-z]/i', '', $desc);
$metrics .= \sprintf('%s;dur=%f;desc="%s", ', $index . $name, $mark->time, $desc);
// Do not create too large headers, some web servers don't love them
if (\strlen($metrics) > 3000) {
$metrics .= 'System;dur=0;desc="Data truncated to 3000 characters", ';
break;
}
}
// Add the module entry
$metrics .= 'Modules;dur=' . $moduleTime . ';desc="Modules", ';
// Add the access entry
$metrics .= 'Access;dur=' . $accessTime . ';desc="Access"';
$this->getApplication()->setHeader('Server-Timing', $metrics);
}
}

View File

@ -0,0 +1,133 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug;
use DebugBar\DebugBar;
use DebugBar\JavascriptRenderer as DebugBarJavascriptRenderer;
use Joomla\CMS\Factory;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Custom JavascriptRenderer for DebugBar
*
* @since 4.0.0
*/
class JavascriptRenderer extends DebugBarJavascriptRenderer
{
/**
* Class constructor.
*
* @param \DebugBar\DebugBar $debugBar DebugBar instance
* @param string $baseUrl The base URL from which assets will be served
* @param string $basePath The path which assets are relative to
*
* @since 4.0.0
*/
public function __construct(DebugBar $debugBar, $baseUrl = null, $basePath = null)
{
parent::__construct($debugBar, $baseUrl, $basePath);
// Disable features that loaded by Joomla! API, or not in use
$this->setEnableJqueryNoConflict(false);
$this->disableVendor('jquery');
$this->disableVendor('fontawesome');
}
/**
* Renders the html to include needed assets
*
* Only useful if Assetic is not used
*
* @return string
*
* @since 4.0.0
*/
public function renderHead()
{
list($cssFiles, $jsFiles, $inlineCss, $inlineJs, $inlineHead) = $this->getAssets(null, self::RELATIVE_URL);
$html = '';
$doc = Factory::getApplication()->getDocument();
foreach ($cssFiles as $file) {
$html .= \sprintf('<link rel="stylesheet" type="text/css" href="%s">' . "\n", $file);
}
foreach ($inlineCss as $content) {
$html .= \sprintf('<style>%s</style>' . "\n", $content);
}
foreach ($jsFiles as $file) {
$html .= \sprintf('<script type="text/javascript" src="%s" defer></script>' . "\n", $file);
}
$nonce = '';
if ($doc->cspNonce) {
$nonce = ' nonce="' . $doc->cspNonce . '"';
}
foreach ($inlineJs as $content) {
$html .= \sprintf('<script type="module"%s>%s</script>' . "\n", $nonce, $content);
}
foreach ($inlineHead as $content) {
$html .= $content . "\n";
}
return $html;
}
/**
* Returns the code needed to display the debug bar
*
* AJAX request should not render the initialization code.
*
* @param boolean $initialize Whether or not to render the debug bar initialization code
* @param boolean $renderStackedData Whether or not to render the stacked data
*
* @return string
*
* @since 4.0.0
*/
public function render($initialize = true, $renderStackedData = true)
{
$js = '';
$doc = Factory::getApplication()->getDocument();
if ($initialize) {
$js = $this->getJsInitializationCode();
}
if ($renderStackedData && $this->debugBar->hasStackedData()) {
foreach ($this->debugBar->getStackedData() as $id => $data) {
$js .= $this->getAddDatasetCode($id, $data, '(stacked)');
}
}
$suffix = !$initialize ? '(ajax)' : null;
$js .= $this->getAddDatasetCode($this->debugBar->getCurrentRequestId(), $this->debugBar->getData(), $suffix);
$nonce = '';
if ($doc->cspNonce) {
$nonce = ' nonce="' . $doc->cspNonce . '"';
}
if ($this->useRequireJs) {
return "<script type=\"module\"$nonce>\nrequire(['debugbar'], function(PhpDebugBar){ $js });\n</script>\n";
}
return "<script type=\"module\"$nonce>\n$js\n</script>\n";
}
}

View File

@ -0,0 +1,134 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2022 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug;
use DebugBar\HttpDriverInterface;
use Joomla\Application\WebApplicationInterface;
use Joomla\CMS\Application\CMSApplicationInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Joomla HTTP driver for DebugBar
*
* @since 4.1.5
*/
final class JoomlaHttpDriver implements HttpDriverInterface
{
/**
* @var CMSApplicationInterface
*
* @since 4.1.5
*/
private $app;
/**
* @var array
*
* @since 4.1.5
*/
private $dummySession = [];
/**
* Constructor.
*
* @param CMSApplicationInterface $app
*
* @since 4.1.5
*/
public function __construct(CMSApplicationInterface $app)
{
$this->app = $app;
}
/**
* Sets HTTP headers
*
* @param array $headers
*
* @since 4.1.5
*/
public function setHeaders(array $headers)
{
if ($this->app instanceof WebApplicationInterface) {
foreach ($headers as $name => $value) {
$this->app->setHeader($name, $value, true);
}
}
}
/**
* Checks if the session is started
*
* @return boolean
*
* @since 4.1.5
*/
public function isSessionStarted()
{
return true;
}
/**
* Sets a value in the session
*
* @param string $name
* @param string $value
*
* @since 4.1.5
*/
public function setSessionValue($name, $value)
{
$this->dummySession[$name] = $value;
}
/**
* Checks if a value is in the session
*
* @param string $name
*
* @return boolean
*
* @since 4.1.5
*/
public function hasSessionValue($name)
{
return \array_key_exists($name, $this->dummySession);
}
/**
* Returns a value from the session
*
* @param string $name
*
* @return mixed
*
* @since 4.1.5
*/
public function getSessionValue($name)
{
return $this->dummySession[$name] ?? null;
}
/**
* Deletes a value from the session
*
* @param string $name
*
* @since 4.1.5
*/
public function deleteSessionValue($name)
{
unset($this->dummySession[$name]);
}
}

View File

@ -0,0 +1,192 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.Debug
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Debug\Storage;
use Joomla\CMS\Factory;
use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\Filesystem\File;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Stores collected data into files
*
* @since 4.0.0
*/
class FileStorage extends \DebugBar\Storage\FileStorage
{
/**
* Saves collected data
*
* @param string $id The log id
* @param string $data The log data
*
* @return void
*
* @since 4.0.0
*/
public function save($id, $data)
{
if (!file_exists($this->dirname)) {
Folder::create($this->dirname);
}
$dataStr = '<?php die(); ?>#(^-^)#' . json_encode($data);
File::write($this->makeFilename($id), $dataStr);
}
/**
* Returns collected data with the specified id
*
* @param string $id The log id
*
* @return array
*
* @since 4.0.0
*/
public function get($id)
{
$dataStr = file_get_contents($this->makeFilename($id));
$dataStr = str_replace('<?php die(); ?>#(^-^)#', '', $dataStr);
return json_decode($dataStr, true) ?: [];
}
/**
* Returns a metadata about collected data
*
* @param array $filters Filtering options
* @param integer $max The limit, items per page
* @param integer $offset The offset
*
* @return array
*
* @since 4.0.0
*/
public function find(array $filters = [], $max = 20, $offset = 0)
{
// Loop through all .php files and remember the modified time and id.
$files = [];
foreach (new \DirectoryIterator($this->dirname) as $file) {
if ($file->getExtension() == 'php') {
$files[] = [
'time' => $file->getMTime(),
'id' => $file->getBasename('.php'),
];
}
}
// Sort the files, newest first
usort(
$files,
function ($a, $b) {
if ($a['time'] === $b['time']) {
return 0;
}
return $a['time'] < $b['time'] ? 1 : -1;
}
);
// Load the metadata and filter the results.
$results = [];
$i = 0;
foreach ($files as $file) {
// When filter is empty, skip loading the offset
if ($i++ < $offset && empty($filters)) {
$results[] = null;
continue;
}
$data = $this->get($file['id']);
if (!$this->isSecureToReturnData($data)) {
continue;
}
$meta = $data['__meta'];
unset($data);
if ($this->filter($meta, $filters)) {
$results[] = $meta;
}
if (\count($results) >= ($max + $offset)) {
break;
}
}
return \array_slice($results, $offset, $max);
}
/**
* Get a full path to the file
*
* @param string $id The log id
*
* @return string
*
* @since 4.0.0
*/
public function makeFilename($id)
{
return $this->dirname . basename($id) . '.php';
}
/**
* Check if the user is allowed to view the request. Users can only see their own requests.
*
* @param array $data The data item to process
*
* @return boolean
*
* @since 4.2.4
*/
private function isSecureToReturnData($data): bool
{
/**
* We only started this collector in Joomla 4.2.4 - any older files we have to assume are insecure.
*/
if (!\array_key_exists('juser', $data)) {
return false;
}
$currentUser = Factory::getUser();
$currentUserId = $currentUser->id;
$currentUserSuperAdmin = $currentUser->authorise('core.admin');
/**
* Guests aren't allowed to look at other requests because there's no guarantee it's the same guest. Potentially
* in the future this could be refined to check the session ID to show some requests. But it's unlikely we want
* guests to be using the debug bar anyhow
*/
if ($currentUserId === 0) {
return false;
}
/** @var \Joomla\CMS\User\User $user */
$user = Factory::getContainer()->get(UserFactoryInterface::class)
->loadUserById($data['juser']['user_id']);
// Super users are allowed to look at other users requests. Otherwise users can only see their own requests.
if ($currentUserSuperAdmin || $user->id === $currentUserId) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_fields</name>
<author>Joomla! Project</author>
<creationDate>2016-03</creationDate>
<copyright>(C) 2016 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.7.0</version>
<description>PLG_SYSTEM_FIELDS_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\System\Fields</namespace>
<files>
<folder plugin="fields">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_system_fields.ini</language>
<language tag="en-GB">language/en-GB/plg_system_fields.sys.ini</language>
</languages>
</extension>

View File

@ -0,0 +1,48 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.fields
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\User\UserFactoryInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\System\Fields\Extension\Fields;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.4.0
*/
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Fields(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('system', 'fields')
);
$plugin->setApplication(Factory::getApplication());
$plugin->setUserFactory($container->get(UserFactoryInterface::class));
return $plugin;
}
);
}
};

View File

@ -0,0 +1,483 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.fields
*
* @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Fields\Extension;
use Joomla\CMS\Event\Content;
use Joomla\CMS\Event\Model;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\User\UserFactoryAwareTrait;
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
use Joomla\Registry\Registry;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Fields Plugin
*
* @since 3.7
*/
final class Fields extends CMSPlugin
{
use UserFactoryAwareTrait;
/**
* Normalizes the request data.
*
* @param Model\NormaliseRequestDataEvent $event The event object
*
* @return void
*
* @since 3.8.7
*/
public function onContentNormaliseRequestData(Model\NormaliseRequestDataEvent $event)
{
$context = $event->getContext();
$data = $event->getData();
$form = $event->getForm();
if (!FieldsHelper::extract($context, $data)) {
return;
}
// Loop over all fields
foreach ($form->getGroup('com_fields') as $field) {
if ($field->disabled === true) {
/**
* Disabled fields should NEVER be added to the request as
* they should NEVER be added by the browser anyway so nothing to check against
* as "disabled" means no interaction at all.
*/
// Make sure the data object has an entry before delete it
if (isset($data->com_fields[$field->fieldname])) {
unset($data->com_fields[$field->fieldname]);
}
continue;
}
// Make sure the data object has an entry
if (isset($data->com_fields[$field->fieldname])) {
continue;
}
// Set a default value for the field
$data->com_fields[$field->fieldname] = false;
}
}
/**
* The save event.
*
* @param string $context The context
* @param \Joomla\CMS\Table\Table $item The table
* @param boolean $isNew Is new item
* @param array $data The validated data
*
* @return void
*
* @since 3.7.0
*/
public function onContentAfterSave($context, $item, $isNew, $data = []): void
{
// Check if data is an array and the item has an id
if (!\is_array($data) || empty($item->id) || empty($data['com_fields'])) {
return;
}
// Create correct context for category
if ($context === 'com_categories.category') {
$context = $item->extension . '.categories';
// Set the catid on the category to get only the fields which belong to this category
$item->catid = $item->id;
}
// Check the context
$parts = FieldsHelper::extract($context, $item);
if (!$parts) {
return;
}
// Compile the right context for the fields
$context = $parts[0] . '.' . $parts[1];
// Loading the fields
$fields = FieldsHelper::getFields($context, $item);
if (!$fields) {
return;
}
// Loading the model
/** @var \Joomla\Component\Fields\Administrator\Model\FieldModel $model */
$model = $this->getApplication()->bootComponent('com_fields')->getMVCFactory()
->createModel('Field', 'Administrator', ['ignore_request' => true]);
// Loop over the fields
foreach ($fields as $field) {
// Determine the value if it is (un)available from the data
if (\array_key_exists($field->name, $data['com_fields'])) {
$value = $data['com_fields'][$field->name] === false ? null : $data['com_fields'][$field->name];
} else {
// Field not available on form, use stored value
$value = $field->rawvalue;
}
// If no value set (empty) remove value from database
if (\is_array($value) ? !\count($value) : !\strlen($value)) {
$value = null;
}
// JSON encode value for complex fields
if (\is_array($value) && (\count($value, COUNT_NORMAL) !== \count($value, COUNT_RECURSIVE) || !\count(array_filter(array_keys($value), 'is_numeric')))) {
$value = json_encode($value);
}
// Setting the value for the field and the item
$model->setFieldValue($field->id, $item->id, $value);
}
}
/**
* The save event.
*
* @param array $userData The date
* @param boolean $isNew Is new
* @param boolean $success Is success
* @param string $msg The message
*
* @return void
*
* @since 3.7.0
*/
public function onUserAfterSave($userData, $isNew, $success, $msg): void
{
// It is not possible to manipulate the user during save events
// Check if data is valid or we are in a recursion
if (!$userData['id'] || !$success) {
return;
}
$user = $this->getUserFactory()->loadUserById($userData['id']);
$task = $this->getApplication()->getInput()->getCmd('task');
// Skip fields save when we activate a user, because we will lose the saved data
if (\in_array($task, ['activate', 'block', 'unblock'])) {
return;
}
// Trigger the events with a real user
$this->onContentAfterSave('com_users.user', $user, false, $userData);
}
/**
* The delete event.
*
* @param string $context The context
* @param \stdClass $item The item
*
* @return void
*
* @since 3.7.0
*/
public function onContentAfterDelete($context, $item): void
{
// Set correct context for category
if ($context === 'com_categories.category') {
$context = $item->extension . '.categories';
}
$parts = FieldsHelper::extract($context, $item);
if (!$parts || empty($item->id)) {
return;
}
$context = $parts[0] . '.' . $parts[1];
/** @var \Joomla\Component\Fields\Administrator\Model\FieldModel $model */
$model = $this->getApplication()->bootComponent('com_fields')->getMVCFactory()
->createModel('Field', 'Administrator', ['ignore_request' => true]);
$model->cleanupValues($context, $item->id);
}
/**
* The user delete event.
*
* @param array $user The context
* @param boolean $success Is success
* @param string $msg The message
*
* @return void
*
* @since 3.7.0
*/
public function onUserAfterDelete($user, $success, $msg): void
{
$item = new \stdClass();
$item->id = $user['id'];
$this->onContentAfterDelete('com_users.user', $item);
}
/**
* The form event.
*
* @param Model\PrepareFormEvent $event The event object
*
* @return void
*
* @since 3.7.0
*/
public function onContentPrepareForm(Model\PrepareFormEvent $event)
{
$form = $event->getForm();
$data = $event->getData();
$context = $form->getName();
// When a category is edited, the context is com_categories.categorycom_content
if (strpos($context, 'com_categories.category') === 0) {
$context = str_replace('com_categories.category', '', $context) . '.categories';
$data = $data ?: $this->getApplication()->getInput()->get('jform', [], 'array');
// Set the catid on the category to get only the fields which belong to this category
if (\is_array($data) && \array_key_exists('id', $data)) {
$data['catid'] = $data['id'];
}
if (\is_object($data) && isset($data->id)) {
$data->catid = $data->id;
}
}
$parts = FieldsHelper::extract($context, $form);
if (!$parts) {
return;
}
$input = $this->getApplication()->getInput();
// If we are on the save command we need the actual data
$jformData = $input->get('jform', [], 'array');
if ($jformData && !$data) {
$data = $jformData;
}
if (\is_array($data)) {
$data = (object) $data;
}
FieldsHelper::prepareForm($parts[0] . '.' . $parts[1], $form, $data);
}
/**
* The display event.
*
* @param Content\AfterTitleEvent $event The event object
*
* @return void
*
* @since 3.7.0
*/
public function onContentAfterTitle(Content\AfterTitleEvent $event)
{
$event->addResult($this->display($event->getContext(), $event->getItem(), $event->getParams(), 1));
}
/**
* The display event.
*
* @param Content\BeforeDisplayEvent $event The event object
*
* @return void
*
* @since 3.7.0
*/
public function onContentBeforeDisplay(Content\BeforeDisplayEvent $event)
{
$event->addResult($this->display($event->getContext(), $event->getItem(), $event->getParams(), 2));
}
/**
* The display event.
*
* @param Content\AfterDisplayEvent $event The event object
*
* @return void
*
* @since 3.7.0
*/
public function onContentAfterDisplay(Content\AfterDisplayEvent $event)
{
$event->addResult($this->display($event->getContext(), $event->getItem(), $event->getParams(), 3));
}
/**
* Performs the display event.
*
* @param string $context The context
* @param \stdClass $item The item
* @param Registry $params The params
* @param integer $displayType The type
*
* @return string
*
* @since 3.7.0
*/
private function display($context, $item, $params, $displayType)
{
$parts = FieldsHelper::extract($context, $item);
if (!$parts) {
return '';
}
// If we have a category, set the catid field to fetch only the fields which belong to it
if ($parts[1] === 'categories' && !isset($item->catid)) {
$item->catid = $item->id;
}
$context = $parts[0] . '.' . $parts[1];
// Convert tags
if ($context == 'com_tags.tag' && !empty($item->type_alias)) {
// Set the context
$context = $item->type_alias;
$item = $this->prepareTagItem($item);
}
if (\is_string($params) || !$params) {
$params = new Registry($params);
}
$fields = FieldsHelper::getFields($context, $item, $displayType);
if ($fields) {
if ($this->getApplication()->isClient('site') && Multilanguage::isEnabled() && isset($item->language) && $item->language === '*') {
$lang = $this->getApplication()->getLanguage()->getTag();
foreach ($fields as $key => $field) {
if ($field->language === '*' || $field->language == $lang) {
continue;
}
unset($fields[$key]);
}
}
}
if ($fields) {
foreach ($fields as $key => $field) {
$fieldDisplayType = $field->params->get('display', '2');
if ($fieldDisplayType == $displayType) {
continue;
}
unset($fields[$key]);
}
}
if ($fields) {
return FieldsHelper::render(
$context,
'fields.render',
[
'item' => $item,
'context' => $context,
'fields' => $fields,
]
);
}
return '';
}
/**
* Performs the display event.
*
* @param Content\ContentPrepareEvent $event The event object
*
* @return void
*
* @since 3.7.0
*/
public function onContentPrepare(Content\ContentPrepareEvent $event)
{
$context = $event->getContext();
$item = $event->getItem();
// Check property exists (avoid costly & useless recreation), if need to recreate them, just unset the property!
if (isset($item->jcfields)) {
return;
}
$parts = FieldsHelper::extract($context, $item);
if (!$parts) {
return;
}
$context = $parts[0] . '.' . $parts[1];
// Convert tags
if ($context == 'com_tags.tag' && !empty($item->type_alias)) {
// Set the context
$context = $item->type_alias;
$item = $this->prepareTagItem($item);
}
// Get item's fields, also preparing their value property for manual display
// (calling plugins events and loading layouts to get their HTML display)
$fields = FieldsHelper::getFields($context, $item, true);
// Adding the fields to the object
$item->jcfields = [];
foreach ($fields as $key => $field) {
$item->jcfields[$field->id] = $field;
}
}
/**
* Prepares a tag item to be ready for com_fields.
*
* @param \stdClass $item The item
*
* @return object
*
* @since 3.8.4
*/
private function prepareTagItem($item)
{
// Map core fields
$item->id = $item->content_item_id;
$item->language = $item->core_language;
// Also handle the catid
if (!empty($item->core_catid)) {
$item->catid = $item->core_catid;
}
return $item;
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_guidedtours</name>
<author>Joomla! Project</author>
<creationDate>2023-02</creationDate>
<copyright>(C) 2023 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>4.3.0</version>
<description>PLG_SYSTEM_GUIDEDTOURS_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\System\GuidedTours</namespace>
<files>
<folder plugin="guidedtours">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_system_guidedtours.ini</language>
<language tag="en-GB">language/en-GB/plg_system_guidedtours.sys.ini</language>
</languages>
</extension>

View File

@ -0,0 +1,57 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.guidedtours
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\WebAsset\WebAssetRegistry;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\System\GuidedTours\Extension\GuidedTours;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.3.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$app = Factory::getApplication();
$plugin = new GuidedTours(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('system', 'guidedtours'),
$app->isClient('administrator')
);
$plugin->setApplication($app);
$plugin->setDatabase($container->get(DatabaseInterface::class));
$wa = $container->get(WebAssetRegistry::class);
$wa->addRegistryFile('media/plg_system_guidedtours/joomla.asset.json');
return $plugin;
}
);
}
};

View File

@ -0,0 +1,386 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.guidedtours
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\GuidedTours\Extension;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Date\Date;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Object\CMSObject;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Session\Session;
use Joomla\Component\Guidedtours\Administrator\Extension\GuidedtoursComponent;
use Joomla\Component\Guidedtours\Administrator\Model\TourModel;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Database\ParameterType;
use Joomla\Event\DispatcherInterface;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Guided Tours plugin to add interactive tours to the administrator interface.
*
* @since 4.3.0
*/
final class GuidedTours extends CMSPlugin implements SubscriberInterface
{
use DatabaseAwareTrait;
/**
* A mapping for the step types
*
* @var string[]
* @since 4.3.0
*/
protected $stepType = [
GuidedtoursComponent::STEP_NEXT => 'next',
GuidedtoursComponent::STEP_REDIRECT => 'redirect',
GuidedtoursComponent::STEP_INTERACTIVE => 'interactive',
];
/**
* A mapping for the step interactive types
*
* @var string[]
* @since 4.3.0
*/
protected $stepInteractiveType = [
GuidedtoursComponent::STEP_INTERACTIVETYPE_FORM_SUBMIT => 'submit',
GuidedtoursComponent::STEP_INTERACTIVETYPE_TEXT => 'text',
GuidedtoursComponent::STEP_INTERACTIVETYPE_OTHER => 'other',
GuidedtoursComponent::STEP_INTERACTIVETYPE_BUTTON => 'button',
GuidedtoursComponent::STEP_INTERACTIVETYPE_CHECKBOX_RADIO => 'checkbox_radio',
GuidedtoursComponent::STEP_INTERACTIVETYPE_SELECT => 'select',
];
/**
* An internal flag whether plugin should listen any event.
*
* @var bool
*
* @since 4.3.0
*/
protected static $enabled = false;
/**
* Constructor
*
* @param DispatcherInterface $dispatcher The object to observe
* @param array $config An optional associative array of configuration settings.
* @param boolean $enabled An internal flag whether plugin should listen any event.
*
* @since 4.3.0
*/
public function __construct(DispatcherInterface $dispatcher, array $config = [], bool $enabled = false)
{
self::$enabled = $enabled;
parent::__construct($dispatcher, $config);
}
/**
* function for getSubscribedEvents : new Joomla 4 feature
*
* @return array
*
* @since 4.3.0
*/
public static function getSubscribedEvents(): array
{
return self::$enabled ? [
'onAjaxGuidedtours' => 'startTour',
'onBeforeCompileHead' => 'onBeforeCompileHead',
] : [];
}
/**
* Retrieve and starts a tour and its steps through Ajax.
*
* @return null|object
*
* @since 4.3.0
*/
public function startTour(Event $event)
{
$tourId = (int) $this->getApplication()->getInput()->getInt('id');
$tourUid = $this->getApplication()->getInput()->getString('uid', '');
$tourUid = $tourUid !== '' ? urldecode($tourUid) : '';
$tour = null;
// Load plugin language files
$this->loadLanguage();
if ($tourId > 0) {
$tour = $this->getTour($tourId);
} elseif ($tourUid !== '') {
$tour = $this->getTour($tourUid);
}
$event->setArgument('result', $tour ?? new \stdClass());
return $tour;
}
/**
* Listener for the `onBeforeCompileHead` event
*
* @return void
*
* @since 4.3.0
*/
public function onBeforeCompileHead()
{
$app = $this->getApplication();
$doc = $app->getDocument();
$user = $app->getIdentity();
if ($user != null && $user->id > 0) {
// Load plugin language files.
$this->loadLanguage();
Text::script('JCANCEL');
Text::script('PLG_SYSTEM_GUIDEDTOURS_BACK');
Text::script('PLG_SYSTEM_GUIDEDTOURS_COMPLETE');
Text::script('PLG_SYSTEM_GUIDEDTOURS_COULD_NOT_LOAD_THE_TOUR');
Text::script('PLG_SYSTEM_GUIDEDTOURS_HIDE_FOREVER');
Text::script('PLG_SYSTEM_GUIDEDTOURS_NEXT');
Text::script('PLG_SYSTEM_GUIDEDTOURS_STEP_NUMBER_OF');
Text::script('PLG_SYSTEM_GUIDEDTOURS_TOUR_ERROR');
Text::script('PLG_SYSTEM_GUIDEDTOURS_TOUR_ERROR_RESPONSE');
Text::script('PLG_SYSTEM_GUIDEDTOURS_TOUR_INVALID_RESPONSE');
$doc->addScriptOptions('com_guidedtours.token', Session::getFormToken());
$doc->addScriptOptions('com_guidedtours.autotour', '');
// Load required assets.
$doc->getWebAssetManager()
->usePreset('plg_system_guidedtours.guidedtours');
$params = ComponentHelper::getParams('com_guidedtours');
// Check if the user has opted out of auto-start
$userAuthorizedAutostart = $user->getParam('allowTourAutoStart', $params->get('allowTourAutoStart', 1));
if (!$userAuthorizedAutostart) {
return;
}
// The following code only relates to the auto-start functionality.
// First, we get the tours for the context.
$factory = $app->bootComponent('com_guidedtours')->getMVCFactory();
$toursModel = $factory->createModel(
'Tours',
'Administrator',
['ignore_request' => true]
);
$toursModel->setState('filter.extension', $app->getInput()->getCmd('option', 'com_cpanel'));
$toursModel->setState('filter.published', 1);
$toursModel->setState('filter.access', $user->getAuthorisedViewLevels());
if (Multilanguage::isEnabled()) {
$toursModel->setState('filter.language', ['*', $app->getLanguage()->getTag()]);
}
$tours = $toursModel->getItems();
foreach ($tours as $tour) {
// Look for the first autostart tour, if any.
if ($tour->autostart) {
$db = $this->getDatabase();
$profileKey = 'guidedtour.id.' . $tour->id;
// Check if the tour state has already been saved some time before.
$query = $db->getQuery(true)
->select($db->quoteName('profile_value'))
->from($db->quoteName('#__user_profiles'))
->where($db->quoteName('user_id') . ' = :user_id')
->where($db->quoteName('profile_key') . ' = :profileKey')
->bind(':user_id', $user->id, ParameterType::INTEGER)
->bind(':profileKey', $profileKey, ParameterType::STRING);
try {
$result = $db->setQuery($query)->loadResult();
} catch (\Exception $e) {
// Do not start the tour.
continue;
}
// A result has been found in the user profiles table
if (!\is_null($result)) {
$values = json_decode($result, true);
if (empty($values)) {
// Do not start the tour.
continue;
}
if ($values['state'] === 'skipped' || $values['state'] === 'completed') {
// Do not start the tour.
continue;
}
if ($values['state'] === 'delayed') {
$delay = $params->get('delayed_time', '60');
$currentTime = Date::getInstance();
$loggedTime = new Date($values['time']['date']);
if ($loggedTime->add(new \DateInterval('PT' . $delay . 'M')) > $currentTime) {
// Do not start the tour.
continue;
}
}
}
// We have a tour to auto start. No need to go any further.
$doc->addScriptOptions('com_guidedtours.autotour', $tour->id);
break;
}
}
}
}
/**
* Get a tour and its steps or null if not found
*
* @param integer|string $tourId The ID or Uid of the tour to load
*
* @return null|object
*
* @since 4.3.0
*/
private function getTour($tourId)
{
$app = $this->getApplication();
$factory = $app->bootComponent('com_guidedtours')->getMVCFactory();
/** @var TourModel $tourModel */
$tourModel = $factory->createModel(
'Tour',
'Administrator',
['ignore_request' => true]
);
$item = $tourModel->getItem($tourId);
return $this->processTour($item);
}
/**
* Return a tour and its steps or null if not found
*
* @param CMSObject $item The tour to load
*
* @return null|object
*
* @since 5.0.0
*/
private function processTour($item)
{
$app = $this->getApplication();
$user = $app->getIdentity();
$factory = $app->bootComponent('com_guidedtours')->getMVCFactory();
if (empty($item->id) || $item->published < 1 || !\in_array($item->access, $user->getAuthorisedViewLevels())) {
return null;
}
// We don't want to show all parameters, so take only a subset of the tour attributes
$tour = new \stdClass();
$tour->id = $item->id;
$tour->autostart = $item->autostart;
$stepsModel = $factory->createModel(
'Steps',
'Administrator',
['ignore_request' => true]
);
$stepsModel->setState('filter.tour_id', $item->id);
$stepsModel->setState('filter.published', 1);
$stepsModel->setState('list.ordering', 'a.ordering');
$stepsModel->setState('list.direction', 'ASC');
$steps = $stepsModel->getItems();
$tour->steps = [];
$temp = new \stdClass();
$temp->id = 0;
$temp->title = $this->getApplication()->getLanguage()->_($item->title);
$temp->description = $this->getApplication()->getLanguage()->_($item->description);
$temp->description = $this->fixImagePaths($temp->description);
$temp->url = $item->url;
// Set the start label for the tour.
$temp->start_label = Text::_('PLG_SYSTEM_GUIDEDTOURS_START');
// What's new tours have a different label.
if (str_contains($item->uid, 'joomla-whatsnew')) {
$temp->start_label = Text::_('PLG_SYSTEM_GUIDEDTOURS_NEXT');
}
$tour->steps[] = $temp;
foreach ($steps as $i => $step) {
$temp = new \stdClass();
$temp->id = $i + 1;
$temp->title = $this->getApplication()->getLanguage()->_($step->title);
$temp->description = $this->getApplication()->getLanguage()->_($step->description);
$temp->description = $this->fixImagePaths($temp->description);
$temp->position = $step->position;
$temp->target = $step->target;
$temp->type = $this->stepType[$step->type];
$temp->interactive_type = $this->stepInteractiveType[$step->interactive_type];
$temp->params = $step->params;
$temp->url = $step->url;
$temp->tour_id = $step->tour_id;
$temp->step_id = $step->id;
$tour->steps[] = $temp;
}
return $tour;
}
/**
* Return a modified version of a given string with usable image paths for tours
*
* @param string $description The string to fix
*
* @return string
*
* @since 5.2.0
*/
private function fixImagePaths($description)
{
return preg_replace(
[
'*src="(?!administrator\/)images/*',
'*src="media/*',
],
[
'src="../images/',
'src="../media/',
],
$description
);
}
}

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_highlight</name>
<author>Joomla! Project</author>
<creationDate>2011-08</creationDate>
<copyright>(C) 2011 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>3.0.0</version>
<description>PLG_SYSTEM_HIGHLIGHT_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\System\Highlight</namespace>
<files>
<folder plugin="highlight">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_system_highlight.ini</language>
<language tag="en-GB">language/en-GB/plg_system_highlight.sys.ini</language>
</languages>
</extension>

View File

@ -0,0 +1,46 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.highlight
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\System\Highlight\Extension\Highlight;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.4.0
*/
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Highlight(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('system', 'highlight')
);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};

View File

@ -0,0 +1,130 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.highlight
*
* @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Highlight\Extension;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Uri\Uri;
use Joomla\Component\Finder\Administrator\Indexer\Result;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* System plugin to highlight terms.
*
* @since 2.5
*/
final class Highlight extends CMSPlugin
{
/**
* Method to catch the onAfterDispatch event.
*
* This is where we setup the click-through content highlighting for.
* The highlighting is done with JavaScript so we just
* need to check a few parameters and the JHtml behavior will do the rest.
*
* @return void
*
* @since 2.5
*/
public function onAfterDispatch()
{
// Check that we are in the site application.
if (!$this->getApplication()->isClient('site')) {
return;
}
// Set the variables.
$input = $this->getApplication()->getInput();
$extension = $input->get('option', '', 'cmd');
// Check if the highlighter is enabled.
if (!ComponentHelper::getParams($extension)->get('highlight_terms', 1)) {
return;
}
// Check if the highlighter should be activated in this environment.
if ($input->get('tmpl', '', 'cmd') === 'component' || $this->getApplication()->getDocument()->getType() !== 'html') {
return;
}
// Get the terms to highlight from the request.
$terms = $input->request->get('highlight', null, 'base64');
$terms = $terms ? json_decode(base64_decode($terms)) : null;
// Check the terms.
if (empty($terms)) {
return;
}
// Clean the terms array.
$filter = InputFilter::getInstance();
$cleanTerms = [];
foreach ($terms as $term) {
$cleanTerms[] = htmlspecialchars($filter->clean($term, 'string'));
}
/** @var \Joomla\CMS\Document\HtmlDocument $doc */
$doc = $this->getApplication()->getDocument();
// Activate the highlighter.
if (!empty($cleanTerms)) {
$doc->getWebAssetManager()->useScript('highlight');
$doc->addScriptOptions(
'highlight',
[[
'class' => 'js-highlight',
'highLight' => $cleanTerms,
]]
);
}
// Adjust the component buffer.
$buf = $doc->getBuffer('component');
$buf = '<div class="js-highlight">' . $buf . '</div>';
$doc->setBuffer($buf, 'component');
}
/**
* Method to catch the onFinderResult event.
*
* @param Result $item The search result
* @param object $query The search query of this result
*
* @return void
*
* @since 4.0.0
*/
public function onFinderResult($item, $query)
{
static $params;
if (\is_null($params)) {
$params = ComponentHelper::getParams('com_finder');
}
// Get the route with highlighting information.
if (
!empty($query->highlight)
&& empty($item->mime)
&& $params->get('highlight_terms', 1)
) {
$uri = new Uri($item->route);
$uri->setVar('highlight', base64_encode(json_encode(\array_slice($query->highlight, 0, 10))));
$item->route = $uri->toString();
}
}
}

View File

@ -0,0 +1,328 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_httpheaders</name>
<author>Joomla! Project</author>
<creationDate>2017-10</creationDate>
<copyright>(C) 2018 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>4.0.0</version>
<description>PLG_SYSTEM_HTTPHEADERS_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\System\Httpheaders</namespace>
<files>
<folder>postinstall</folder>
<folder plugin="httpheaders">services</folder>
<folder>src</folder>
</files>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="xframeoptions"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_XFRAMEOPTIONS"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
validate="options"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
<field
name="referrerpolicy"
type="list"
label="PLG_SYSTEM_HTTPHEADERS_REFERRERPOLICY"
default="strict-origin-when-cross-origin"
validate="options"
>
<option value="disabled">JDISABLED</option>
<option value="no-referrer">no-referrer</option>
<option value="no-referrer-when-downgrade">no-referrer-when-downgrade</option>
<option value="origin">origin</option>
<option value="origin-when-cross-origin">origin-when-cross-origin</option>
<option value="same-origin">same-origin</option>
<option value="strict-origin">strict-origin</option>
<option value="strict-origin-when-cross-origin">strict-origin-when-cross-origin</option>
<option value="unsafe-url">unsafe-url</option>
</field>
<field
name="coop"
type="list"
label="PLG_SYSTEM_HTTPHEADERS_COOP"
default="same-origin"
validate="options"
>
<option value="disabled">JDISABLED</option>
<option value="same-origin">same-origin</option>
<option value="same-origin-allow-popups">same-origin-allow-popups</option>
<option value="unsafe-none">unsafe-none</option>
</field>
<field
name="additional_httpheader"
type="subform"
label="PLG_SYSTEM_HTTPHEADERS_ADDITIONAL_HEADER"
multiple="true"
>
<form>
<field
name="key"
type="list"
label="PLG_SYSTEM_HTTPHEADERS_ADDITIONAL_HEADER_KEY"
validate="options"
class="col-md-4"
>
<option value="content-security-policy">Content-Security-Policy</option>
<option value="content-security-policy-report-only">Content-Security-Policy-Report-Only</option>
<option value="cross-origin-opener-policy">Cross-Origin-Opener-Policy</option>
<option value="expect-ct">Expect-CT</option>
<option value="feature-policy">Feature-Policy</option>
<option value="nel">NEL</option>
<option value="permissions-policy">Permissions-Policy</option>
<option value="referrer-policy">Referrer-Policy</option>
<option value="report-to">Report-To</option>
<option value="strict-transport-security">Strict-Transport-Security</option>
<option value="x-frame-options">X-Frame-Options</option>
</field>
<field
name="value"
type="text"
label="PLG_SYSTEM_HTTPHEADERS_ADDITIONAL_HEADER_VALUE"
class="col-md-10"
/>
<field
name="client"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_HEADER_CLIENT"
default="site"
validate="options"
class="col-md-12"
>
<option value="site">JSITE</option>
<option value="administrator">JADMINISTRATOR</option>
<option value="both">PLG_SYSTEM_HTTPHEADERS_HEADER_CLIENT_BOTH</option>
</field>
</form>
</field>
</fieldset>
<fieldset name="hsts" label="Strict-Transport-Security (HSTS)">
<field
name="hsts"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_HSTS"
layout="joomla.form.field.radio.switcher"
default="0"
filter="integer"
validate="options"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
<field
name="hsts_maxage"
type="number"
label="PLG_SYSTEM_HTTPHEADERS_HSTS_MAXAGE"
description="PLG_SYSTEM_HTTPHEADERS_HSTS_MAXAGE_DESC"
default="31536000"
filter="integer"
validate="number"
min="300"
showon="hsts:1"
/>
<field
name="hsts_subdomains"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_HSTS_SUBDOMAINS"
description="PLG_SYSTEM_HTTPHEADERS_HSTS_SUBDOMAINS_DESC"
layout="joomla.form.field.radio.switcher"
default="0"
filter="integer"
validate="options"
showon="hsts:1"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
<field
name="hsts_preload"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_HSTS_PRELOAD"
description="PLG_SYSTEM_HTTPHEADERS_HSTS_PRELOAD_NOTE_DESC"
layout="joomla.form.field.radio.switcher"
default="0"
filter="integer"
validate="options"
showon="hsts:1"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
</fieldset>
<fieldset name="csp" label="Content-Security-Policy (CSP)">
<field
name="contentsecuritypolicy"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY"
layout="joomla.form.field.radio.switcher"
default="0"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
<field
name="contentsecuritypolicy_client"
type="list"
label="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_CLIENT"
default="site"
validate="options"
showon="contentsecuritypolicy:1"
>
<option value="site">JSITE</option>
<option value="administrator">JADMINISTRATOR</option>
<option value="both">PLG_SYSTEM_HTTPHEADERS_HEADER_CLIENT_BOTH</option>
</field>
<field
name="contentsecuritypolicy_report_only"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_REPORT_ONLY"
description="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_REPORT_ONLY_DESC"
layout="joomla.form.field.radio.switcher"
default="1"
showon="contentsecuritypolicy:1"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
<field
name="nonce_enabled"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_NONCE_ENABLED"
description="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_NONCE_ENABLED_DESC"
layout="joomla.form.field.radio.switcher"
default="0"
showon="contentsecuritypolicy:1"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
<field
name="script_hashes_enabled"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_SCRIPT_HASHES_ENABLED"
description="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_SCRIPT_HASHES_ENABLED_DESC"
layout="joomla.form.field.radio.switcher"
default="0"
showon="contentsecuritypolicy:1"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
<field
name="strict_dynamic_enabled"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_STRICT_DYNAMIC_ENABLED"
description="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_STRICT_DYNAMIC_ENABLED_DESC"
layout="joomla.form.field.radio.switcher"
default="0"
showon="contentsecuritypolicy:1"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
<field
name="style_hashes_enabled"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_STYLE_HASHES_ENABLED"
description="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_STYLE_HASHES_ENABLED_DESC"
layout="joomla.form.field.radio.switcher"
default="0"
showon="contentsecuritypolicy:1"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
<field
name="frame_ancestors_self_enabled"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_FRAME_ANCESTORS_SELF_ENABLED"
description="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_FRAME_ANCESTORS_SELF_ENABLED_DESC"
layout="joomla.form.field.radio.switcher"
default="1"
showon="contentsecuritypolicy:1"
>
<option value="0">JDISABLED</option>
<option value="1">JENABLED</option>
</field>
<field
name="contentsecuritypolicy_values"
type="subform"
label="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_VALUES"
multiple="true"
showon="contentsecuritypolicy:1"
>
<form>
<field
name="directive"
type="list"
label="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_VALUES_DIRECTIVE"
class="col-md-4"
validate="options"
>
<option value="child-src">child-src</option>
<option value="connect-src">connect-src</option>
<option value="default-src">default-src</option>
<option value="font-src">font-src</option>
<option value="frame-src">frame-src</option>
<option value="img-src">img-src</option>
<option value="manifest-src">manifest-src</option>
<option value="media-src">media-src</option>
<option value="prefetch-src">prefetch-src</option>
<option value="object-src">object-src</option>
<option value="script-src">script-src</option>
<option value="script-src-elem">script-src-elem</option>
<option value="script-src-attr">script-src-attr</option>
<option value="style-src">style-src</option>
<option value="style-src-elem">style-src-elem</option>
<option value="style-src-attr">style-src-attr</option>
<option value="worker-src">worker-src</option>
<option value="base-uri">base-uri</option>
<option value="plugin-types">plugin-types</option>
<option value="sandbox">sandbox</option>
<option value="form-action">form-action</option>
<option value="frame-ancestors">frame-ancestors</option>
<option value="navigate-to">navigate-to</option>
<option value="report-uri">report-uri</option>
<option value="report-to">report-to</option>
<option value="block-all-mixed-content">block-all-mixed-content</option>
<option value="upgrade-insecure-requests">upgrade-insecure-requests</option>
<option value="require-sri-for">require-sri-for</option>
</field>
<field
name="value"
type="text"
label="PLG_SYSTEM_HTTPHEADERS_CONTENTSECURITYPOLICY_VALUES_VALUE"
class="col-md-10"
showon="directive!:block-all-mixed-content[AND]directive!:upgrade-insecure-requests"
/>
<field
name="client"
type="radio"
label="PLG_SYSTEM_HTTPHEADERS_HEADER_CLIENT"
default="site"
class="col-md-12"
>
<option value="site">JSITE</option>
<option value="administrator">JADMINISTRATOR</option>
<option value="both">PLG_SYSTEM_HTTPHEADERS_HEADER_CLIENT_BOTH</option>
</field>
</form>
</field>
</fieldset>
</fields>
</config>
<languages>
<language tag="en-GB">language/en-GB/plg_system_httpheaders.ini</language>
<language tag="en-GB">language/en-GB/plg_system_httpheaders.sys.ini</language>
</languages>
</extension>

View File

@ -0,0 +1,62 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.HttpHeaders
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
use Joomla\CMS\Factory;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Checks if the plugin is enabled. If not it returns true, meaning that the
* message concerning the HTTPHeaders Plugin should be displayed.
*
* @return integer
*
* @since 4.0.0
*/
function httpheaders_postinstall_condition()
{
return !Joomla\CMS\Plugin\PluginHelper::isEnabled('system', 'httpheaders');
}
/**
* Enables the HTTPHeaders plugin
*
* @return void
*
* @since 4.0.0
*/
function httpheaders_postinstall_action()
{
// Enable the plugin
$db = Factory::getDbo();
$query = $db->getQuery(true)
->update($db->quoteName('#__extensions'))
->set($db->quoteName('enabled') . ' = 1')
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
->where($db->quoteName('element') . ' = ' . $db->quote('httpheaders'));
$db->setQuery($query);
$db->execute();
$query = $db->getQuery(true)
->select('extension_id')
->from($db->quoteName('#__extensions'))
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
->where($db->quoteName('element') . ' = ' . $db->quote('httpheaders'));
$db->setQuery($query);
$extensionId = $db->loadResult();
$url = 'index.php?option=com_plugins&task=plugin.edit&extension_id=' . $extensionId;
Factory::getApplication()->redirect($url);
}

View File

@ -0,0 +1,48 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.httpheaders
*
* @copyright (C) 2023 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
\defined('_JEXEC') or die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\System\Httpheaders\Extension\Httpheaders;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.4.0
*/
public function register(Container $container): void
{
$container->set(
PluginInterface::class,
function (Container $container) {
$plugin = new Httpheaders(
$container->get(DispatcherInterface::class),
(array) PluginHelper::getPlugin('system', 'httpheaders'),
Factory::getApplication()
);
$plugin->setDatabase($container->get(DatabaseInterface::class));
return $plugin;
}
);
}
};

View File

@ -0,0 +1,456 @@
<?php
/**
* @package Joomla.Plugin
* @subpackage System.httpheaders
*
* @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Httpheaders\Extension;
use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Uri\Uri;
use Joomla\Database\DatabaseAwareTrait;
use Joomla\Event\DispatcherInterface;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Plugin class for HTTP Headers
*
* @since 4.0.0
*/
final class Httpheaders extends CMSPlugin implements SubscriberInterface
{
use DatabaseAwareTrait;
/**
* The generated csp nonce value
*
* @var string
* @since 4.0.0
*/
private $cspNonce;
/**
* The list of the supported HTTP headers
*
* @var array
* @since 4.0.0
*/
private $supportedHttpHeaders = [
'strict-transport-security',
'content-security-policy',
'content-security-policy-report-only',
'x-frame-options',
'referrer-policy',
'expect-ct',
'feature-policy',
'cross-origin-opener-policy',
'report-to',
'permissions-policy',
'nel',
];
/**
* The list of valid directives based on: https://www.w3.org/TR/CSP3/#csp-directives
*
* @var array
* @since 4.0.0
*/
private $validDirectives = [
'child-src',
'connect-src',
'default-src',
'font-src',
'frame-src',
'img-src',
'manifest-src',
'media-src',
'prefetch-src',
'object-src',
'script-src',
'script-src-elem',
'script-src-attr',
'style-src',
'style-src-elem',
'style-src-attr',
'worker-src',
'base-uri',
'plugin-types',
'sandbox',
'form-action',
'frame-ancestors',
'navigate-to',
'report-uri',
'report-to',
'block-all-mixed-content',
'upgrade-insecure-requests',
'require-sri-for',
];
/**
* The list of directives without a value
*
* @var array
* @since 4.0.0
*/
private $noValueDirectives = [
'block-all-mixed-content',
'upgrade-insecure-requests',
];
/**
* The list of directives supporting nonce
*
* @var array
* @since 4.0.0
*/
private $nonceDirectives = [
'script-src',
'style-src',
];
/**
* @param DispatcherInterface $dispatcher The object to observe -- event dispatcher.
* @param array $config An optional associative array of configuration settings.
* @param CMSApplicationInterface $app The app
*
* @since 4.0.0
*/
public function __construct(DispatcherInterface $dispatcher, array $config, CMSApplicationInterface $app)
{
parent::__construct($dispatcher, $config);
$this->setApplication($app);
$nonceEnabled = (int) $this->params->get('nonce_enabled', 0);
// Nonce generation when it's enabled
if ($nonceEnabled) {
$this->cspNonce = base64_encode(bin2hex(random_bytes(64)));
}
// Set the nonce, when not set we set it to NULL which is checked down the line
$this->getApplication()->set('csp_nonce', $this->cspNonce);
}
/**
* Returns an array of events this subscriber will listen to.
*
* @return array
*
* @since 4.0.0
*/
public static function getSubscribedEvents(): array
{
return [
'onAfterInitialise' => 'setHttpHeaders',
'onAfterRender' => 'applyHashesToCspRule',
];
}
/**
* The `applyHashesToCspRule` method makes sure the csp hashes are added to the csp header when enabled
*
* @param Event $event
*
* @return void
*
* @since 4.0.0
*/
public function applyHashesToCspRule(Event $event): void
{
// CSP is only relevant on html pages. Let's early exit here.
if ($this->getApplication()->getDocument()->getType() !== 'html') {
return;
}
$scriptHashesEnabled = (int) $this->params->get('script_hashes_enabled', 0);
$styleHashesEnabled = (int) $this->params->get('style_hashes_enabled', 0);
// Early exit when both options are disabled
if (!$scriptHashesEnabled && !$styleHashesEnabled) {
return;
}
$headData = $this->getApplication()->getDocument()->getHeadData();
$scriptHashes = [];
$styleHashes = [];
if ($scriptHashesEnabled) {
// Generate the hashes for the script-src
$inlineScripts = \is_array($headData['script']) ? $headData['script'] : [];
foreach ($inlineScripts as $type => $scripts) {
foreach ($scripts as $hash => $scriptContent) {
$scriptHashes[] = "'sha256-" . base64_encode(hash('sha256', $scriptContent, true)) . "'";
}
}
}
if ($styleHashesEnabled) {
// Generate the hashes for the style-src
$inlineStyles = \is_array($headData['style']) ? $headData['style'] : [];
foreach ($inlineStyles as $type => $styles) {
foreach ($styles as $hash => $styleContent) {
$styleHashes[] = "'sha256-" . base64_encode(hash('sha256', $styleContent, true)) . "'";
}
}
}
// Replace the hashes in the csp header when set.
$headers = $this->getApplication()->getHeaders();
foreach ($headers as $id => $headerConfiguration) {
if (
strtolower($headerConfiguration['name']) === 'content-security-policy'
|| strtolower($headerConfiguration['name']) === 'content-security-policy-report-only'
) {
$newHeaderValue = $headerConfiguration['value'];
if (!empty($scriptHashes)) {
$newHeaderValue = str_replace('{script-hashes}', implode(' ', $scriptHashes), $newHeaderValue);
} else {
$newHeaderValue = str_replace('{script-hashes}', '', $newHeaderValue);
}
if (!empty($styleHashes)) {
$newHeaderValue = str_replace('{style-hashes}', implode(' ', $styleHashes), $newHeaderValue);
} else {
$newHeaderValue = str_replace('{style-hashes}', '', $newHeaderValue);
}
$this->getApplication()->setHeader($headerConfiguration['name'], $newHeaderValue, true);
}
}
}
/**
* The `setHttpHeaders` method handle the setting of the configured HTTP Headers
*
* @param Event $event
*
* @return void
*
* @since 4.0.0
*/
public function setHttpHeaders(Event $event): void
{
// Set the default header when they are enabled
$this->setStaticHeaders();
// Handle CSP Header configuration
$cspEnabled = (int) $this->params->get('contentsecuritypolicy', 0);
$cspClient = (string) $this->params->get('contentsecuritypolicy_client', 'site');
// Check whether CSP is enabled and enabled by the current client
if ($cspEnabled && ($this->getApplication()->isClient($cspClient) || $cspClient === 'both')) {
$this->setCspHeader();
}
}
/**
* Set the CSP header when enabled
*
* @return void
*
* @since 4.0.0
*/
private function setCspHeader(): void
{
$cspReadOnly = (int) $this->params->get('contentsecuritypolicy_report_only', 1);
$cspHeader = $cspReadOnly === 0 ? 'content-security-policy' : 'content-security-policy-report-only';
// In custom mode we compile the header from the values configured
$cspValues = $this->params->get('contentsecuritypolicy_values', []);
$nonceEnabled = (int) $this->params->get('nonce_enabled', 0);
$scriptHashesEnabled = (int) $this->params->get('script_hashes_enabled', 0);
$strictDynamicEnabled = (int) $this->params->get('strict_dynamic_enabled', 0);
$styleHashesEnabled = (int) $this->params->get('style_hashes_enabled', 0);
$frameAncestorsSelfEnabled = (int) $this->params->get('frame_ancestors_self_enabled', 1);
$frameAncestorsSet = false;
foreach ($cspValues as $cspValue) {
// Handle the client settings foreach header
if (!$this->getApplication()->isClient($cspValue->client) && $cspValue->client != 'both') {
continue;
}
// Handle non value directives
if (\in_array($cspValue->directive, $this->noValueDirectives)) {
$newCspValues[] = trim($cspValue->directive);
continue;
}
// We can only use this if this is a valid entry
if (
\in_array($cspValue->directive, $this->validDirectives)
&& !empty($cspValue->value)
) {
if (\in_array($cspValue->directive, $this->nonceDirectives) && $nonceEnabled) {
/**
* That line is for B/C we do no longer require to add the nonce tag
* but add it once the setting is enabled so this line here is needed
* to remove the outdated tag that was required until 4.2.0
*/
$cspValue->value = str_replace('{nonce}', '', $cspValue->value);
// Append the nonce when the nonce setting is enabled
$cspValue->value = "'nonce-" . $this->cspNonce . "' " . $cspValue->value;
}
// Append the script hashes placeholder
if ($scriptHashesEnabled && strpos($cspValue->directive, 'script-src') === 0) {
$cspValue->value = '{script-hashes} ' . $cspValue->value;
}
// Append the style hashes placeholder
if ($styleHashesEnabled && strpos($cspValue->directive, 'style-src') === 0) {
$cspValue->value = '{style-hashes} ' . $cspValue->value;
}
if ($cspValue->directive === 'frame-ancestors') {
$frameAncestorsSet = true;
}
// Add strict-dynamic to the script-src directive when enabled
if (
$strictDynamicEnabled
&& $cspValue->directive === 'script-src'
&& strpos($cspValue->value, 'strict-dynamic') === false
) {
$cspValue->value = "'strict-dynamic' " . $cspValue->value;
}
$newCspValues[] = trim($cspValue->directive) . ' ' . trim($cspValue->value);
}
}
if ($frameAncestorsSelfEnabled && !$frameAncestorsSet) {
$newCspValues[] = "frame-ancestors 'self'";
}
if (empty($newCspValues)) {
return;
}
$this->getApplication()->setHeader($cspHeader, trim(implode('; ', $newCspValues)));
}
/**
* Get the configured static headers.
*
* @return array We return the array of static headers with its values.
*
* @since 4.0.0
*/
private function getStaticHeaderConfiguration(): array
{
$staticHeaderConfiguration = [];
// X-frame-options
if ($this->params->get('xframeoptions', 1) === 1) {
$staticHeaderConfiguration['x-frame-options#both'] = 'SAMEORIGIN';
}
// Referrer-policy
$referrerPolicy = (string) $this->params->get('referrerpolicy', 'strict-origin-when-cross-origin');
if ($referrerPolicy !== 'disabled') {
$staticHeaderConfiguration['referrer-policy#both'] = $referrerPolicy;
}
// Cross-Origin-Opener-Policy
$coop = (string) $this->params->get('coop', 'same-origin');
if ($coop !== 'disabled') {
$staticHeaderConfiguration['cross-origin-opener-policy#both'] = $coop;
}
// Generate the strict-transport-security header and make sure the site is SSL
if ($this->params->get('hsts', 0) === 1 && Uri::getInstance()->isSsl() === true) {
$hstsOptions = [];
$hstsOptions[] = 'max-age=' . (int) $this->params->get('hsts_maxage', 31536000);
if ($this->params->get('hsts_subdomains', 0) === 1) {
$hstsOptions[] = 'includeSubDomains';
}
if ($this->params->get('hsts_preload', 0) === 1) {
$hstsOptions[] = 'preload';
}
$staticHeaderConfiguration['strict-transport-security#both'] = implode('; ', $hstsOptions);
}
// Generate the additional headers
$additionalHttpHeaders = $this->params->get('additional_httpheader', []);
foreach ($additionalHttpHeaders as $additionalHttpHeader) {
// Make sure we have a key and a value
if (empty($additionalHttpHeader->key) || empty($additionalHttpHeader->value)) {
continue;
}
// Make sure the header is a valid and supported header
if (!\in_array(strtolower($additionalHttpHeader->key), $this->supportedHttpHeaders)) {
continue;
}
// Make sure we do not add one header twice but we support to set a different header per client.
if (
isset($staticHeaderConfiguration[$additionalHttpHeader->key . '#' . $additionalHttpHeader->client])
|| isset($staticHeaderConfiguration[$additionalHttpHeader->key . '#both'])
) {
continue;
}
// Allow the custom csp headers to use the random $cspNonce in the rules
if (\in_array(strtolower($additionalHttpHeader->key), ['content-security-policy', 'content-security-policy-report-only'])) {
$additionalHttpHeader->value = str_replace('{nonce}', "'nonce-" . $this->cspNonce . "'", $additionalHttpHeader->value);
}
$staticHeaderConfiguration[$additionalHttpHeader->key . '#' . $additionalHttpHeader->client] = $additionalHttpHeader->value;
}
return $staticHeaderConfiguration;
}
/**
* Set the static headers when enabled
*
* @return void
*
* @since 4.0.0
*/
private function setStaticHeaders(): void
{
$staticHeaderConfiguration = $this->getStaticHeaderConfiguration();
if (empty($staticHeaderConfiguration)) {
return;
}
foreach ($staticHeaderConfiguration as $headerAndClient => $value) {
$headerAndClient = explode('#', $headerAndClient);
$header = $headerAndClient[0];
$client = $headerAndClient[1] ?? 'both';
if (!$this->getApplication()->isClient($client) && $client != 'both') {
continue;
}
$this->getApplication()->setHeader($header, $value, true);
}
}
}

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>PLG_JLCONTENTFIELDSFILTER</name>
<author>Joomline</author>
<creationDate>01.08.2023</creationDate>
<copyright>(C) 2017-2023 Arkadiy Sedelnikov, Sergey Tolkachyov, Joomline. All rights reserved.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>sales@joomline.ru</authorEmail>
<authorUrl>https://joomline.ru</authorUrl>
<version>3.0.0</version>
<description>PLG_JLCONTENTFIELDSFILTER_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\System\Jlcontentfieldsfilter</namespace>
<files>
<folder plugin="jlcontentfieldsfilter">src</folder>
<folder>services</folder>
<filename>jlcontentfieldsfilter.xml</filename>
</files>
<languages folder="language">
<language tag="en-GB">en-GB/plg_system_jlcontentfieldsfilter.ini</language>
<language tag="en-GB">en-GB/plg_system_jlcontentfieldsfilter.sys.ini</language>
<language tag="ru-RU">ru-RU/plg_system_jlcontentfieldsfilter.ini</language>
<language tag="ru-RU">ru-RU/plg_system_jlcontentfieldsfilter.sys.ini</language>
<language tag="fr-FR">fr-FR/plg_system_jlcontentfieldsfilter.ini</language>
<language tag="fr-FR">fr-FR/plg_system_jlcontentfieldsfilter.sys.ini</language>
</languages>
<scriptfile>script.php</scriptfile>
<config>
<fields name="params">
<fieldset name="basic">
</fieldset>
</fields>
</config>
</extension>

View File

@ -0,0 +1,84 @@
<?php
/**
* JL Content Fields Filter
*
* @version 3.0.0
* @author Joomline
* @copyright (C) 2017-2023 Arkadiy Sedelnikov, Sergey Tolkachyov, Joomline. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// Запрет прямого доступа.
defined('_JEXEC') or die;
class plgSystemJlcontentfieldsfilterInstallerScript
{
/**
* Метод для обновления компонента.
*
* @param object $parent Класс, который вызывает этом метод.
*
* @return void
*/
public function update($parent)
{
}
/**
* Метод для установки компонента.
*
* @param object $parent Класс, который вызывает этом метод.
*
* @return void
*/
public function install($parent)
{
//$parent->getParent()->setRedirectURL('index.php?option=com_helloworld');
}
/**
* Метод для удаления компонента.
*
* @param object $parent Класс, который вызывает этом метод.
*
* @return void
*/
public function uninstall($parent)
{
//echo '<p>' . JText::_('COM_HELLOWORLD_UNINSTALL_TEXT') . '</p>';
}
/**
* Метод, который исполняется до install/update/uninstall.
*
* @param object $type Тип изменений: install, update или discover_install
* @param object $parent Класс, который вызывает этом метод. Класс, который вызывает этом метод.
*
* @return void
*/
public function preflight($type, $parent)
{
//echo '<p>' . JText::_('PLG_MINICCK_PREFLIGHT_' . strtoupper($type) . '_TEXT') . '</p>';
}
/**
* Метод, который исполняется после install/update/uninstall.
*
* @param object $type Тип изменений: install, update или discover_install
* @param object $parent Класс, который вызывает этом метод. Класс, который вызывает этом метод.
*
* @return void
*/
public function postflight($type, $parent)
{
$db = \Joomla\CMS\Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
$query = $db->getQuery(true);
$query->update('#__extensions')
->set('enabled = 1')
->where('element = '.$db->quote('jlcontentfieldsfilter'))
->where('type = '.$db->quote('plugin'))
->where('folder = '.$db->quote('system'))
;
$db->setQuery($query)->execute();
}
}

View File

@ -0,0 +1,45 @@
<?php
/**
* JL Content Fields Filter
*
* @version 3.0.0
* @author Joomline
* @copyright (C) 2017-2023 Arkadiy Sedelnikov, Sergey Tolkachyov, Joomline. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
defined('_JEXEC') || die;
use Joomla\CMS\Extension\PluginInterface;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\Database\DatabaseInterface;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
use Joomla\Event\DispatcherInterface;
use Joomla\Plugin\System\Jlcontentfieldsfilter\Extension\Jlcontentfieldsfilter;
return new class () implements ServiceProviderInterface {
/**
* Registers the service provider with a DI container.
*
* @param Container $container The DI container.
*
* @return void
*
* @since 4.0.0
*/
public function register(Container $container)
{
$container->set(
PluginInterface::class,
function (Container $container) {
$subject = $container->get(DispatcherInterface::class);
$config = (array)PluginHelper::getPlugin('system', 'Jlcontentfieldsfilter');
$plugin = new Jlcontentfieldsfilter($subject, $config);
$plugin->setApplication(Factory::getApplication());
return $plugin;
}
);
}
};

View File

@ -0,0 +1,369 @@
<?php
/**
* JL Content Fields Filter
*
* @version 3.0.0
* @author Joomline
* @copyright (C) 2017-2023 Arkadiy Sedelnikov, Sergey Tolkachyov, Joomline. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Jlcontentfieldsfilter\Extension;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Form\Form;
use Joomla\Database\DatabaseInterface;
defined('_JEXEC') or die;
class Jlcontentfieldsfilter extends CMSPlugin
{
/**
* Affects constructor behavior. If true, language files will be loaded automatically.
*
* @var boolean
* @since 1.0.0
*/
protected $autoloadLanguage = true;
/**
*
* @param $form
* @param $data
*
* @return bool
*
* @throws Exception
* @since 1.0.0
*/
public function onContentPrepareForm($form, $data)
{
if (!($form instanceof Form)) {
return false;
}
$name = $form->getName();
$app = $this->getApplication();
if (!in_array($name, ['com_fields.fieldcom_content.article', 'com_fields.field.com_content.article', 'com_fields.fieldcom_contact.contact', 'com_fields.field.com_contact.contact'])
|| !$app->isClient('administrator')) {
return true;
} else {
$category_extension = explode('.', str_replace(['com_fields.field.', 'com_fields.field'], '', $name))[0];
}
Form::addFormPath(JPATH_SITE . '/plugins/system/jlcontentfieldsfilter/src/Params');
$plugin = 'plg_system_jlcontentfieldsfilter';
$lang = $app->getLanguage();
$lang->load($plugin , JPATH_ADMINISTRATOR);
$form->loadFile('params', false);
if (is_object($data) && !empty($data->type)) {
$dataType = $data->type;
} else if (is_array($data) && !empty($data['type'])) {
$dataType = $data['type'];
} else {
$dataType = $form->getFieldAttribute('type', 'default');
}
$form->setFieldAttribute('content_filter', 'dataType', $dataType, 'params');
$form->setFieldAttribute('disabled_categories', 'extension', $category_extension, 'params');
return true;
}
public function onBeforeCompileHead()
{
if ($this->getApplication()->isClient('administrator')) {
return;
}
$this->doMeta();
}
/**
* Подмена модели категории контента.
*
* @throws Exception
*/
public function onAfterRoute()
{
if ($this->getApplication()->isClient('administrator')) {
return;
}
$app = $this->getApplication();
$option = $app->getInput()->getString('option', '');
$view = $app->getInput()->getString('view', '');
$catid = $app->getInput()->getInt('id', 0);
if ($option == 'com_tags') {
if ($view != 'tag') {
return;
}
$catid = $app->getUserStateFromRequest($option . '.jlcontentfieldsfilter.tag_category_id', 'tag_category_id', 0, 'int');
$tagids = $app->getUserStateFromRequest($option . '.jlcontentfieldsfilter.tag_ids', 'id', [], 'array');
if (!empty($tagids))
{
foreach ($tagids as $key => $tag)
{
if(!is_numeric($tag) && strpos($tag,':')){
$tag = explode(':', $tag);
$tagids[$key] = $tag[0];
}
}
}
$itemid = implode(',', $tagids) . ':' . $app->getInput()->get('Itemid', 0, 'int');
} else if (
!in_array($option, ['com_content', 'com_contact']) || $view != 'category' || $catid == 0) {
return;
} else {
$itemid = $app->getInput()->get('id', 0, 'int') . ':' . $app->getInput()->get('Itemid', 0, 'int');
}
if ($option == 'com_tags') {
$context = $option . '.cat_' . implode('_', $tagids) . '.jlcontentfieldsfilter';
} else {
$context = $option . '.cat_' . $catid . '.jlcontentfieldsfilter';
}
$filterData = $app->getUserStateFromRequest($context, 'jlcontentfieldsfilter', [], 'array');
if (!count($filterData)) {
return;
}
if ($option == 'com_content' && !class_exists('CategoryModel')) {
require_once JPATH_SITE . '/plugins/system/jlcontentfieldsfilter/src/Models/com_content/CategoryModel.php';
$context = 'com_content.article';
} else if ($option == 'com_contact' && !class_exists('CategoryModel')) {
require_once JPATH_SITE . '/plugins/system/jlcontentfieldsfilter/src/Models/com_contact/CategoryModel.php';
$context = 'com_contact.contact';
} else if ($option == 'com_tags' && !class_exists('TagModel')) {
require_once JPATH_SITE . '/plugins/system/jlcontentfieldsfilter/src/Models/com_tags/TagModel.php';
$context = 'com_content.article';
}
$db = Factory::getContainer()->get(DatabaseInterface::class);
$query = $db->getQuery(true);
$query->select('id, type');
$query->from('#__fields');
$query->where('context = ' . $db->quote($context));
$fieldsTypes = $db->setQuery($query)->loadObjectList('id');
$count = 0;
$filterArticles = [];
foreach ($filterData as $k => $v) {
if (!isset($fieldsTypes[$k])) {
continue;
}
$where = '';
switch ($fieldsTypes[$k]->type) {
case 'radio':
case 'checkboxes':
case 'list':
if (is_array($v) && count($v)) {
$newVal = [];
foreach ($v as $val) {
if ($val !== '')
$newVal[] = $val;
}
if (count($newVal)) {
$where = '(field_id = ' . (int)$k . ' AND value IN(\'' . implode("', '", $newVal) . '\'))';
}
} else if (!empty($v)) {
$where = '(field_id = ' . (int)$k . ' AND value = ' . $db->quote($v) . ')';
}
break;
case 'text':
if (!empty($v)) {
if (is_array($v)) {
if (!empty($v['from']) && !empty($v['to'])) {
$where = '(field_id = ' . (int)$k . ' AND CAST(`value` AS SIGNED) BETWEEN ' . (int)$v['from'] . ' AND ' . $v['to'] . ')';
} else if (!empty($v['from'])) {
$where = '(field_id = ' . (int)$k . ' AND CAST(`value` AS SIGNED) >= ' . (int)$v['from'] . ')';
} else if (!empty($v['to'])) {
$where = '(field_id = ' . (int)$k . ' AND CAST(`value` AS SIGNED) <= ' . (int)$v['to'] . ')';
}
} else {
$where = '(field_id = ' . (int)$k . ' AND value LIKE ' . $db->quote('%' . $v . '%') . ')';
}
}
break;
default:
break;
}
if (!empty($where)) {
$query->clear()->select(' DISTINCT item_id');
$query->from('#__fields_values');
$query->where($where);
$query->group('item_id');
$aIds = $db->setQuery($query)->loadColumn();
$aIds = !is_array($aIds) ? [] : $aIds;
if ($count == 0) {
$filterArticles = $aIds;
} else {
$filterArticles = array_intersect($filterArticles, $aIds);
}
$count++;
if (!count($filterArticles)) {
break;
}
}
}
$context = $option . '.category.list.' . $itemid;
if ($count > 0) {
if (!count($filterArticles)) {
$filterArticles = [0];
}
$app->setUserState($context . 'filter.article_id_include', true);
$app->setUserState($context . 'filter.article_id', $filterArticles);
} else {
$app->setUserState($context . 'filter.article_id_include', null);
$app->setUserState($context . 'filter.article_id', null);
}
if (!empty($filterData['ordering'])) {
list($ordering, $dirn) = explode('.', $filterData['ordering']);
$dirn = !empty($dirn) ? strtoupper($dirn) : 'ASC';
switch ($option) {
case 'com_content':
switch ($ordering) {
case 'ordering':
$ordering = 'a.ordering';
break;
case 'title':
$ordering = 'a.title';
break;
case 'created':
$ordering = 'a.created';
break;
case 'created_by':
$ordering = 'a.created_by';
break;
case 'hits':
$ordering = 'a.hits';
break;
}
break;
case 'com_contact':
switch ($ordering) {
case 'ordering':
$ordering = 'a.ordering';
break;
case 'name':
$ordering = 'a.name';
break;
case 'position':
$ordering = 'a.con_position';
break;
case 'hits':
$ordering = 'a.hits';
break;
}
break;
}
if (!empty($ordering)) {
$app->setUserState($option . '.category.list.' . $itemid . '.filter_order', $ordering);
$app->setUserState($option . '.category.list.' . $itemid . '.filter_order_Dir', $dirn);
}
}
}
private function doMeta()
{
if (!ComponentHelper::isEnabled('com_jlcontentfieldsfilter')) {
return;
}
$app = $this->getApplication();
$option = $app->getInput()->getString('option', '');
$view = $app->getInput()->getString('view', '');
$catid = $app->getInput()->getInt('id', 0);
if (!in_array($option, ['com_content']) || $view != 'category' || $catid == 0) {
return;
}
if ($option == 'com_tags') {
$tagIds = $app->getUserStateFromRequest($option . '.jlcontentfieldsfilter.tag_ids', 'id', [], 'array');
$context = $option . '.cat_' . implode('_', $tagIds) . '.jlcontentfieldsfilter';
} else {
$context = $option . '.cat_' . $catid . '.jlcontentfieldsfilter';
}
$filterData = $app->getUserStateFromRequest($context, 'jlcontentfieldsfilter', [], 'array');
if (isset($filterData['ordering'])) {
unset($filterData['ordering']);
}
if (isset($filterData['is_filter'])) {
unset($filterData['is_filter']);
}
if (!is_array($filterData) || !count($filterData)) {
return;
}
$params = ComponentHelper::getParams('com_jlcontentfieldsfilter');
$autogeneration = $params->get('autogeneration', 0);
\JLoader::register('JlcontentfieldsfilterHelper', JPATH_ADMINISTRATOR . '/components/com_jlcontentfieldsfilter/helpers/jlcontentfieldsfilter.php');
$filter = \JlcontentfieldsfilterHelper::createFilterString($filterData);
$unsafe_filter = \JlcontentfieldsfilterHelper::createFilterString($filterData, false);
$hash = \JlcontentfieldsfilterHelper::createHash($filter);
$unsafe_hash = \JlcontentfieldsfilterHelper::createHash($unsafe_filter);
$db = Factory::getContainer()->get(DatabaseInterface::class);
$query = $db->getQuery(true);
$query->select('*')
->from('`#__jlcontentfieldsfilter_data`')
->where('`filter_hash` = ' . $db->quote($hash), 'OR')
->where('`filter_hash` = ' . $db->quote($unsafe_hash))
->andWhere('`publish` = 1');
$result = $db->setQuery($query, 0, 1)->loadObject();
if (empty($result->filter_hash)) {
if (!$autogeneration) {
return;
} else {
$result = \JlcontentfieldsfilterHelper::createMeta($catid, $filterData);
}
}
$doc = $app->getDocument();
if (!empty($result->meta_title)) {
$doc->setTitle($result->meta_title);
}
if (!empty($result->meta_desc)) {
$doc->setMetaData('description', $result->meta_desc);
}
if (!empty($result->meta_keywords)) {
$doc->setMetaData('keywords', $result->meta_keywords);
}
}
}

View File

@ -0,0 +1,95 @@
<?php
/**
* JL Content Fields Filter
*
* @version 3.0.0
* @author Joomline
* @copyright (C) 2017-2023 Arkadiy Sedelnikov, Sergey Tolkachyov, Joomline. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Plugin\System\Jlcontentfieldsfilter\Fields;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\Form\Field\ListField;
use Joomla\CMS\Form\FormHelper;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
FormHelper::loadFieldClass('list');
class JlcontentfieldsfilterfieldsField extends ListField
{
/**
* The form field type.
*
* @var string
*/
protected $type = 'Jlcontentfieldsfilterfields';
/**
* The current extra field type
*
* @var string
*/
protected $dataType = null;
/**
* Method to attach a JForm object to the field.
*
* @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object.
* @param mixed $value The form field value to validate.
* @param string $group The field name group control value. This acts as an array container for the field.
* For example if the field has name="foo" and the group value is set to "bar" then the
* full field name would end up being "bar[foo]".
*
* @return boolean True on success.
*
* @see JFormField::setup()
*/
public function setup(\SimpleXMLElement $element, $value, $group = null)
{
if ($return = parent::setup($element, $value, $group))
{
$this->dataType = (!empty($this->element['dataType'])) ? (string) $this->element['dataType'] : '';
}
return $return;
}
/**
* Method to get the field options.
*
* @return array The field option objects.
*
*/
protected function getOptions()
{
$options = [];
$options[] = HTMLHelper::_('select.option', '', Text::_('JNO'));
switch ($this->dataType)
{
case 'list':
case 'radio':
case 'checkboxes':
$options[] = HTMLHelper::_('select.option', 'radio', Text::_('PLG_JLCONTENTFIELDSFILTER_FILTER_RADIO'));
$options[] = HTMLHelper::_('select.option', 'list', Text::_('PLG_JLCONTENTFIELDSFILTER_FILTER_LIST'));
$options[] = HTMLHelper::_('select.option', 'checkboxes', Text::_('PLG_JLCONTENTFIELDSFILTER_FILTER_CHECKBOXES'));
break;
case 'text':
$options[] = HTMLHelper::_('select.option', 'text', Text::_('PLG_JLCONTENTFIELDSFILTER_FILTER_TEXT'));
$options[] = HTMLHelper::_('select.option', 'range', Text::_('PLG_JLCONTENTFIELDSFILTER_FILTER_RANGE'));
break;
default:
break;
}
return $options;
}
}

View File

@ -0,0 +1,137 @@
<?php
namespace Joomla\Plugin\System\Jlcontentfieldsfilter\Fields;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Application\ApplicationHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\Filesystem\Folder;
use Joomla\Filesystem\Path;
use Joomla\CMS\Form\FormHelper;
use Joomla\CMS\Form\Form;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use \Joomla\CMS\Form\FormField;
use Joomla\Database\DatabaseInterface;
class JlcontentfieldslayoutsField extends FormField
{
protected $type = 'Jlcontentfieldslayouts';
protected $layouts_path = '/modules/mod_jlcontentfieldsfilter/layouts/mod_jlcontentfieldsfilter';
protected $layouts_overrided_path = '/mod_jlcontentfieldsfilter';
protected function getFrontTemplate()
{
$db = Factory::getContainer()->get(DatabaseInterface::class);
$query = $db->getQuery(true);
$query
->select('template')
->from('#__template_styles')
->where('client_id = 0')
->where('home = 1');
$db->setQuery($query);
return $db->loadResult();
}
protected function getInput()
{
$client = ApplicationHelper::getClientInfo(0);
$layouts_path = Path::clean($client->path . $this->layouts_path);
$plugin_layouts = [];
$groups = [];
if (is_dir($layouts_path) && ($plugin_layouts = Folder::files($layouts_path, '^[^_]*\.php$'))) {
$groups['_'] = [];
$groups['_']['id'] = $this->id . '__';
$groups['_']['text'] = Text::sprintf('JOPTION_FROM_MODULE');
$groups['_']['items'] = [ HTMLHelper::_('select.option', '', Text::_('JNO')) ];
foreach ($plugin_layouts as $file) {
$value = basename($file, '.php');
$groups['_']['items'][] = HTMLHelper::_('select.option', '_:' . $value, $value);
}
}
$template = $this->getFrontTemplate();
$template_style_id = '';
if ($this->form instanceof Form && !empty($template_style_id = $this->form->getValue('template_style_id'))) {
$template_style_id = preg_replace('#\W#', '', $template_style_id);
}
$db = Factory::getContainer()->get(DatabaseInterface::class);
$query = $db->getQuery(true);
$query
->select('element, name')
->from('#__extensions as e')
->where('e.client_id = 0')
->where('e.type = ' . $db->quote('template'))
->where('e.enabled = 1');
if ($template) {
$query->where('e.element = ' . $db->quote($template));
}
if ($template_style_id) {
$query
->join('LEFT', '#__template_styles as s on s.template=e.element')
->where('s.id=' . (int)$template_style_id);
}
$db->setQuery($query);
$templates = $db->loadObjectList('element');
$lang = Factory::getApplication()->getLanguage();
if ($templates) {
foreach ($templates as $template) {
$lang->load('tpl_' . $template->element . '.sys', $client->path, null, false, true)
|| $lang->load('tpl_' . $template->element . '.sys', $client->path . '/templates/' . $template->element, null, false, true);
$template_path = Path::clean($client->path . '/templates/' . $template->element . '/html/layouts' . $this->layouts_overrided_path);
if (is_dir($template_path) && ($files = Folder::files($template_path, '^[^_]*\.php$'))) {
foreach ($files as $i => $file) {
if (in_array($file, $plugin_layouts)) {
unset($files[$i]);
}
}
if (count($files)) {
$groups[$template->element] = [];
$groups[$template->element]['id'] = $this->id . '_' . $template->element;
$groups[$template->element]['text'] = Text::sprintf('JOPTION_FROM_TEMPLATE', $template->name);
$groups[$template->element]['items'] = [];
foreach ($files as $file) {
$value = basename($file, '.php');
$groups[$template->element]['items'][] = HTMLHelper::_('select.option', $template->element . ':' . $value, $value);
}
}
}
}
}
$attr = $this->element['size'] ? ' size="' . (int)$this->element['size'] . '"' : '';
$attr .= $this->element['class'] ? ' class="' . (string)$this->element['class'] . '"' : '';
$html = [];
$selected = [$this->value];
$html[] = HTMLHelper::_('select.groupedlist', $groups, $this->name, ['id' => $this->id, 'group.id' => 'id', 'list.attr' => $attr, 'list.select' => $selected]);
return implode($html);
}
}

View File

@ -0,0 +1,486 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_contact
*
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Contact\Site\Model;
use Joomla\CMS\Categories\Categories;
use Joomla\CMS\Categories\CategoryNode;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\TagsHelper;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\CMS\Table\Table;
use Joomla\Database\ParameterType;
use Joomla\Registry\Registry;
use Joomla\Utilities\ArrayHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Single item model for a contact
*
* @package Joomla.Site
* @subpackage com_contact
* @since 1.5
*/
class CategoryModel extends ListModel
{
/**
* Category item data
*
* @var CategoryNode
*/
protected $_item;
/**
* Category left and right of this one
*
* @var CategoryNode[]|null
*/
protected $_siblings;
/**
* Array of child-categories
*
* @var CategoryNode[]|null
*/
protected $_children;
/**
* Parent category of the current one
*
* @var CategoryNode|null
*/
protected $_parent;
/**
* The category that applies.
*
* @var object
*/
protected $_category;
/**
* The list of other contact categories.
*
* @var array
*/
protected $_categories;
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings.
*
* @since 1.6
*/
public function __construct($config = [])
{
if (empty($config['filter_fields'])) {
$config['filter_fields'] = [
'id', 'a.id',
'name', 'a.name',
'con_position', 'a.con_position',
'suburb', 'a.suburb',
'state', 'a.state',
'country', 'a.country',
'ordering', 'a.ordering',
'sortname',
'sortname1', 'a.sortname1',
'sortname2', 'a.sortname2',
'sortname3', 'a.sortname3',
'featuredordering', 'a.featured',
];
}
parent::__construct($config);
}
/**
* Method to get a list of items.
*
* @return mixed An array of objects on success, false on failure.
*/
public function getItems()
{
// Invoke the parent getItems method to get the main list
$items = parent::getItems();
if ($items === false) {
return false;
}
$taggedItems = [];
// Convert the params field into an object, saving original in _params
foreach ($items as $item) {
if (!isset($this->_params)) {
$item->params = new Registry($item->params);
}
// Some contexts may not use tags data at all, so we allow callers to disable loading tag data
if ($this->getState('load_tags', true)) {
$item->tags = new TagsHelper();
$taggedItems[$item->id] = $item;
}
}
// Load tags of all items.
if ($taggedItems) {
$tagsHelper = new TagsHelper();
$itemIds = \array_keys($taggedItems);
foreach ($tagsHelper->getMultipleItemTags('com_contact.contact', $itemIds) as $id => $tags) {
$taggedItems[$id]->tags->itemTags = $tags;
}
}
return $items;
}
/**
* Method to build an SQL query to load the list data.
*
* @return \Joomla\Database\DatabaseQuery An SQL query
*
* @since 1.6
*/
protected function getListQuery()
{
$user = $this->getCurrentUser();
$groups = $user->getAuthorisedViewLevels();
// Create a new query object.
$db = $this->getDatabase();
/** @var \Joomla\Database\DatabaseQuery $query */
$query = $db->getQuery(true);
$query->select($this->getState('list.select', 'a.*'))
->select($this->getSlugColumn($query, 'a.id', 'a.alias') . ' AS slug')
->select($this->getSlugColumn($query, 'c.id', 'c.alias') . ' AS catslug')
/**
* @todo: we actually should be doing it but it's wrong this way
* . ' CASE WHEN CHAR_LENGTH(a.alias) THEN CONCAT_WS(\':\', a.id, a.alias) ELSE a.id END as slug, '
* . ' CASE WHEN CHAR_LENGTH(c.alias) THEN CONCAT_WS(\':\', c.id, c.alias) ELSE c.id END AS catslug ');
*/
->from($db->quoteName('#__contact_details', 'a'))
->leftJoin($db->quoteName('#__categories', 'c') . ' ON c.id = a.catid')
->whereIn($db->quoteName('a.access'), $groups);
// Filter by category.
if ($categoryId = $this->getState('category.id')) {
$query->where($db->quoteName('a.catid') . ' = :acatid')
->whereIn($db->quoteName('c.access'), $groups);
$query->bind(':acatid', $categoryId, ParameterType::INTEGER);
}
// Join over the users for the author and modified_by names.
$query->select("CASE WHEN a.created_by_alias > ' ' THEN a.created_by_alias ELSE ua.name END AS author")
->select('ua.email AS author_email')
->leftJoin($db->quoteName('#__users', 'ua') . ' ON ua.id = a.created_by')
->leftJoin($db->quoteName('#__users', 'uam') . ' ON uam.id = a.modified_by');
// Filter by state
$state = $this->getState('filter.published');
if (is_numeric($state)) {
$query->where($db->quoteName('a.published') . ' = :published');
$query->bind(':published', $state, ParameterType::INTEGER);
} else {
$query->whereIn($db->quoteName('c.published'), [0,1,2]);
}
// Filter by start and end dates.
$nowDate = Factory::getDate()->toSql();
if ($this->getState('filter.publish_date')) {
$query->where('(' . $db->quoteName('a.publish_up')
. ' IS NULL OR ' . $db->quoteName('a.publish_up') . ' <= :publish_up)')
->where('(' . $db->quoteName('a.publish_down')
. ' IS NULL OR ' . $db->quoteName('a.publish_down') . ' >= :publish_down)')
->bind(':publish_up', $nowDate)
->bind(':publish_down', $nowDate);
}
// Filter by search in title
$search = $this->getState('list.filter');
if (!empty($search)) {
$search = '%' . trim($search) . '%';
$query->where($db->quoteName('a.name') . ' LIKE :name ');
$query->bind(':name', $search);
}
// Filter on the language.
if ($this->getState('filter.language')) {
$query->whereIn($db->quoteName('a.language'), [Factory::getApplication()->getLanguage()->getTag(), '*'], ParameterType::STRING);
}
//Joomline hack start
// Filter by a single or group of articles.
$articleId = $this->getState('filter.article_id');
if (is_numeric($articleId))
{
$query->where('a.id = ' . (int) $articleId);
}
elseif (is_array($articleId) && count($articleId))
{
$articleId = ArrayHelper::toInteger($articleId);
$articleId = implode(',', $articleId);
$query->where('a.id IN (' . $articleId . ')');
}
//Joomline hack end
// Set sortname ordering if selected
if ($this->getState('list.ordering') === 'sortname') {
$query->order($db->escape('a.sortname1') . ' ' . $db->escape($this->getState('list.direction', 'ASC')))
->order($db->escape('a.sortname2') . ' ' . $db->escape($this->getState('list.direction', 'ASC')))
->order($db->escape('a.sortname3') . ' ' . $db->escape($this->getState('list.direction', 'ASC')));
} elseif ($this->getState('list.ordering') === 'featuredordering') {
$query->order($db->escape('a.featured') . ' DESC')
->order($db->escape('a.ordering') . ' ASC');
} else {
$query->order($db->escape($this->getState('list.ordering', 'a.ordering')) . ' ' . $db->escape($this->getState('list.direction', 'ASC')));
}
return $query;
}
/**
* Method to auto-populate the model state.
*
* Note. Calling getState in this method will result in recursion.
*
* @param string $ordering An optional ordering field.
* @param string $direction An optional direction (asc|desc).
*
* @return void
*
* @since 1.6
*/
protected function populateState($ordering = null, $direction = null)
{
$app = Factory::getApplication();
$input = $app->getInput();
$params = $app->getParams();
$this->setState('params', $params);
// List state information
$format = $input->getWord('format');
if ($format === 'feed') {
$limit = $app->get('feed_limit');
} else {
$limit = $app->getUserStateFromRequest(
'com_contact.category.list.limit',
'limit',
$params->get('contacts_display_num', $app->get('list_limit')),
'uint'
);
}
$this->setState('list.limit', $limit);
$limitstart = $input->get('limitstart', 0, 'uint');
$this->setState('list.start', $limitstart);
// Optional filter text
$itemid = $input->get('Itemid', 0, 'int');
$search = $app->getUserStateFromRequest('com_contact.category.list.' . $itemid . '.filter-search', 'filter-search', '', 'string');
$this->setState('list.filter', $search);
$orderCol = $input->get('filter_order', $params->get('initial_sort', 'ordering'));
if (!in_array($orderCol, $this->filter_fields)) {
$orderCol = 'ordering';
}
$this->setState('list.ordering', $orderCol);
$listOrder = $input->get('filter_order_Dir', 'ASC');
if (!in_array(strtoupper($listOrder), ['ASC', 'DESC', ''])) {
$listOrder = 'ASC';
}
$this->setState('list.direction', $listOrder);
$id = $input->get('id', 0, 'int');
$this->setState('category.id', $id);
//Joomline hack start
$context = 'com_contact.category.list.' . $id . ':' . $itemid;
$value = $app->getUserState($context . 'filter.article_id', 'filter_article_id');
$this->setState('filter.article_id', $value);
//Joomline hack start
$user = $this->getCurrentUser();
if ((!$user->authorise('core.edit.state', 'com_contact')) && (!$user->authorise('core.edit', 'com_contact'))) {
// Limit to published for people who can't edit or edit.state.
$this->setState('filter.published', 1);
// Filter by start and end dates.
$this->setState('filter.publish_date', true);
}
$this->setState('filter.language', Multilanguage::isEnabled());
}
/**
* Method to get category data for the current category
*
* @return object The category object
*
* @since 1.5
*/
public function getCategory()
{
if (!is_object($this->_item)) {
$app = Factory::getApplication();
$menu = $app->getMenu();
$active = $menu->getActive();
if ($active) {
$params = $active->getParams();
} else {
$params = new Registry();
}
$options = [];
$options['countItems'] = $params->get('show_cat_items', 1) || $params->get('show_empty_categories', 0);
$categories = Categories::getInstance('Contact', $options);
$this->_item = $categories->get($this->getState('category.id', 'root'));
if (is_object($this->_item)) {
$this->_children = $this->_item->getChildren();
$this->_parent = false;
if ($this->_item->getParent()) {
$this->_parent = $this->_item->getParent();
}
$this->_rightsibling = $this->_item->getSibling();
$this->_leftsibling = $this->_item->getSibling(false);
} else {
$this->_children = false;
$this->_parent = false;
}
}
return $this->_item;
}
/**
* Get the parent category.
*
* @return mixed An array of categories or false if an error occurs.
*/
public function getParent()
{
if (!is_object($this->_item)) {
$this->getCategory();
}
return $this->_parent;
}
/**
* Get the sibling (adjacent) categories.
*
* @return mixed An array of categories or false if an error occurs.
*/
public function &getLeftSibling()
{
if (!is_object($this->_item)) {
$this->getCategory();
}
return $this->_leftsibling;
}
/**
* Get the sibling (adjacent) categories.
*
* @return mixed An array of categories or false if an error occurs.
*/
public function &getRightSibling()
{
if (!is_object($this->_item)) {
$this->getCategory();
}
return $this->_rightsibling;
}
/**
* Get the child categories.
*
* @return mixed An array of categories or false if an error occurs.
*/
public function &getChildren()
{
if (!is_object($this->_item)) {
$this->getCategory();
}
return $this->_children;
}
/**
* Generate column expression for slug or catslug.
*
* @param \Joomla\Database\DatabaseQuery $query Current query instance.
* @param string $id Column id name.
* @param string $alias Column alias name.
*
* @return string
*
* @since 4.0.0
*/
private function getSlugColumn($query, $id, $alias)
{
return 'CASE WHEN '
. $query->charLength($alias, '!=', '0')
. ' THEN '
. $query->concatenate([$query->castAsChar($id), $alias], ':')
. ' ELSE '
. $query->castAsChar($id) . ' END';
}
/**
* Increment the hit counter for the category.
*
* @param integer $pk Optional primary key of the category to increment.
*
* @return boolean True if successful; false otherwise and internal error set.
*
* @since 3.2
*/
public function hit($pk = 0)
{
$input = Factory::getApplication()->getInput();
$hitcount = $input->getInt('hitcount', 1);
if ($hitcount) {
$pk = (!empty($pk)) ? $pk : (int) $this->getState('category.id');
$table = Table::getInstance('Category');
$table->hit($pk);
}
return true;
}
}

View File

@ -0,0 +1,485 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_content
*
* @copyright (C) 2006 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Content\Site\Model;
use Joomla\CMS\Categories\Categories;
use Joomla\CMS\Categories\CategoryNode;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Multilanguage;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\CMS\Table\Table;
use Joomla\Component\Content\Site\Helper\QueryHelper;
use Joomla\Utilities\ArrayHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* This models supports retrieving a category, the articles associated with the category,
* sibling, child and parent categories.
*
* @since 1.5
*/
class CategoryModel extends ListModel
{
/**
* Category items data
*
* @var array
*/
protected $_item = null;
/**
* Array of articles in the category
*
* @var \stdClass[]
*/
protected $_articles = null;
/**
* Category left and right of this one
*
* @var CategoryNode[]|null
*/
protected $_siblings = null;
/**
* Array of child-categories
*
* @var CategoryNode[]|null
*/
protected $_children = null;
/**
* Parent category of the current one
*
* @var CategoryNode|null
*/
protected $_parent = null;
/**
* Model context string.
*
* @var string
*/
protected $_context = 'com_content.category';
/**
* The category that applies.
*
* @var object
*/
protected $_category = null;
/**
* The list of categories.
*
* @var array
*/
protected $_categories = null;
/**
* @param array $config An optional associative array of configuration settings.
*
* @since 1.6
*/
public function __construct($config = [])
{
if (empty($config['filter_fields'])) {
$config['filter_fields'] = [
'id', 'a.id',
'title', 'a.title',
'alias', 'a.alias',
'checked_out', 'a.checked_out',
'checked_out_time', 'a.checked_out_time',
'catid', 'a.catid', 'category_title',
'state', 'a.state',
'access', 'a.access', 'access_level',
'created', 'a.created',
'created_by', 'a.created_by',
'modified', 'a.modified',
'ordering', 'a.ordering',
'featured', 'a.featured',
'language', 'a.language',
'hits', 'a.hits',
'publish_up', 'a.publish_up',
'publish_down', 'a.publish_down',
'author', 'a.author',
'filter_tag',
];
}
parent::__construct($config);
}
/**
* Method to auto-populate the model state.
*
* Note. Calling getState in this method will result in recursion.
*
* @param string $ordering The field to order on.
* @param string $direction The direction to order on.
*
* @return void
*
* @since 1.6
*/
protected function populateState($ordering = null, $direction = null)
{
$app = Factory::getApplication();
$pk = $app->getInput()->getInt('id');
$this->setState('category.id', $pk);
// Load the parameters. Merge Global and Menu Item params into new object
$params = $app->getParams();
$this->setState('params', $params);
$user = $this->getCurrentUser();
$asset = 'com_content';
if ($pk) {
$asset .= '.category.' . $pk;
}
if ((!$user->authorise('core.edit.state', $asset)) && (!$user->authorise('core.edit', $asset))) {
// Limit to published for people who can't edit or edit.state.
$this->setState('filter.published', 1);
} else {
$this->setState('filter.published', [0, 1]);
}
// Process show_noauth parameter
if (!$params->get('show_noauth')) {
$this->setState('filter.access', true);
} else {
$this->setState('filter.access', false);
}
$itemid = $app->getInput()->get('id', 0, 'int') . ':' . $app->getInput()->get('Itemid', 0, 'int');
$value = $this->getUserStateFromRequest('com_content.category.filter.' . $itemid . '.tag', 'filter_tag', 0, 'int', false);
$this->setState('filter.tag', $value);
// Optional filter text
$search = $app->getUserStateFromRequest('com_content.category.list.' . $itemid . '.filter-search', 'filter-search', '', 'string');
$this->setState('list.filter', $search);
// Filter.order
$orderCol = $app->getUserStateFromRequest('com_content.category.list.' . $itemid . '.filter_order', 'filter_order', '', 'string');
if (!in_array($orderCol, $this->filter_fields)) {
$orderCol = 'a.ordering';
}
$this->setState('list.ordering', $orderCol);
$listOrder = $app->getUserStateFromRequest('com_content.category.list.' . $itemid . '.filter_order_Dir', 'filter_order_Dir', '', 'cmd');
if (!in_array(strtoupper($listOrder), ['ASC', 'DESC', ''])) {
$listOrder = 'ASC';
}
$this->setState('list.direction', $listOrder);
$this->setState('list.start', $app->getInput()->get('limitstart', 0, 'uint'));
// Set limit for query. If list, use parameter. If blog, add blog parameters for limit.
if (($app->getInput()->get('layout') === 'blog') || $params->get('layout_type') === 'blog') {
$limit = $params->get('num_leading_articles') + $params->get('num_intro_articles') + $params->get('num_links');
$this->setState('list.links', $params->get('num_links'));
} else {
$limit = $app->getUserStateFromRequest('com_content.category.list.' . $itemid . '.limit', 'limit', $params->get('display_num'), 'uint');
}
$this->setState('list.limit', $limit);
// Set the depth of the category query based on parameter
$showSubcategories = $params->get('show_subcategory_content', '0');
if ($showSubcategories) {
$this->setState('filter.max_category_levels', $params->get('show_subcategory_content', '1'));
$this->setState('filter.subcategories', true);
}
$this->setState('filter.language', Multilanguage::isEnabled());
$this->setState('layout', $app->getInput()->getString('layout'));
// Set the featured articles state
$this->setState('filter.featured', $params->get('show_featured'));
//Joomline hack start
$value = $this->getUserStateFromRequest('com_content.category.list.' . $itemid . 'filter.article_id_include', 'filter_article_id_include', false, 'boolen');
$this->setState('filter.article_id.include', $value);
$value = $this->getUserStateFromRequest('com_content.category.list.' . $itemid . 'filter.article_id', 'filter_article_id', null, 'array');
$this->setState('filter.article_id', $value);
//Joomline hack end
}
/**
* Get the articles in the category
*
* @return array|bool An array of articles or false if an error occurs.
*
* @since 1.5
*/
public function getItems()
{
$limit = $this->getState('list.limit');
if ($this->_articles === null && $category = $this->getCategory()) {
$model = $this->bootComponent('com_content')->getMVCFactory()
->createModel('Articles', 'Site', ['ignore_request' => true]);
$model->setState('params', Factory::getApplication()->getParams());
$model->setState('filter.category_id', $category->id);
$model->setState('filter.published', $this->getState('filter.published'));
$model->setState('filter.access', $this->getState('filter.access'));
$model->setState('filter.language', $this->getState('filter.language'));
$model->setState('filter.featured', $this->getState('filter.featured'));
$model->setState('list.ordering', $this->_buildContentOrderBy());
$model->setState('list.start', $this->getState('list.start'));
$model->setState('list.limit', $limit);
$model->setState('list.direction', $this->getState('list.direction'));
$model->setState('list.filter', $this->getState('list.filter'));
$model->setState('filter.tag', $this->getState('filter.tag'));
// Filter.subcategories indicates whether to include articles from subcategories in the list or blog
$model->setState('filter.subcategories', $this->getState('filter.subcategories'));
$model->setState('filter.max_category_levels', $this->getState('filter.max_category_levels'));
$model->setState('list.links', $this->getState('list.links'));
//Joomline hack start
$model->setState('filter.article_id.include', $this->getState('filter.article_id.include'));
$model->setState('filter.article_id', $this->getState('filter.article_id'));
//Joomline hack end
if ($limit >= 0) {
$this->_articles = $model->getItems();
if ($this->_articles === false) {
$this->setError($model->getError());
}
} else {
$this->_articles = [];
}
$this->_pagination = $model->getPagination();
}
return $this->_articles;
}
/**
* Build the orderby for the query
*
* @return string $orderby portion of query
*
* @since 1.5
*/
protected function _buildContentOrderBy()
{
$app = Factory::getApplication();
$db = $this->getDatabase();
$params = $this->state->params;
$itemid = $app->getInput()->get('id', 0, 'int') . ':' . $app->getInput()->get('Itemid', 0, 'int');
$orderCol = $app->getUserStateFromRequest('com_content.category.list.' . $itemid . '.filter_order', 'filter_order', '', 'string');
$orderDirn = $app->getUserStateFromRequest('com_content.category.list.' . $itemid . '.filter_order_Dir', 'filter_order_Dir', '', 'cmd');
$orderby = ' ';
if (!in_array($orderCol, $this->filter_fields)) {
$orderCol = null;
}
if (!in_array(strtoupper($orderDirn), ['ASC', 'DESC', ''])) {
$orderDirn = 'ASC';
}
if ($orderCol && $orderDirn) {
$orderby .= $db->escape($orderCol) . ' ' . $db->escape($orderDirn) . ', ';
}
$articleOrderby = $params->get('orderby_sec', 'rdate');
$articleOrderDate = $params->get('order_date');
$categoryOrderby = $params->def('orderby_pri', '');
$secondary = QueryHelper::orderbySecondary($articleOrderby, $articleOrderDate, $this->getDatabase()) . ', ';
$primary = QueryHelper::orderbyPrimary($categoryOrderby);
$orderby .= $primary . ' ' . $secondary . ' a.created ';
return $orderby;
}
/**
* Method to get a JPagination object for the data set.
*
* @return \Joomla\CMS\Pagination\Pagination A JPagination object for the data set.
*
* @since 3.0.1
*/
public function getPagination()
{
if (empty($this->_pagination)) {
return null;
}
return $this->_pagination;
}
/**
* Method to get category data for the current category
*
* @return object
*
* @since 1.5
*/
public function getCategory()
{
if (!is_object($this->_item)) {
if (isset($this->state->params)) {
$params = $this->state->params;
$options = [];
$options['countItems'] = $params->get('show_cat_num_articles', 1) || !$params->get('show_empty_categories_cat', 0);
$options['access'] = $params->get('check_access_rights', 1);
} else {
$options['countItems'] = 0;
}
$categories = Categories::getInstance('Content', $options);
$this->_item = $categories->get($this->getState('category.id', 'root'));
// Compute selected asset permissions.
if (is_object($this->_item)) {
$user = $this->getCurrentUser();
$asset = 'com_content.category.' . $this->_item->id;
// Check general create permission.
if ($user->authorise('core.create', $asset)) {
$this->_item->getParams()->set('access-create', true);
}
// @todo: Why aren't we lazy loading the children and siblings?
$this->_children = $this->_item->getChildren();
$this->_parent = false;
if ($this->_item->getParent()) {
$this->_parent = $this->_item->getParent();
}
$this->_rightsibling = $this->_item->getSibling();
$this->_leftsibling = $this->_item->getSibling(false);
} else {
$this->_children = false;
$this->_parent = false;
}
}
return $this->_item;
}
/**
* Get the parent category.
*
* @return mixed An array of categories or false if an error occurs.
*
* @since 1.6
*/
public function getParent()
{
if (!is_object($this->_item)) {
$this->getCategory();
}
return $this->_parent;
}
/**
* Get the left sibling (adjacent) categories.
*
* @return mixed An array of categories or false if an error occurs.
*
* @since 1.6
*/
public function &getLeftSibling()
{
if (!is_object($this->_item)) {
$this->getCategory();
}
return $this->_leftsibling;
}
/**
* Get the right sibling (adjacent) categories.
*
* @return mixed An array of categories or false if an error occurs.
*
* @since 1.6
*/
public function &getRightSibling()
{
if (!is_object($this->_item)) {
$this->getCategory();
}
return $this->_rightsibling;
}
/**
* Get the child categories.
*
* @return mixed An array of categories or false if an error occurs.
*
* @since 1.6
*/
public function &getChildren()
{
if (!is_object($this->_item)) {
$this->getCategory();
}
// Order subcategories
if ($this->_children) {
$params = $this->getState()->get('params');
$orderByPri = $params->get('orderby_pri');
if ($orderByPri === 'alpha' || $orderByPri === 'ralpha') {
$this->_children = ArrayHelper::sortObjects($this->_children, 'title', ($orderByPri === 'alpha') ? 1 : (-1));
}
}
return $this->_children;
}
/**
* Increment the hit counter for the category.
*
* @param int $pk Optional primary key of the category to increment.
*
* @return boolean True if successful; false otherwise and internal error set.
*/
public function hit($pk = 0)
{
$input = Factory::getApplication()->getInput();
$hitcount = $input->getInt('hitcount', 1);
if ($hitcount) {
$pk = (!empty($pk)) ? $pk : (int) $this->getState('category.id');
$table = Table::getInstance('Category', 'JTable');
$table->hit($pk);
}
return true;
}
}

View File

@ -0,0 +1,365 @@
<?php
/**
* @package Joomla.Site
* @subpackage com_tags
*
* @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org>
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace Joomla\Component\Tags\Site\Model;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Helper\TagsHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\CMS\Object\CMSObject;
use Joomla\Component\Tags\Site\Helper\RouteHelper;
use Joomla\Database\DatabaseQuery;
use Joomla\Utilities\ArrayHelper;
// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects
/**
* Tags Component Tag Model
*
* @since 3.1
*/
class TagModel extends ListModel
{
/**
* The list of items associated with the tags.
*
* @var array
* @since 3.1
*/
protected $items = null;
/**
* Array of tags
*
* @var CMSObject[]
* @since 4.3.0
*/
protected $item = [];
/**
* Constructor.
*
* @param array $config An optional associative array of configuration settings.
* @param MVCFactoryInterface $factory The factory.
*
* @since 1.6
*/
public function __construct($config = [], MVCFactoryInterface $factory = null)
{
if (empty($config['filter_fields'])) {
$config['filter_fields'] = [
'core_content_id', 'c.core_content_id',
'core_title', 'c.core_title',
'core_type_alias', 'c.core_type_alias',
'core_checked_out_user_id', 'c.core_checked_out_user_id',
'core_checked_out_time', 'c.core_checked_out_time',
'core_catid', 'c.core_catid',
'core_state', 'c.core_state',
'core_access', 'c.core_access',
'core_created_user_id', 'c.core_created_user_id',
'core_created_time', 'c.core_created_time',
'core_modified_time', 'c.core_modified_time',
'core_ordering', 'c.core_ordering',
'core_featured', 'c.core_featured',
'core_language', 'c.core_language',
'core_hits', 'c.core_hits',
'core_publish_up', 'c.core_publish_up',
'core_publish_down', 'c.core_publish_down',
'core_images', 'c.core_images',
'core_urls', 'c.core_urls',
'match_count',
];
}
parent::__construct($config, $factory);
}
/**
* Method to get a list of items for a list of tags.
*
* @return mixed An array of objects on success, false on failure.
*
* @since 3.1
*/
public function getItems()
{
// Invoke the parent getItems method to get the main list
$items = parent::getItems();
foreach ($items as $item) {
$item->link = RouteHelper::getItemRoute(
$item->content_item_id,
$item->core_alias,
$item->core_catid,
$item->core_language,
$item->type_alias,
$item->router
);
// Get display date
switch ($this->state->params->get('tag_list_show_date')) {
case 'modified':
$item->displayDate = $item->core_modified_time;
break;
case 'created':
$item->displayDate = $item->core_created_time;
break;
default:
$item->displayDate = ($item->core_publish_up == 0) ? $item->core_created_time : $item->core_publish_up;
break;
}
}
return $items;
}
/**
* Method to build an SQL query to load the list data of all items with a given tag.
*
* @return DatabaseQuery An SQL query
*
* @since 3.1
*/
protected function getListQuery()
{
$tagId = $this->getState('tag.id') ?: '';
$typesr = $this->getState('tag.typesr');
$orderByOption = $this->getState('list.ordering', 'c.core_title');
$includeChildren = $this->state->params->get('include_children', 0);
$orderDir = $this->getState('list.direction', 'ASC');
$matchAll = $this->getState('params')->get('return_any_or_all', 1);
$language = $this->getState('tag.language');
$stateFilter = $this->getState('tag.state');
// Optionally filter on language
if (empty($language)) {
$language = ComponentHelper::getParams('com_tags')->get('tag_list_language_filter', 'all');
}
$query = (new TagsHelper())->getTagItemsQuery($tagId, $typesr, $includeChildren, $orderByOption, $orderDir, $matchAll, $language, $stateFilter);
if ($this->state->get('list.filter')) {
$db = $this->getDatabase();
$query->where($db->quoteName('c.core_title') . ' LIKE ' . $db->quote('%' . $this->state->get('list.filter') . '%'));
}
//Joomline hack start
$app = Factory::getApplication();
$itemid = implode(',', $app->getInput()->get('id', 0, 'int')) . ':' . $app->getInput()->get('Itemid', 0, 'int');
$context = 'com_tags.category.list.' . $itemid;
$article_id_include = $app->getUserState($context . 'filter.article_id_include', false);
$filterArticles = $app->getUserState($context . 'filter.article_id', []);
if($article_id_include && is_array($filterArticles) && count($filterArticles)){
$query->where($this->_db->quoteName('m.type_alias') . ' = ' . $this->_db->quote('com_content.article'));
$query->where($this->_db->quoteName('m.content_item_id') . ' IN ("'.implode('","', $filterArticles).'")');
}
//Joomline hack end
return $query;
}
/**
* Method to auto-populate the model state.
*
* Note. Calling getState in this method will result in recursion.
*
* @param string $ordering An optional ordering field.
* @param string $direction An optional direction (asc|desc).
*
* @return void
*
* @since 3.1
*/
protected function populateState($ordering = 'c.core_title', $direction = 'ASC')
{
$app = Factory::getApplication();
// Load the parameters.
$params = $app->isClient('administrator') ? ComponentHelper::getParams('com_tags') : $app->getParams();
$this->setState('params', $params);
// Load state from the request.
$ids = (array) $app->getInput()->get('id', [], 'string');
if (count($ids) == 1) {
$ids = explode(',', $ids[0]);
}
$ids = ArrayHelper::toInteger($ids);
// Remove zero values resulting from bad input
$ids = array_filter($ids);
$pkString = implode(',', $ids);
$this->setState('tag.id', $pkString);
// Get the selected list of types from the request. If none are specified all are used.
$typesr = $app->getInput()->get('types', [], 'array');
if ($typesr) {
// Implode is needed because the array can contain a string with a coma separated list of ids
$typesr = implode(',', $typesr);
// Sanitise
$typesr = explode(',', $typesr);
$typesr = ArrayHelper::toInteger($typesr);
$this->setState('tag.typesr', $typesr);
}
$language = $app->getInput()->getString('tag_list_language_filter');
$this->setState('tag.language', $language);
// List state information
$format = $app->getInput()->getWord('format');
if ($format === 'feed') {
$limit = $app->get('feed_limit');
} else {
$limit = $params->get('display_num', $app->get('list_limit', 20));
$limit = $app->getUserStateFromRequest('global.list.limit', 'limit', $limit, 'uint');
}
$this->setState('list.limit', $limit);
$offset = $app->getInput()->get('limitstart', 0, 'uint');
$this->setState('list.start', $offset);
$itemid = $pkString . ':' . $app->getInput()->get('Itemid', 0, 'int');
$orderCol = $app->getUserStateFromRequest('com_tags.tag.list.' . $itemid . '.filter_order', 'filter_order', '', 'string');
$orderCol = !$orderCol ? $this->state->params->get('tag_list_orderby', 'c.core_title') : $orderCol;
if (!in_array($orderCol, $this->filter_fields)) {
$orderCol = 'c.core_title';
}
$this->setState('list.ordering', $orderCol);
$listOrder = $app->getUserStateFromRequest('com_tags.tag.list.' . $itemid . '.filter_order_direction', 'filter_order_Dir', '', 'string');
$listOrder = !$listOrder ? $this->state->params->get('tag_list_orderby_direction', 'ASC') : $listOrder;
if (!in_array(strtoupper($listOrder), ['ASC', 'DESC', ''])) {
$listOrder = 'ASC';
}
$this->setState('list.direction', $listOrder);
$this->setState('tag.state', 1);
// Optional filter text
$filterSearch = $app->getUserStateFromRequest('com_tags.tag.list.' . $itemid . '.filter_search', 'filter-search', '', 'string');
$this->setState('list.filter', $filterSearch);
//Joomline hack start
$value = $this->getUserStateFromRequest('com_content.category.list.' . $itemid . 'filter.article_id_include', 'filter_article_id_include', false, 'boolen');
$this->setState('filter.article_id.include', $value);
$value = $this->getUserStateFromRequest('com_content.category.list.' . $itemid . 'filter.article_id', 'filter_article_id', null, 'array');
$this->setState('filter.article_id', $value);
//Joomline hack end
}
/**
* Method to get tag data for the current tag or tags
*
* @param integer $pk An optional ID
*
* @return array
*
* @since 3.1
*/
public function getItem($pk = null)
{
if (!count($this->item)) {
if (empty($pk)) {
$pk = $this->getState('tag.id');
}
// Get a level row instance.
/** @var \Joomla\Component\Tags\Administrator\Table\TagTable $table */
$table = $this->getTable();
$idsArray = explode(',', $pk);
// Attempt to load the rows into an array.
foreach ($idsArray as $id) {
try {
$table->load($id);
// Check published state.
if ($published = $this->getState('tag.state')) {
if ($table->published != $published) {
continue;
}
}
if (!in_array($table->access, $this->getCurrentUser()->getAuthorisedViewLevels())) {
continue;
}
// Convert the Table to a clean CMSObject.
$properties = $table->getProperties(1);
$this->item[] = ArrayHelper::toObject($properties, CMSObject::class);
} catch (\RuntimeException $e) {
$this->setError($e->getMessage());
return false;
}
}
if (count($this->item) != count($idsArray)) {
throw new \Exception(Text::_('COM_TAGS_TAG_NOT_FOUND'), 404);
}
}
return $this->item;
}
/**
* Increment the hit counter.
*
* @param integer $pk Optional primary key of the article to increment.
*
* @return boolean True if successful; false otherwise and internal error set.
*
* @since 3.2
*/
public function hit($pk = 0)
{
$input = Factory::getApplication()->getInput();
$hitcount = $input->getInt('hitcount', 1);
if ($hitcount) {
$pk = (!empty($pk)) ? $pk : (int) $this->getState('tag.id');
/** @var \Joomla\Component\Tags\Administrator\Table\TagTable $table */
$table = $this->getTable();
$table->hit($pk);
// Load the table data for later
$table->load($pk);
if (!$table->hasPrimaryKey()) {
throw new \Exception(Text::_('COM_TAGS_TAG_NOT_FOUND'), 404);
}
}
return true;
}
}

View File

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<form>
<fields name="params" addfieldprefix="Joomla\Plugin\System\Jlcontentfieldsfilter\Fields">
<fieldset
name="params"
label="PLG_JLCONTENTFIELDSFILTER_FILTER_PARAMS"
>
<field
name="content_filter"
type="jlcontentfieldsfilterfields"
label="PLG_JLCONTENTFIELDSFILTER_FILTER_TYPE"
description="PLG_JLCONTENTFIELDSFILTER_FILTER_TYPE_DESC"
default="0"
>
<option value="">JNO</option>
</field>
<field
name="filter_layout"
type="jlcontentfieldslayouts"
label="PLG_JLCONTENTFIELDSFILTER_FILTER_LAYOUT"
description="PLG_JLCONTENTFIELDSFILTER_FILTER_LAYOUT_DESC"
class="form-control"
/>
<field
name="disabled_categories"
type="category"
extension=""
default="0"
multiple="multiple"
layout="joomla.form.field.list-fancy-select"
label="PLG_JLCONTENTFIELDSFILTER_FILTER_DISABLEDCATS"
description="PLG_JLCONTENTFIELDSFILTER_FILTER_DISABLEDCATS_DESC"
/>
<field
name="field_hidden"
type="radio"
default="0"
label="PLG_JLCONTENTFIELDSFILTER_FILTER_FIELD_HIDDEN_EMPTY"
description="PLG_JLCONTENTFIELDSFILTER_FILTER_FIELD_HIDDEN_EMPTY_DESC"
class="btn-group btn-group-yesno"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="options_hidden"
type="radio"
default="0"
label="PLG_JLCONTENTFIELDSFILTER_FILTER_FIELD_HIDDEN_OPTIONS_EMPTY"
description="PLG_JLCONTENTFIELDSFILTER_FILTER_FIELD_HIDDEN_OPTIONS_EMPTY_DESC"
class="btn-group btn-group-yesno"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
</fields>
</form>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<extension type="plugin" group="system" method="upgrade">
<name>plg_system_jooa11y</name>
<author>Joomla! Project</author>
<creationDate>2022-02</creationDate>
<copyright>(C) 2021 Open Source Matters, Inc.</copyright>
<license>GNU General Public License version 2 or later; see LICENSE.txt</license>
<authorEmail>admin@joomla.org</authorEmail>
<authorUrl>www.joomla.org</authorUrl>
<version>4.2.0</version>
<description>PLG_SYSTEM_JOOA11Y_XML_DESCRIPTION</description>
<namespace path="src">Joomla\Plugin\System\Jooa11y</namespace>
<files>
<folder plugin="jooa11y">services</folder>
<folder>src</folder>
</files>
<languages>
<language tag="en-GB">language/en-GB/plg_system_jooa11y.ini</language>
<language tag="en-GB">language/en-GB/plg_system_jooa11y.sys.ini</language>
</languages>
<config>
<fields name="params">
<fieldset name="basic">
<field
name="showAlways"
type="radio"
label="PLG_SYSTEM_JOOA11Y_FIELD_SHOW_ALWAYS"
description="PLG_SYSTEM_JOOA11Y_FIELD_SHOW_ALWAYS_DESC"
layout="joomla.form.field.radio.switcher"
default="0"
filter="integer"
>
<option value="0">JOFF</option>
<option value="1">JON</option>
</field>
<field
name="contrastPlugin"
type="radio"
label="PLG_SYSTEM_JOOA11Y_FIELD_CONTRAST"
description="PLG_SYSTEM_JOOA11Y_FIELD_CONTRAST_DESC"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JOFF</option>
<option value="1">JON</option>
</field>
<field
name="formLabelsPlugin"
type="radio"
label="PLG_SYSTEM_JOOA11Y_FIELD_FORM_LABELS"
description="PLG_SYSTEM_JOOA11Y_FIELD_FORM_LABELS_DESC"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JOFF</option>
<option value="1">JON</option>
</field>
<field
name="linksAdvancedPlugin"
type="radio"
label="PLG_SYSTEM_JOOA11Y_FIELD_LINKS_ADVANCED"
description="PLG_SYSTEM_JOOA11Y_FIELD_LINKS_ADVANCED_DESC"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JOFF</option>
<option value="1">JON</option>
</field>
<field
name="colourFilterPlugin"
type="radio"
label="PLG_SYSTEM_JOOA11Y_FIELD_COLOUR_FILTER"
description="PLG_SYSTEM_JOOA11Y_FIELD_COLOUR_FILTER_DESC"
layout="joomla.form.field.radio.switcher"
default="1"
filter="integer"
>
<option value="0">JOFF</option>
<option value="1">JON</option>
</field>
<field
name="additionalChecks"
type="radio"
label="PLG_SYSTEM_JOOA11Y_FIELD_ADDITIONAL_CHECKS"
description="PLG_SYSTEM_JOOA11Y_FIELD_ADDITIONAL_CHECKS_DESC"
layout="joomla.form.field.radio.switcher"
default="0"
filter="integer"
>
<option value="0">JOFF</option>
<option value="1">JON</option>
</field>
<field
name="checkRoot"
type="text"
label="PLG_SYSTEM_JOOA11Y_FIELD_CHECK_ROOT"
description="PLG_SYSTEM_JOOA11Y_FIELD_CHECK_ROOT_DESC"
default="main"
filter="string"
/>
<field
name="readabilityRoot"
type="text"
label="PLG_SYSTEM_JOOA11Y_FIELD_READABILITY_ROOT"
description="PLG_SYSTEM_JOOA11Y_FIELD_READABILITY_ROOT_DESC"
default="main"
filter="string"
/>
<field
name="containerIgnore"
type="text"
label="PLG_SYSTEM_JOOA11Y_FIELD_CONTAINER_IGNORE"
description="PLG_SYSTEM_JOOA11Y_FIELD_CONTAINER_IGNORE_DESC"
filter="string"
/>
<field
name="shadowComponents"
type="text"
label="PLG_SYSTEM_JOOA11Y_FIELD_WEB_COMPONENTS"
description="PLG_SYSTEM_JOOA11Y_FIELD_WEB_COMPONENTS_DESC"
filter="string"
/>
<field
name="extraProps"
type="subform"
label="PLG_SYSTEM_JOOA11Y_FIELD_EXTRA_PROPS"
description="PLG_SYSTEM_JOOA11Y_FIELD_EXTRA_PROPS_DESC"
multiple="true"
>
<form>
<field type="text" name="key" label="PLG_SYSTEM_JOOA11Y_KEY"/>
<field type="text" name="value" label="PLG_SYSTEM_JOOA11Y_VALUE"/>
</form>
</field>
</fieldset>
</fields>
</config>
</extension>

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