This commit is contained in:
2024-12-31 11:07:09 +01:00
parent df7915205d
commit e089172b15
1916 changed files with 165422 additions and 271 deletions

View File

@ -0,0 +1,87 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link http://www.tassos.gr
* @copyright Copyright © 2019 Tassos Marinos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use Joomla\CMS\Uri\Uri;
use \NRFramework\Conditions\ConditionBuilder;
/**
* Advanced Custom Fields Helper
*/
class ACFHelper
{
/**
* Check field publishing assignments.
*
* @param object $field The field object
*
* @return mixed Null when the field does not have rules, boolean when the field runs checks
*/
public static function checkConditions($field)
{
$rules = $field->params->get('rules', []);
if (empty($rules))
{
return;
}
// Convert object to array recursively
$rules = json_decode(json_encode($rules), true);
return ConditionBuilder::pass($rules);
}
public static function getFileSources($sources, $allowedExtensions = null)
{
if (!$sources)
{
return;
}
// Support comma separated values
$sources = is_array($sources) ? $sources : explode(',', $sources);
$result = array();
foreach ($sources as $source)
{
if (!$pathinfo = pathinfo($source))
{
continue;
}
if (!isset($pathinfo['extension']))
{
continue;
}
if ($allowedExtensions && !in_array($pathinfo['extension'], $allowedExtensions))
{
continue;
}
// Add root path to local source
if (strpos($source, 'http') === false)
{
$source = Uri::root() . ltrim($source, '/');
}
$result[] = array(
'ext' => $pathinfo['extension'],
'file' => $source
);
}
return $result;
}
}

View File

