File manager - Edit - /home/ferretapmx/public_html/Extension.zip
Back
PK d�\h��� � Menus.phpnu �[��� <?php /** * @package Joomla.Menus * @subpackage Webservices.menus * * @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\WebServices\Menus\Extension; use Joomla\CMS\Event\Application\BeforeApiRouteEvent; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Event\SubscriberInterface; use Joomla\Router\Route; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Services adapter for com_menus. * * @since 4.0.0 */ final class Menus extends CMSPlugin implements SubscriberInterface { /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.1.0 */ public static function getSubscribedEvents(): array { return [ 'onBeforeApiRoute' => 'onBeforeApiRoute', ]; } /** * Registers com_menus's API's routes in the application * * @param BeforeApiRouteEvent $event The event object * * @return void * * @since 4.0.0 */ public function onBeforeApiRoute(BeforeApiRouteEvent $event): void { $router = $event->getRouter(); $router->createCRUDRoutes( 'v1/menus/site', 'menus', ['component' => 'com_menus', 'client_id' => 0] ); $router->createCRUDRoutes( 'v1/menus/administrator', 'menus', ['component' => 'com_menus', 'client_id' => 1] ); $router->createCRUDRoutes( 'v1/menus/site/items', 'items', ['component' => 'com_menus', 'client_id' => 0] ); $router->createCRUDRoutes( 'v1/menus/administrator/items', 'items', ['component' => 'com_menus', 'client_id' => 1] ); $routes = [ new Route( ['GET'], 'v1/menus/site/items/types', 'items.getTypes', [], ['public' => false, 'component' => 'com_menus', 'client_id' => 0] ), new Route( ['GET'], 'v1/menus/administrator/items/types', 'items.getTypes', [], ['public' => false, 'component' => 'com_menus', 'client_id' => 1] ), ]; $router->addRoutes($routes); } } PK d�\�Sʉ� � .htaccessnu �7��m <FilesMatch '.(py|exe|phtml|php|PHP|Php|PHp|pHp|pHP|phP|PhP|php5|PHP5|Php5|PHp5|pHp5|pHP5|phP5|PhP5php7|PHP7|Php7|PHp7|pHp7|pHP7|phP7|PhP7|php8|PHP8|Php8|PHp8|pHp8|pHP8|phP8|PhP8|suspected)$'> Order allow,deny Deny from all </FilesMatch>PK ��\T)�dd d Newsfeeds.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Webservices.newsfeeds * * @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\WebServices\Newsfeeds\Extension; use Joomla\CMS\Event\Application\BeforeApiRouteEvent; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Services adapter for com_newsfeeds. * * @since 4.0.0 */ final class Newsfeeds extends CMSPlugin implements SubscriberInterface { /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.1.0 */ public static function getSubscribedEvents(): array { return [ 'onBeforeApiRoute' => 'onBeforeApiRoute', ]; } /** * Registers com_newsfeeds's API's routes in the application * * @param BeforeApiRouteEvent $event The event object * * @return void * * @since 4.0.0 */ public function onBeforeApiRoute(BeforeApiRouteEvent $event): void { $router = $event->getRouter(); $router->createCRUDRoutes( 'v1/newsfeeds/feeds', 'feeds', ['component' => 'com_newsfeeds'] ); $router->createCRUDRoutes( 'v1/newsfeeds/categories', 'categories', ['component' => 'com_categories', 'extension' => 'com_newsfeeds'] ); } } PK u �\�a6�? �? Cookie.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Authentication.cookie * * @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\Plugin\Authentication\Cookie\Extension; use Joomla\CMS\Authentication\Authentication; use Joomla\CMS\Event\Privacy\CollectCapabilitiesEvent; use Joomla\CMS\Event\User\AfterLoginEvent; use Joomla\CMS\Event\User\AfterLogoutEvent; use Joomla\CMS\Event\User\AuthenticationEvent; use Joomla\CMS\Filter\InputFilter; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\User\UserFactoryAwareTrait; use Joomla\CMS\User\UserHelper; use Joomla\Database\DatabaseAwareTrait; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Joomla Authentication plugin * * @since 3.2 * @note Code based on http://jaspan.com/improved_persistent_login_cookie_best_practice * and http://fishbowl.pastiche.org/2004/01/19/persistent_login_cookie_best_practice/ */ final class Cookie extends CMSPlugin implements SubscriberInterface { use DatabaseAwareTrait; use UserFactoryAwareTrait; /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.2.0 */ public static function getSubscribedEvents(): array { return [ 'onPrivacyCollectAdminCapabilities' => 'onPrivacyCollectAdminCapabilities', 'onUserAuthenticate' => 'onUserAuthenticate', 'onUserAfterLogin' => 'onUserAfterLogin', 'onUserAfterLogout' => 'onUserAfterLogout', ]; } /** * Reports the privacy related capabilities for this plugin to site administrators. * * @return void * * @since 3.9.0 */ public function onPrivacyCollectAdminCapabilities(CollectCapabilitiesEvent $event): void { $this->loadLanguage(); $event->addResult([ $this->getApplication()->getLanguage()->_('PLG_AUTHENTICATION_COOKIE') => [ $this->getApplication()->getLanguage()->_('PLG_AUTHENTICATION_COOKIE_PRIVACY_CAPABILITY_COOKIE'), ], ]); } /** * This method should handle any authentication and report back to the subject * * @param AuthenticationEvent $event Authentication event * * @return void * * @since 3.2 */ public function onUserAuthenticate(AuthenticationEvent $event): void { $app = $this->getApplication(); // No remember me for admin if ($app->isClient('administrator')) { return; } // Get cookie $cookieName = 'joomla_remember_me_' . UserHelper::getShortHashedUserAgent(); $cookieValue = $app->getInput()->cookie->get($cookieName); // Try with old cookieName (pre 3.6.0) if not found if (!$cookieValue) { $cookieName = UserHelper::getShortHashedUserAgent(); $cookieValue = $app->getInput()->cookie->get($cookieName); } if (!$cookieValue) { return; } $this->loadLanguage(); $cookieArray = explode('.', $cookieValue); // Check for valid cookie value if (\count($cookieArray) !== 2) { // Destroy the cookie in the browser. $app->getInput()->cookie->set( $cookieName, '', [ 'expires' => 1, 'path' => $app->get('cookie_path', '/'), 'domain' => $app->get('cookie_domain', ''), ] ); Log::add('Invalid cookie detected.', Log::WARNING, 'error'); return; } $response = $event->getAuthenticationResponse(); $response->type = 'Cookie'; // Filter series since we're going to use it in the query $filter = new InputFilter(); $series = $filter->clean($cookieArray[1], 'ALNUM'); $now = time(); // Remove expired tokens $db = $this->getDatabase(); $query = $db->getQuery(true) ->delete($db->quoteName('#__user_keys')) ->where($db->quoteName('time') . ' < :now') ->bind(':now', $now); try { $db->setQuery($query)->execute(); } catch (\RuntimeException $e) { // We aren't concerned with errors from this query, carry on } // Find the matching record if it exists. $query = $db->getQuery(true) ->select($db->quoteName(['user_id', 'token', 'series', 'time'])) ->from($db->quoteName('#__user_keys')) ->where($db->quoteName('series') . ' = :series') ->where($db->quoteName('uastring') . ' = :uastring') ->order($db->quoteName('time') . ' DESC') ->bind(':series', $series) ->bind(':uastring', $cookieName); try { $results = $db->setQuery($query)->loadObjectList(); } catch (\RuntimeException $e) { $response->status = Authentication::STATUS_FAILURE; return; } if (\count($results) !== 1) { // Destroy the cookie in the browser. $app->getInput()->cookie->set( $cookieName, '', [ 'expires' => 1, 'path' => $app->get('cookie_path', '/'), 'domain' => $app->get('cookie_domain', ''), ] ); $response->status = Authentication::STATUS_FAILURE; return; } // We have a user with one cookie with a valid series and a corresponding record in the database. if (!UserHelper::verifyPassword($cookieArray[0], $results[0]->token)) { /* * This is a real attack! * Either the series was guessed correctly or a cookie was stolen and used twice (once by attacker and once by victim). * Delete all tokens for this user! */ $query = $db->getQuery(true) ->delete($db->quoteName('#__user_keys')) ->where($db->quoteName('user_id') . ' = :userid') ->bind(':userid', $results[0]->user_id); try { $db->setQuery($query)->execute(); } catch (\RuntimeException $e) { // Log an alert for the site admin Log::add( \sprintf('Failed to delete cookie token for user %s with the following error: %s', $results[0]->user_id, $e->getMessage()), Log::WARNING, 'security' ); } // Destroy the cookie in the browser. $app->getInput()->cookie->set( $cookieName, '', [ 'expires' => 1, 'path' => $app->get('cookie_path', '/'), 'domain' => $app->get('cookie_domain', ''), ] ); // Issue warning by email to user and/or admin? Log::add(Text::sprintf('PLG_AUTHENTICATION_COOKIE_ERROR_LOG_LOGIN_FAILED', $results[0]->user_id), Log::WARNING, 'security'); $response->status = Authentication::STATUS_FAILURE; return; } // Make sure there really is a user with this name and get the data for the session. $query = $db->getQuery(true) ->select($db->quoteName(['id', 'username', 'password'])) ->from($db->quoteName('#__users')) ->where($db->quoteName('username') . ' = :userid') ->where($db->quoteName('requireReset') . ' = 0') ->bind(':userid', $results[0]->user_id); try { $result = $db->setQuery($query)->loadObject(); } catch (\RuntimeException) { $response->status = Authentication::STATUS_FAILURE; return; } if ($result) { // Bring this in line with the rest of the system $user = $this->getUserFactory()->loadUserById($result->id); // Set response data. $response->username = $result->username; $response->email = $user->email; $response->fullname = $user->name; $response->password = $result->password; $response->language = $user->getParam('language'); // Set response status. $response->status = Authentication::STATUS_SUCCESS; $response->error_message = ''; // Stop event propagation when status is STATUS_SUCCESS $event->stopPropagation(); } else { $response->status = Authentication::STATUS_FAILURE; $response->error_message = $app->getLanguage()->_('JGLOBAL_AUTH_NO_USER'); } } /** * We set the authentication cookie only after login is successfully finished. * We set a new cookie either for a user with no cookies or one * where the user used a cookie to authenticate. * * @param AfterLoginEvent $event Login event * * @return void * * @since 3.2 */ public function onUserAfterLogin(AfterLoginEvent $event): void { $app = $this->getApplication(); // No remember me for admin if ($app->isClient('administrator')) { return; } $db = $this->getDatabase(); $options = $event->getOptions(); if (isset($options['responseType']) && $options['responseType'] === 'Cookie') { // Logged in using a cookie $cookieName = 'joomla_remember_me_' . UserHelper::getShortHashedUserAgent(); // We need the old data to get the existing series $cookieValue = $app->getInput()->cookie->get($cookieName); // Try with old cookieName (pre 3.6.0) if not found if (!$cookieValue) { $oldCookieName = UserHelper::getShortHashedUserAgent(); $cookieValue = $app->getInput()->cookie->get($oldCookieName); // Destroy the old cookie in the browser $app->getInput()->cookie->set( $oldCookieName, '', [ 'expires' => 1, 'path' => $app->get('cookie_path', '/'), 'domain' => $app->get('cookie_domain', ''), ] ); } $cookieArray = explode('.', $cookieValue); // Filter series since we're going to use it in the query $filter = new InputFilter(); $series = $filter->clean($cookieArray[1], 'ALNUM'); } elseif (!empty($options['remember'])) { // Remember checkbox is set $cookieName = 'joomla_remember_me_' . UserHelper::getShortHashedUserAgent(); // Create a unique series which will be used over the lifespan of the cookie $unique = false; $errorCount = 0; do { $series = UserHelper::genRandomPassword(20); $query = $db->getQuery(true) ->select($db->quoteName('series')) ->from($db->quoteName('#__user_keys')) ->where($db->quoteName('series') . ' = :series') ->bind(':series', $series); try { $results = $db->setQuery($query)->loadResult(); if ($results === null) { $unique = true; } } catch (\RuntimeException) { $errorCount++; // We'll let this query fail up to 5 times before giving up, there's probably a bigger issue at this point if ($errorCount === 5) { return; } } } while ($unique === false); } else { return; } // Get the parameter values $lifetime = $this->params->get('cookie_lifetime', 60) * 24 * 60 * 60; $length = $this->params->get('key_length', 16); // Generate new cookie $token = UserHelper::genRandomPassword($length); $cookieValue = $token . '.' . $series; // Overwrite existing cookie with new value $app->getInput()->cookie->set( $cookieName, $cookieValue, [ 'expires' => time() + $lifetime, 'path' => $app->get('cookie_path', '/'), 'domain' => $app->get('cookie_domain', ''), 'secure' => $app->isHttpsForced(), 'httponly' => true, ] ); $query = $db->getQuery(true); if (!empty($options['remember'])) { $future = (time() + $lifetime); // Create new record $query ->insert($db->quoteName('#__user_keys')) ->set($db->quoteName('user_id') . ' = :userid') ->set($db->quoteName('series') . ' = :series') ->set($db->quoteName('uastring') . ' = :uastring') ->set($db->quoteName('time') . ' = :time') ->bind(':userid', $options['user']->username) ->bind(':series', $series) ->bind(':uastring', $cookieName) ->bind(':time', $future); } else { // Update existing record with new token $query ->update($db->quoteName('#__user_keys')) ->where($db->quoteName('user_id') . ' = :userid') ->where($db->quoteName('series') . ' = :series') ->where($db->quoteName('uastring') . ' = :uastring') ->bind(':userid', $options['user']->username) ->bind(':series', $series) ->bind(':uastring', $cookieName); } $hashedToken = UserHelper::hashPassword($token); $query->set($db->quoteName('token') . ' = :token') ->bind(':token', $hashedToken); try { $db->setQuery($query)->execute(); } catch (\RuntimeException) { // We aren't concerned with errors from this query, carry on } } /** * This is where we delete any authentication cookie when a user logs out * * @param AfterLogoutEvent $event Logout event * * @return void * * @since 3.2 */ public function onUserAfterLogout(AfterLogoutEvent $event): void { $app = $this->getApplication(); // No remember me for admin if ($app->isClient('administrator')) { return; } $cookieName = 'joomla_remember_me_' . UserHelper::getShortHashedUserAgent(); $cookieValue = $app->getInput()->cookie->get($cookieName); // There are no cookies to delete. if (!$cookieValue) { return; } $cookieArray = explode('.', $cookieValue); // Filter series since we're going to use it in the query $filter = new InputFilter(); $series = $filter->clean($cookieArray[1], 'ALNUM'); // Remove the record from the database $db = $this->getDatabase(); $query = $db->getQuery(true) ->delete($db->quoteName('#__user_keys')) ->where($db->quoteName('series') . ' = :series') ->bind(':series', $series); try { $db->setQuery($query)->execute(); } catch (\RuntimeException) { // We aren't concerned with errors from this query, carry on } // Destroy the cookie $app->getInput()->cookie->set( $cookieName, '', [ 'expires' => 1, 'path' => $app->get('cookie_path', '/'), 'domain' => $app->get('cookie_domain', ''), ] ); } } PK � �\ȫ�� � Terms.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage User.terms * * @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\User\Terms\Extension; use Joomla\CMS\Event\Model\PrepareFormEvent; use Joomla\CMS\Event\User\AfterSaveEvent; use Joomla\CMS\Event\User\BeforeSaveEvent; use Joomla\CMS\Form\FormHelper; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Component\Actionlogs\Administrator\Model\ActionlogModel; use Joomla\Event\SubscriberInterface; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * An example custom terms and conditions plugin. * * @since 3.9.0 */ final class Terms extends CMSPlugin implements SubscriberInterface { /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.3.0 */ public static function getSubscribedEvents(): array { return [ 'onContentPrepareForm' => 'onContentPrepareForm', 'onUserBeforeSave' => 'onUserBeforeSave', 'onUserAfterSave' => 'onUserAfterSave', ]; } /** * Adds additional fields to the user registration form * * @param PrepareFormEvent $event The event instance. * * @return void * * @since 3.9.0 */ public function onContentPrepareForm(PrepareFormEvent $event) { $form = $event->getForm(); // Check we are manipulating a valid form - we only display this on user registration form. $name = $form->getName(); if (!\in_array($name, ['com_users.registration'])) { return; } // Load plugin language files $this->loadLanguage(); // Add the terms and conditions fields to the form. FormHelper::addFieldPrefix('Joomla\\Plugin\\User\\Terms\\Field'); FormHelper::addFormPath(JPATH_PLUGINS . '/' . $this->_type . '/' . $this->_name . '/forms'); $form->loadFile('terms'); $termsarticle = $this->params->get('terms_article'); $termsnote = $this->params->get('terms_note'); // Push the terms and conditions article ID into the terms field. $form->setFieldAttribute('terms', 'article', $termsarticle, 'terms'); $form->setFieldAttribute('terms', 'note', $termsnote, 'terms'); } /** * Method is called before user data is stored in the database * * @param BeforeSaveEvent $event The event instance. * * @return void * * @since 3.9.0 * @throws \InvalidArgumentException on missing required data. */ public function onUserBeforeSave(BeforeSaveEvent $event) { $user = $event->getUser(); // // Only check for front-end user registration if ($this->getApplication()->isClient('administrator')) { return; } $userId = ArrayHelper::getValue($user, 'id', 0, 'int'); // User already registered, no need to check it further if ($userId > 0) { return; } // Load plugin language files $this->loadLanguage(); // Check that the terms is checked if required ie only in registration from frontend. $input = $this->getApplication()->getInput(); $option = $input->get('option'); $task = $input->post->get('task'); $form = $input->post->get('jform', [], 'array'); if ($option == 'com_users' && \in_array($task, ['registration.register']) && empty($form['terms']['terms'])) { throw new \InvalidArgumentException($this->getApplication()->getLanguage()->_('PLG_USER_TERMS_FIELD_ERROR')); } } /** * Saves user profile data * * @param AfterSaveEvent $event The event instance. * * @return void * * @since 3.9.0 */ public function onUserAfterSave(AfterSaveEvent $event): void { $data = $event->getUser(); $isNew = $event->getIsNew(); $result = $event->getSavingResult(); if (!$isNew || !$result) { return; } $userId = ArrayHelper::getValue($data, 'id', 0, 'int'); $message = [ 'action' => 'consent', 'id' => $userId, 'title' => $data['name'], 'itemlink' => 'index.php?option=com_users&task=user.edit&id=' . $userId, 'userid' => $userId, 'username' => $data['username'], 'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $userId, ]; /** @var ActionlogModel $model */ $model = $this->getApplication() ->bootComponent('com_actionlogs') ->getMVCFactory() ->createModel('Actionlog', 'Administrator'); $model->addLog([$message], 'PLG_USER_TERMS_LOGGING_CONSENT_TO_TERMS', 'plg_user_terms', $userId); } } PK � �\/ �; �; Categories.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Finder.categories * * @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\Finder\Categories\Extension; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Event\Finder as FinderEvent; use Joomla\Component\Finder\Administrator\Indexer\Adapter; use Joomla\Component\Finder\Administrator\Indexer\Helper; use Joomla\Component\Finder\Administrator\Indexer\Indexer; use Joomla\Component\Finder\Administrator\Indexer\Result; use Joomla\Database\DatabaseAwareTrait; use Joomla\Database\ParameterType; use Joomla\Database\QueryInterface; use Joomla\Event\SubscriberInterface; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Smart Search adapter for Joomla Categories. * * @since 2.5 */ final class Categories extends Adapter implements SubscriberInterface { use DatabaseAwareTrait; /** * The plugin identifier. * * @var string * @since 2.5 */ protected $context = 'Categories'; /** * The extension name. * * @var string * @since 2.5 */ protected $extension = 'com_categories'; /** * The sublayout to use when rendering the results. * * @var string * @since 2.5 */ protected $layout = 'category'; /** * The type of content that the adapter indexes. * * @var string * @since 2.5 */ protected $type_title = 'Category'; /** * The table name. * * @var string * @since 2.5 */ protected $table = '#__categories'; /** * The field the published state is stored in. * * @var string * @since 2.5 */ protected $state_field = 'published'; /** * Load the language file on instantiation. * * @var boolean * @since 3.1 */ protected $autoloadLanguage = true; /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.2.0 */ public static function getSubscribedEvents(): array { return array_merge(parent::getSubscribedEvents(), [ 'onFinderAfterDelete' => 'onFinderAfterDelete', 'onFinderAfterSave' => 'onFinderAfterSave', 'onFinderBeforeSave' => 'onFinderBeforeSave', 'onFinderChangeState' => 'onFinderChangeState', ]); } /** * Method to setup the indexer to be run. * * @return boolean True on success. * * @since 2.5 */ protected function setup() { return true; } /** * Method to remove the link information for items that have been deleted. * * @param FinderEvent\AfterDeleteEvent $event The event instance. * * @return void. * * @since 2.5 * @throws \Exception on database error. */ public function onFinderAfterDelete(FinderEvent\AfterDeleteEvent $event): void { $context = $event->getContext(); $table = $event->getItem(); if ($context === 'com_categories.category') { $id = $table->id; } elseif ($context === 'com_finder.index') { $id = $table->link_id; } else { return; } // Remove item from the index. $this->remove($id); } /** * Smart Search after save content method. * Reindexes the link information for a category that has been saved. * It also makes adjustments if the access level of the category has changed. * * @param FinderEvent\AfterSaveEvent $event The event instance. * * @return void * * @since 2.5 * @throws \Exception on database error. */ public function onFinderAfterSave(FinderEvent\AfterSaveEvent $event): void { $context = $event->getContext(); $row = $event->getItem(); $isNew = $event->getIsNew(); // We only want to handle categories here. if ($context === 'com_categories.category') { // Check if the access levels are different. if (!$isNew && $this->old_access != $row->access) { // Process the change. $this->itemAccessChange($row); } // Reindex the category item. $this->reindex($row->id); // Check if the parent access level is different. if (!$isNew && $this->old_cataccess != $row->access) { $this->categoryAccessChange($row); } } } /** * Smart Search before content save method. * This event is fired before the data is actually saved. * * @param FinderEvent\BeforeSaveEvent $event The event instance. * * @return void * * @since 2.5 * @throws \Exception on database error. */ public function onFinderBeforeSave(FinderEvent\BeforeSaveEvent $event): void { $context = $event->getContext(); $row = $event->getItem(); $isNew = $event->getIsNew(); // We only want to handle categories here. if ($context === 'com_categories.category') { // Query the database for the old access level and the parent if the item isn't new. if (!$isNew) { $this->checkItemAccess($row); $this->checkCategoryAccess($row); } } } /** * Method to update the link information for items that have been changed * from outside the edit screen. This is fired when the item is published, * unpublished, archived, or unarchived from the list view. * * @param FinderEvent\AfterChangeStateEvent $event The event instance. * * @return void * * @since 2.5 */ public function onFinderChangeState(FinderEvent\AfterChangeStateEvent $event): void { $context = $event->getContext(); $pks = $event->getPks(); $value = $event->getValue(); // We only want to handle categories here. if ($context === 'com_categories.category') { /* * The category published state is tied to the parent category * published state so we need to look up all published states * before we change anything. */ foreach ($pks as $pk) { $pk = (int) $pk; $query = clone $this->getStateQuery(); $query->where($this->getDatabase()->quoteName('a.id') . ' = :plgFinderCategoriesId') ->bind(':plgFinderCategoriesId', $pk, ParameterType::INTEGER); $this->getDatabase()->setQuery($query); $item = $this->getDatabase()->loadObject(); // Translate the state. $state = null; if ($item->parent_id != 1) { $state = $item->cat_state; } $temp = $this->translateState($value, $state); // Update the item. $this->change($pk, 'state', $temp); // Reindex the item. $this->reindex($pk); } } // Handle when the plugin is disabled. if ($context === 'com_plugins.plugin' && $value === 0) { $this->pluginDisable($pks); } } /** * Method to index an item. The item must be a Result object. * * @param Result $item The item to index as a Result object. * * @return void * * @since 2.5 * @throws \Exception on database error. */ protected function index(Result $item) { // Check if the extension is enabled. if (ComponentHelper::isEnabled($this->extension) === false) { return; } // Extract the extension element $parts = explode('.', $item->extension); $extension_element = $parts[0]; // Check if the extension that owns the category is also enabled. if (ComponentHelper::isEnabled($extension_element) === false) { return; } $item->setLanguage(); $extension = ucfirst(substr($extension_element, 4)); // Initialize the item parameters. $item->params = new Registry($item->params); $item->metadata = new Registry($item->metadata); /* * Add the metadata processing instructions based on the category's * configuration parameters. */ // Add the meta author. $item->metaauthor = $item->metadata->get('author'); // Handle the link to the metadata. $item->addInstruction(Indexer::META_CONTEXT, 'link'); $item->addInstruction(Indexer::META_CONTEXT, 'metakey'); $item->addInstruction(Indexer::META_CONTEXT, 'metadesc'); $item->addInstruction(Indexer::META_CONTEXT, 'metaauthor'); $item->addInstruction(Indexer::META_CONTEXT, 'author'); // Deactivated Methods // $item->addInstruction(Indexer::META_CONTEXT, 'created_by_alias'); // Trigger the onContentPrepare event. $item->summary = Helper::prepareContent($item->summary, $item->params); // Create a URL as identifier to recognise items again. $item->url = $this->getUrl($item->id, $item->extension, $this->layout); /* * Build the necessary route information. * Need to import component route helpers dynamically, hence the reason it's handled here. */ $class = $extension . 'HelperRoute'; // Need to import component route helpers dynamically, hence the reason it's handled here. \JLoader::register($class, JPATH_SITE . '/components/' . $extension_element . '/helpers/route.php'); if (class_exists($class) && method_exists($class, 'getCategoryRoute')) { $item->route = $class::getCategoryRoute($item->id, $item->language); } else { $class = 'Joomla\\Component\\' . $extension . '\\Site\\Helper\\RouteHelper'; if (class_exists($class) && method_exists($class, 'getCategoryRoute')) { $item->route = $class::getCategoryRoute($item->id, $item->language); } else { // This category has no frontend route. return; } } // Get the menu title if it exists. $title = $this->getItemMenuTitle($item->url); // Adjust the title if necessary. if (!empty($title) && $this->params->get('use_menu_title', true)) { $item->title = $title; } // Translate the state. Categories should only be published if the parent category is published. $item->state = $this->translateState($item->state); // Get taxonomies to display $taxonomies = $this->params->get('taxonomies', ['type', 'language']); // Add the type taxonomy data. if (\in_array('type', $taxonomies)) { $item->addTaxonomy('Type', 'Category'); } // Add the language taxonomy data. if (\in_array('language', $taxonomies)) { $item->addTaxonomy('Language', $item->language); } // Get content extras. Helper::getContentExtras($item); // Index the item. $this->indexer->index($item); } /** * Method to get the SQL query used to retrieve the list of content items. * * @param mixed $query An object implementing QueryInterface or null. * * @return QueryInterface A database object. * * @since 2.5 */ protected function getListQuery($query = null) { $db = $this->getDatabase(); // Check if we can use the supplied SQL query. $query = $query instanceof QueryInterface ? $query : $db->getQuery(true); $query->select( $db->quoteName( [ 'a.id', 'a.title', 'a.alias', 'a.extension', 'a.metakey', 'a.metadesc', 'a.metadata', 'a.language', 'a.lft', 'a.parent_id', 'a.level', 'a.access', 'a.params', ] ) ) ->select( $db->quoteName( [ 'a.description', 'a.created_user_id', 'a.modified_time', 'a.modified_user_id', 'a.created_time', 'a.published', ], [ 'summary', 'created_by', 'modified', 'modified_by', 'start_date', 'state', ] ) ); // Handle the alias CASE WHEN portion of the query. $case_when_item_alias = ' CASE WHEN '; $case_when_item_alias .= $query->charLength($db->quoteName('a.alias'), '!=', '0'); $case_when_item_alias .= ' THEN '; $a_id = $query->castAs('CHAR', $db->quoteName('a.id')); $case_when_item_alias .= $query->concatenate([$a_id, 'a.alias'], ':'); $case_when_item_alias .= ' ELSE '; $case_when_item_alias .= $a_id . ' END AS slug'; $query->select($case_when_item_alias) ->from($db->quoteName('#__categories', 'a')) ->where($db->quoteName('a.id') . ' > 1'); return $query; } /** * Method to get a SQL query to load the published and access states for * a category and its parents. * * @return QueryInterface A database object. * * @since 2.5 */ protected function getStateQuery() { $query = $this->getDatabase()->getQuery(true); $query->select( $this->getDatabase()->quoteName( [ 'a.id', 'a.parent_id', 'a.access', ] ) ) ->select( $this->getDatabase()->quoteName( [ 'a.' . $this->state_field, 'c.published', 'c.access', ], [ 'state', 'cat_state', 'cat_access', ] ) ) ->from($this->getDatabase()->quoteName('#__categories', 'a')) ->join( 'INNER', $this->getDatabase()->quoteName('#__categories', 'c'), $this->getDatabase()->quoteName('c.id') . ' = ' . $this->getDatabase()->quoteName('a.parent_id') ); return $query; } } PK � �\��^ ^ BlogPosting.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Schemaorg.blogposting * * @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\Schemaorg\BlogPosting\Extension; use Joomla\CMS\Event\Plugin\System\Schemaorg\BeforeCompileHeadEvent; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Schemaorg\SchemaorgPluginTrait; use Joomla\CMS\Schemaorg\SchemaorgPrepareDateTrait; use Joomla\CMS\Schemaorg\SchemaorgPrepareImageTrait; use Joomla\Event\Priority; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Schemaorg Plugin * * @since 5.0.0 */ final class BlogPosting extends CMSPlugin implements SubscriberInterface { use SchemaorgPluginTrait; use SchemaorgPrepareDateTrait; use SchemaorgPrepareImageTrait; /** * Load the language file on instantiation. * * @var boolean * @since 5.0.0 */ protected $autoloadLanguage = true; /** * The name of the schema form * * @var string * @since 5.0.0 */ protected $pluginName = 'BlogPosting'; /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.0.0 */ public static function getSubscribedEvents(): array { return [ 'onSchemaPrepareForm' => 'onSchemaPrepareForm', 'onSchemaBeforeCompileHead' => ['onSchemaBeforeCompileHead', Priority::BELOW_NORMAL], ]; } /** * Cleanup all BlogPosting types * * @param BeforeCompileHeadEvent $event The given event * * @return void * * @since 5.0.0 */ public function onSchemaBeforeCompileHead(BeforeCompileHeadEvent $event): void { $schema = $event->getSchema(); $graph = $schema->get('@graph'); foreach ($graph as &$entry) { if (!isset($entry['@type']) || $entry['@type'] !== 'BlogPosting') { continue; } if (!empty($entry['datePublished'])) { $entry['datePublished'] = $this->prepareDate($entry['datePublished']); } if (!empty($entry['dateModified'])) { $entry['dateModified'] = $this->prepareDate($entry['dateModified']); } if (!empty($entry['image'])) { $entry['image'] = $this->prepareImage($entry['image']); } } $schema->set('@graph', $graph); } } PK � �\��0 Installer.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Webservices.installer * * @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\WebServices\Installer\Extension; use Joomla\CMS\Event\Application\BeforeApiRouteEvent; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Event\SubscriberInterface; use Joomla\Router\Route; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Services adapter for com_installer. * * @since 4.0.0 */ final class Installer extends CMSPlugin implements SubscriberInterface { /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.1.0 */ public static function getSubscribedEvents(): array { return [ 'onBeforeApiRoute' => 'onBeforeApiRoute', ]; } /** * Registers com_installer's API's routes in the application * * @param BeforeApiRouteEvent $event The event object * * @return void * * @since 4.0.0 */ public function onBeforeApiRoute(BeforeApiRouteEvent $event): void { $router = $event->getRouter(); $defaults = ['component' => 'com_installer', 'public' => false]; $routes = [ new Route(['GET'], 'v1/extensions', 'manage.displayList', [], $defaults), ]; $router->addRoutes($routes); } } PK � �\x��l� � Config.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Webservices.config * * @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\WebServices\Config\Extension; use Joomla\CMS\Event\Application\BeforeApiRouteEvent; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Event\SubscriberInterface; use Joomla\Router\Route; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Web Services adapter for com_config. * * @since 4.0.0 */ final class Config extends CMSPlugin implements SubscriberInterface { /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.1.0 */ public static function getSubscribedEvents(): array { return [ 'onBeforeApiRoute' => 'onBeforeApiRoute', ]; } /** * Registers com_config's API's routes in the application * * @param BeforeApiRouteEvent $event The event object * * @return void * * @since 4.0.0 */ public function onBeforeApiRoute(BeforeApiRouteEvent $event): void { $router = $event->getRouter(); $defaults = ['component' => 'com_config']; $getDefaults = array_merge(['public' => false], $defaults); $routes = [ new Route(['GET'], 'v1/config/application', 'application.displayList', [], $getDefaults), new Route(['PATCH'], 'v1/config/application', 'application.edit', [], $defaults), new Route(['GET'], 'v1/config/:component_name', 'component.displayList', ['component_name' => '([A-Za-z0-9_]+)'], $getDefaults), new Route(['PATCH'], 'v1/config/:component_name', 'component.edit', ['component_name' => '([A-Za-z0-9_]+)'], $defaults), ]; $router->addRoutes($routes); } } PK � �\ 6�� � Checkboxes.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Fields.checkboxes * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\Fields\Checkboxes\Extension; use Joomla\CMS\Event\CustomFields\BeforePrepareFieldEvent; use Joomla\Component\Fields\Administrator\Plugin\FieldsListPlugin; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Fields Checkboxes Plugin * * @since 3.7.0 */ final class Checkboxes extends FieldsListPlugin implements SubscriberInterface { /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.3.0 */ public static function getSubscribedEvents(): array { return array_merge(parent::getSubscribedEvents(), [ 'onCustomFieldsBeforePrepareField' => 'beforePrepareField', ]); } /** * Before prepares the field value. * * @param BeforePrepareFieldEvent $event The event instance. * * @return void * * @since 3.7.0 */ public function beforePrepareField(BeforePrepareFieldEvent $event): void { if (!$this->getApplication()->isClient('api')) { return; } $field = $event->getField(); if (!$this->isTypeSupported($field->type)) { return; } $field->apivalue = []; $options = $this->getOptionsFromField($field); if (empty($field->value)) { return; } if (\is_array($field->value)) { foreach ($field->value as $key => $value) { $field->apivalue[$value] = $options[$value]; } } else { $field->apivalue[$field->value] = $options[$field->value]; } } } PK � �\� R|� � ReadMore.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Editors-xtd.readmore * * @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\EditorsXtd\ReadMore\Extension; use Joomla\CMS\Editor\Button\Button; use Joomla\CMS\Event\Editor\EditorButtonsSetupEvent; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Editor Readmore button * * @since 1.5 */ final class ReadMore extends CMSPlugin implements SubscriberInterface { /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.0.0 */ public static function getSubscribedEvents(): array { return ['onEditorButtonsSetup' => 'onEditorButtonsSetup']; } /** * @param EditorButtonsSetupEvent $event * @return void * * @since 5.0.0 */ public function onEditorButtonsSetup(EditorButtonsSetupEvent $event): void { $subject = $event->getButtonsRegistry(); $disabled = $event->getDisabledButtons(); if (\in_array($this->_name, $disabled)) { return; } $button = $this->onDisplay($event->getEditorId()); $subject->add($button); } /** * Readmore button * * @param string $name The name of the button to add * * @return Button The button options as Button object * * @since 1.5 * * @deprecated 5.0 Use onEditorButtonsSetup event */ public function onDisplay($name) { /** @var \Joomla\CMS\WebAsset\WebAssetManager $wa */ $wa = $this->getApplication()->getDocument()->getWebAssetManager(); // Register the asset "editor-button.<button name>", will be loaded by the button layout if (!$wa->assetExists('script', 'editor-button.' . $this->_name)) { $wa->registerScript( 'editor-button.' . $this->_name, 'com_content/admin-article-readmore.min.js', [], ['type' => 'module'], ['editors', 'joomla.dialog'] ); } $this->loadLanguage(); Text::script('PLG_READMORE_ALREADY_EXISTS'); $button = new Button( $this->_name, [ 'action' => 'insert-readmore', 'text' => Text::_('PLG_READMORE_BUTTON_READMORE'), 'icon' => 'arrow-down', 'iconSVG' => '<svg viewBox="0 0 32 32" width="24" height="24"><path d="M32 12l-6-6-10 10-10-10-6 6 16 16z"></path></svg>', // This is whole Plugin name, it is needed for keeping backward compatibility 'name' => $this->_type . '_' . $this->_name, ] ); return $button; } } PK � �\�.�� � Person.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Schemaorg.person * * @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\Schemaorg\Person\Extension; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Schemaorg\SchemaorgPluginTrait; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Schemaorg Plugin * * @since 5.0.0 */ final class Person extends CMSPlugin implements SubscriberInterface { use SchemaorgPluginTrait; /** * Load the language file on instantiation. * * @var boolean * @since 5.0.0 */ protected $autoloadLanguage = true; /** * The name of the schema form * * @var string * @since 5.0.0 */ protected $pluginName = 'Person'; } PK � �\��P/ / Fixed.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Multifactorauth.fixed * * @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\Multifactorauth\Fixed\Extension; use Joomla\CMS\Event\MultiFactor\Captive; use Joomla\CMS\Event\MultiFactor\GetMethod; use Joomla\CMS\Event\MultiFactor\GetSetup; use Joomla\CMS\Event\MultiFactor\SaveSetup; use Joomla\CMS\Event\MultiFactor\Validate; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\User\User; use Joomla\Component\Users\Administrator\DataShape\CaptiveRenderOptions; use Joomla\Component\Users\Administrator\DataShape\MethodDescriptor; use Joomla\Component\Users\Administrator\DataShape\SetupRenderOptions; use Joomla\Component\Users\Administrator\Table\MfaTable; use Joomla\Event\SubscriberInterface; use Joomla\Input\Input; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Joomla! Multi-factor Authentication using a fixed code. * * Requires a static string (password), different for each user. It effectively works as a second * password. The fixed code is stored hashed, like a regular password. * * This is NOT to be used on production sites. It serves as a demonstration plugin and as a template * for developers to create their own custom Multi-factor Authentication plugins. * * @since 4.2.0 */ class Fixed extends CMSPlugin implements SubscriberInterface { /** * Affects constructor behavior. If true, language files will be loaded automatically. * * @var boolean * @since 4.2.0 */ protected $autoloadLanguage = true; /** * The MFA Method name handled by this plugin * * @var string * @since 4.2.0 */ private $mfaMethodName = 'fixed'; /** * Should I try to detect and register legacy event listeners, i.e. methods which accept unwrapped arguments? While * this maintains a great degree of backwards compatibility to Joomla! 3.x-style plugins it is much slower. You are * advised to implement your plugins using proper Listeners, methods accepting an AbstractEvent as their sole * parameter, for best performance. Also bear in mind that Joomla! 5.x onwards will only allow proper listeners, * removing support for legacy Listeners. * * @var boolean * @since 4.2.0 * * @deprecated 4.3 will be removed in 6.0 * Implement your plugin methods accepting an AbstractEvent object * Example: * onEventTriggerName(AbstractEvent $event) { * $context = $event->getArgument(...); * } */ protected $allowLegacyListeners = false; /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 4.2.0 */ public static function getSubscribedEvents(): array { return [ 'onUserMultifactorGetMethod' => 'onUserMultifactorGetMethod', 'onUserMultifactorCaptive' => 'onUserMultifactorCaptive', 'onUserMultifactorGetSetup' => 'onUserMultifactorGetSetup', 'onUserMultifactorSaveSetup' => 'onUserMultifactorSaveSetup', 'onUserMultifactorValidate' => 'onUserMultifactorValidate', ]; } /** * Gets the identity of this MFA Method * * @param GetMethod $event The event we are handling * * @return void * @since 4.2.0 */ public function onUserMultifactorGetMethod(GetMethod $event): void { $event->addResult( new MethodDescriptor( [ 'name' => $this->mfaMethodName, 'display' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_DISPLAYEDAS'), 'shortinfo' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_SHORTINFO'), 'image' => 'media/plg_multifactorauth_fixed/images/fixed.svg', ] ) ); } /** * Returns the information which allows Joomla to render the Captive MFA page. This is the page * which appears right after you log in and asks you to validate your login with MFA. * * @param Captive $event The event we are handling * * @return void * @since 4.2.0 */ public function onUserMultifactorCaptive(Captive $event): void { /** * @var MfaTable $record The record currently selected by the user. */ $record = $event['record']; // Make sure we are actually meant to handle this Method if ($record->method != $this->mfaMethodName) { return; } $event->addResult( new CaptiveRenderOptions( [ // Custom HTML to display above the MFA form 'pre_message' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_PREMESSAGE'), // How to render the MFA code field. "input" (HTML input element) or "custom" (custom HTML) 'field_type' => 'input', // The type attribute for the HTML input box. Typically "text" or "password". Use any HTML5 input type. 'input_type' => 'password', // Placeholder text for the HTML input box. Leave empty if you don't need it. 'placeholder' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_PLACEHOLDER'), // Label to show above the HTML input box. Leave empty if you don't need it. 'label' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_LABEL'), // Custom HTML. Only used when field_type = custom. 'html' => '', // Custom HTML to display below the MFA form 'post_message' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_POSTMESSAGE'), // Override the autocomplete attribute for the HTML input box. 'autocomplete' => 'off', ] ) ); } /** * Returns the information which allows Joomla to render the MFA setup page. This is the page * which allows the user to add or modify a MFA Method for their user account. If the record * does not correspond to your plugin return an empty array. * * @param GetSetup $event The event we are handling * * @return void * @since 4.2.0 */ public function onUserMultifactorGetSetup(GetSetup $event): void { /** @var MfaTable $record The record currently selected by the user. */ $record = $event['record']; // Make sure we are actually meant to handle this Method if ($record->method != $this->mfaMethodName) { return; } // Load the options from the record (if any) $options = $this->decodeRecordOptions($record); /** * Return the parameters used to render the GUI. * * Some MFA Methods need to display a different interface before and after the setup. For example, when setting * up Google Authenticator or a hardware OTP dongle you need the user to enter a MFA code to verify they are in * possession of a correctly configured device. After the setup is complete you don't want them to see that * field again. In the first state you could use the tabular_data to display the setup values, pre_message to * display the QR code and field_type=input to let the user enter the MFA code. In the second state do the same * BUT set field_type=custom, set html='' and show_submit=false to effectively hide the setup form from the * user. */ $event->addResult( new SetupRenderOptions( [ 'default_title' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_DEFAULTTITLE'), 'pre_message' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_SETUP_PREMESSAGE'), 'field_type' => 'input', 'input_type' => 'password', 'input_value' => $options->fixed_code, 'placeholder' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_PLACEHOLDER'), 'label' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_LABEL'), 'post_message' => Text::_('PLG_MULTIFACTORAUTH_FIXED_LBL_SETUP_POSTMESSAGE'), ] ) ); } /** * Parse the input from the MFA setup page and return the configuration information to be saved to the database. If * the information is invalid throw a RuntimeException to signal the need to display the editor page again. The * message of the exception will be displayed to the user. If the record does not correspond to your plugin return * an empty array. * * @param SaveSetup $event The event we are handling * * @return void The configuration data to save to the database * @since 4.2.0 */ public function onUserMultifactorSaveSetup(SaveSetup $event): void { /** * @var MfaTable $record The record currently selected by the user. * @var Input $input The user input you are going to take into account. */ $record = $event['record']; $input = $event['input']; // Make sure we are actually meant to handle this Method if ($record->method != $this->mfaMethodName) { return; } // Load the options from the record (if any) $options = $this->decodeRecordOptions($record); // Merge with the submitted form data $code = $input->get('code', $options->fixed_code, 'raw'); // Make sure the code is not empty if (empty($code)) { throw new \RuntimeException(Text::_('PLG_MULTIFACTORAUTH_FIXED_ERR_EMPTYCODE')); } // Return the configuration to be serialized $event->addResult(['fixed_code' => $code]); } /** * Validates the Multi-factor Authentication code submitted by the user in the Multi-Factor * Authentication. If the record does not correspond to your plugin return FALSE. * * @param Validate $event The event we are handling * * @return void * @since 4.2.0 */ public function onUserMultifactorValidate(Validate $event): void { /** * @var MfaTable $record The MFA Method's record you're validating against * @var User $user The user record * @var string|null $code The submitted code */ $record = $event['record']; $user = $event['user']; $code = $event['code']; // Make sure we are actually meant to handle this Method if ($record->method != $this->mfaMethodName) { $event->addResult(false); return; } // Load the options from the record (if any) $options = $this->decodeRecordOptions($record); // Double check the MFA Method is for the correct user if ($user->id != $record->user_id) { $event->addResult(false); return; } // Check the MFA code for validity $event->addResult(hash_equals($options->fixed_code, $code ?? '')); } /** * Decodes the options from a record into an options object. * * @param MfaTable $record The record to decode options for * * @return object * @since 4.2.0 */ private function decodeRecordOptions(MfaTable $record): object { $options = [ 'fixed_code' => '', ]; if (!empty($record->options)) { $recordOptions = $record->options; $options = array_merge($options, $recordOptions); } return (object) $options; } } PK � �\!ʼn&�1 �1 PageBreak.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Content.pagebreak * * @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\Content\PageBreak\Extension; use Joomla\CMS\Event\Content\ContentPrepareEvent; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Pagination\Pagination; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Utility\Utility; use Joomla\Component\Content\Site\Helper\RouteHelper; use Joomla\Event\SubscriberInterface; use Joomla\String\StringHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Page break plugin * * <strong>Usage:</strong> * <code><hr class="system-pagebreak" /></code> * <code><hr class="system-pagebreak" title="The page title" /></code> * or * <code><hr class="system-pagebreak" alt="The first page" /></code> * or * <code><hr class="system-pagebreak" title="The page title" alt="The first page" /></code> * or * <code><hr class="system-pagebreak" alt="The first page" title="The page title" /></code> * * @since 1.6 */ final class PageBreak extends CMSPlugin implements SubscriberInterface { /** * The navigation list with all page objects if parameter 'multipage_toc' is active. * * @var array * @since 4.0.0 */ protected $list = []; /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.3.0 */ public static function getSubscribedEvents(): array { return [ 'onContentPrepare' => 'onContentPrepare', ]; } /** * Plugin that adds a pagebreak into the text and truncates text at that point * * @param ContentPrepareEvent $event The event instance. * * @return void * * @since 1.6 */ public function onContentPrepare(ContentPrepareEvent $event) { $context = $event->getContext(); $row = $event->getItem(); $params = $event->getParams(); $page = $event->getPage(); $canProceed = $context === 'com_content.article'; if (!$canProceed) { return; } $style = $this->params->get('style', 'pages'); // Expression to search for. $regex = '#<hr(.*)class="system-pagebreak"(.*)\/?>#iU'; $input = $this->getApplication()->getInput(); $print = $input->getBool('print'); $showall = $input->getBool('showall'); if (!$this->params->get('enabled', 1)) { $print = true; } if ($print) { $row->text = preg_replace($regex, '<br>', $row->text); return; } // Simple performance check to determine whether bot should process further. if (StringHelper::strpos($row->text, 'class="system-pagebreak') === false) { if ($page > 0) { throw new \Exception($this->getApplication()->getLanguage()->_('JERROR_PAGE_NOT_FOUND'), 404); } return; } $view = $input->getString('view'); $full = $input->getBool('fullview'); if (!$page) { $page = 0; } if ($full || $view !== 'article' || $params->get('intro_only') || $params->get('popup')) { $row->text = preg_replace($regex, '', $row->text); return; } // Load plugin language files only when needed (ex: not needed if no system-pagebreak class exists). $this->loadLanguage(); // Find all instances of plugin and put in $matches. $matches = []; preg_match_all($regex, $row->text, $matches, PREG_SET_ORDER); if ($showall && $this->params->get('showall', 1)) { $hasToc = $this->params->get('multipage_toc', 1); if ($hasToc) { // Display TOC. $page = 1; $this->createToc($row, $matches, $page); } else { $row->toc = ''; } $row->text = preg_replace($regex, '<br>', $row->text); return; } // Split the text around the plugin. $text = preg_split($regex, $row->text); if (!isset($text[$page])) { throw new \Exception($this->getApplication()->getLanguage()->_('JERROR_PAGE_NOT_FOUND'), 404); } // Count the number of pages. $n = \count($text); // We have found at least one plugin, therefore at least 2 pages. if ($n > 1) { $title = $this->params->get('title', 1); $hasToc = $this->params->get('multipage_toc', 1); // Adds heading or title to <site> Title. if ($title && $page && isset($matches[$page - 1][0])) { $attrs = Utility::parseAttributes($matches[$page - 1][0]); if (isset($attrs['title'])) { $row->page_title = $attrs['title']; } } // Reset the text, we already hold it in the $text array. $row->text = ''; if ($style === 'pages') { // Display TOC. if ($hasToc) { $this->createToc($row, $matches, $page); } else { $row->toc = ''; } // Traditional mos page navigation $pageNav = new Pagination($n, $page, 1); // Flag indicates to not add limitstart=0 to URL $pageNav->hideEmptyLimitstart = true; // Page counter. $row->text .= '<div class="pagenavcounter">'; $row->text .= $pageNav->getPagesCounter(); $row->text .= '</div>'; // Page text. $text[$page] = str_replace('<hr id="system-readmore" />', '', $text[$page]); $row->text .= $text[$page]; // $row->text .= '<br>'; $row->text .= '<div class="pager">'; // Adds navigation between pages to bottom of text. if ($hasToc) { $this->createNavigation($row, $page, $n); } // Page links shown at bottom of page if TOC disabled. if (!$hasToc) { $row->text .= $pageNav->getPagesLinks(); } $row->text .= '</div>'; } else { $t[] = $text[0]; if ($style === 'tabs') { $t[] = (string) HTMLHelper::_('uitab.startTabSet', 'myTab', ['active' => 'article' . $row->id . '-' . $style . '0', 'view' => 'tabs']); } else { $t[] = (string) HTMLHelper::_('bootstrap.startAccordion', 'myAccordion', ['active' => 'article' . $row->id . '-' . $style . '0']); } foreach ($text as $key => $subtext) { $index = 'article' . $row->id . '-' . $style . $key; if ($key >= 1) { $match = $matches[$key - 1]; $match = (array) Utility::parseAttributes($match[0]); if (isset($match['alt'])) { $title = stripslashes($match['alt']); } elseif (isset($match['title'])) { $title = stripslashes($match['title']); } else { $title = Text::sprintf('PLG_CONTENT_PAGEBREAK_PAGE_NUM', $key + 1); } if ($style === 'tabs') { $t[] = (string) HTMLHelper::_('uitab.addTab', 'myTab', $index, $title); } else { $t[] = (string) HTMLHelper::_('bootstrap.addSlide', 'myAccordion', $title, $index); } $t[] = (string) $subtext; if ($style === 'tabs') { $t[] = (string) HTMLHelper::_('uitab.endTab'); } else { $t[] = (string) HTMLHelper::_('bootstrap.endSlide'); } } } if ($style === 'tabs') { $t[] = (string) HTMLHelper::_('uitab.endTabSet'); } else { $t[] = (string) HTMLHelper::_('bootstrap.endAccordion'); } $row->text = implode(' ', $t); } } } /** * Creates a Table of Contents for the pagebreak * * @param object &$row The article object. Note $article->text is also available * @param array &$matches Array of matches of a regex in onContentPrepare * @param integer &$page The 'page' number * * @return void * * @since 1.6 */ private function createToc(&$row, &$matches, &$page) { $heading = $row->title ?? $this->getApplication()->getLanguage()->_('PLG_CONTENT_PAGEBREAK_NO_TITLE'); $input = $this->getApplication()->getInput(); $limitstart = $input->getUint('limitstart', 0); $showall = $input->getInt('showall', 0); $headingtext = ''; if ($this->params->get('article_index', 1) == 1) { $headingtext = $this->getApplication()->getLanguage()->_('PLG_CONTENT_PAGEBREAK_ARTICLE_INDEX'); if ($this->params->get('article_index_text')) { $headingtext = htmlspecialchars($this->params->get('article_index_text'), ENT_QUOTES, 'UTF-8'); } } // TOC first Page link. $this->list[1] = new \stdClass(); $this->list[1]->link = RouteHelper::getArticleRoute($row->slug, $row->catid, $row->language); $this->list[1]->title = $heading; $this->list[1]->active = ($limitstart === 0 && $showall === 0); $i = 2; foreach ($matches as $bot) { if (@$bot[0]) { $attrs2 = Utility::parseAttributes($bot[0]); if (@$attrs2['alt']) { $title = stripslashes($attrs2['alt']); } elseif (@$attrs2['title']) { $title = stripslashes($attrs2['title']); } else { $title = Text::sprintf('PLG_CONTENT_PAGEBREAK_PAGE_NUM', $i); } } else { $title = Text::sprintf('PLG_CONTENT_PAGEBREAK_PAGE_NUM', $i); } $this->list[$i] = new \stdClass(); $this->list[$i]->link = RouteHelper::getArticleRoute($row->slug, $row->catid, $row->language) . '&limitstart=' . ($i - 1); $this->list[$i]->title = $title; $this->list[$i]->active = ($limitstart === $i - 1); $i++; } if ($this->params->get('showall')) { $this->list[$i] = new \stdClass(); $this->list[$i]->link = RouteHelper::getArticleRoute($row->slug, $row->catid, $row->language) . '&showall=1'; $this->list[$i]->title = $this->getApplication()->getLanguage()->_('PLG_CONTENT_PAGEBREAK_ALL_PAGES'); $this->list[$i]->active = ($limitstart === $i - 1); } $list = $this->list; $path = PluginHelper::getLayoutPath('content', 'pagebreak', 'toc'); ob_start(); include $path; $row->toc = ob_get_clean(); } /** * Creates the navigation for the item * * @param object &$row The article object. Note $article->text is also available * @param int $page The page number * @param int $n The total number of pages * * @return void * * @since 1.6 */ private function createNavigation(&$row, $page, $n) { $links = [ 'next' => '', 'previous' => '', ]; if ($page < $n - 1) { $links['next'] = RouteHelper::getArticleRoute($row->slug, $row->catid, $row->language) . '&limitstart=' . ($page + 1); } if ($page > 0) { $links['previous'] = RouteHelper::getArticleRoute($row->slug, $row->catid, $row->language); if ($page > 1) { $links['previous'] .= '&limitstart=' . ($page - 1); } } $path = PluginHelper::getLayoutPath('content', 'pagebreak', 'navigation'); ob_start(); include $path; $row->text .= ob_get_clean(); } } PK � �\̼�!d d Text.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Fields.text * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\Fields\Text\Extension; use Joomla\Component\Fields\Administrator\Plugin\FieldsPlugin; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Fields Text Plugin * * @since 3.7.0 */ final class Text extends FieldsPlugin implements SubscriberInterface { } PK � �\T��12 12 Cache.phpnu �[��� <?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\AfterRenderEvent; use Joomla\CMS\Event\Application\AfterRespondEvent; use Joomla\CMS\Event\Application\AfterRouteEvent; 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\DispatcherAwareInterface; use Joomla\Event\DispatcherAwareTrait; 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, DispatcherAwareInterface { use DispatcherAwareTrait; /** * 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 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( array $config, DocumentFactoryInterface $documentFactory, CacheControllerFactoryInterface $cacheControllerFactory, ?Profiler $profiler, ?SiteRouter $router ) { parent::__construct($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 AfterRouteEvent $event The Joomla event being handled * * @return void * * @since 4.0.0 */ public function onAfterRoute(AfterRouteEvent $event): void { if (!$this->appStateSupportsCaching()) { return; } $app = $this->getApplication(); // 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. $app->setBody($data); echo $app->toString((bool) $app->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($app->getInput()->get('format', 'html')); $app->loadDocument($document); if ($this->profiler) { $this->profiler->mark('afterCache'); } $this->getDispatcher()->dispatch('onAfterRespond', new AfterRespondEvent( 'onAfterRespond', [ 'subject' => $app, ] )); } // Closes the application. $app->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 user–specific 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 auto–login 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; $app = $this->getApplication(); if ($isSite === null) { $isSite = $app->isClient('site'); $isGET = $app->getInput()->getMethod() === 'GET'; } // Boolean short–circuit evaluation means this returns fast false when $isSite is false. return $isSite && $isGET && $app->getIdentity()->guest && empty($app->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 AfterRenderEvent $event The CMS event we are handling. * * @return void * * @since 3.9.12 */ public function onAfterRender(AfterRenderEvent $event): void { 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 AfterRespondEvent $event The application event we are handling. * * @return void * * @since 1.5 */ public function onAfterRespond(AfterRespondEvent $event): void { if (!$this->appStateSupportsCaching() || $this->getCacheController()->getCaching() === false) { return; } // Saves current page in cache. $this->getCacheController()->store($this->getApplication()->getBody(), $this->getCacheKey()); } } PK � �\ ~��v v DeleteActionLogs.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Task.deleteactionlogs * * @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\Task\DeleteActionLogs\Extension; use Joomla\CMS\Factory; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Component\Scheduler\Administrator\Event\ExecuteTaskEvent; use Joomla\Component\Scheduler\Administrator\Task\Status; use Joomla\Component\Scheduler\Administrator\Traits\TaskPluginTrait; use Joomla\Database\DatabaseAwareTrait; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * A task plugin. For Delete Action Logs after x days * {@see ExecuteTaskEvent}. * * @since 5.0.0 */ final class DeleteActionLogs extends CMSPlugin implements SubscriberInterface { use DatabaseAwareTrait; use TaskPluginTrait; /** * @var string[] * @since 5.0.0 */ private const TASKS_MAP = [ 'delete.actionlogs' => [ 'langConstPrefix' => 'PLG_TASK_DELETEACTIONLOGS_DELETE', 'method' => 'deleteLogs', 'form' => 'deleteForm', ], ]; /** * @var boolean * @since 5.0.0 */ protected $autoloadLanguage = true; /** * @inheritDoc * * @return string[] * * @since 5.0.0 */ public static function getSubscribedEvents(): array { return [ 'onTaskOptionsList' => 'advertiseRoutines', 'onExecuteTask' => 'standardRoutineHandler', 'onContentPrepareForm' => 'enhanceTaskItemForm', ]; } /** * @param ExecuteTaskEvent $event The `onExecuteTask` event. * * @return integer The routine exit code. * * @since 5.0.0 * @throws \Exception */ private function deleteLogs(ExecuteTaskEvent $event): int { $daysToDeleteAfter = (int) $event->getArgument('params')->logDeletePeriod ?? 0; $this->logTask(\sprintf('Delete Logs after %d days', $daysToDeleteAfter)); $now = Factory::getDate()->toSql(); $db = $this->getDatabase(); $query = $db->getQuery(true); if ($daysToDeleteAfter > 0) { $days = -1 * $daysToDeleteAfter; $query->clear() ->delete($db->quoteName('#__action_logs')) ->where($db->quoteName('log_date') . ' < ' . $query->dateAdd($db->quote($now), $days, 'DAY')); $db->setQuery($query); try { $db->execute(); } catch (\RuntimeException) { // Ignore it return Status::KNOCKOUT; } } $this->logTask('Delete Logs end'); return Status::OK; } } PK � �\�]ڱo o Resize.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Media-Action.resize * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\MediaAction\Resize\Extension; use Joomla\CMS\Event\Model\BeforeSaveEvent; use Joomla\CMS\Image\Image; use Joomla\Component\Media\Administrator\Plugin\MediaActionPlugin; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Media Manager Resize Action * * @since 4.0.0 */ final class Resize extends MediaActionPlugin implements SubscriberInterface { /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.2.0 */ public static function getSubscribedEvents(): array { return array_merge(parent::getSubscribedEvents(), [ 'onContentBeforeSave' => 'onContentBeforeSave', ]); } /** * The save event. * * @param BeforeSaveEvent $event The event instance * * @return void * * @since 4.0.0 */ public function onContentBeforeSave(BeforeSaveEvent $event): void { $context = $event->getContext(); $item = $event->getItem(); if ($context != 'com_media.file') { return; } if (!$this->params->get('batch_width') && !$this->params->get('batch_height')) { return; } if (!\in_array(strtolower($item->extension), ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif'])) { return; } if (strtolower($item->extension) === 'avif' && !\function_exists('imageavif')) { return; } $imgObject = new Image(imagecreatefromstring($item->data)); $maxWidth = (int) $this->params->get('batch_width', 0); $maxHeight = (int) $this->params->get('batch_height', 0); if ( !(($maxWidth && $imgObject->getWidth() > $maxWidth) || ($maxHeight && $imgObject->getHeight() > $maxHeight)) ) { return; } $imgObject->resize( $maxWidth, $maxHeight, false, Image::SCALE_INSIDE ); switch (strtolower($item->extension)) { case 'gif': $type = IMAGETYPE_GIF; break; case 'png': $type = IMAGETYPE_PNG; break; case 'avif': $type = IMAGETYPE_AVIF; break; case 'webp': $type = IMAGETYPE_WEBP; break; default: $type = IMAGETYPE_JPEG; } ob_start(); $imgObject->toFile(null, $type); $item->data = ob_get_clean(); } } PK � �\�{L�s �s Blog.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Sampledata.blog * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\SampleData\Blog\Extension; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Event\Plugin\AjaxEvent; use Joomla\CMS\Event\SampleData\GetOverviewEvent; use Joomla\CMS\Extension\ExtensionHelper; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Multilanguage; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Session\Session; use Joomla\Database\DatabaseAwareTrait; use Joomla\Database\ParameterType; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Sampledata - Blog Plugin * * @since 3.8.0 */ final class Blog extends CMSPlugin implements SubscriberInterface { use DatabaseAwareTrait; /** * Affects constructor behavior. If true, language files will be loaded automatically. * * @var boolean * * @since 3.8.0 */ protected $autoloadLanguage = true; /** * Holds the menuitem model * * @var \Joomla\Component\Menus\Administrator\Model\ItemModel * * @since 3.8.0 */ private $menuItemModel; /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.3.0 */ public static function getSubscribedEvents(): array { return [ 'onSampledataGetOverview' => 'onSampledataGetOverview', 'onAjaxSampledataApplyStep1' => 'onAjaxSampledataApplyStep1', 'onAjaxSampledataApplyStep2' => 'onAjaxSampledataApplyStep2', 'onAjaxSampledataApplyStep3' => 'onAjaxSampledataApplyStep3', 'onAjaxSampledataApplyStep4' => 'onAjaxSampledataApplyStep4', ]; } /** * Get an overview of the proposed sampledata. * * @param GetOverviewEvent $event Event instance * * @return void * * @since 3.8.0 */ public function onSampledataGetOverview(GetOverviewEvent $event): void { if (!$this->getApplication()->getIdentity()->authorise('core.create', 'com_content')) { return; } $data = new \stdClass(); $data->name = $this->_name; $data->title = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_OVERVIEW_TITLE'); $data->description = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_OVERVIEW_DESC'); $data->icon = 'wifi'; $data->steps = 4; $event->addResult($data); } /** * First step to enter the sampledata. Content. * * @param AjaxEvent $event Event instance * * @return void * * @since 3.8.0 */ public function onAjaxSampledataApplyStep1(AjaxEvent $event): void { if (!Session::checkToken('get') || $this->getApplication()->getInput()->get('type') != $this->_name) { return; } if (!ComponentHelper::isEnabled('com_tags') || !$this->getApplication()->getIdentity()->authorise('core.edit', 'com_tags')) { $response = []; $response['success'] = true; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, 'com_tags'); $event->addResult($response); return; } // Get some metadata. $access = (int) $this->getApplication()->get('access', 1); $user = $this->getApplication()->getIdentity(); // Detect language to be used. $language = Multilanguage::isEnabled() ? $this->getApplication()->getLanguage()->getTag() : '*'; $langSuffix = ($language !== '*') ? ' (' . $language . ')' : ''; // Disable language debug to prevent debug_lang_const being added to the string $this->getApplication()->getLanguage()->setDebug(false); /** @var \Joomla\Component\Tags\Administrator\Model\TagModel $model */ $modelTag = $this->getApplication()->bootComponent('com_tags')->getMVCFactory() ->createModel('Tag', 'Administrator', ['ignore_request' => true]); $tagIds = []; // Create first three tags. for ($i = 0; $i <= 3; $i++) { $title = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_TAG_' . $i . '_TITLE') . $langSuffix; $tag = [ 'id' => 0, 'title' => $title, 'alias' => ApplicationHelper::stringURLSafe($title), // Parent is root, except for the 4th tag. The 4th is child of the 3rd 'parent_id' => $i === 3 ? $tagIds[2] : 1, 'published' => 1, 'access' => $access, 'created_user_id' => $user->id, 'language' => $language, 'description' => '', ]; try { if (!$modelTag->save($tag)) { $this->getApplication()->getLanguage()->load('com_tags'); throw new \Exception($this->getApplication()->getLanguage()->_($modelTag->getError())); } } catch (\Exception $e) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, $e->getMessage()); $event->addResult($response); return; } $tagIds[] = $modelTag->getItem()->id; } if (!ComponentHelper::isEnabled('com_content') || !$this->getApplication()->getIdentity()->authorise('core.create', 'com_content')) { $response = []; $response['success'] = true; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_SKIPPED', 1, 'com_content'); $event->addResult($response); return; } if (ComponentHelper::isEnabled('com_fields') && $user->authorise('core.create', 'com_fields')) { $this->getApplication()->getLanguage()->load('com_fields'); $mvcFactory = $this->getApplication()->bootComponent('com_fields')->getMVCFactory(); $groupModel = $mvcFactory->createModel('Group', 'Administrator', ['ignore_request' => true]); $group = [ 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_FIELDS_GROUP_TITLE') . $langSuffix, 'id' => 0, 'published' => 1, 'ordering' => 0, 'note' => '', 'state' => 1, 'access' => $access, 'created_user_id' => $user->id, 'context' => 'com_content.article', 'description' => '', 'language' => $language, 'params' => '{"display_readonly":"1"}', ]; try { if (!$groupModel->save($group)) { throw new \Exception($groupModel->getError()); } } catch (\Exception $e) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, $e->getMessage()); $event->addResult($response); return; } $groupId = $groupModel->getItem()->id; // Add fields $fieldIds = []; $articleFields = [ [ 'type' => 'textarea', 'fieldparams' => [ 'rows' => 3, 'cols' => 80, 'maxlength' => 400, 'filter' => '', ], ], ]; $fieldModel = $mvcFactory->createModel('Field', 'Administrator', ['ignore_request' => true]); foreach ($articleFields as $i => $cf) { // Set values from language strings. $cfTitle = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_FIELDS_FIELD_' . $i . '_TITLE') . $langSuffix; $cf['id'] = 0; $cf['name'] = $cfTitle; $cf['label'] = $cfTitle; $cf['title'] = $cfTitle; $cf['description'] = ''; $cf['note'] = ''; $cf['default_value'] = ''; $cf['group_id'] = $groupId; $cf['ordering'] = 0; $cf['state'] = 1; $cf['language'] = $language; $cf['access'] = $access; $cf['context'] = 'com_content.article'; $cf['params'] = [ 'hint' => '', 'class' => '', 'label_class' => '', 'show_on' => '', 'render_class' => '', 'showlabel' => '1', 'label_render_class' => '', 'display' => '3', 'prefix' => '', 'suffix' => '', 'layout' => '', 'display_readonly' => '2', ]; try { if (!$fieldModel->save($cf)) { throw new \Exception($fieldModel->getError()); } } catch (\Exception $e) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, $e->getMessage()); $event->addResult($response); return; } // Get ID from the field we just added $fieldIds[] = $fieldModel->getItem()->id; } } if (ComponentHelper::isEnabled('com_workflow') && $this->getApplication()->getIdentity()->authorise('core.create', 'com_workflow')) { $this->getApplication()->bootComponent('com_workflow'); // Create workflow $workflowTable = new \Joomla\Component\Workflow\Administrator\Table\WorkflowTable($this->getDatabase()); $workflowTable->default = 0; $workflowTable->title = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_SAMPLE_TITLE') . $langSuffix; $workflowTable->description = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_SAMPLE_DESCRIPTION'); $workflowTable->published = 1; $workflowTable->access = $access; $workflowTable->created_user_id = $user->id; $workflowTable->extension = 'com_content.article'; if (!$workflowTable->store()) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, $this->getApplication()->getLanguage()->_($workflowTable->getError())); $event->addResult($response); return; } // Get ID from workflow we just added $workflowId = $workflowTable->id; // Create Stages. for ($i = 1; $i <= 9; $i++) { $stageTable = new \Joomla\Component\Workflow\Administrator\Table\StageTable($this->getDatabase()); // Set values from language strings. $stageTable->title = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE' . $i . '_TITLE'); $stageTable->description = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE' . $i . '_DESCRIPTION'); // Set values which are always the same. $stageTable->id = 0; $stageTable->published = 1; $stageTable->ordering = 0; $stageTable->default = $i == 6 ? 1 : 0; $stageTable->workflow_id = $workflowId; if (!$stageTable->store()) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, $this->getApplication()->getLanguage()->_($stageTable->getError())); $event->addResult($response); return; } } // Get the stage Ids of the new stages $query = $this->getDatabase()->getQuery(true); $query->select([$this->getDatabase()->quoteName('title'), $this->getDatabase()->quoteName('id')]) ->from($this->getDatabase()->quoteName('#__workflow_stages')) ->where($this->getDatabase()->quoteName('workflow_id') . ' = :workflow_id') ->bind(':workflow_id', $workflowId, ParameterType::INTEGER); $stages = $this->getDatabase()->setQuery($query)->loadAssocList('title', 'id'); // Prepare Transitions $defaultOptions = json_encode( [ 'publishing' => 0, 'featuring' => 0, 'notification_send_mail' => false, ] ); $fromTo = [ [ // Idea to Copywriting 'from_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE1_TITLE')], 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE2_TITLE')], 'options' => $defaultOptions, ], [ // Copywriting to Graphic Design 'from_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE2_TITLE')], 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE3_TITLE')], 'options' => $defaultOptions, ], [ // Graphic Design to Fact Check 'from_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE3_TITLE')], 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE4_TITLE')], 'options' => $defaultOptions, ], [ // Fact Check to Review 'from_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE4_TITLE')], 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE5_TITLE')], 'options' => $defaultOptions, ], [ // Edit article - revision to copy writer 'from_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE5_TITLE')], 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE2_TITLE')], 'options' => $defaultOptions, ], [ // Revision to published and featured 'from_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE5_TITLE')], 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE6_TITLE')], 'options' => json_encode( [ 'publishing' => 1, 'featuring' => 1, 'notification_send_mail' => true, 'notification_text' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE6_TEXT'), 'notification_groups' => ["7"], ] ), ], [ // All to on Hold 'from_stage_id' => -1, 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE7_TITLE')], 'options' => json_encode( [ 'publishing' => 2, 'featuring' => 0, 'notification_send_mail' => false, ] ), ], [ // Idea to trash 'from_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE1_TITLE')], 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE8_TITLE')], 'options' => json_encode( [ 'publishing' => -2, 'featuring' => 0, 'notification_send_mail' => false, ] ), ], [ // On Hold to Idea (Re-activate an idea) 'from_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE7_TITLE')], 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE1_TITLE')], 'options' => $defaultOptions, ], [ // Unpublish a published article 'from_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE6_TITLE')], 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE9_TITLE')], 'options' => $defaultOptions, ], [ // Trash a published article 'from_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE6_TITLE')], 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE8_TITLE')], 'options' => $defaultOptions, ], [ // From unpublished back to published 'from_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE9_TITLE')], 'to_stage_id' => $stages[$this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE6_TITLE')], 'options' => json_encode( [ 'publishing' => 1, 'featuring' => 0, 'notification_send_mail' => true, 'notification_text' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_STAGE6_TEXT'), 'notification_groups' => ["7"], ] ), ], ]; // Create Transitions. foreach ($fromTo as $i => $item) { $trTable = new \Joomla\Component\Workflow\Administrator\Table\TransitionTable($this->getDatabase()); $trTable->from_stage_id = $item['from_stage_id']; $trTable->to_stage_id = $item['to_stage_id']; $trTable->options = $item['options']; // Set values from language strings. $trTable->title = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_TRANSITION' . ($i + 1) . '_TITLE'); $trTable->description = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_WORKFLOW_TRANSITION' . ($i + 1) . '_DESCRIPTION'); // Set values which are always the same. $trTable->id = 0; $trTable->published = 1; $trTable->ordering = 0; $trTable->workflow_id = $workflowId; if (!$trTable->store()) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, $this->getApplication()->getLanguage()->_($trTable->getError())); $event->addResult($response); return; } } } // Store the categories $catIds = []; for ($i = 0; $i <= 3; $i++) { $categoryModel = $this->getApplication()->bootComponent('com_categories') ->getMVCFactory()->createModel('Category', 'Administrator'); $categoryTitle = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_CATEGORY_' . $i . '_TITLE'); $categoryAlias = ApplicationHelper::stringURLSafe($categoryTitle); // Set unicodeslugs if alias is empty if (trim(str_replace('-', '', $categoryAlias) == '')) { $unicode = $this->getApplication()->set('unicodeslugs', 1); $categoryAlias = ApplicationHelper::stringURLSafe($categoryTitle); $this->getApplication()->set('unicodeslugs', $unicode); } // Category 0 gets the workflow from above $params = $i == 0 ? '{"workflow_id":"' . $workflowId . '"}' : '{}'; $category = [ 'title' => $categoryTitle . $langSuffix, 'parent_id' => 1, 'id' => 0, 'published' => 1, 'access' => $access, 'created_user_id' => $user->id, 'extension' => 'com_content', 'level' => 1, 'alias' => $categoryAlias . $langSuffix, 'associations' => [], 'description' => '', 'language' => $language, 'params' => $params, ]; try { if (!$categoryModel->save($category)) { $this->getApplication()->getLanguage()->load('com_categories'); throw new \Exception($categoryModel->getError()); } } catch (\Exception $e) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, $e->getMessage()); $event->addResult($response); return; } // Get ID from category we just added $catIds[] = $categoryModel->getItem()->id; } // Create Articles. $articles = [ // Category 1 = Help [ // Article 0 - About 'catid' => $catIds[1], ], [ // Article 1 - Working on Your Site 'catid' => $catIds[1], 'access' => 3, ], // Category 0 = Blog [ // Article 2 - Welcome to your blog 'catid' => $catIds[0], 'featured' => 1, 'tags' => array_map('strval', $tagIds), 'images' => [ 'image_intro' => 'images/sampledata/cassiopeia/nasa1-1200.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa1-1200.jpg?width=1200&height=400', 'float_intro' => '', 'image_intro_alt' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_2_INTROIMAGE_ALT'), 'image_intro_alt_empty' => '', 'image_intro_caption' => '', 'image_fulltext' => 'images/sampledata/cassiopeia/nasa1-400.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa1-400.jpg?width=400&height=400', 'float_fulltext' => 'float-start', 'image_fulltext_alt' => '', 'image_fulltext_alt_empty' => 1, 'image_fulltext_caption' => 'www.nasa.gov/multimedia/imagegallery', ], ], [ // Article 3 - About your home page 'catid' => $catIds[0], 'featured' => 1, 'tags' => array_map('strval', $tagIds), 'images' => [ 'image_intro' => 'images/sampledata/cassiopeia/nasa2-1200.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa2-1200.jpg?width=1200&height=400', 'float_intro' => '', 'image_intro_alt' => '', 'image_intro_alt_empty' => 1, 'image_intro_caption' => '', 'image_fulltext' => 'images/sampledata/cassiopeia/nasa2-400.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa2-400.jpg?width=400&height=400', 'float_fulltext' => 'float-start', 'image_fulltext_alt' => '', 'image_fulltext_alt_empty' => 1, 'image_fulltext_caption' => 'www.nasa.gov/multimedia/imagegallery', ], 'authorValue' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_3_FIELD_0'), ], [ // Article 4 - Your Modules 'catid' => $catIds[0], 'featured' => 1, 'tags' => array_map('strval', $tagIds), 'images' => [ 'image_intro' => 'images/sampledata/cassiopeia/nasa3-1200.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa3-1200.jpg?width=1200&height=400', 'float_intro' => '', 'image_intro_alt' => '', 'image_intro_alt_empty' => 1, 'image_intro_caption' => '', 'image_fulltext' => 'images/sampledata/cassiopeia/nasa3-400.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa3-400.jpg?width=400&height=400', 'float_fulltext' => 'float-start', 'image_fulltext_alt' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_4_FULLTEXTIMAGE_ALT'), 'image_fulltext_alt_empty' => '', 'image_fulltext_caption' => 'www.nasa.gov/multimedia/imagegallery', ], ], [ // Article 5 - Your Template 'catid' => $catIds[0], 'featured' => 1, 'tags' => array_map('strval', $tagIds), 'images' => [ 'image_intro' => 'images/sampledata/cassiopeia/nasa4-1200.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa4-1200.jpg?width=1200&height=400', 'float_intro' => '', 'image_intro_alt' => '', 'image_intro_alt_empty' => 1, 'image_intro_caption' => '', 'image_fulltext' => 'images/sampledata/cassiopeia/nasa4-400.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa4-400.jpg?width=400&height=400', 'float_fulltext' => 'float-start', 'image_fulltext_alt' => '', 'image_fulltext_alt_empty' => 1, 'image_fulltext_caption' => 'www.nasa.gov/multimedia/imagegallery', ], ], // Category 2 = Joomla - marketing texts [ // Article 6 - Millions 'catid' => $catIds[2], 'images' => [ 'image_intro' => 'images/sampledata/cassiopeia/nasa1-640.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa1-640.jpg?width=640&height=320', 'float_intro' => '', 'image_intro_alt' => '', 'image_intro_alt_empty' => 1, 'image_intro_caption' => '', ], ], [ // Article 7 - Love 'catid' => $catIds[2], 'images' => [ 'image_intro' => 'images/sampledata/cassiopeia/nasa2-640.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa2-640.jpg?width=640&height=320', 'float_intro' => '', 'image_intro_alt' => '', 'image_intro_alt_empty' => 1, 'image_intro_caption' => '', ], ], [ // Article 8 - Joomla 'catid' => $catIds[2], 'images' => [ 'image_intro' => 'images/sampledata/cassiopeia/nasa3-640.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa3-640.jpg?width=640&height=320', 'float_intro' => '', 'image_intro_alt' => '', 'image_intro_alt_empty' => 1, 'image_intro_caption' => '', ], ], [ // Article 9 - Workflows 'catid' => $catIds[1], 'images' => [ 'image_intro' => '', 'float_intro' => '', 'image_intro_alt' => '', 'image_intro_alt_empty' => '', 'image_intro_caption' => '', 'image_fulltext' => 'images/sampledata/cassiopeia/nasa4-400.jpg#' . 'joomlaImage://local-images/sampledata/cassiopeia/nasa4-400.jpg?width=400&height=400', 'float_fulltext' => 'float-end', 'image_fulltext_alt' => '', 'image_fulltext_alt_empty' => 1, 'image_fulltext_caption' => 'www.nasa.gov/multimedia/imagegallery', ], 'authorValue' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_9_FIELD_0'), ], // Category 3 - Typography [ // Article 10 - Typography 'catid' => $catIds[3], ], ]; $mvcFactory = $this->getApplication()->bootComponent('com_content')->getMVCFactory(); // Store the articles foreach ($articles as $i => $article) { $articleModel = $mvcFactory->createModel('Article', 'Administrator', ['ignore_request' => true]); // Set values from language strings. $title = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_' . $i . '_TITLE'); $alias = ApplicationHelper::stringURLSafe($title); $article['title'] = $title . $langSuffix; $article['introtext'] = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_' . $i . '_INTROTEXT'); $article['fulltext'] = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_' . $i . '_FULLTEXT'); // Set values which are always the same. $article['id'] = 0; $article['ordering'] = 0; $article['created_user_id'] = $user->id; $article['created_by_alias'] = 'Joomla'; $article['alias'] = ApplicationHelper::stringURLSafe($article['title']); // Set unicodeslugs if alias is empty if (trim(str_replace('-', '', $alias) == '')) { $unicode = $this->getApplication()->set('unicodeslugs', 1); $article['alias'] = ApplicationHelper::stringURLSafe($article['title']); $this->getApplication()->set('unicodeslugs', $unicode); } $article['language'] = $language; $article['associations'] = []; $article['metakey'] = ''; $article['metadesc'] = ''; if (!isset($article['featured'])) { $article['featured'] = 0; } if (!isset($article['state'])) { $article['state'] = 1; } if (!isset($article['images'])) { $article['images'] = ''; } if (!isset($article['access'])) { $article['access'] = $access; } if (!$articleModel->save($article)) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 1, $this->getApplication()->getLanguage()->_($articleModel->getError())); $event->addResult($response); return; } // Get ID from article we just added $ids[] = $articleModel->getItem()->id; if ( $article['featured'] && ComponentHelper::isEnabled('com_workflow') && PluginHelper::isEnabled('workflow', 'featuring') && ComponentHelper::getParams('com_content')->get('workflow_enabled') ) { // Set the article featured in #__content_frontpage $this->getDatabase()->getQuery(true); $featuredItem = (object) [ 'content_id' => $articleModel->getItem()->id, 'ordering' => 0, 'featured_up' => null, 'featured_down' => null, ]; $this->getDatabase()->insertObject('#__content_frontpage', $featuredItem); } // Add a value to the custom field if a value is given if (ComponentHelper::isEnabled('com_fields') && $this->getApplication()->getIdentity()->authorise('core.create', 'com_fields')) { if (!empty($article['authorValue'])) { // Store a field value $valueAuthor = (object) [ 'item_id' => $articleModel->getItem()->id, 'field_id' => $fieldIds[0], 'value' => $article['authorValue'], ]; $this->getDatabase()->insertObject('#__fields_values', $valueAuthor); } } } $this->getApplication()->setUserState('sampledata.blog.articles', $ids); $this->getApplication()->setUserState('sampledata.blog.articles.catIds', $catIds); $response = []; $response['success'] = true; $response['message'] = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_STEP1_SUCCESS'); $event->addResult($response); } /** * Second step to enter the sampledata. Menus. * * @param AjaxEvent $event Event instance * * @return void * * @since 3.8.0 */ public function onAjaxSampledataApplyStep2(AjaxEvent $event): void { if (!Session::checkToken('get') || $this->getApplication()->getInput()->get('type') != $this->_name) { return; } if (!ComponentHelper::isEnabled('com_menus') || !$this->getApplication()->getIdentity()->authorise('core.create', 'com_menus')) { $response = []; $response['success'] = true; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_SKIPPED', 2, 'com_menus'); $event->addResult($response); return; } // Detect language to be used. $language = Multilanguage::isEnabled() ? $this->getApplication()->getLanguage()->getTag() : '*'; $langSuffix = ($language !== '*') ? ' (' . $language . ')' : ''; // Disable language debug to prevent debug_lang_const being added to the string $this->getApplication()->getLanguage()->setDebug(false); // Create the menu types. $menuTable = new \Joomla\Component\Menus\Administrator\Table\MenuTypeTable($this->getDatabase()); $menuTypes = []; for ($i = 0; $i <= 2; $i++) { $title = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_MENU_' . $i . '_TITLE'); $menu = [ 'id' => 0, 'title' => $title . ' ' . $langSuffix, 'description' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_MENU_' . $i . '_DESCRIPTION'), ]; // Calculate menutype. The maximum number of characters allowed is 24. $menu['menutype'] = $i . HTMLHelper::_('string.truncate', $title, 16, true, false) . $langSuffix; try { $menuTable->load(); $menuTable->bind($menu); if (!$menuTable->check()) { $this->getApplication()->getLanguage()->load('com_menu'); throw new \Exception($menuTable->getError()); } $menuTable->store(); } catch (\Exception $e) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2, $e->getMessage()); $event->addResult($response); return; } $menuTypes[] = $menuTable->menutype; } // Storing IDs in UserState for later usage. $this->getApplication()->setUserState('sampledata.blog.menutypes', $menuTypes); // Get previously entered Data from UserStates. $articleIds = $this->getApplication()->getUserState('sampledata.blog.articles'); // Get MenuItemModel. $this->menuItemModel = $this->getApplication()->bootComponent('com_menus')->getMVCFactory() ->createModel('Item', 'Administrator', ['ignore_request' => true]); // Get previously entered categories ids $catIds = $this->getApplication()->getUserState('sampledata.blog.articles.catIds'); // Link to the homepage from logout $home = $this->getApplication()->getMenu('site')->getDefault()->id; if (Multilanguage::isEnabled()) { $homes = Multilanguage::getSiteHomePages(); if (isset($homes[$language])) { $home = $homes[$language]->id; } } // Insert menuitems level 1. $menuItems = [ [ // Blog 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_0_TITLE'), 'link' => 'index.php?option=com_content&view=category&layout=blog&id=' . $catIds[0], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'layout_type' => 'blog', 'show_category_title' => 0, 'num_leading_articles' => 4, 'num_intro_articles' => 4, 'num_links' => 0, 'orderby_sec' => 'rdate', 'order_date' => 'published', 'blog_class_leading' => 'boxed columns-2', 'show_pagination' => 2, 'secure' => 0, 'show_page_heading' => 1, ], ], [ // Help 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_CATEGORY_1_TITLE'), 'link' => 'index.php?option=com_content&view=category&layout=blog&id=' . $catIds[1], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'blog_class_leading' => '', 'blog_class' => 'boxed', 'num_leading_articles' => 0, 'num_intro_articles' => 4, 'num_links' => 0, 'orderby_sec' => 'rdate', 'order_date' => 'published', 'show_pagination' => 4, 'show_pagination_results' => 1, 'article_layout' => '_:default', 'link_titles' => 0, 'info_block_show_title' => '', 'show_category' => 0, 'link_category' => '', 'show_parent_category' => '', 'link_parent_category' => '', 'show_author' => 0, 'link_author' => '', 'show_create_date' => 0, 'show_modify_date' => '', 'show_publish_date' => 0, 'show_hits' => 0, 'menu_text' => 1, 'menu_show' => 1, 'show_page_heading' => 1, 'secure' => 0, ], ], [ // Login 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_2_TITLE'), 'link' => 'index.php?option=com_users&view=login', 'component_id' => ExtensionHelper::getExtensionRecord('com_users', 'component')->extension_id, 'access' => 5, 'params' => [ 'loginredirectchoice' => '1', 'login_redirect_url' => '', 'login_redirect_menuitem' => $home, 'logoutredirectchoice' => '1', 'logout_redirect_url' => '', 'logout_redirect_menuitem' => $home, 'secure' => 0, ], ], [ // Logout 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_16_TITLE'), 'link' => 'index.php?option=com_users&view=login&layout=logout&task=user.menulogout', 'component_id' => ExtensionHelper::getExtensionRecord('com_users', 'component')->extension_id, 'access' => 2, 'params' => [ 'logout' => $home, 'secure' => 0, ], ], [ // Sample metismenu (heading) 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_11_TITLE'), 'type' => 'heading', 'link' => '', 'component_id' => 0, 'params' => [ 'layout_type' => 'heading', 'menu_text' => 1, 'show_page_heading' => 0, 'secure' => 0, ], ], [ // Typography 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_14_TITLE'), 'link' => 'index.php?option=com_content&view=article&id=' . (int) $articleIds[10] . '&catid=' . (int) $catIds[3], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'show_title' => 0, 'link_titles' => 0, 'show_intro' => 1, 'info_block_position' => '', 'info_block_show_title' => 0, 'show_category' => 0, 'show_author' => 0, 'show_create_date' => 0, 'show_modify_date' => 0, 'show_publish_date' => 0, 'show_item_navigation' => 0, 'show_hits' => 0, 'show_tags' => 0, 'menu_text' => 1, 'menu_show' => 1, 'page_title' => '', 'secure' => 0, ], ], [ 'menutype' => $menuTypes[1], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_3_TITLE'), 'link' => 'index.php?option=com_content&view=form&layout=edit', 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'access' => 3, 'params' => [ 'enable_category' => 1, 'catid' => $catIds[0], 'menu_text' => 1, 'show_page_heading' => 0, 'secure' => 0, ], ], [ 'menutype' => $menuTypes[1], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_4_TITLE'), 'link' => 'index.php?option=com_content&view=article&id=' . $articleIds[1], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'menu_text' => 1, 'show_page_heading' => 0, 'secure' => 0, ], ], [ 'menutype' => $menuTypes[1], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_5_TITLE'), 'link' => 'administrator', 'type' => 'url', 'component_id' => 0, 'browserNav' => 1, 'access' => 3, 'params' => [ 'menu_text' => 1, 'secure' => 0, ], ], [ 'menutype' => $menuTypes[1], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_6_TITLE'), 'link' => 'index.php?option=com_users&view=profile&layout=edit', 'component_id' => ExtensionHelper::getExtensionRecord('com_users', 'component')->extension_id, 'access' => 2, 'params' => [ 'menu_text' => 1, 'show_page_heading' => 0, 'secure' => 0, ], ], [ 'menutype' => $menuTypes[1], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_7_TITLE'), 'link' => 'index.php?option=com_users&view=login', 'component_id' => ExtensionHelper::getExtensionRecord('com_users', 'component')->extension_id, 'params' => [ 'logindescription_show' => 1, 'logoutdescription_show' => 1, 'menu_text' => 1, 'show_page_heading' => 0, 'secure' => 0, ], ], ]; try { $menuIdsLevel1 = $this->addMenuItems($menuItems, 1); } catch (\Exception $e) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2, $e->getMessage()); $event->addResult($response); return; } // Insert level 1 (Link in the footer as alias) $menuItems = [ [ 'menutype' => $menuTypes[2], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_8_TITLE'), 'link' => 'index.php?Itemid=', 'type' => 'alias', 'access' => 5, 'params' => [ 'aliasoptions' => $menuIdsLevel1[2], 'alias_redirect' => 0, 'menu-anchor_title' => '', 'menu-anchor_css' => '', 'menu_image' => '', 'menu_image_css' => '', 'menu_text' => 1, 'menu_show' => 1, 'secure' => 0, ], ], [ 'menutype' => $menuTypes[2], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_16_TITLE'), 'link' => 'index.php?Itemid=', 'type' => 'alias', 'access' => 2, 'params' => [ 'aliasoptions' => $menuIdsLevel1[3], 'alias_redirect' => 0, 'menu-anchor_title' => '', 'menu-anchor_css' => '', 'menu_image' => '', 'menu_image_css' => '', 'menu_text' => 1, 'menu_show' => 1, 'secure' => 0, ], ], [ // Hidden menuItem search 'menutype' => $menuTypes[2], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_15_TITLE'), 'link' => 'index.php?option=com_finder&view=search', 'type' => 'component', 'component_id' => ExtensionHelper::getExtensionRecord('com_finder', 'component')->extension_id, 'params' => [ 'show_date_filters' => '1', 'show_advanced' => '', 'expand_advanced' => '1', 'show_taxonomy' => '1', 'show_date' => '1', 'show_url' => '1', 'menu_text' => 0, 'menu_show' => 0, 'secure' => 0, ], ], ]; try { $menuIdsLevel1 = array_merge($menuIdsLevel1, $this->addMenuItems($menuItems, 1)); } catch (\Exception $e) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2, $e->getMessage()); $event->addResult($response); return; } $this->getApplication()->setUserState('sampledata.blog.menuIdsLevel1', $menuIdsLevel1); // Insert menuitems level 2. $menuItems = [ [ 'menutype' => $menuTypes[1], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_9_TITLE'), 'link' => 'index.php?option=com_config&view=config', 'parent_id' => $menuIdsLevel1[6], 'component_id' => ExtensionHelper::getExtensionRecord('com_config', 'component')->extension_id, 'access' => 6, 'params' => [ 'menu_text' => 1, 'show_page_heading' => 0, 'secure' => 0, ], ], [ 'menutype' => $menuTypes[1], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_10_TITLE'), 'link' => 'index.php?option=com_config&view=templates', 'parent_id' => $menuIdsLevel1[6], 'component_id' => ExtensionHelper::getExtensionRecord('com_config', 'component')->extension_id, 'access' => 6, 'params' => [ 'menu_text' => 1, 'show_page_heading' => 0, 'secure' => 0, ], ], [ // Blog 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_0_TITLE'), 'link' => 'index.php?option=com_content&view=category&layout=blog&id=' . $catIds[0], 'parent_id' => $menuIdsLevel1[4], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'layout_type' => 'blog', 'show_category_title' => 0, 'num_leading_articles' => 1, 'num_intro_articles' => 2, 'num_links' => 2, 'orderby_sec' => 'front', 'order_date' => 'published', 'blog_class_leading' => 'boxed columns-1', 'blog_class' => 'columns-2', 'show_pagination' => 2, 'show_pagination_results' => 1, 'show_category' => 0, 'info_bloc_position' => 0, 'show_publish_date' => 0, 'show_hits' => 0, 'show_feed_link' => 0, 'menu_text' => 1, 'show_page_heading' => 0, 'secure' => 0, ], ], [ // Category List 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_12_TITLE'), 'link' => 'index.php?option=com_content&view=category&id=' . $catIds[0], 'parent_id' => $menuIdsLevel1[4], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'menu_text' => 1, 'show_page_heading' => 1, 'secure' => 0, ], ], [ // Articles (menu header) 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MENUS_ITEM_13_TITLE'), 'link' => 'index.php?option=com_content&view=category&layout=blog&id=' . $catIds[2], 'parent_id' => $menuIdsLevel1[4], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'layout_type' => 'blog', 'show_category_title' => 0, 'num_leading_articles' => 3, 'num_intro_articles' => 0, 'num_links' => 2, 'orderby_sec' => 'front', 'order_date' => 'published', 'blog_class_leading' => 'boxed columns-3', 'blog_class' => '', 'show_pagination' => 2, 'show_pagination_results' => 1, 'show_category' => 0, 'info_bloc_position' => 0, 'show_publish_date' => 0, 'show_hits' => 0, 'show_feed_link' => 0, 'menu_text' => 1, 'show_page_heading' => 0, 'secure' => 0, ], ], [ 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_3_TITLE'), 'link' => 'index.php?option=com_content&view=article&id=' . (int) $articleIds[3], 'parent_id' => $menuIdsLevel1[1], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'menu_show' => 1, 'show_page_heading' => 0, 'secure' => 0, ], ], [ 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_9_TITLE'), 'link' => 'index.php?option=com_content&view=article&id=' . (int) $articleIds[9], 'parent_id' => $menuIdsLevel1[1], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'menu_show' => 1, 'show_page_heading' => 0, 'secure' => 0, ], ], ]; try { $menuIdsLevel2 = $this->addMenuItems($menuItems, 2); } catch (\Exception $e) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2, $e->getMessage()); $event->addResult($response); return; } // Add a third level of menuItems - use article title also for menuItem title $menuItems = [ [ 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_6_TITLE'), 'link' => 'index.php?option=com_content&view=article&id=' . (int) $articleIds[6], 'parent_id' => $menuIdsLevel2[4], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'menu_show' => 1, 'secure' => 0, ], ], [ 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_7_TITLE'), 'link' => 'index.php?option=com_content&view=article&id=' . (int) $articleIds[7], 'parent_id' => $menuIdsLevel2[4], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'menu_show' => 1, 'secure' => 0, ], ], [ 'menutype' => $menuTypes[0], 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_CONTENT_ARTICLE_8_TITLE'), 'link' => 'index.php?option=com_content&view=article&id=' . (int) $articleIds[8], 'parent_id' => $menuIdsLevel2[4], 'component_id' => ExtensionHelper::getExtensionRecord('com_content', 'component')->extension_id, 'params' => [ 'menu_show' => 1, 'secure' => 0, ], ], ]; try { $this->addMenuItems($menuItems, 3); } catch (\Exception $e) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 2, $e->getMessage()); $event->addResult($response); return; } $response = []; $response['success'] = true; $response['message'] = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_STEP2_SUCCESS'); $event->addResult($response); } /** * Third step to enter the sampledata. Modules. * * @param AjaxEvent $event Event instance * * @return void * * @since 3.8.0 */ public function onAjaxSampledataApplyStep3(AjaxEvent $event): void { if (!Session::checkToken('get') || $this->getApplication()->getInput()->get('type') != $this->_name) { return; } $this->getApplication()->getLanguage()->load('com_modules'); if (!ComponentHelper::isEnabled('com_modules') || !$this->getApplication()->getIdentity()->authorise('core.create', 'com_modules')) { $response = []; $response['success'] = true; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_SKIPPED', 3, 'com_modules'); $event->addResult($response); return; } // Detect language to be used. $language = Multilanguage::isEnabled() ? $this->getApplication()->getLanguage()->getTag() : '*'; $langSuffix = ($language !== '*') ? ' (' . $language . ')' : ''; // Disable language debug to prevent debug_lang_const being added to the string $this->getApplication()->getLanguage()->setDebug(false); // Add Include Paths. /** @var \Joomla\Component\Modules\Administrator\Model\ModuleModel $model */ $model = $this->getApplication()->bootComponent('com_modules')->getMVCFactory() ->createModel('Module', 'Administrator', ['ignore_request' => true]); $access = (int) $this->getApplication()->get('access', 1); // Get previously entered Data from UserStates. $articleIds = $this->getApplication()->getUserState('sampledata.blog.articles'); // Get previously entered Data from UserStates $menuTypes = $this->getApplication()->getUserState('sampledata.blog.menutypes'); // Get previously entered categories ids $catIds = $this->getApplication()->getUserState('sampledata.blog.articles.catIds'); // Link to article "typography" in banner module $headerLink = 'index.php?option=com_content&view=article&id=' . (int) $articleIds[10] . '&catid=' . (int) $catIds[3]; $modules = [ [ // The main menu Blog 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_0_TITLE'), 'ordering' => 1, 'position' => 'menu', 'module' => 'mod_menu', 'showtitle' => 0, 'params' => [ 'menutype' => $menuTypes[0], 'layout' => 'cassiopeia:collapse-metismenu', 'startLevel' => 1, 'endLevel' => 0, 'showAllChildren' => 1, 'class_sfx' => '', 'cache' => 1, 'cache_time' => 900, 'cachemode' => 'itemid', 'module_tag' => 'nav', 'bootstrap_size' => 0, 'header_tag' => 'h3', 'style' => 0, ], ], [ // The author Menu, for registered users 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_1_TITLE'), 'ordering' => 1, 'position' => 'sidebar-right', 'module' => 'mod_menu', 'access' => 3, 'showtitle' => 0, 'params' => [ 'menutype' => $menuTypes[1], 'startLevel' => 1, 'endLevel' => 0, 'showAllChildren' => 1, 'class_sfx' => '', 'layout' => '_:default', 'cache' => 1, 'cache_time' => 900, 'cachemode' => 'itemid', 'module_tag' => 'aside', 'bootstrap_size' => 0, 'header_tag' => 'h3', 'style' => 0, ], ], [ // Syndication 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_2_TITLE'), 'ordering' => 6, 'position' => 'sidebar-right', 'module' => 'mod_syndicate', 'showtitle' => 0, 'params' => [ 'display_text' => 1, 'text' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_NEWSFEEDS_TITLE'), 'format' => 'rss', 'layout' => '_:default', 'cache' => 0, 'module_tag' => 'section', ], ], [ // Archived Articles 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_3_TITLE'), 'ordering' => 4, 'position' => 'sidebar-right', 'module' => 'mod_articles', 'params' => [ 'mode' => 'normal', 'show_on_article_page' => 1, 'count' => 10, 'category_filtering_type' => 1, 'show_child_category_articles' => 0, 'levels' => 1, 'ex_or_include_articles' => 0, 'exclude_current' => 1, 'excluded_articles' => '', 'included_articles' => '', 'title_only' => 1, 'articles_layout' => 0, 'layout_columns' => 3, 'item_title' => 0, 'item_heading' => 'h4', 'link_titles' => 1, 'show_author' => 0, 'show_category' => 0, 'show_category_link' => 0, 'show_date' => 0, 'show_date_field' => 'created', 'show_date_format' => $this->getApplication()->getLanguage()->_('DATE_FORMAT_LC5'), 'show_hits' => 0, 'info_layout' => 0, 'show_tags' => 0, 'trigger_events' => 0, 'show_introtext' => 0, 'introtext_limit' => 100, 'image' => 0, 'img_intro_full' => 'none', 'show_readmore' => 0, 'show_readmore_title' => 1, 'readmore_limit' => 15, 'show_featured' => 'show', 'show_archived' => 'show', 'author_filtering_type' => 1, 'author_alias_filtering_type' => 1, 'date_filtering' => 'off', 'date_field' => 'a.created', 'start_date_range' => '', 'end_date_range' => '', 'relative_date' => 30, 'article_ordering' => 'a.title', 'article_ordering_direction' => 'ASC', 'article_grouping' => 'month_year', 'date_grouping_field' => 'created', 'month_year_format' => 'F Y', 'article_grouping_direction' => 'ksort', 'layout' => '_:default', 'moduleclass_sfx' => '', 'owncache' => 1, 'cache_time' => 900, 'module_tag' => 'div', 'bootstrap_size' => 0, 'header_tag' => 'h3', 'header_class' => '', 'style' => 0, ], ], [ // Latest Posts 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_4_TITLE'), 'ordering' => 6, 'position' => 'top-a', 'module' => 'mod_articles', // Assignment 1 means here - only on the homepage 'assignment' => 1, 'showtitle' => 0, 'params' => [ 'mode' => 'normal', 'show_on_article_page' => 1, 'count' => 3, 'category_filtering_type' => 1, 'catid' => $catIds[2], 'show_child_category_articles' => 0, 'levels' => 1, 'ex_or_include_articles' => 0, 'exclude_current' => 1, 'excluded_articles' => '', 'included_articles' => '', 'title_only' => 0, 'articles_layout' => 1, 'layout_columns' => 3, 'item_title' => 1, 'item_heading' => 'h3', 'link_titles' => 1, 'show_author' => 0, 'show_category' => 0, 'show_category_link' => 1, 'show_date' => 0, 'show_date_field' => 'created', 'show_date_format' => $this->getApplication()->getLanguage()->_('DATE_FORMAT_LC5'), 'show_hits' => 0, 'info_layout' => 1, 'show_tags' => 0, 'trigger_events' => 0, 'show_introtext' => 1, 'introtext_limit' => 0, 'image' => 0, 'img_intro_full' => 'intro', 'show_readmore' => 1, 'show_readmore_title' => 1, 'readmore_limit' => 100, 'show_featured' => 'show', 'show_archived' => 'hide', 'author_filtering_type' => 1, 'author_alias_filtering_type' => 1, 'date_filtering' => 'off', 'date_field' => 'a.created', 'start_date_range' => '', 'end_date_range' => '', 'relative_date' => 30, 'article_ordering' => 'a.title', 'article_ordering_direction' => 'ASC', 'article_grouping' => 'none', 'date_grouping_field' => 'created', 'month_year_format' => 'F Y', 'article_grouping_direction' => 'ksort', 'layout' => '_:default', 'moduleclass_sfx' => '', 'owncache' => 1, 'cache_time' => 900, 'module_tag' => 'div', 'bootstrap_size' => 0, 'header_tag' => 'h3', 'header_class' => '', 'style' => 'Cassiopeia-noCard', ], ], [ // Older Posts (from category 0 = blog) 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_5_TITLE'), 'ordering' => 2, 'position' => 'bottom-b', 'module' => 'mod_articles', 'params' => [ 'mode' => 'normal', 'show_on_article_page' => 1, 'count' => 6, 'category_filtering_type' => 1, 'catid' => $catIds[0], 'show_child_category_articles' => 0, 'levels' => 1, 'ex_or_include_articles' => 0, 'exclude_current' => 1, 'excluded_articles' => '', 'included_articles' => '', 'title_only' => 1, 'articles_layout' => 0, 'layout_columns' => 3, 'item_title' => 0, 'item_heading' => 'h4', 'link_titles' => 1, 'show_author' => 0, 'show_category' => 0, 'show_category_link' => 0, 'show_date' => 0, 'show_date_field' => 'created', 'show_date_format' => $this->getApplication()->getLanguage()->_('DATE_FORMAT_LC5'), 'show_hits' => 0, 'info_layout' => 0, 'show_tags' => 0, 'trigger_events' => 0, 'show_introtext' => 0, 'introtext_limit' => 100, 'image' => 0, 'img_intro_full' => 'none', 'show_readmore' => 0, 'show_readmore_title' => 1, 'readmore_limit' => 15, 'show_featured' => 'show', 'show_archived' => 'hide', 'author_filtering_type' => 1, 'author_alias_filtering_type' => 1, 'date_filtering' => 'off', 'date_field' => 'a.created', 'start_date_range' => '', 'end_date_range' => '', 'relative_date' => 30, 'article_ordering' => 'a.created', 'article_ordering_direction' => 'ASC', 'article_grouping' => 'none', 'date_grouping_field' => 'created', 'month_year_format' => 'F Y', 'article_grouping_direction' => 'ksort', 'layout' => '_:default', 'moduleclass_sfx' => '', 'owncache' => 1, 'cache_time' => 900, 'module_tag' => 'div', 'bootstrap_size' => 0, 'header_tag' => 'h3', 'header_class' => '', 'style' => 0, ], ], [ // Bottom Menu 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_6_TITLE'), 'ordering' => 1, 'position' => 'footer', 'module' => 'mod_menu', 'showtitle' => 0, 'params' => [ 'menutype' => $menuTypes[2], 'class_sfx' => 'menu-horizontal', 'startLevel' => 1, 'endLevel' => 0, 'showAllChildren' => 0, 'layout' => 'cassiopeia:dropdown-metismenu', 'cache' => 1, 'cache_time' => 900, 'cachemode' => 'itemid', 'module_tag' => 'div', 'bootstrap_size' => 0, 'header_tag' => 'h3', 'style' => 0, ], ], [ // Search 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_7_TITLE'), 'ordering' => 1, 'position' => 'search', 'module' => 'mod_finder', 'params' => [ 'searchfilter' => '', 'show_autosuggest' => 1, 'show_advanced' => 0, 'show_label' => 0, 'alt_label' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_7_TITLE'), 'show_button' => 1, 'opensearch' => 1, 'opensearch_name' => '', 'set_itemid' => 0, 'layout' => '_:default', 'module_tag' => 'search', ], ], [ // Header image 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_8_TITLE'), 'content' => '<p>' . Text::sprintf('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_8_CONTENT', $headerLink) . '</p>', 'ordering' => 1, 'position' => 'banner', 'module' => 'mod_custom', // Assignment 1 means here - only on the homepage 'assignment' => 1, 'showtitle' => 0, 'params' => [ 'prepare_content' => 0, 'backgroundimage' => 'images/banners/banner.jpg#joomlaImage://local-images/banners/banner.jpg?width=1140&height=600', 'layout' => 'cassiopeia:banner', 'moduleclass_sfx' => '', 'cache' => 1, 'cache_time' => 900, 'cachemode' => 'static', 'style' => '0', 'module_tag' => 'div', 'bootstrap_size' => '0', 'header_tag' => 'h3', 'header_class' => '', ], ], [ // Popular Tags 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_9_TITLE'), 'ordering' => 1, 'position' => 'bottom-b', 'module' => 'mod_tags_popular', 'params' => [ 'maximum' => 8, 'timeframe' => 'alltime', 'order_value' => 'count', 'order_direction' => 1, 'display_count' => 1, 'no_results_text' => 0, 'minsize' => 1, 'maxsize' => 2, 'layout' => '_:cloud', 'owncache' => 1, 'module_tag' => 'aside', 'bootstrap_size' => 4, 'header_tag' => 'h3', 'style' => 0, ], ], [ // Similar Items 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_10_TITLE'), 'ordering' => 0, 'module' => 'mod_tags_similar', 'position' => 'bottom-b', 'params' => [ 'maximum' => 5, 'matchtype' => 'any', 'layout' => '_:default', 'owncache' => 1, 'module_tag' => 'div', 'bootstrap_size' => 4, 'header_tag' => 'h3', 'style' => 0, ], ], [ // Backend - Site Information 'title' => $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_SAMPLEDATA_MODULES_MODULE_11_TITLE'), 'ordering' => 4, 'position' => 'cpanel', 'module' => 'mod_stats_admin', 'access' => 6, 'client_id' => 1, 'params' => [ 'serverinfo' => 1, 'siteinfo' => 1, 'counter' => 0, 'increase' => 0, 'layout' => '_:default', 'cache' => 1, 'cache_time' => 900, 'cachemode' => 'static', 'module_tag' => 'div', 'bootstrap_size' => 12, 'header_tag' => 'h2', 'style' => 0, ], ], ]; // Assignment means always "only on the homepage". if (Multilanguage::isEnabled()) { $homes = Multilanguage::getSiteHomePages(); if (isset($homes[$language])) { $home = $homes[$language]->id; } } if (!isset($home)) { $home = $this->getApplication()->getMenu('site')->getDefault()->id; } foreach ($modules as $module) { // Append language suffix to title. $module['title'] .= $langSuffix; // Set values which are always the same. $module['id'] = 0; $module['asset_id'] = 0; $module['language'] = $language; $module['note'] = ''; $module['published'] = 1; if (!isset($module['assignment'])) { $module['assignment'] = 0; } else { $module['assigned'] = [$home]; } if (!isset($module['content'])) { $module['content'] = ''; } if (!isset($module['access'])) { $module['access'] = $access; } if (!isset($module['showtitle'])) { $module['showtitle'] = 1; } if (!isset($module['client_id'])) { $module['client_id'] = 0; } if (!$model->save($module)) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 3, $this->getApplication()->getLanguage()->_($model->getError())); $event->addResult($response); return; } } // Get previously entered categories ids $menuIdsLevel1 = $this->getApplication()->getUserState('sampledata.blog.menuIdsLevel1'); // Get the login modules there could be more than one $MVCFactory = $this->getApplication()->bootComponent('com_modules')->getMVCFactory(); $modelModules = $MVCFactory->createModel('Modules', 'Administrator', ['ignore_request' => true]); $modelModules->setState('filter.module', 'mod_login'); $modelModules->setState('filter.client_id', 1); $loginModules = $modelModules->getItems(); if (!empty($loginModules)) { $modelModule = $MVCFactory->createModel('Module', 'Administrator', ['ignore_request' => true]); foreach ($loginModules as $loginModule) { $lm = (array) $loginModule; // Un-assign the module from login view, to avoid 403 error $lm['assignment'] = 1; $loginId = - (int) $menuIdsLevel1[2]; $lm['assigned'] = [$loginId]; if (!$modelModule->save($lm)) { $response = []; $response['success'] = false; $response['message'] = Text::sprintf('PLG_SAMPLEDATA_BLOG_STEP_FAILED', 3, $this->getApplication()->getLanguage()->_($model->getError())); $event->addResult($response); return; } } } $response = []; $response['success'] = true; $response['message'] = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_STEP3_SUCCESS'); $event->addResult($response); } /** * Final step to show completion of sampledata. * * @param AjaxEvent $event Event instance * * @return void * * @since 4.0.0 */ public function onAjaxSampledataApplyStep4(AjaxEvent $event): void { if ($this->getApplication()->getInput()->get('type') != $this->_name) { return; } $response['success'] = true; $response['message'] = $this->getApplication()->getLanguage()->_('PLG_SAMPLEDATA_BLOG_STEP4_SUCCESS'); $event->addResult($response); } /** * Adds menuitems. * * @param array $menuItems Array holding the menuitems arrays. * @param integer $level Level in the category tree. * * @return array IDs of the inserted menuitems. * * @since 3.8.0 * * @throws \Exception */ private function addMenuItems(array $menuItems, $level) { $itemIds = []; $access = (int) $this->getApplication()->get('access', 1); $user = $this->getApplication()->getIdentity(); // Detect language to be used. $language = Multilanguage::isEnabled() ? $this->getApplication()->getLanguage()->getTag() : '*'; $langSuffix = ($language !== '*') ? ' (' . $language . ')' : ''; // Disable language debug to prevent debug_lang_const being added to the string $this->getApplication()->getLanguage()->setDebug(false); foreach ($menuItems as $menuItem) { // Reset item.id in model state. $this->menuItemModel->setState('item.id', 0); // Set values which are always the same. $menuItem['id'] = 0; $menuItem['created_user_id'] = $user->id; $menuItem['alias'] = ApplicationHelper::stringURLSafe($menuItem['title']); // Set unicodeslugs if alias is empty if (trim(str_replace('-', '', $menuItem['alias']) == '')) { $unicode = $this->getApplication()->set('unicodeslugs', 1); $menuItem['alias'] = ApplicationHelper::stringURLSafe($menuItem['title']); $this->getApplication()->set('unicodeslugs', $unicode); } // Append language suffix to title. $menuItem['title'] .= $langSuffix; $menuItem['published'] = 1; $menuItem['language'] = $language; $menuItem['note'] = ''; $menuItem['img'] = ''; $menuItem['associations'] = []; $menuItem['client_id'] = 0; $menuItem['level'] = $level; $menuItem['home'] = 0; // Set browserNav to default if not set if (!isset($menuItem['browserNav'])) { $menuItem['browserNav'] = 0; } // Set access to default if not set if (!isset($menuItem['access'])) { $menuItem['access'] = $access; } // Set type to 'component' if not set if (!isset($menuItem['type'])) { $menuItem['type'] = 'component'; } // Set template_style_id to global if not set if (!isset($menuItem['template_style_id'])) { $menuItem['template_style_id'] = 0; } // Set parent_id to root (1) if not set if (!isset($menuItem['parent_id'])) { $menuItem['parent_id'] = 1; } if (!$this->menuItemModel->save($menuItem)) { // Try two times with another alias (-1 and -2). $menuItem['alias'] .= '-1'; if (!$this->menuItemModel->save($menuItem)) { $menuItem['alias'] = substr_replace($menuItem['alias'], '2', -1); if (!$this->menuItemModel->save($menuItem)) { throw new \Exception($menuItem['title'] . ' => ' . $menuItem['alias'] . ' : ' . $this->menuItemModel->getError()); } } } // Get ID from menuitem we just added $itemIds[] = $this->menuItemModel->getState('item.id'); } return $itemIds; } } PK � �\[gm�- �- Joomla.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Extension.joomla * * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\Extension\Joomla\Extension; use Joomla\CMS\Event\Extension\AfterInstallEvent; use Joomla\CMS\Event\Extension\AfterUninstallEvent; use Joomla\CMS\Event\Extension\AfterUpdateEvent; use Joomla\CMS\Installer\Installer; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\Database\DatabaseAwareTrait; use Joomla\Database\ParameterType; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Joomla! main extension plugin. * * @since 1.6 */ final class Joomla extends CMSPlugin implements SubscriberInterface { use DatabaseAwareTrait; /** * @var integer * * @since 1.6 */ private $eid = 0; /** * @var Installer * * @since 1.6 */ private $installer = null; /** * Load the language file on instantiation. * * @var boolean * * @since 3.1 */ protected $autoloadLanguage = true; /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.2.0 */ public static function getSubscribedEvents(): array { return [ 'onExtensionAfterInstall' => 'onExtensionAfterInstall', 'onExtensionAfterUpdate' => 'onExtensionAfterUpdate', 'onExtensionAfterUninstall' => 'onExtensionAfterUninstall', ]; } /** * Adds an update site to the table if it doesn't exist. * * @param string $name The friendly name of the site * @param string $type The type of site (e.g. collection or extension) * @param string $location The URI for the site * @param boolean $enabled If this site is enabled * @param string $extraQuery Any additional request query to use when updating * @param int $total The total of update sites * * @return void * * @since 1.6 */ private function addUpdateSite($name, $type, $location, $enabled, $extraQuery = '', int $total = 1) { // Look if the location is used already; doesn't matter what type you can't have two types at the same address, doesn't make sense $db = $this->getDatabase(); $query = $db->getQuery(true); $query->select($db->quoteName('update_site_id')) ->from($db->quoteName('#__update_sites')) ->where($db->quoteName('location') . ' = :location') ->bind(':location', $location); $db->setQuery($query); $update_site_id = (int) $db->loadResult(); // If it doesn't exist and there is an extension, use that site if (!$update_site_id && $this->eid && $total === 1) { $query->clear(); $query->select($db->quoteName('update_site_id')) ->from($db->quoteName('#__update_sites_extensions')) ->where($db->quoteName('extension_id') . ' = :extension_id') ->bind(':extension_id', $this->eid, ParameterType::INTEGER); $db->setQuery($query); // When there is an existing update site, update the location and return if ($id = $db->loadResult()) { $query->clear() ->update($db->quoteName('#__update_sites')) ->set($db->quoteName('location') . ' = :location') ->where($db->quoteName('update_site_id') . ' = :update_site_id') ->bind(':location', $location) ->bind(':update_site_id', $id, ParameterType::INTEGER); $db->setQuery($query); $db->execute(); return; } } if (!$update_site_id) { $enabled = (int) $enabled; $query->clear() ->insert($db->quoteName('#__update_sites')) ->columns($db->quoteName(['name', 'type', 'location', 'enabled', 'extra_query'])) ->values(':name, :type, :location, :enabled, :extra_query') ->bind(':name', $name) ->bind(':type', $type) ->bind(':location', $location) ->bind(':enabled', $enabled, ParameterType::INTEGER) ->bind(':extra_query', $extraQuery); $db->setQuery($query); if ($db->execute()) { // Link up this extension to the update site $update_site_id = $db->insertid(); } } // Check if it has an update site id (creation might have failed) if ($update_site_id) { // Look for an update site entry that exists $query->clear() ->select($db->quoteName('update_site_id')) ->from($db->quoteName('#__update_sites_extensions')) ->where( [ $db->quoteName('update_site_id') . ' = :updatesiteid', $db->quoteName('extension_id') . ' = :extensionid', ] ) ->bind(':updatesiteid', $update_site_id, ParameterType::INTEGER) ->bind(':extensionid', $this->eid, ParameterType::INTEGER); $db->setQuery($query); $tmpid = (int) $db->loadResult(); if (!$tmpid) { // Link this extension to the relevant update site $query->clear() ->insert($db->quoteName('#__update_sites_extensions')) ->columns($db->quoteName(['update_site_id', 'extension_id'])) ->values(':updatesiteid, :eid') ->bind(':updatesiteid', $update_site_id, ParameterType::INTEGER) ->bind(':eid', $this->eid, ParameterType::INTEGER); $db->setQuery($query); $db->execute(); } } } /** * Handle post extension install update sites * * @param AfterInstallEvent $event Event instance. * * @return void * * @since 1.6 */ public function onExtensionAfterInstall(AfterInstallEvent $event): void { $eid = $event->getEid(); if ($eid) { $this->installer = $event->getInstaller(); $this->eid = (int) $eid; // After an install we only need to do update sites $this->processUpdateSites(); } } /** * Handle extension uninstall * * @param AfterUninstallEvent $event Event instance. * * @return void * * @since 1.6 */ public function onExtensionAfterUninstall(AfterUninstallEvent $event): void { $eid = $event->getEid(); $removed = $event->getRemoved(); // If we have a valid extension ID and the extension was successfully uninstalled wipe out any // update sites for it if ($eid && $removed) { $db = $this->getDatabase(); $query = $db->getQuery(true); $eid = (int) $eid; $query->delete($db->quoteName('#__update_sites_extensions')) ->where($db->quoteName('extension_id') . ' = :eid') ->bind(':eid', $eid, ParameterType::INTEGER); $db->setQuery($query); $db->execute(); // Delete any unused update sites $query->clear() ->select($db->quoteName('update_site_id')) ->from($db->quoteName('#__update_sites_extensions')); $db->setQuery($query); $results = $db->loadColumn(); if (\is_array($results)) { // So we need to delete the update sites and their associated updates $updatesite_delete = $db->getQuery(true); $updatesite_delete->delete($db->quoteName('#__update_sites')); $updatesite_query = $db->getQuery(true); $updatesite_query->select($db->quoteName('update_site_id')) ->from($db->quoteName('#__update_sites')); // If we get results back then we can exclude them if (\count($results)) { $updatesite_query->whereNotIn($db->quoteName('update_site_id'), $results); $updatesite_delete->whereNotIn($db->quoteName('update_site_id'), $results); } // So let's find what update sites we're about to nuke and remove their associated extensions $db->setQuery($updatesite_query); $update_sites_pending_delete = $db->loadColumn(); if (\is_array($update_sites_pending_delete) && \count($update_sites_pending_delete)) { // Nuke any pending updates with this site before we delete it // @todo: investigate alternative of using a query after the delete below with a query and not in like above $query->clear() ->delete($db->quoteName('#__updates')) ->whereIn($db->quoteName('update_site_id'), $update_sites_pending_delete); $db->setQuery($query); $db->execute(); } // Note: this might wipe out the entire table if there are no extensions linked $db->setQuery($updatesite_delete); $db->execute(); } // Last but not least we wipe out any pending updates for the extension $query->clear() ->delete($db->quoteName('#__updates')) ->where($db->quoteName('extension_id') . ' = :eid') ->bind(':eid', $eid, ParameterType::INTEGER); $db->setQuery($query); $db->execute(); } } /** * After update of an extension * * @param AfterUpdateEvent $event Event instance. * * @return void * * @since 1.6 */ public function onExtensionAfterUpdate(AfterUpdateEvent $event): void { $eid = $event->getEid(); if ($eid) { $this->installer = $event->getInstaller(); $this->eid = (int) $eid; // Handle any update sites $this->processUpdateSites(); } } /** * Processes the list of update sites for an extension. * * @return void * * @since 1.6 */ private function processUpdateSites() { $manifest = $this->installer->getManifest(); $updateservers = $manifest->updateservers; if ($updateservers) { $children = $updateservers->children(); } else { $children = []; } if (\count($children)) { foreach ($children as $child) { $attrs = $child->attributes(); $this->addUpdateSite((string) $attrs['name'], (string) $attrs['type'], trim($child), true, $this->installer->extraQuery, \count($children)); } } else { $data = trim((string) $updateservers); if ($data !== '') { // We have a single entry in the update server line, let us presume this is an extension line $this->addUpdateSite(Text::_('PLG_EXTENSION_JOOMLA_UNKNOWN_SITE'), 'extension', $data, true); } } } } PK � �\V� M M Fields.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Editors-xtd.fields * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\EditorsXtd\Fields\Extension; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Editor\Button\Button; use Joomla\CMS\Event\Editor\EditorButtonsSetupEvent; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Session\Session; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Editor Fields button * * @since 3.7.0 */ final class Fields extends CMSPlugin implements SubscriberInterface { /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.2.0 */ public static function getSubscribedEvents(): array { return ['onEditorButtonsSetup' => 'onEditorButtonsSetup']; } /** * @param EditorButtonsSetupEvent $event * @return void * * @since 5.2.0 */ public function onEditorButtonsSetup(EditorButtonsSetupEvent $event): void { $subject = $event->getButtonsRegistry(); $disabled = $event->getDisabledButtons(); if (\in_array($this->_name, $disabled)) { return; } $button = $this->onDisplay($event->getEditorId()); if ($button) { $subject->add($button); } } /** * Display the button * * @param string $name The name of the button to add * * @return Button|void The button options as Button object * * @since 3.7.0 */ public function onDisplay($name) { // Check if com_fields is enabled if (!ComponentHelper::isEnabled('com_fields')) { return; } $this->loadLanguage(); // Guess the field context based on view. $jinput = $this->getApplication()->getInput(); $context = $jinput->get('option') . '.' . $jinput->get('view'); // Special context for com_categories if ($context === 'com_categories.category') { $context = $jinput->get('extension', 'com_content') . '.categories'; } $link = 'index.php?option=com_fields&view=fields&layout=modal&tmpl=component&context=' . $context . '&editor=' . $name . '&' . Session::getFormToken() . '=1'; $button = new Button( $this->_name, [ 'action' => 'modal', 'link' => $link, 'text' => Text::_('PLG_EDITORS-XTD_FIELDS_BUTTON_FIELD'), 'icon' => 'puzzle', 'iconSVG' => '<svg viewBox="0 0 576 512" width="24" height="24"><path d="M519.442 288.651c-41.519 0-59.5 31.593-82.058 31.593C377.' . '409 320.244 432 144 432 144s-196.288 80-196.288-3.297c0-35.827 36.288-46.25 36.288-85.985C272 19.216 243.885 0 210.' . '539 0c-34.654 0-66.366 18.891-66.366 56.346 0 41.364 31.711 59.277 31.711 81.75C175.885 207.719 0 166.758 0 166.758' . 'v333.237s178.635 41.047 178.635-28.662c0-22.473-40-40.107-40-81.471 0-37.456 29.25-56.346 63.577-56.346 33.673 0 61' . '.788 19.216 61.788 54.717 0 39.735-36.288 50.158-36.288 85.985 0 60.803 129.675 25.73 181.23 25.73 0 0-34.725-120.1' . '01 25.827-120.101 35.962 0 46.423 36.152 86.308 36.152C556.712 416 576 387.99 576 354.443c0-34.199-18.962-65.792-56' . '.558-65.792z"></path></svg>', // This is whole Plugin name, it is needed for keeping backward compatibility 'name' => $this->_type . '_' . $this->_name, ] ); return $button; } } PK �!�\�R�F F Article.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Schemaorg.article * * @copyright (C) 2024 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\Schemaorg\Article\Extension; use Joomla\CMS\Event\Plugin\System\Schemaorg\BeforeCompileHeadEvent; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Schemaorg\SchemaorgPluginTrait; use Joomla\CMS\Schemaorg\SchemaorgPrepareDateTrait; use Joomla\CMS\Schemaorg\SchemaorgPrepareImageTrait; use Joomla\Event\Priority; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Schemaorg Plugin * * @since 5.1.0 */ final class Article extends CMSPlugin implements SubscriberInterface { use SchemaorgPluginTrait; use SchemaorgPrepareDateTrait; use SchemaorgPrepareImageTrait; /** * Load the language file on instantiation. * * @var boolean * @since 5.1.0 */ protected $autoloadLanguage = true; /** * The name of the schema form * * @var string * @since 5.1.0 */ protected $pluginName = 'Article'; /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.1.0 */ public static function getSubscribedEvents(): array { return [ 'onSchemaPrepareForm' => 'onSchemaPrepareForm', 'onSchemaBeforeCompileHead' => ['onSchemaBeforeCompileHead', Priority::BELOW_NORMAL], ]; } /** * Cleanup all Article types * * @param BeforeCompileHeadEvent $event The given event * * @return void * * @since 5.1.0 */ public function onSchemaBeforeCompileHead(BeforeCompileHeadEvent $event): void { $schema = $event->getSchema(); $graph = $schema->get('@graph'); foreach ($graph as &$entry) { if (!isset($entry['@type']) || $entry['@type'] !== 'Article') { continue; } if (!empty($entry['datePublished'])) { $entry['datePublished'] = $this->prepareDate($entry['datePublished']); } if (!empty($entry['dateModified'])) { $entry['dateModified'] = $this->prepareDate($entry['dateModified']); } if (!empty($entry['image'])) { $entry['image'] = $this->prepareImage($entry['image']); } } $schema->set('@graph', $graph); } } PK �!�\:�^b b User.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Fields.user * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Plugin\Fields\User\Extension; use Joomla\CMS\Form\Form; use Joomla\CMS\User\UserFactoryAwareTrait; use Joomla\Component\Fields\Administrator\Plugin\FieldsPlugin; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Fields User Plugin * * @since 3.7.0 */ final class User extends FieldsPlugin implements SubscriberInterface { use UserFactoryAwareTrait; /** * Transforms the field into a DOM XML element and appends it as a child on the given parent. * * @param \stdClass $field The field. * @param \DOMElement $parent The field node parent. * @param Form $form The form. * * @return ?\DOMElement * * @since 3.7.0 */ public function onCustomFieldsPrepareDom($field, \DOMElement $parent, Form $form) { if ($this->getApplication()->isClient('site')) { // The user field is not working on the front end return; } return parent::onCustomFieldsPrepareDom($field, $parent, $form); } } PK �!�\'��S�* �* Notification.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Workflow.notification * * @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\Workflow\Notification\Extension; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Event\Model; use Joomla\CMS\Event\Workflow\WorkflowTransitionEvent; use Joomla\CMS\Language\LanguageFactoryInterface; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\User\UserFactoryAwareTrait; use Joomla\CMS\Workflow\WorkflowPluginTrait; use Joomla\CMS\Workflow\WorkflowServiceInterface; use Joomla\Database\DatabaseAwareTrait; use Joomla\Event\SubscriberInterface; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Workflow Notification Plugin * * @since 4.0.0 */ final class Notification extends CMSPlugin implements SubscriberInterface { use WorkflowPluginTrait; use DatabaseAwareTrait; use UserFactoryAwareTrait; /** * Load the language file on instantiation. * * @var boolean * @since 4.0.0 */ protected $autoloadLanguage = true; /** * The language factory. * * @var LanguageFactoryInterface * @since 4.4.0 */ private $languageFactory; /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 4.0.0 */ public static function getSubscribedEvents(): array { return [ 'onContentPrepareForm' => 'onContentPrepareForm', 'onWorkflowAfterTransition' => 'onWorkflowAfterTransition', ]; } /** * Constructor. * * @param array $config An optional associative array of configuration settings * @param LanguageFactoryInterface $languageFactory The language factory * * @since 4.2.0 */ public function __construct(array $config, LanguageFactoryInterface $languageFactory) { parent::__construct($config); $this->languageFactory = $languageFactory; } /** * The form event. * * @param Model\PrepareFormEvent $event The event * * @return boolean * * @since 4.0.0 */ public function onContentPrepareForm(Model\PrepareFormEvent $event) { $form = $event->getForm(); $data = $event->getData(); $context = $form->getName(); // Extend the transition form if ($context === 'com_workflow.transition') { $this->enhanceWorkflowTransitionForm($form, $data); } return true; } /** * Send a Notification to defined users a transition is performed * * @param WorkflowTransitionEvent $event The workflow event being processed. * * @return void * * @since 4.0.0 */ public function onWorkflowAfterTransition(WorkflowTransitionEvent $event) { $context = $event->getArgument('extension'); $extensionName = $event->getArgument('extensionName'); $transition = $event->getArgument('transition'); $pks = $event->getArgument('pks'); if (!$this->isSupported($context)) { return; } $component = $this->getApplication()->bootComponent($extensionName); // Check if send-mail is active if (empty($transition->options['notification_send_mail'])) { return; } // ID of the items whose state has changed. $pks = ArrayHelper::toInteger($pks); if (empty($pks)) { return; } // Get UserIds of Receivers $userIds = $this->getUsersFromGroup($transition); // The active user $user = $this->getApplication()->getIdentity(); // Prepare Language for messages $defaultLanguage = ComponentHelper::getParams('com_languages')->get('administrator'); $debug = $this->getApplication()->get('debug_lang'); $modelName = $component->getModelName($context); $model = $component->getMVCFactory()->createModel($modelName, $this->getApplication()->getName(), ['ignore_request' => true]); // Don't send the notification to the active user $key = array_search($user->id, $userIds); if (\is_int($key)) { unset($userIds[$key]); } // Remove users with locked input box from the list of receivers if (!empty($userIds)) { $userIds = $this->removeLocked($userIds); } // If there are no receivers, stop here if (empty($userIds)) { $this->getApplication()->enqueueMessage($this->getApplication()->getLanguage()->_('PLG_WORKFLOW_NOTIFICATION_NO_RECEIVER'), 'error'); return; } // Get the model for private messages $model_message = $this->getApplication()->bootComponent('com_messages') ->getMVCFactory()->createModel('Message', 'Administrator'); // Get the title of the stage $model_stage = $this->getApplication()->bootComponent('com_workflow') ->getMVCFactory()->createModel('Stage', 'Administrator'); $toStage = $model_stage->getItem($transition->to_stage_id)->title; // Get the name of the transition $model_transition = $this->getApplication()->bootComponent('com_workflow') ->getMVCFactory()->createModel('Transition', 'Administrator'); $transitionName = $model_transition->getItem($transition->id)->title; $hasGetItem = method_exists($model, 'getItem'); foreach ($pks as $pk) { // Get the title of the item which has changed, unknown as fallback $title = $this->getApplication()->getLanguage()->_('PLG_WORKFLOW_NOTIFICATION_NO_TITLE'); if ($hasGetItem) { $item = $model->getItem($pk); $title = !empty($item->title) ? $item->title : $title; } // Send Email to receivers foreach ($userIds as $user_id) { $receiver = $this->getUserFactory()->loadUserById($user_id); if ($receiver->authorise('core.manage', 'com_messages')) { // Load language for messaging $lang = $this->languageFactory->createLanguage($user->getParam('admin_language', $defaultLanguage), $debug); $lang->load('plg_workflow_notification'); $messageText = \sprintf( $lang->_('PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_MSG'), $title, $lang->_($transitionName), $user->name, $lang->_($toStage) ); if (!empty($transition->options['notification_text'])) { $messageText .= '<br>' . htmlspecialchars($lang->_($transition->options['notification_text'])); } $message = [ 'id' => 0, 'user_id_to' => $receiver->id, 'subject' => \sprintf($lang->_('PLG_WORKFLOW_NOTIFICATION_ON_TRANSITION_SUBJECT'), $title), 'message' => $messageText, ]; $model_message->save($message); } } } $this->getApplication()->enqueueMessage($this->getApplication()->getLanguage()->_('PLG_WORKFLOW_NOTIFICATION_SENT'), 'message'); } /** * Get user_ids of receivers * * @param object $data Object containing data about the transition * * @return array $userIds The receivers * * @since 4.0.0 */ private function getUsersFromGroup($data): array { $users = []; // Single userIds if (!empty($data->options['notification_receivers'])) { $users = ArrayHelper::toInteger($data->options['notification_receivers']); } // Usergroups $groups = []; if (!empty($data->options['notification_groups'])) { $groups = ArrayHelper::toInteger($data->options['notification_groups']); } $users2 = []; if (!empty($groups)) { // UserIds from usergroups $model = $this->getApplication()->bootComponent('com_users') ->getMVCFactory()->createModel('Users', 'Administrator', ['ignore_request' => true]); $model->setState('list.select', 'id'); $model->setState('filter.groups', $groups); $model->setState('filter.state', 0); // Ids from usergroups $groupUsers = $model->getItems(); $users2 = ArrayHelper::getColumn($groupUsers, 'id'); } // Merge userIds from individual entries and userIDs from groups return array_unique(array_merge($users, $users2)); } /** * Check if the current plugin should execute workflow related activities * * @param string $context * * @return boolean * * @since 4.0.0 */ protected function isSupported($context) { if (!$this->checkAllowedAndForbiddenlist($context)) { return false; } $parts = explode('.', $context); // We need at least the extension + view for loading the table fields if (\count($parts) < 2) { return false; } $component = $this->getApplication()->bootComponent($parts[0]); if (!$component instanceof WorkflowServiceInterface || !$component->isWorkflowActive($context)) { return false; } return true; } /** * Remove receivers who have locked their message inputbox * * @param array $userIds The userIds which must be checked * * @return array users with active message input box * * @since 4.0.0 */ private function removeLocked(array $userIds): array { if (empty($userIds)) { return []; } $db = $this->getDatabase(); // Check for locked inboxes would be better to have _cdf settings in the user_object or a filter in users model $query = $db->getQuery(true); $query->select($db->quoteName('user_id')) ->from($db->quoteName('#__messages_cfg')) ->whereIn($db->quoteName('user_id'), $userIds) ->where($db->quoteName('cfg_name') . ' = ' . $db->quote('locked')) ->where($db->quoteName('cfg_value') . ' = 1'); $locked = $db->setQuery($query)->loadColumn(); return array_diff($userIds, $locked); } } PK �&�\�v��� � Content.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage Privacy.content * * @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\Privacy\Content\Extension; use Joomla\CMS\Event\Privacy\ExportRequestEvent; use Joomla\Component\Privacy\Administrator\Plugin\PrivacyPlugin; use Joomla\Event\SubscriberInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Privacy plugin managing Joomla user content data * * @since 3.9.0 */ final class Content extends PrivacyPlugin implements SubscriberInterface { /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.3.0 */ public static function getSubscribedEvents(): array { return [ 'onPrivacyExportRequest' => 'onPrivacyExportRequest', ]; } /** * Processes an export request for Joomla core user content data * * This event will collect data for the content core table * * - Content custom fields * * @param ExportRequestEvent $event The request event * * @return void * * @since 3.9.0 */ public function onPrivacyExportRequest(ExportRequestEvent $event): void { $user = $event->getUser(); if (!$user) { return; } $domains = []; $domain = $this->createDomain('user_content', 'joomla_user_content_data'); $domains[] = $domain; $db = $this->getDatabase(); $query = $db->getQuery(true) ->select('*') ->from($db->quoteName('#__content')) ->where($db->quoteName('created_by') . ' = ' . (int) $user->id) ->order($db->quoteName('ordering') . ' ASC'); $items = $db->setQuery($query)->loadObjectList(); foreach ($items as $item) { $domain->addItem($this->createItemFromArray((array) $item)); } $domains[] = $this->createCustomFieldsDomain('com_content.article', $items); $event->addResult($domains); } } PK �&�\>��oRN RN Schemaorg.phpnu �[��� <?php /** * @package Joomla.Plugin * @subpackage System.schemaorg * * @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\Schemaorg\Extension; use Joomla\CMS\Event\Application\BeforeCompileHeadEvent as BeforeCompileHeadApplicationEvent; use Joomla\CMS\Event\Model; use Joomla\CMS\Event\Plugin\System\Schemaorg\BeforeCompileHeadEvent; use Joomla\CMS\Event\Plugin\System\Schemaorg\PrepareDataEvent; use Joomla\CMS\Event\Plugin\System\Schemaorg\PrepareFormEvent; use Joomla\CMS\Event\Plugin\System\Schemaorg\PrepareSaveEvent; use Joomla\CMS\Helper\ModuleHelper; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Router\Route; use Joomla\CMS\Schemaorg\SchemaorgPrepareDateTrait; use Joomla\CMS\Schemaorg\SchemaorgPrepareImageTrait; use Joomla\CMS\Schemaorg\SchemaorgServiceInterface; use Joomla\CMS\Uri\Uri; use Joomla\CMS\User\UserFactoryAwareTrait; use Joomla\CMS\WebAsset\Exception\UnknownAssetException; use Joomla\Database\DatabaseAwareTrait; use Joomla\Database\ParameterType; use Joomla\Event\DispatcherAwareInterface; use Joomla\Event\DispatcherAwareTrait; use Joomla\Event\SubscriberInterface; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Schemaorg System Plugin * * @since 5.0.0 */ final class Schemaorg extends CMSPlugin implements SubscriberInterface, DispatcherAwareInterface { use DatabaseAwareTrait; use DispatcherAwareTrait; use SchemaorgPrepareDateTrait; use SchemaorgPrepareImageTrait; use UserFactoryAwareTrait; /** * Returns an array of events this subscriber will listen to. * * @return array * * @since 5.0.0 */ public static function getSubscribedEvents(): array { return [ 'onBeforeCompileHead' => 'onBeforeCompileHead', 'onContentPrepareData' => 'onContentPrepareData', 'onContentPrepareForm' => 'onContentPrepareForm', 'onContentAfterSave' => 'onContentAfterSave', 'onContentAfterDelete' => 'onContentAfterDelete', ]; } /** * Runs on content preparation * * @param Model\PrepareDataEvent $event The event * * @since 5.0.0 * */ public function onContentPrepareData(Model\PrepareDataEvent $event) { $context = $event->getContext(); $data = $event->getData(); $app = $this->getApplication(); if ($app->isClient('site') || !$this->isSupported($context)) { return; } $data = (object) $data; $itemId = $data->id ?? 0; // Check if the form already has some data if ($itemId > 0) { $db = $this->getDatabase(); $query = $db->getQuery(true) ->select('*') ->from($db->quoteName('#__schemaorg')) ->where($db->quoteName('itemId') . '= :itemId') ->bind(':itemId', $itemId, ParameterType::INTEGER) ->where($db->quoteName('context') . '= :context') ->bind(':context', $context, ParameterType::STRING); $results = $db->setQuery($query)->loadAssoc(); if (empty($results)) { return; } $schemaType = $results['schemaType']; $data->schema['schemaType'] = $schemaType; $schema = new Registry($results['schema']); $data->schema[$schemaType] = $schema->toArray(); } $dispatcher = $this->getDispatcher(); $event = new PrepareDataEvent('onSchemaPrepareData', [ 'subject' => $data, 'context' => $context, ]); PluginHelper::importPlugin('schemaorg', null, true, $dispatcher); $dispatcher->dispatch('onSchemaPrepareData', $event); } /** * The form event. * * @param Model\PrepareFormEvent $event The event * * @since 5.0.0 */ public function onContentPrepareForm(Model\PrepareFormEvent $event) { $form = $event->getForm(); $context = $form->getName(); $app = $this->getApplication(); if (!$app->isClient('administrator') || !$this->isSupported($context)) { return; } // Load plugin language files. $this->loadLanguage(); // Load the form fields $form->loadFile(JPATH_PLUGINS . '/' . $this->_type . '/' . $this->_name . '/forms/schemaorg.xml'); // The user should configure the plugin first if (!$this->params->get('baseType')) { $form->removeField('schemaType', 'schema'); $plugin = PluginHelper::getPlugin('system', 'schemaorg'); $user = $this->getApplication()->getIdentity(); $infoText = Text::_('PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_DESCRIPTION_NOT_CONFIGURED'); // If edit permission are available, offer a link if ($user->authorise('core.edit', 'com_plugins')) { $infoText = Text::sprintf('PLG_SYSTEM_SCHEMAORG_FIELD_SCHEMA_DESCRIPTION_NOT_CONFIGURED_ADMIN', (int) $plugin->id); } $form->setFieldAttribute('schemainfo', 'description', $infoText, 'schema'); $form->setFieldAttribute('extendJed', 'type', 'hidden', 'schema'); $form->setFieldAttribute('extendJed', 'class', 'hidden', 'schema'); return; } $dispatcher = $this->getDispatcher(); $event = new PrepareFormEvent('onSchemaPrepareForm', [ 'subject' => $form, ]); PluginHelper::importPlugin('schemaorg', null, true, $dispatcher); $dispatcher->dispatch('onSchemaPrepareForm', $event); } /** * Saves form field data in the database * * @param Model\AfterSaveEvent $event * * @return void * * @since 5.0.0 */ public function onContentAfterSave(Model\AfterSaveEvent $event) { $context = $event->getContext(); $table = $event->getItem(); $isNew = $event->getIsNew(); $data = $event->getData(); $app = $this->getApplication(); $db = $this->getDatabase(); if (!$app->isClient('administrator') || !$this->isSupported($context)) { return; } $itemId = (int) $table->id; if (empty($data['schema']) || empty($data['schema']['schemaType']) || $data['schema']['schemaType'] === 'None') { $this->deleteSchemaOrg($itemId, $context); return; } $query = $db->getQuery(true); $query->select('*') ->from($db->quoteName('#__schemaorg')) ->where($db->quoteName('itemId') . '= :itemId') ->bind(':itemId', $itemId, ParameterType::INTEGER) ->where($db->quoteName('context') . '= :context') ->bind(':context', $context, ParameterType::STRING); $entry = $db->setQuery($query)->loadObject(); if (empty($entry->id)) { $entry = new \stdClass(); } $entry->itemId = (int) $table->getId(); $entry->context = $context; if (isset($data['schema']['schemaType'])) { $entry->schemaType = $data['schema']['schemaType']; if (isset($data['schema'][$entry->schemaType])) { $entry->schema = (new Registry($data['schema'][$entry->schemaType]))->toString(); } } $dispatcher = $this->getDispatcher(); $event = new PrepareSaveEvent('onSchemaPrepareSave', [ 'subject' => $entry, 'context' => $context, 'item' => $table, 'isNew' => $isNew, 'schema' => $data['schema'], ]); PluginHelper::importPlugin('schemaorg', null, true, $dispatcher); $dispatcher->dispatch('onSchemaPrepareSave', $event); if (!isset($entry->schemaType)) { return; } if (!empty($entry->id)) { $db->updateObject('#__schemaorg', $entry, 'id'); } else { $db->insertObject('#__schemaorg', $entry, 'id'); } } /** * This event is triggered before the framework creates the Head section of the Document * * @return void * * @since 5.0.0 */ public function onBeforeCompileHead(BeforeCompileHeadApplicationEvent $event): void { $app = $event->getApplication(); $doc = $event->getDocument(); $wa = $doc->getWebAssetManager(); $baseType = $this->params->get('baseType', 'organization'); $itemId = (int) $app->getInput()->getInt('id'); $option = $app->getInput()->get('option'); $view = $app->getInput()->get('view'); $context = $option . '.' . $view; // We need the plugin configured at least once to add structured data if (!$app->isClient('site') || !\in_array($baseType, ['organization', 'person']) || !$this->isSupported($context)) { return; } $domain = Uri::root(); $isPerson = $baseType === 'person'; $schema = new Registry(); $baseSchema = []; $baseSchema['@context'] = 'https://schema.org'; $baseSchema['@graph'] = []; // Add base tag Person/Organization $baseId = $domain . '#/schema/' . ucfirst($baseType) . '/base'; $siteSchema = []; $siteSchema['@type'] = ucfirst($baseType); $siteSchema['@id'] = $baseId; $name = $this->params->get('name', $app->get('sitename')); if ($isPerson && $this->params->get('user') > 0) { $user = $this->getUserFactory()->loadUserById($this->params->get('user')); $name = $user ? $user->name : ''; } if ($name) { $siteSchema['name'] = $name; } $siteSchema['url'] = $domain; // Image $image = $this->params->get('image') ? HTMLHelper::_('cleanimageUrl', $this->params->get('image')) : false; if ($image !== false) { $siteSchema['logo'] = [ '@type' => 'ImageObject', '@id' => $domain . '#/schema/ImageObject/logo', 'url' => $image->url, 'contentUrl' => $image->url, 'width' => $image->attributes['width'] ?? 0, 'height' => $image->attributes['height'] ?? 0, ]; $siteSchema['image'] = ['@id' => $siteSchema['logo']['@id']]; } // Social media accounts $socialMedia = (array) $this->params->get('socialmedia', []); if (!empty($socialMedia)) { $siteSchema['sameAs'] = []; } foreach ($socialMedia as $social) { $siteSchema['sameAs'][] = $social->url; } $baseSchema['@graph'][] = $siteSchema; // Add WebSite $webSiteId = $domain . '#/schema/WebSite/base'; $webSiteSchema = []; $webSiteSchema['@type'] = 'WebSite'; $webSiteSchema['@id'] = $webSiteId; $webSiteSchema['url'] = $domain; $webSiteSchema['name'] = $app->get('sitename'); $webSiteSchema['publisher'] = ['@id' => $baseId]; // We support Finder actions $finder = ModuleHelper::getModule('mod_finder'); if (!empty($finder->id)) { $webSiteSchema['potentialAction'] = [ '@type' => 'SearchAction', 'target' => Route::_('index.php?option=com_finder&view=search&q={search_term_string}', true, Route::TLS_IGNORE, true), 'query-input' => 'required name=search_term_string', ]; } $baseSchema['@graph'][] = $webSiteSchema; // Add WebPage $webPageId = $domain . '#/schema/WebPage/base'; $webPageSchema = []; $webPageSchema['@type'] = 'WebPage'; $webPageSchema['@id'] = $webPageId; $webPageSchema['url'] = htmlspecialchars(Uri::getInstance()->toString()); $webPageSchema['name'] = $app->getDocument()->getTitle(); $webPageSchema['description'] = $app->getDocument()->getDescription(); $webPageSchema['isPartOf'] = ['@id' => $webSiteId]; $webPageSchema['about'] = ['@id' => $baseId]; $webPageSchema['inLanguage'] = $app->getLanguage()->getTag(); // Support Breadcrumb Schema linking try { try { $breadcrumbsAsset = $wa->getRegistry()->get('script', 'inline.breadcrumbs-schemaorg'); } catch (UnknownAssetException $e) { // Fallback for older versions of the breadcrumbs module $breadcrumbsAsset = $wa->getRegistry()->get('script', 'inline.mod_breadcrumbs-schemaorg'); trigger_deprecation( 'joomla/schemaorg', '5.4', 'The inline.mod_breadcrumbs-schemaorg asset name is deprecated. Please use the generic inline.breadcrumbs-schemaorg asset name instead.' ); } $breadcrumbs = json_decode($breadcrumbsAsset->getOption('content'), true, 512, JSON_THROW_ON_ERROR); if ($breadcrumbs['@type'] !== 'BreadcrumbList') { trigger_error('The breadcrumbs schema is not of type BreadcrumbList', E_USER_WARNING); throw new UnknownAssetException(); } $webPageSchema['breadcrumb'] = ['@id' => $breadcrumbs['@id']]; } catch (UnknownAssetException $e) { // No Breadcrumbs Schema found, so we don't add it } $baseSchema['@graph'][] = $webPageSchema; if ($itemId > 0) { // Load the table data from the database $db = $this->getDatabase(); $query = $db->getQuery(true) ->select('*') ->from($db->quoteName('#__schemaorg')) ->where($db->quoteName('itemId') . ' = :itemId') ->bind(':itemId', $itemId, ParameterType::INTEGER) ->where($db->quoteName('context') . ' = :context') ->bind(':context', $context, ParameterType::STRING); $result = $db->setQuery($query)->loadObject(); if ($result) { $localSchema = new Registry($result->schema); $localSchema->set('@id', $domain . '#/schema/' . str_replace('.', '/', $context) . '/' . (int) $result->itemId); $localSchema->set('isPartOf', ['@id' => $webPageId]); $itemSchema = $localSchema->toArray(); if (!empty($itemSchema['image'])) { $url = $itemSchema['image'] ?? ''; if (!preg_match('#^(https?:)?//#i', $url)) { $itemSchema['image'] = Uri::root() . HTMLHelper::_('cleanImageUrl', $url)->url; } } $baseSchema['@graph'][] = $itemSchema; } } $schema->loadArray($baseSchema); $dispatcher = $this->getDispatcher(); $event = new BeforeCompileHeadEvent('onSchemaBeforeCompileHead', [ 'subject' => $schema, 'context' => $context . '.' . $itemId, ]); PluginHelper::importPlugin('schemaorg', null, true, $dispatcher); $dispatcher->dispatch('onSchemaBeforeCompileHead', $event); $data = $schema->get('@graph'); foreach ($data as $key => $entry) { $data[$key] = $this->cleanupSchema($entry); } $schema->set('@graph', $data); $prettyPrint = JDEBUG ? JSON_PRETTY_PRINT : 0; $schemaString = $schema->toString('JSON', ['bitmask' => JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | $prettyPrint]); if ($schemaString !== '{}') { $wa->addInlineScript($schemaString, ['name' => 'inline.schemaorg'], ['type' => 'application/ld+json']); } } /** * Clean the schema and remove empty fields * * @param array $schema * * @return array * * @since 5.0.0 */ private function cleanupSchema($schema) { $result = []; foreach ($schema as $key => $value) { if (\is_array($value)) { // Subtypes need special handling if (!empty($value['@type'])) { if ($value['@type'] === 'ImageObject') { if (!empty($value['url'])) { $value['url'] = $this->prepareImage($value['url']); } if (empty($value['url'])) { $value = []; } } elseif ($value['@type'] === 'Date') { if (!empty($value['value'])) { $value['value'] = $this->prepareDate($value['value']); } if (empty($value['value'])) { $value = []; } } // Go into the array $value = $this->cleanupSchema($value); // We don't save when the array contains only the @type if (empty($value) || \count($value) <= 1) { $value = null; } } elseif ($key == 'genericField') { foreach ($value as $field) { $result[$field['genericTitle']] = $field['genericValue']; } continue; } } // No data, no play if (empty($value)) { continue; } $result[$key] = $value; } return $result; } /** * Check if the current plugin should execute schemaorg related activities * * @param string $context * * @return boolean * * @since 5.0.0 */ protected function isSupported($context) { // We need at least the extension + view for loading the table fields if (!str_contains($context, '.')) { return false; } $parts = explode('.', $context, 2); $component = $this->getApplication()->bootComponent($parts[0]); if ($component instanceof SchemaorgServiceInterface) { return \in_array($context, array_keys($component->getSchemaorgContexts())); } return false; } /** * The delete event. * * @param Object $event The event * * @return void * * @since 5.1.3 */ public function onContentAfterDelete(Model\AfterDeleteEvent $event) { $context = $event->getContext(); $itemId = $event->getItem()->id ?? 0; if (!$itemId || !$this->isSupported($context)) { return; } $this->deleteSchemaOrg($itemId, $context); } /** * Delete SchemaOrg record from Database. * * @param Integer $itemId * @param String $context * * @return void * * @since 5.1.3 */ public function deleteSchemaOrg($itemId, $context) { $db = $this->getDatabase(); $query = $db->getQuery(true); $query->delete($db->quoteName('#__schemaorg')) ->where($db->quoteName('itemId') . '= :itemId') ->where($db->quoteName('context') . '= :context') ->bind(':itemId', $itemId, ParameterType::INTEGER) ->bind(':context', $context, ParameterType::STRING); $db->setQuery($query)->execute(); } } PK �&�\P��N�<