461 lines
11 KiB
PHP
461 lines
11 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @package Advanced Custom Fields
|
|
* @version 2.8.8 Pro
|
|
*
|
|
* @author Tassos Marinos <info@tassos.gr>
|
|
* @link http://www.tassos.gr
|
|
* @copyright Copyright © 2023 Tassos Marinos All Rights Reserved
|
|
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
|
*/
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
use NRFramework\Conditions\Conditions\Component\ContentBase;
|
|
use Joomla\CMS\Language\Text;
|
|
use Joomla\Registry\Registry;
|
|
use Joomla\CMS\Factory;
|
|
use NRFramework\Cache;
|
|
|
|
JLoader::register('ACF_Field', JPATH_PLUGINS . '/system/acf/helper/plugin.php');
|
|
|
|
if (!class_exists('ACF_Field'))
|
|
{
|
|
Factory::getApplication()->enqueueMessage('Advanced Custom Fields System Plugin is missing', 'error');
|
|
return;
|
|
}
|
|
|
|
class PlgFieldsACFArticles extends ACF_Field
|
|
{
|
|
/**
|
|
* Update the label of the field in filters.
|
|
*
|
|
* @param \Bluecoder\Component\Jfilters\Administrator\Model\Filter\Option\Collection $options
|
|
*
|
|
* @return \Bluecoder\Component\Jfilters\Administrator\Model\Filter\Option\Collection
|
|
*/
|
|
public function onJFiltersOptionsAfterCreation(\Bluecoder\Component\Jfilters\Administrator\Model\Filter\Option\Collection $options)
|
|
{
|
|
// Make sure it is a field of that type
|
|
if ($options->getFilterItem()->getAttributes()->get('type') !== $this->_name)
|
|
{
|
|
return $options;
|
|
}
|
|
|
|
$contentAssignment = new ContentBase();
|
|
|
|
foreach ($options as $option)
|
|
{
|
|
if (!$article = $contentAssignment->getItem($option->getLabel()))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
$option->setLabel($article->title);
|
|
}
|
|
|
|
return $options;
|
|
}
|
|
|
|
|
|
public function onContentBeforeSave($context, $item, $isNew, $data = [])
|
|
{
|
|
if (!is_array($data))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (!isset($data['com_fields']))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Create correct context for category
|
|
if ($context == 'com_categories.category')
|
|
{
|
|
$context = $item->get('extension') . '.categories';
|
|
}
|
|
|
|
// Load Fields Component Helper class
|
|
JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR . '/components/com_fields/helpers/fields.php');
|
|
|
|
// Check the context
|
|
$parts = FieldsHelper::extract($context, $item);
|
|
|
|
if (!$parts)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Compile the right context for the fields
|
|
$context = $parts[0] . '.' . $parts[1];
|
|
|
|
// Loading the fields
|
|
$fields = FieldsHelper::getFields($context, $item);
|
|
|
|
if (!$fields)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
// Get the fields data
|
|
$fieldsData = !empty($data['com_fields']) ? $data['com_fields'] : [];
|
|
|
|
// Whether we should clean up the temp folder at the end of this process
|
|
$should_clean = false;
|
|
|
|
// Get the Fields Model
|
|
if (!defined('nrJ4'))
|
|
{
|
|
$model = JModelLegacy::getInstance('Field', 'FieldsModel', ['ignore_request' => true]);
|
|
}
|
|
else
|
|
{
|
|
$model = Factory::getApplication()->bootComponent('com_fields')->getMVCFactory()->createModel('Field', 'Administrator', ['ignore_request' => true]);
|
|
}
|
|
|
|
// Cache subform fields
|
|
$subform_fields = [];
|
|
|
|
$error = false;
|
|
|
|
// Loop over the fields
|
|
foreach ($fields as $field)
|
|
{
|
|
$field_type = $field->type;
|
|
|
|
/**
|
|
* Check whether a Gallery field is used within the Subform field.
|
|
*/
|
|
if ($field_type === 'subform')
|
|
{
|
|
// Ensure it has a value
|
|
if (!$subform_value = json_decode($field->value, true))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach ($subform_value as $key => $value)
|
|
{
|
|
if (!is_array($value))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach ($value as $_key => $_value)
|
|
{
|
|
// Get Field ID
|
|
$field_id = str_replace('field', '', $_key);
|
|
|
|
// Get Field by ID
|
|
$subform_field = isset($subform_fields[$field_id]) ? $subform_fields[$field_id] : $model->getItem($field_id);
|
|
|
|
// Only proceed for this field type
|
|
if ($subform_field->type !== $this->_name)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Cache field
|
|
if (!isset($subform_fields[$field_id]))
|
|
{
|
|
$subform_fields[$field_id] = $subform_field;
|
|
}
|
|
|
|
$check_value = isset($fieldsData[$field->name][$key][$_key]) ? $fieldsData[$field->name][$key][$_key] : false;
|
|
|
|
if (!$check_value)
|
|
{
|
|
break;
|
|
}
|
|
|
|
$fieldParams = new Registry($subform_field->fieldparams);
|
|
|
|
$check_value = is_array($check_value) ? $check_value : [$check_value];
|
|
|
|
if ($min_articles = (int) $fieldParams->get('min_articles', 0))
|
|
{
|
|
if (count($check_value) < $min_articles)
|
|
{
|
|
Factory::getApplication()->enqueueMessage(sprintf(Text::_('ACF_ARTICLES_MIN_ITEMS_REQUIRED'), $subform_field->title, $min_articles), 'error');
|
|
$error = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($max_articles = (int) $fieldParams->get('max_articles', 0))
|
|
{
|
|
if (count($check_value) > $max_articles)
|
|
{
|
|
Factory::getApplication()->enqueueMessage(sprintf(Text::_('ACF_ARTICLES_MAX_ITEMS_REQUIRED'), $subform_field->title, $max_articles), 'error');
|
|
$error = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Only proceed for this field type
|
|
if ($field_type !== $this->_name)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Determine the value if it is available from the data
|
|
$value = array_key_exists($field->name, $fieldsData) ? $fieldsData[$field->name] : null;
|
|
|
|
if (!$value)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
$value = is_array($value) ? $value : [$value];
|
|
|
|
if ($min_articles = (int) $field->fieldparams->get('min_articles', 0))
|
|
{
|
|
if (count($value) < $min_articles)
|
|
{
|
|
Factory::getApplication()->enqueueMessage(sprintf(Text::_('ACF_ARTICLES_MIN_ITEMS_REQUIRED'), $field->title, $min_articles), 'error');
|
|
$error = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ($max_articles = (int) $field->fieldparams->get('max_articles', 0))
|
|
{
|
|
if (count($value) > $max_articles)
|
|
{
|
|
Factory::getApplication()->enqueueMessage(sprintf(Text::_('ACF_ARTICLES_MAX_ITEMS_REQUIRED'), $field->title, $max_articles), 'error');
|
|
$error = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return !$error;
|
|
}
|
|
|
|
|
|
/**
|
|
* 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, Joomla\CMS\Form\Form $form)
|
|
{
|
|
if (!$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form))
|
|
{
|
|
return $fieldNode;
|
|
}
|
|
|
|
$field_type = $field->fieldparams->get('articles_type', 'default');
|
|
|
|
$fieldNode->setAttribute('multiple', true);
|
|
|
|
|
|
$max_articles = (int) $field->fieldparams->get('max_articles', 0);
|
|
if ($max_articles === 1)
|
|
{
|
|
$fieldNode->setAttribute('multiple', false);
|
|
}
|
|
|
|
// Linked
|
|
if ($field_type === 'linked')
|
|
{
|
|
$fieldNode->setAttribute('multiple', false);
|
|
$fieldNode->setAttribute('type', 'NRToggle');
|
|
// Default state
|
|
$fieldNode->setAttribute('default', 'false');
|
|
|
|
// Checked if Default Value = 1/true
|
|
if (isset($field->value) && in_array($field->value, ['1', 'true']))
|
|
{
|
|
$fieldNode->setAttribute('checked', 'true');
|
|
}
|
|
}
|
|
|
|
|
|
return $fieldNode;
|
|
}
|
|
|
|
/**
|
|
* Prepares the field value for the (front-end) layout
|
|
*
|
|
* @param string $context The context.
|
|
* @param stdclass $item The item.
|
|
* @param stdclass $field The field.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function onCustomFieldsPrepareField($context, $item, $field)
|
|
{
|
|
// Check if the field should be processed by us
|
|
if (!$this->isTypeSupported($field->type))
|
|
{
|
|
return parent::onCustomFieldsPrepareField($context, $item, $field);
|
|
}
|
|
|
|
$value = array_filter((array) $field->value);
|
|
|
|
|
|
$type = $field->fieldparams->get('articles_type', 'default');
|
|
|
|
// Linked articles
|
|
if ($type === 'linked')
|
|
{
|
|
// Abort if no ACF Articles fields are selected
|
|
if (!$acf_articles = array_filter($field->fieldparams->get('articles_fields', [])))
|
|
{
|
|
$field->value = [];
|
|
return parent::onCustomFieldsPrepareField($context, $item, $field);
|
|
}
|
|
|
|
// Proceed only if Field Value = 1/true
|
|
if (!in_array($field->value, ['1', 'true']))
|
|
{
|
|
$field->value = [];
|
|
return parent::onCustomFieldsPrepareField($context, $item, $field);
|
|
}
|
|
|
|
$cache_key = 'ACFArticles_' . $item->id . '_' . md5(implode(',', $acf_articles));
|
|
|
|
if (Cache::has($cache_key))
|
|
{
|
|
$field->value = Cache::get($cache_key);
|
|
}
|
|
else
|
|
{
|
|
// Grab all linked articles
|
|
$db = Factory::getDbo();
|
|
$query = $db->getQuery(true);
|
|
$query->select('a.*')
|
|
->from($db->quoteName('#__fields_values', 'fv'))
|
|
->join('LEFT', $db->quoteName('#__content', 'a') . ' ON a.id = fv.item_id')
|
|
->where($db->quoteName('fv.field_id') . ' IN (' . implode(',', $acf_articles) . ')')
|
|
->where($db->quoteName('fv.value') . ' = ' . $db->q($item->id));
|
|
|
|
$this->prepareArticles($context, $query, $field, $value, true);
|
|
|
|
Cache::set($cache_key, $field->value);
|
|
}
|
|
|
|
return parent::onCustomFieldsPrepareField($context, $item, $field);
|
|
}
|
|
|
|
|
|
if (!$value)
|
|
{
|
|
return parent::onCustomFieldsPrepareField($context, $item, $field);
|
|
}
|
|
|
|
$cache_key = 'ACFArticles_Auto_' . $item->id . '_' . md5(implode(',', $value));
|
|
|
|
if (Cache::has($cache_key))
|
|
{
|
|
$field->value = Cache::get($cache_key);
|
|
}
|
|
else
|
|
{
|
|
// Default articles
|
|
$db = Factory::getDbo();
|
|
$query = $db->getQuery(true);
|
|
$query->select('a.*')
|
|
->from($db->quoteName('#__content', 'a'))
|
|
->where($db->quoteName('a.id') . ' IN (' . implode(',', array_map('intval', $value)) . ')');
|
|
|
|
$this->prepareArticles($context, $query, $field, $value);
|
|
|
|
Cache::set($cache_key, $field->value);
|
|
}
|
|
|
|
return parent::onCustomFieldsPrepareField($context, $item, $field);
|
|
}
|
|
|
|
/**
|
|
* Prepares the articles.
|
|
*
|
|
* @param string $context
|
|
* @param object $query
|
|
* @param object $field
|
|
* @param array $articles
|
|
* @param bool $all_filters
|
|
*
|
|
* @return void
|
|
*/
|
|
private function prepareArticles($context, $query, &$field, $articles, $all_filters = true)
|
|
{
|
|
$db = Factory::getDbo();
|
|
|
|
// Filter results
|
|
require_once 'fields/acfarticlesfilters.php';
|
|
$payload = $all_filters ? $field->fieldparams : ['order' => $field->fieldparams->get('order')];
|
|
$filters = new ACFArticlesFilters($query, $payload);
|
|
$query = $filters->apply();
|
|
|
|
// Set query
|
|
$db->setQuery($query);
|
|
|
|
// Get articles
|
|
if (!$articles = $db->loadAssocList())
|
|
{
|
|
$field->value = [];
|
|
return;
|
|
}
|
|
|
|
|
|
// Get and set the articles values
|
|
foreach ($articles as &$article)
|
|
{
|
|
$article['custom_fields'] = $this->fetchCustomFields($article);
|
|
}
|
|
|
|
|
|
$field->value = $articles;
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns an article's custom fields.
|
|
*
|
|
* @return array
|
|
*/
|
|
private function fetchCustomFields($article = null)
|
|
{
|
|
if (!$article)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
$callback = function() use ($article)
|
|
{
|
|
\JLoader::register('FieldsHelper', JPATH_ADMINISTRATOR . '/components/com_fields/helpers/fields.php');
|
|
|
|
if (!$fields = \FieldsHelper::getFields('com_content.article', $article, false))
|
|
{
|
|
return [];
|
|
}
|
|
|
|
$fieldsAssoc = [];
|
|
|
|
foreach ($fields as $field)
|
|
{
|
|
$fieldsAssoc[$field->name] = $field->value;
|
|
}
|
|
|
|
return $fieldsAssoc;
|
|
};
|
|
|
|
return Cache::memo('ACFArticlesFetchCustomFields' . $article['id'], $callback);
|
|
}
|
|
|
|
} |