@ -0,0 +1,412 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link http://www.tassos.gr
* @copyright Copyright © 2021 Tassos Marinos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die('Restricted access');
use NRFramework\Extension;
use Joomla\Registry\Registry;
use Joomla\Filesystem\Path;
use Joomla\CMS\Factory;
class ACFMigrator
{
/**
* Application object.
*
* @var object
*/
private $app;
/**
* Database object.
*
* @var object
*/
private $db;
/**
* Database object.
*
* @var object
*/
private $dbDestination;
/**
* The currently installed version.
*
* @var string
*/
private $installedVersion;
/**
* Class constructor
*
* @param string $installedVersion The current extension version
*/
public function __construct($installedVersion, $dbSource = null, $dbDestination = null)
{
$this->app = Factory::getApplication();
$this->db = $dbSource ? $dbSource : Factory::getDbo();
$this->dbDestination = $dbDestination ? $dbDestination : Factory::getDbo();
$this->installedVersion = $installedVersion;
}
public function do()
{
if (version_compare($this->installedVersion, '1.3.0', '<='))
{
$this->uploadFieldConvertBasenameToRelativePaths();
}
if (version_compare($this->installedVersion, '2.1', '<='))
{
$this->migratePublishingRulesToConditionBuilder();
}
if (version_compare($this->installedVersion, '2.7.2', '<='))
{
$this->updateMapMaximumMarkers();
}
if (version_compare($this->installedVersion, '2.7.3', '<='))
{
$this->updateAddressDefaultMarkerImage();
$this->updateMapValue();
}
}
/**
* ACF Address used the default marker image from the ACF OSM custom field.
*
* Old path: media/plg_fields_acfosm/img/marker.png
*
* However, since the ACF OSM map is now removed from the build, we must update it
* to point to the same file but from the ACF Address custom field.
*
* New value: media/plg_fields_acfaddress/img/marker.png
*/
public function updateAddressDefaultMarkerImage()
{
// Get all custom fields.
$db = $this->db;
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__fields'))
->where($db->quoteName('type') . ' = ' . $db->q('acfaddress'));
$db->setQuery($query);
if (!$fields = $db->loadObjectList())
{
return;
}
foreach ($fields as $key => $field)
{
if (!isset($field->fieldparams))
{
continue;
}
$params = json_decode($field->fieldparams);
$markerImage = $params->marker_image;
if ($markerImage !== 'media/plg_fields_acfosm/img/marker.png')
{
continue;
}
$params->marker_image = 'media/plg_fields_acfaddress/img/marker.png';
// Update field `param` with new value
$dbDestination = $this->dbDestination;
$query = $dbDestination->getQuery(true)
->update($dbDestination->quoteName('#__fields'))
->set($dbDestination->quoteName('fieldparams') . '=' . $dbDestination->quote(json_encode($params)))
->where($dbDestination->quoteName('id') . '=' . $dbDestination->quote($field->id));
$dbDestination->setQuery($query);
$dbDestination->execute();
}
}
public function updateMapValue()
{
// Get all custom fields.
$db = $this->db;
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__fields'))
->where($db->quoteName('type') . ' = ' . $db->q('acfmap'));
$db->setQuery($query);
if (!$fields = $db->loadObjectList())
{
return;
}
$count = 0;
foreach ($fields as $key => $field)
{
// Find now all field values
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__fields_values'))
->where($db->quoteName('field_id') . ' = ' . $field->id);
$db->setQuery($query);
if (!$values = $db->loadObjectList())
{
return;
}
foreach ($values as $value)
{
if (!$decoded_value = json_decode($value->value, true))
{
continue;
}
if (!isset($decoded_value['markers']))
{
continue;
}
$newValue = $decoded_value['markers'];
$query = $db->getQuery(true);
$fields = [
$db->quoteName('value') . ' = ' . $db->q($newValue)
];
$conditions = [
$db->quoteName('field_id') . ' = ' . $value->field_id,
$db->quoteName('item_id') . ' = ' . $db->quote($value->item_id),
$db->quoteName('value') . ' = ' . $db->quote($value->value)
];
$query->update($db->quoteName('#__fields_values'))->set($fields)->where($conditions);
$db->setQuery($query);
$db->execute();
$count++;
}
}
return $count;
}
public function updateMapMaximumMarkers()
{
// Get all custom fields.
$db = $this->db;
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__fields'))
->where($db->quoteName('type') . ' = ' . $db->q('acfmap'));
$db->setQuery($query);
if (!$fields = $db->loadObjectList())
{
return;
}
foreach ($fields as $key => $field)
{
if (!isset($field->fieldparams))
{
continue;
}
$params = json_decode($field->fieldparams);
if (isset($params->maximum_markers))
{
continue;
}
$params->maximum_markers = 0;
// Update field `param` with new value
$dbDestination = $this->dbDestination;
$query = $dbDestination->getQuery(true)
->update($dbDestination->quoteName('#__fields'))
->set($dbDestination->quoteName('fieldparams') . '=' . $dbDestination->quote(json_encode($params)))
->where($dbDestination->quoteName('id') . '=' . $dbDestination->quote($field->id));
$dbDestination->setQuery($query);
$dbDestination->execute();
}
}
public function migratePublishingRulesToConditionBuilder()
{
// Get all custom fields.
$db = $this->db;
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__fields'));
$db->setQuery($query);
if (!$fields = $db->loadObjectList())
{
return;
}
foreach ($fields as $key => $field)
{
if (!isset($field->params))
{
continue;
}
$params = new Registry($field->params);
\NRFramework\Conditions\Migrator::run($params);
if (!isset($params['rules']) || empty($params['rules']))
{
continue;
}
// Update field `param` with new value
$dbDestination = $this->dbDestination;
$query = $dbDestination->getQuery(true)
->update($dbDestination->quoteName('#__fields'))
->set($dbDestination->quoteName('params') . '=' . $dbDestination->quote(json_encode($params)))
->where($dbDestination->quoteName('id') . '=' . $dbDestination->quote($field->id));
$dbDestination->setQuery($query);
$dbDestination->execute();
}
}
/**
* Since v1.3.0, the File Upload field is no longer storing just the file's name in the database but the full relative path to Joomla's root.
*
* This migration tasks, loops through all file values in the database and prepends to them the Upload Folder as configured in the Field settings.
*
* Previous value: myAwesomePhoto.jpg
* New value: media/myimages/myAwesomePhoto.jpg
*
* @return mixed Null when the migrationt ask doesn't run, Integer when the migration run.
*/
public function uploadFieldConvertBasenameToRelativePaths()
{
// Get all upload fields.
$db = $this->db;
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__fields'))
->where($db->quoteName('type') . ' = ' . $db->q('acfupload'));
$db->setQuery($query);
if (!$fields = $db->loadObjectList())
{
return;
}
$count = 0;
foreach ($fields as $key => $field)
{
if (!isset($field->fieldparams))
{
continue;
}
$params = json_decode($field->fieldparams);
if (!isset($params->upload_folder))
{
continue;
}
$upload_folder = $params->upload_folder;
// Find now all field values
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__fields_values'))
->where($db->quoteName('field_id') . ' = ' . $field->id);
$db->setQuery($query);
if (!$values = $db->loadObjectList())
{
return;
}
foreach ($values as $value)
{
if (!isset($value->value) || empty($value->value))
{
continue;
}
// If the path has a slash, consider it as already fixed.
if (strpos($value->value, DIRECTORY_SEPARATOR) !== false)
{
continue;
}
$newValue = trim(Path::clean($upload_folder . '/' . $value->value));
$query = $db->getQuery(true);
$fields = [
$db->quoteName('value') . ' = ' . $db->q($newValue)
];
$conditions = [
$db->quoteName('field_id') . ' = ' . $value->field_id,
$db->quoteName('item_id') . ' = ' . $db->quote($value->item_id),
$db->quoteName('value') . ' = ' . $db->quote($value->value)
];
$query->update($db->quoteName('#__fields_values'))->set($fields)->where($conditions);
$db->setQuery($query);
$db->execute();
$count++;
}
}
return $count;
}
}

View File

