* @link http://www.tassos.gr * @copyright Copyright © 2019 Tassos Marinos All Rights Reserved * @license GNU GPLv3 or later */ defined('_JEXEC') or die('Restricted access'); // Initialize ACF Namespace require_once __DIR__ . '/autoload.php'; use NRFramework\HTML; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Plugin\CMSPlugin; use Joomla\CMS\Uri\Uri; use Joomla\CMS\Session\Session; use Joomla\CMS\Language\Text; use Joomla\Registry\Registry; use Joomla\CMS\HTML\HTMLHelper; use NRFramework\Helpers\Widgets\GalleryManager as GalleryManagerHelper; /** * Advanced Custom Fields System Plugin */ class PlgSystemACF extends CMSPlugin { /** * Auto load plugin's language file * * @var boolean */ protected $autoloadLanguage = true; /** * Application Object * * @var object */ protected $app; /** * The loaded indicator of helper * * @var boolean */ private $init; /** * The field preview data. * * This is an array that holds * both the HTML of the field as well * as the assets that it requires. * * @var array */ private $field_preview_data = []; public function onAfterInitialise() { // YooTheme Pro Integration \ACF\Helpers\Yoo::initFieldParser(); } /** * After a tag has been deleted, then delete it from * all ACF - Gallery instances. * * @param string $context * @param object $item * * @return void */ public function onContentAfterDelete($context, $item) { // Delete all Joomla article assets if ($context === 'com_content.article') { \ACF\Helpers\Fields\Gallery::deleteFilesFromItem($item->id); \ACF\Helpers\Fields\Upload::deleteFilesFromItem($item->id); } // Delete all tag assets if ($context === 'com_tags.tag') { GalleryManagerHelper::deleteTagFromFieldsValues($item->id); } } /** * onCustomFieldsBeforePrepareField Event */ public function onCustomFieldsBeforePrepareField($context, $item, &$field) { // Validate supported component/views if (!in_array($context, [ 'com_content.article', 'com_dpcalendar.event' ])) { return; } // Get Helper if (!$this->getHelper()) { return; } // Only if assignments option is enabled in the plugin settings if (!$this->params->get('assignments', true)) { return; } if (ACFHelper::checkConditions($field) === false) { // According to the components/com_fields/layouts/fields/render.php file, if the field's value is empty it won't show up in the front-end. $field->value = ''; // Unset rawvalue too, as it may be used in template overrides. $field->rawvalue = ''; } } /** * Append publishing assignments XML to the * * @param Form $form The form to be altered. * @param mixed $data The associated data for the form. * * @return boolean */ public function onContentPrepareForm(Form $form, $data) { // Run Display Conditions checks for the User Profile page. // NOTE: The System Fields plugin must be placed before this plugin in order for the $form to include the custom fields information. if ($this->params->get('assignments', true) && $form->getName() == 'com_users.profile' && $this->app->isClient('site') && $form instanceof Form) { JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR . '/components/com_fields/helpers/fields.php'); if ($fields = FieldsHelper::getFields('com_users.user', Factory::getUser(), true)) { foreach ($fields as $field) { if (ACFHelper::checkConditions($field) === false) { $form->removeField($field->name, 'com_fields'); } } } } // Run only on backend if (!$this->app->isClient('administrator') || !$form instanceof Form) { return; } $context = $form->getName(); $this->loadPreviewer($context); if (!in_array($context, [ 'com_fields.field.com_users.user', 'com_fields.field.com_content.article', 'com_fields.field.com_contact.contact', 'com_fields.field.com_dpcalendar.event' ])) { return; } // Load Publishing Rules tab if assignments option is enabled in the plugin settings if ($this->params->get('assignments', true)) { $form->loadFile(__DIR__ . '/form/conditions.xml', false); if ($context == 'com_fields.field.com_users.user') { // If plg_system_fields is not positioned before plg_system_acf, display a warning. $db = Factory::getDbo(); $query = $db->getQuery(true) ->select('name, ordering') ->from($db->quoteName('#__extensions')) ->where($db->quoteName('name') . ' = ' . $db->q('plg_system_acf')) ->orWhere($db->quoteName('name') . ' = ' . $db->q('plg_system_fields')) ->order($db->quoteName('ordering')); $db->setQuery($query); $plugins = $db->loadObjectList(); if (count($plugins) == 2 && $plugins[0]->name !== 'plg_system_fields') { $form->setField(new SimpleXMLElement('
')); } } } // Load "ACF Options" tab if the option is enabled in the plugin settings if ($this->params->get('acf_options', true)) { $form->loadFile(__DIR__ . '/form/options.xml', false); } // Always load our stylesheet even if it's a non-ACF field. The Publishing Rules tab shows up on all fields. HTMLHelper::stylesheet('plg_system_acf/acf-backend.css', ['relative' => true, 'version' => 'auto']); if (defined('nrJ4')) { HTMLHelper::stylesheet('plg_system_acf/joomla4.css', ['relative' => true, 'version' => 'auto']); HTMLHelper::stylesheet('plg_system_nrframework/joomla4.css', ['relative' => true, 'version' => 'auto']); HTML::fixFieldTooltips(); } else { HTMLHelper::stylesheet('plg_system_acf/joomla3.css', ['relative' => true, 'version' => 'auto']); } return true; } /** * Load previewer assets. * * @param string $context * * @return void */ private function loadPreviewer($context) { $allowed_context = [ 'com_fields.field.com_content.article', 'com_fields.field.com_content.categories', 'com_fields.field.com_contact.contact', 'com_fields.field.com_contact.mail', 'com_fields.field.com_contact.categories' ]; if (!in_array($context, $allowed_context)) { return; } // Data passed as JS object $doc = Factory::getDocument(); $options = $doc->getScriptOptions('acf_js_object'); $options = is_array($options) ? $options : []; $options = [ 'root_url' => Uri::base() ]; $doc->addScriptOptions('acf_js_object', $options); // Framework helper to load assets HTMLHelper::script('plg_system_nrframework/helper.js', ['relative' => true, 'version' => 'auto']); // Load Field Previewer HTMLHelper::script('plg_system_acf/field_previewer.js', ['relative' => true, 'version' => 'auto']); } /** * Listens to AJAX requests on ?option=com_ajax&format=raw&plugin=acf * * @return void */ public function onAjaxAcf() { Session::checkToken('request') or jexit(Text::_('JINVALID_TOKEN')); // Only in backend if (!$this->app->isClient('administrator')) { return; } // Check if we have a valid task $task = $this->app->input->get('task', null); // Check if we have a valid method task $taskMethod = 'ajaxTask' . $task; if (!method_exists($this, $taskMethod)) { die('Task not found'); } $this->$taskMethod(); } /** * Fields Previewer. * * @return string */ private function ajaxTaskFieldsPreviewer() { $field = $this->app->input->get('field', null); if (!$field) { echo json_encode([ 'error' => true, 'message' => 'Missing field name.' ]); die(); } if (!$data = json_decode(file_get_contents('php://input'))) { echo json_encode([ 'error' => true, 'message' => 'Missing field data to generate preview.' ]); die(); } // Prepare data $registry = new Registry(); foreach ($data as $key => $value) { $key = str_replace(['jform[', ']', '['], ['', '', '.'], $key); $registry->set($key, $value); } $data = $registry->toArray(); // We require the type of the field to save the fields data to the JSON file and be able to generate the preview if (!isset($data['type'])) { echo json_encode([ 'error' => true, 'message' => 'Missing field type to generate preview.' ]); die(); } // ACF Field Previewer Class $class = '\ACF\Previewer\\' . $field; // Ensure class exists if (!class_exists($class)) { echo json_encode([ 'error' => true, 'message' => 'Cannot preview field: ' . $field ]); die(); } // Get class $class = new $class($data); // Setup previewer $class->setup(); echo json_encode([ 'error' => false ]); } /** * Fields Previewer HTML. * * @return string */ private function ajaxTaskFieldsPreviewerHTML() { $field = $this->app->input->get('field', null); if (!$field) { echo json_encode([ 'error' => true, 'message' => 'Missing field name.' ]); die(); } if (!$html = \ACF\Helpers\Previewer::getFieldPreviewData($field)) { return; } echo $html; } /** * Loads the helper classes of plugin * * @return bool */ private function getHelper() { // Return if is helper is already loaded if ($this->init) { return true; } // Return if we are not in frontend if (!$this->app->isClient('site')) { return false; } // Load Novarain Framework if (!@include_once(JPATH_PLUGINS . '/system/nrframework/autoload.php')) { return; } // Load Plugin Helper JLoader::register('ACFHelper', __DIR__ . '/helper/helper.php'); return ($this->init = true); } /** * Let each condition check the value before it's savced into the database * * @param string $context * @param object $article * @param bool $isNew * * @return void */ public function onContentBeforeSave($context, $article, $isNew) { if (!in_array($context, ['com_fields.field'])) { return; } if (!isset($article->params)) { return; } $params = json_decode($article->params, true); if (!isset($params['rules'])) { return; } NRFramework\Conditions\ConditionsHelper::getInstance()->onBeforeSave($params['rules']); $article->params = json_encode($params); } }