@ -0,0 +1,239 @@
<?php
/**
* @package Advanced Custom Fields
* @version 2.8.8 Pro
*
* @author Tassos Marinos <info@tassos.gr>
* @link http://www.tassos.gr
* @copyright Copyright © 2019 Tassos Marinos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
defined('_JEXEC') or die;
if (!@include_once(JPATH_PLUGINS . '/system/nrframework/autoload.php'))
{
throw new RuntimeException('Novarain Framework is not installed', 500);
}
use \NRFramework\HTML;
use \ACF\Helpers\Field;
use Joomla\CMS\Form\Form;
use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
JLoader::register('ACFHelper', __DIR__ . '/helper.php');
class ACF_Field extends FieldsPlugin
{
/**
* Override the field type
*
* @var string
*/
protected $overrideType;
/**
* Whether the field is required
*
* @var bool
*/
protected $required = false;
/**
* The validation rule will be used to validate the field on saving
*
* @var string
*/
protected $validate;
/**
* Field's Hint Description
*
* @var string
*/
protected $hint;
/**
* Field's Class
*
* @var string
*/
protected $class;
/**
* 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)
{
if (!$field->rawvalue)
{
return parent::onCustomFieldsPrepareField($context, $item, $field);
}
// Add Custom CSS
$custom_css = $field->params->get('acf_custom_css');
if (!empty($custom_css))
{
Factory::getDocument()->addStyleDeclaration($custom_css);
}
return parent::onCustomFieldsPrepareField($context, $item, $field);
}
/**
* 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 (!$fieldNode = parent::onCustomFieldsPrepareDom($field, $parent, $form))
{
return;
}
// Load framework's fields
$form->addFieldPath(JPATH_PLUGINS . '/system/nrframework/fields');
$form->addFieldPath(JPATH_PLUGINS . '/fields/' . $field->type . '/fields');
// Set Field Class
if ($this->class)
{
$fieldNode->setAttribute('class', $this->class);
}
// Set field placeholder
if ($hint = $field->params->get('hint', $this->hint))
{
$fieldNode->setAttribute('hint', $hint);
}
// Set Field Type
if ($this->overrideType)
{
$fieldNode->setAttribute('type', $this->overrideType);
}
// Set Field Required
if ($this->required)
{
$fieldNode->setAttribute('required', $this->required);
}
// Set validation rule
if ($this->validate)
{
$form->addRulePath(JPATH_PLUGINS . '/system/nrframework/NRFramework/Rules');
$form->addRulePath(JPATH_PLUGINS . '/system/acf/form/rules');
$fieldNode->setAttribute('validate', $this->validate);
}
// Set Field Description
$desc_def = Text::_(str_replace('ACF', 'ACF_', strtoupper($field->type)) . '_VALUE_DESC');
$desc_user = $fieldNode->getAttribute('description');
$desc = !empty($desc_user) ? $desc_user : $desc_def;
$fieldNode->setAttribute('description', $desc);
// Gather all Joomla 3 CSS fixes in a file and load it.
if (!defined('nrJ4'))
{
HTMLHelper::stylesheet('plg_system_nrframework/joomla3.css', ['relative' => true, 'version' => 'auto']);
HTMLHelper::stylesheet('plg_system_acf/joomla3.css', ['relative' => true, 'version' => 'auto']);
}
else
{
HTMLHelper::stylesheet('plg_system_nrframework/joomla4.css', ['relative' => true, 'version' => 'auto']);
}
return $fieldNode;
}
/**
* The form event. Load additional parameters when available into the field form.
* Only when the type of the form is of interest.
*
* @param Form $form The form
* @param stdClass $data The data
*
* @return void
*
* @since 3.7.0
*/
public function onContentPrepareForm(Form $form, $data)
{
$data = (object) $data;
// Make sure we are manipulating the right field.
if (!isset($data->type) || (isset($data->type) && ($data->type != $this->_name)))
{
return;
}
if (isset($data->type))
{
// Remove "layout" from ACF - Options if the current custom field is not widget-based
$widget = Field::isWidgetBased($data->type, $data);
if (Factory::getApplication()->isClient('administrator') && !$widget)
{
$form->removeField('acf_layout_override', 'params');
}
}
// Load framework's fields
$form->addFieldPath(JPATH_PLUGINS . '/system/nrframework/fields');
// Load ACF fields
$form->addFieldPath(JPATH_PLUGINS . '/system/acf/form/fields');
if (Factory::getApplication()->isClient('administrator'))
{
// Set the wiget in the "acf_layout_override" field in order to retrieve all layout overrides created by the user for this field.
if (isset($widget))
{
$form->setFieldAttribute('acf_layout_override', 'widget_name', $widget, 'params');
if (isset($data->type))
{
$form->setFieldAttribute('acf_layout_override', 'field_type', $data->type, 'params');
}
}
// load ACF backend style
HTMLHelper::stylesheet('plg_system_acf/acf-backend.css', ['relative' => true, 'version' => 'auto']);
if (defined('nrJ4'))
{
HTMLHelper::stylesheet('plg_system_nrframework/joomla4.css', ['relative' => true, 'version' => 'auto']);
HTML::fixFieldTooltips();
}
// Display extension notices
\NRFramework\Notices\Notices::getInstance([
'ext_element' => 'acf',
'ext_type' => 'plugin',
'ext_xml' => 'plg_system_acf',
'exclude' => [
'Geolocation'
]
])->show();
}
return parent::onContentPrepareForm($form, $data);
}
}