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,63 @@
<?php
/**
* @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
*/
namespace ACF\Helpers;
defined('_JEXEC') or die;
class Field
{
/**
* Returns the widget for which the ACF custom field is based upon.
*
* @param string $type
* @param object $field_options
*
* @return string
*/
public static function isWidgetBased($type = '', $field_options = [])
{
if (!$type)
{
return false;
}
$widget_name = self::getWidgetName($type);
$widget = \NRFramework\Widgets\Helper::find($widget_name);
if ($widget === 'Map' && !is_null($field_options->fieldparams))
{
return !empty($field_options->fieldparams['provider']) ? $field_options->fieldparams['provider'] : $widget;
}
return $widget;
}
/**
* Returns the widget name of an ACF custom field.
*
* @param string @type
*
* @return string
*/
public static function getWidgetName($type = '')
{
// Remove the "acf" prefix
$type = str_replace('acf', '', $type);
// Map for any ACF fields that do not automatically translate to a Widget
$map = [
'address' => 'MapAddress'
];
// Transform a field type to its corresponding widget from the map
return isset($map[$type]) ? $map[$type] : $type;
}
}

View File

@ -0,0 +1,189 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
use YOOtheme\Str;
class Address
{
/**
* Returns the YooTheme type.
*
* If this accepts one image:
* - Tells YooTheme to use the default type for the dropdown mapping option.
*
* If this accepts multiple images:
* - Tells YooTheme to only return the value of this field in the dropdown mapping option.
*
* @param object $field
* @param object $source
*
* @return array
*/
public static function getYooType($field = [], $source = [])
{
$fields = [
[
'type' => 'String',
'name' => 'latitude',
'metadata' => [
'label' => 'Latitude'
],
],
[
'type' => 'String',
'name' => 'longitude',
'metadata' => [
'label' => 'Longitude'
],
],
[
'type' => 'String',
'name' => 'value',
'metadata' => [
'label' => 'Coordinates'
],
],
[
'type' => 'String',
'name' => 'address',
'metadata' => [
'label' => 'Address'
],
],
[
'type' => 'String',
'name' => 'postal_code',
'metadata' => [
'label' => 'Postal Code'
],
],
[
'type' => 'String',
'name' => 'country_code',
'metadata' => [
'label' => 'Country Code'
],
],
[
'type' => 'String',
'name' => 'country',
'metadata' => [
'label' => 'Country'
],
],
[
'type' => 'String',
'name' => 'state',
'metadata' => [
'label' => 'State'
],
],
[
'type' => 'String',
'name' => 'municipality',
'metadata' => [
'label' => 'Municipality'
],
],
[
'type' => 'String',
'name' => 'town',
'metadata' => [
'label' => 'Town'
],
],
[
'type' => 'String',
'name' => 'city',
'metadata' => [
'label' => 'City'
],
],
[
'type' => 'String',
'name' => 'road',
'metadata' => [
'label' => 'Road'
],
]
];
$name = Str::camelCase(['Field', $field->name], true);
$source->objectType($name, compact('fields'));
return $name;
}
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? json_encode($item["field{$args['field_id']}"]) : '';
// Use the subform field
$field = $subfield;
}
$value = $field->rawvalue;
if (is_string($value))
{
if (!$value = json_decode($value, true))
{
return;
}
}
if (!is_array($value))
{
return;
}
$lat = isset($value['address']['latitude']) ? $value['address']['latitude'] : null;
$lng = isset($value['address']['longitude']) ? $value['address']['longitude'] : null;
return [
'latitude' => $lat,
'longitude' => $lng,
'value' => $lat && $lng ? implode(',', [$lat, $lng]) : null,
'address' => isset($value['address']['address']) ? $value['address']['address'] : null,
'postal_code' => isset($value['address']['postal_code']) ? $value['address']['postal_code'] : null,
'country_code' => isset($value['address']['country_code']) ? $value['address']['country_code'] : null,
'country' => isset($value['address']['country']) ? $value['address']['country'] : null,
'state' => isset($value['address']['state']) ? $value['address']['state'] : null,
'municipality' => isset($value['address']['municipality']) ? $value['address']['municipality'] : null,
'town' => isset($value['address']['town']) ? $value['address']['town'] : null,
'city' => isset($value['address']['city']) ? $value['address']['city'] : null,
'road' => isset($value['address']['road']) ? $value['address']['road'] : null
];
}
}

View File

@ -0,0 +1,172 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
use YOOtheme\Builder\Joomla\Source\ArticleHelper;
use Joomla\CMS\Factory;
class Articles
{
/**
* Returns the YooTheme type.
*
* If this accepts one image:
* - Tells YooTheme to use the default type for the dropdown mapping option.
*
* If this accepts multiple images:
* - Tells YooTheme to only return the value of this field in the dropdown mapping option.
*
* @param object $field
* @param object $source
*
* @return array
*/
public static function getYooType($field = [], $source = [])
{
if ($field->only_use_in_subform === 1)
{
return;
}
$max_articles = (int) $field->fieldparams->get('max_articles', 0);
$multiple = $max_articles === 0 || $max_articles > 1;
return $multiple ? ['listOf' => 'Article'] : 'Article';
}
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? $item["field{$args['field_id']}"] : '';
// Use the subform field
$field = $subfield;
}
$ids = $field->rawvalue;
$max_articles = 0;
$multiple = true;
// Handle Linked Articles
$field_type = $field->fieldparams->get('articles_type', 'default');
if ($field_type === 'linked')
{
if (in_array($ids, ['1', 'true']))
{
$ids = self::getLinkedArticlesIDs($item->id, $field);
}
}
else
{
$max_articles = (int) $field->fieldparams->get('max_articles', 0);
$multiple = $max_articles === 0 || $max_articles > 1;
}
if (is_scalar($ids))
{
$ids = [(int) $ids];
}
if (!is_array($ids))
{
return;
}
$value = ArticleHelper::get($ids);
if ($field->only_use_in_subform === 1)
{
$data = array_values(array_map(function($article) {
return $article->title;
}, $value));
return implode(', ', $data);
}
if ($multiple)
{
return array_values(array_map(function ($value) {
return is_scalar($value) ? compact('value') : $value;
}, $value));
}
else
{
return array_shift($value);
}
}
public static function getLinkedArticlesIDs($item_id = null, $field = [])
{
if (!$acf_articles = array_filter($field->fieldparams->get('articles_fields', [])))
{
return;
}
// Grab all linked articles
$db = Factory::getDbo();
$query = $db->getQuery(true);
$query->select('a.id')
->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));
// Filter results
require_once JPATH_PLUGINS . '/fields/acfarticles/fields/acfarticlesfilters.php';
$payload = $field->fieldparams;
$filters = new \ACFArticlesFilters($query, $payload);
$query = $filters->apply();
// Set query
$db->setQuery($query);
// Get articles
if (!$articles = $db->loadAssocList())
{
return;
}
// Return article IDs
$articles = array_map(function($article) {
return $article['id'];
}, $articles);
return $articles;
}
}

View File

@ -0,0 +1,93 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
use YOOtheme\Str;
class Chainedfields
{
/**
* Returns the YooTheme type.
*
* If this accepts one image:
* - Tells YooTheme to use the default type for the dropdown mapping option.
*
* If this accepts multiple images:
* - Tells YooTheme to only return the value of this field in the dropdown mapping option.
*
* @param object $field
* @param object $source
*
* @return array
*/
public static function getYooType($field = [], $source = [])
{
$fields = [
[
'type' => 'String',
'name' => 'value',
'metadata' => [
'label' => 'Choices'
],
]
];
$name = Str::camelCase(['Field', $field->name], true);
$source->objectType($name, compact('fields'));
return $name;
}
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? $item["field{$args['field_id']}"] : null;
// Use the subform field
$field = $subfield;
}
if (!$value = $field->rawvalue)
{
return;
}
if (!is_array($value))
{
return;
}
return [
'value' => implode(', ', $value)
];
}
}

View File

@ -0,0 +1,139 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
use YOOtheme\Str;
class Country
{
/**
* Returns the YooTheme type.
*
* @param object $field
* @param object $source
*
* @return array
*/
public static function getYooType($field = [], $source = [])
{
$multiple_selection = $field->fieldparams->get('multiple_selection', '0') === '1';
if (!$multiple_selection)
{
return null;
}
$fields = [
[
'type' => 'String',
'name' => 'code',
'metadata' => [
'label' => 'Country Code'
],
],
[
'type' => 'String',
'name' => 'name',
'metadata' => [
'label' => 'Country Name'
],
]
];
$name = Str::camelCase(['Field', $field->name], true);
$source->objectType($name, compact('fields'));
return $name;
}
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? $item["field{$args['field_id']}"] : '';
// Use the subform field
$field = $subfield;
}
$value = $field->rawvalue;
$multiple_selection = $field->fieldparams->get('multiple_selection', '0') === '1';
if ($multiple_selection)
{
if (!is_array($value))
{
$value = [$value];
}
return [
'code' => implode(',', $value),
'name' => implode(',', self::getNames($value))
];
}
else
{
// If it's an array, try to grab the first item.
if (is_array($value))
{
$value = array_values($value);
$value = isset($value[0]) ? $value[0] : $value;
}
if (!is_string($value))
{
return;
}
$display_mode = $field->fieldparams->get('countrydisplay', 'name');
if ($display_mode === 'code')
{
return $value;
}
if (!$country = \NRFramework\Countries::getCountry($value))
{
return $value;
}
return $country['name'];
}
}
public static function getNames($items = [])
{
return array_map(function ($value) {
$country = \NRFramework\Countries::getCountry($value);
return isset($country['name']) ? $country['name'] : $value['code'];
}, $items);
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
class Downloadbutton
{
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? $item["field{$args['field_id']}"] : '';
// Use the subform field
$field = $subfield;
}
$filename = $field->rawvalue;
if (!is_string($filename))
{
return;
}
$directory = $field->fieldparams->get('directory');
return implode(DIRECTORY_SEPARATOR, [$directory, $filename]);
}
}

View File

@ -0,0 +1,107 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
use YOOtheme\Str;
class Faq
{
/**
* Returns the YooTheme type.
*
* @param object $field
* @param object $source
*
* @return array
*/
public static function getYooType($field = [], $source = [])
{
$fields = [
[
'type' => 'String',
'name' => 'question',
'metadata' => [
'label' => 'Question'
],
],
[
'type' => 'String',
'name' => 'answer',
'metadata' => [
'label' => 'Answer'
],
],
];
$name = Str::camelCase(['Field', $field->name], true);
$source->objectType($name, compact('fields'));
return ['listOf' => $name];
}
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? $item["field{$args['field_id']}"] : '';
// Use the subform field
$field = $subfield;
}
$value = $field->rawvalue;
if (is_string($value))
{
if (!$value = json_decode($value, true))
{
return;
}
}
if (!is_array($value))
{
return;
}
if (!isset($value['value']) || !is_array($value['value']))
{
return;
}
$value = array_values($value['value']);
$value = array_filter($value, function($item) {
return !empty($item['question']) && !empty($item['answer']);
});
return $value;
}
}

View File

@ -0,0 +1,388 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use Joomla\CMS\Helper\TagsHelper;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
use YOOtheme\Str;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
class Gallery
{
public static function deleteFilesFromItem($item_id = '')
{
if (!$item_id)
{
return;
}
self::deleteGalleryFiles($item_id);
if (version_compare(JVERSION, '4', '>='))
{
self::deleteGalleryFilesInSubform($item_id);
}
}
protected static function deleteGalleryFiles($item_id = '')
{
if (!$item_id)
{
return;
}
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select('fv.value')
->from('#__fields_values AS fv')
->join('LEFT', '#__fields AS f ON fv.field_id = f.id')
->where('fv.item_id = ' . $db->quote($item_id))
->where('f.type = ' . $db->quote('acfgallery'));
$db->setQuery($query);
$fieldsValues = $db->loadAssocList();
if (!$fieldsValues)
{
return;
}
foreach ($fieldsValues as $value)
{
$files = json_decode($value['value'], true);
if (!$files)
{
return;
}
if (!isset($files['items']) || !is_array($files['items']) || !count($files['items']))
{
return;
}
foreach ($files['items'] as $file)
{
self::deleteGalleryItem('source', $file);
self::deleteGalleryItem('image', $file);
self::deleteGalleryItem('thumbnail', $file);
self::deleteGalleryItem('slideshow', $file);
}
}
}
protected static function deleteGalleryFilesInSubform($item_id = '')
{
if (!$item_id)
{
return;
}
$db = Factory::getDbo();
// Get all ACF File Upload custom field IDs
$query = $db->getQuery(true)
->select('distinct f.id')
->from('#__fields as f')
->join('LEFT', '#__fields_values AS fv ON fv.field_id = f.id')
->where('fv.item_id = ' . (int) $item_id)
->where('f.type = ' . $db->quote('acfgallery'));
$db->setQuery($query);
$fileupload_ids = array_keys($db->loadAssocList('id'));
if (!$fileupload_ids)
{
return;
}
// Get all Subform custom fields
$query->clear()
->select('f.id as field_id, fv.item_id as item_id, fv.value as value')
->from('#__fields as f')
->join('LEFT', '#__fields_values AS fv ON fv.field_id = f.id')
->where('fv.item_id = ' . (int) $item_id)
->where('f.type = ' . $db->quote('subform'));
$db->setQuery($query);
$subform_fields = $db->loadAssocList();
foreach ($subform_fields as $subform_field)
{
if (!$subform_field_items = json_decode($subform_field['value'], true))
{
continue;
}
foreach ($subform_field_items as $row => &$row_items)
{
if (!is_array($row_items))
{
continue;
}
foreach ($row_items as $field_name => &$field_value)
{
// Get the field id
$field_id = str_replace('field', '', $field_name);
// Check if its a gallery field
if (!in_array($field_id, $fileupload_ids))
{
continue;
}
if (!is_array($field_value))
{
continue;
}
if (!isset($field_value['items']) || !is_array($field_value['items']) || !count($field_value['items']))
{
return;
}
foreach ($field_value['items'] as $file)
{
self::deleteGalleryItem('source', $file);
self::deleteGalleryItem('image', $file);
self::deleteGalleryItem('thumbnail', $file);
self::deleteGalleryItem('slideshow', $file);
}
}
}
}
}
private static function deleteGalleryItem($key, $item)
{
if (isset($item[$key]) && !empty($item[$key]))
{
// Original file path
$path = implode(DIRECTORY_SEPARATOR, [JPATH_SITE, $item[$key]]);
if (!file_exists($path))
{
return;
}
unlink($path);
}
}
/**
* Returns the YooTheme type.
*
* If this accepts one image:
* - Tells YooTheme to use the default type for the dropdown mapping option.
*
* If this accepts multiple images:
* - Tells YooTheme to only return the value of this field in the dropdown mapping option.
*
* @param object $field
* @param object $source
*
* @return array
*/
public static function getYooType($field = [], $source = [])
{
$fields = [
[
'type' => 'String',
'name' => 'thumb',
'metadata' => [
'label' => 'Thumbnail Image URL'
],
],
[
'type' => 'String',
'name' => 'value',
'metadata' => [
'label' => 'Full Image URL'
],
],
[
'type' => 'String',
'name' => 'source',
'metadata' => [
'label' => 'Source Image URL'
],
],
[
'type' => 'String',
'name' => 'caption',
'metadata' => [
'label' => 'Caption'
],
],
[
'type' => 'String',
'name' => 'alt',
'metadata' => [
'label' => 'Alt'
],
],
[
'type' => 'String',
'name' => 'tags',
'metadata' => [
'label' => 'Tags'
],
]
];
$name = Str::camelCase(['Field', $field->name], true);
$source->objectType($name, compact('fields'));
$limit_files = (int) $field->fieldparams->get('limit_files', 0);
if ($limit_files === 1)
{
return $name;
}
return ['listOf' => $name];
}
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? json_encode($item["field{$args['field_id']}"]) : '';
// Use the subform field
$field = $subfield;
}
$value = $field->rawvalue;
if (is_string($value))
{
if (!$value = json_decode($value, true))
{
return;
}
}
if (!is_array($value))
{
return;
}
if (!isset($value['items']))
{
return;
}
$tagsHelper = new TagsHelper();
// Apply ordering
$ordering = $field->fieldparams->get('ordering', 'default');
self::randomize($value['items'], $ordering);
$limit_files = (int) $field->fieldparams->get('limit_files', 0);
if ($limit_files === 1)
{
$uploaded_data = array_values($value['items']);
$tags = isset($uploaded_data[0]['tags']) && is_array($uploaded_data[0]['tags']) ? $tagsHelper->getTagNames($uploaded_data[0]['tags']) : [];
return [
'caption' => isset($uploaded_data[0]['caption']) ? $uploaded_data[0]['caption'] : '',
'source' => isset($uploaded_data[0]['source']) ? $uploaded_data[0]['source'] : '',
'thumb' => isset($uploaded_data[0]['thumbnail']) ? $uploaded_data[0]['thumbnail'] : '',
'alt' => isset($uploaded_data[0]['alt']) ? $uploaded_data[0]['alt'] : '',
'value' => isset($uploaded_data[0]['image']) ? $uploaded_data[0]['image'] : '',
'tags' => implode(', ', $tags)
];
}
$data = array_values(array_map(function($item) use ($tagsHelper) {
$tags = isset($item['tags']) && is_array($item['tags']) ? $tagsHelper->getTagNames($item['tags']) : [];
return [
'value' => $item['image'],
'thumb' => $item['thumbnail'],
'source' => isset($item['source']) ? $item['source'] : '',
'alt' => isset($item['alt']) ? $item['alt'] : '',
'caption' => $item['caption'],
'tags' => implode(', ', $tags)
];
}, $value['items']));
return $data;
}
public static function randomize(&$data = [], $ordering = 'default')
{
if (!is_array($data))
{
return;
}
switch ($ordering)
{
case 'random':
shuffle($data);
break;
case 'alphabetical':
usort($data, [__CLASS__, 'compareByThumbnailASC']);
break;
case 'reverse_alphabetical':
usort($data, [__CLASS__, 'compareByThumbnailDESC']);
break;
}
}
/**
* Compares thumbnail file names in ASC order
*
* @param array $a
* @param array $b
*
* @return bool
*/
public static function compareByThumbnailASC($a, $b)
{
return strcmp(basename($a['thumbnail']), basename($b['thumbnail']));
}
/**
* Compares thumbnail file names in DESC order
*
* @param array $a
* @param array $b
*
* @return bool
*/
public static function compareByThumbnailDESC($a, $b)
{
return strcmp(basename($b['thumbnail']), basename($a['thumbnail']));
}
}

View File

@ -0,0 +1,136 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use Joomla\CMS\Language\Text;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
use YOOtheme\Str;
class Map
{
/**
* Returns the YooTheme type.
*
* @param object $field
* @param object $source
*
* @return array
*/
public static function getYooType($field = [], $source = [])
{
$fields = [
[
'type' => 'String',
'name' => 'address',
'metadata' => [
'label' => Text::_('NR_MARKER_ADDRESS')
],
],
[
'type' => 'String',
'name' => 'coordinates',
'metadata' => [
'label' => Text::_('NR_MARKER_COORDINATES')
],
],
[
'type' => 'String',
'name' => 'latitude',
'metadata' => [
'label' => Text::_('NR_MARKER_LATITUDE')
],
],
[
'type' => 'String',
'name' => 'longitude',
'metadata' => [
'label' => Text::_('NR_MARKER_LONGITUDE')
],
],
[
'type' => 'String',
'name' => 'label',
'metadata' => [
'label' => Text::_('NR_MARKER_LABEL')
],
],
[
'type' => 'String',
'name' => 'description',
'metadata' => [
'label' => Text::_('NR_MARKER_DESCRIPTION')
],
],
];
$name = Str::camelCase(['Field', $field->name], true);
$source->objectType($name, compact('fields'));
return ['listOf' => $name];
}
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? $item["field{$args['field_id']}"] : '';
// Use the subform field
$field = $subfield;
}
$value = $field->rawvalue;
if (is_string($value))
{
if (!$value = json_decode($value, true))
{
return;
}
}
if (!is_array($value))
{
return;
}
foreach ($value as $key => &$v)
{
if (!isset($v['latitude']) || !isset($v['longitude']))
{
continue;
}
$v['coordinates'] = $v['latitude'] . ',' . $v['longitude'];
}
return $value;
}
}

View File

@ -0,0 +1,66 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
class Osm
{
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? json_encode($item["field{$args['field_id']}"]) : '';
// Use the subform field
$field = $subfield;
}
$value = $field->rawvalue;
if (!is_string($value))
{
return;
}
if (!$value = json_decode($value, true))
{
return;
}
if (!isset($value['coordinates']))
{
return;
}
return $value['coordinates'];
}
}

View File

@ -0,0 +1,65 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\Registry\Registry;
class Php
{
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? $item["field{$args['field_id']}"] : '';
// Use the subform field
$field = $subfield;
}
if (!$value = $field->rawvalue)
{
return;
}
// Get plugin params
$plugin = PluginHelper::getPlugin('fields', 'acfphp');
$params = new Registry($plugin->params);
// Enable buffer output
$executer = new \NRFramework\Executer($value);
return $executer
->setForbiddenPHPFunctions($params->get('forbidden_php_functions'))
->run();
}
}

View File

@ -0,0 +1,58 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
class Soundcloud
{
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? $item["field{$args['field_id']}"] : '';
// Use the subform field
$field = $subfield;
}
$value = $field->rawvalue;
$value = is_string($value) ? json_decode($value, true) : $value;
if (!is_array($value))
{
return;
}
return isset($value['id']) ? $value['id'] : null;
}
}

View File

@ -0,0 +1,141 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
use YOOtheme\Str;
class Telephone
{
/**
* Returns the YooTheme type.
*
* If this accepts one image:
* - Tells YooTheme to use the default type for the dropdown mapping option.
*
* If this accepts multiple images:
* - Tells YooTheme to only return the value of this field in the dropdown mapping option.
*
* @param object $field
* @param object $source
*
* @return array
*/
public static function getYooType($field = [], $source = [])
{
$fields = [
[
'type' => 'String',
'name' => 'phone_number',
'metadata' => [
'label' => 'Phone Number'
],
],
[
'type' => 'String',
'name' => 'calling_code',
'metadata' => [
'label' => 'Calling Code'
],
],
[
'type' => 'String',
'name' => 'country_code',
'metadata' => [
'label' => 'Country Code'
],
],
[
'type' => 'String',
'name' => 'country_name',
'metadata' => [
'label' => 'Country Name'
],
]
];
$name = Str::camelCase(['Field', $field->name], true);
$source->objectType($name, compact('fields'));
return $name;
}
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
// var_dump($info->rootValue['parent']->children[0]);
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? $item["field{$args['field_id']}"] : '';
// Use the subform field
$field = $subfield;
}
$value = $field->rawvalue;
if (is_string($value) && json_decode($value, true))
{
$value = json_decode($value, true);
}
$countryCode = '';
$callingCode = '';
if (is_array($value))
{
$countryCode = isset($value['code']) ? $value['code'] : '';
$phoneNumber = isset($value['value']) ? $value['value'] : '';
if ($phoneNumber)
{
$callingCode = \NRFramework\Countries::getCallingCodeByCountryCode($countryCode);
$callingCode = $callingCode !== '' ? '+' . $callingCode : '';
$value = $callingCode . $phoneNumber;
}
else
{
$value = '';
}
}
if (!$value)
{
return;
}
return [
'phone_number' => $value,
'calling_code' => $callingCode,
'country_code' => $countryCode,
'country_name' => ($countryCode ? \NRFramework\Countries::toCountryName($countryCode) : '')
];
}
}

View File

@ -0,0 +1,300 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
use YOOtheme\Str;
use Joomla\CMS\Factory;
class Upload
{
public static function deleteFilesFromItem($item_id = '')
{
if (!$item_id)
{
return;
}
self::deleteFileUploadFiles($item_id);
if (version_compare(JVERSION, '4', '>='))
{
self::deleteFileUploadFilesInSubform($item_id);
}
}
protected static function deleteFileUploadFiles($item_id = '')
{
if (!$item_id)
{
return;
}
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select('fv.value')
->from('#__fields_values AS fv')
->join('LEFT', '#__fields AS f ON fv.field_id = f.id')
->where('fv.item_id = ' . $db->quote($item_id))
->where('f.type = ' . $db->quote('acfupload'));
$db->setQuery($query);
$fieldsValues = $db->loadAssocList();
if (!$fieldsValues)
{
return;
}
foreach ($fieldsValues as $value)
{
$files = json_decode($value['value'], true);
if (!$files)
{
return;
}
foreach ($files as $file)
{
$filePath = implode(DIRECTORY_SEPARATOR, [JPATH_ROOT, $file['value']]);
if (!file_exists($filePath))
{
continue;
}
unlink($filePath);
}
}
}
protected static function deleteFileUploadFilesInSubform($item_id = '')
{
if (!$item_id)
{
return;
}
$db = Factory::getDbo();
// Get all ACF File Upload custom field IDs
$query = $db->getQuery(true)
->select('distinct f.id')
->from('#__fields as f')
->join('LEFT', '#__fields_values AS fv ON fv.field_id = f.id')
->where('fv.item_id = ' . (int) $item_id)
->where('f.type = ' . $db->quote('acfupload'));
$db->setQuery($query);
$fileupload_ids = array_keys($db->loadAssocList('id'));
if (!$fileupload_ids)
{
return;
}
// Get all Subform custom fields
$query->clear()
->select('f.id as field_id, fv.item_id as item_id, fv.value as value')
->from('#__fields as f')
->join('LEFT', '#__fields_values AS fv ON fv.field_id = f.id')
->where('fv.item_id = ' . (int) $item_id)
->where('f.type = ' . $db->quote('subform'));
$db->setQuery($query);
$subform_fields = $db->loadAssocList();
foreach ($subform_fields as $subform_field)
{
if (!$subform_field_items = json_decode($subform_field['value'], true))
{
continue;
}
foreach ($subform_field_items as $row => &$row_items)
{
if (!is_array($row_items))
{
continue;
}
foreach ($row_items as $field_name => &$field_value)
{
// Get the field id
$field_id = str_replace('field', '', $field_name);
// Check if its a gallery field
if (!in_array($field_id, $fileupload_ids))
{
continue;
}
if (!is_array($field_value))
{
continue;
}
foreach ($field_value as $file)
{
$filePath = implode(DIRECTORY_SEPARATOR, [JPATH_ROOT, $file['value']]);
if (!file_exists($filePath))
{
continue;
}
unlink($filePath);
}
}
}
}
}
/**
* Returns the YooTheme type.
*
* If this accepts one image:
* - Tells YooTheme to use the default type for the dropdown mapping option.
*
* If this accepts multiple images:
* - Tells YooTheme to only return the value of this field in the dropdown mapping option.
*
* @param object $field
* @param object $source
*
* @return array
*/
public static function getYooType($field = [], $source = [])
{
$limit_files = (int) $field->fieldparams->get('limit_files', 0);
$fields = [
[
'type' => 'String',
'name' => 'value',
'metadata' => [
'label' => 'File URL'
],
],
[
'type' => 'String',
'name' => 'title',
'metadata' => [
'label' => 'Title'
],
],
[
'type' => 'String',
'name' => 'description',
'metadata' => [
'label' => 'Description'
],
],
[
'type' => 'String',
'name' => 'filesize',
'metadata' => [
'label' => 'File size'
],
],
];
$name = Str::camelCase(['Field', $field->name], true);
$source->objectType($name, compact('fields'));
if ($limit_files === 1)
{
return $name;
}
return ['listOf' => $name];
}
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? json_encode($item["field{$args['field_id']}"]) : '';
// Use the subform field
$field = $subfield;
}
$value = $field->rawvalue;
$value = is_string($value) ? json_decode($value, true) ?? $value : $value;
if (!is_array($value))
{
return;
}
$value = array_values($value);
if (is_array($value))
{
// Fix new lines in description
foreach ($value as $key => &$val)
{
if (isset($val['description']))
{
$val['description'] = nl2br($val['description']);
}
}
}
foreach ($value as $key => &$val)
{
$val['filesize'] = '';
$path = implode(DIRECTORY_SEPARATOR, [JPATH_ROOT, $val['value']]);
if (file_exists($path))
{
$val['filesize'] = filesize($path);
$val['filesize'] = sprintf("%4.2f MB", $val['filesize'] / 1024 / 1024);
}
if (isset($val['value']))
{
$val['value'] = $val['value'];
}
}
$limit_files = (int) $field->fieldparams->get('limit_files', 0);
if ($limit_files === 1 && is_array($value) && count($value) === 1)
{
return $value[0];
}
return $value;
}
}

View File

@ -0,0 +1,106 @@
<?php
/**
* @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
*/
namespace ACF\Helpers\Fields;
defined('_JEXEC') or die;
use YOOtheme\Builder\Joomla\Fields\Type\FieldsType;
use YOOtheme\Str;
class Url
{
/**
* Returns the YooTheme type.
*
* If this accepts one image:
* - Tells YooTheme to use the default type for the dropdown mapping option.
*
* If this accepts multiple images:
* - Tells YooTheme to only return the value of this field in the dropdown mapping option.
*
* @param object $field
* @param object $source
*
* @return array
*/
public static function getYooType($field = [], $source = [])
{
$fields = [
[
'type' => 'String',
'name' => 'url',
'metadata' => [
'label' => 'URL'
],
],
[
'type' => 'String',
'name' => 'text',
'metadata' => [
'label' => 'Label'
],
],
[
'type' => 'String',
'name' => 'target',
'metadata' => [
'label' => 'Target'
],
]
];
$name = Str::camelCase(['Field', $field->name], true);
$source->objectType($name, compact('fields'));
return $name;
}
/**
* Transforms the field value to an appropriate value that YooTheme can understand.
*
* @return array
*/
public static function yooResolve($item, $args, $ctx, $info)
{
// var_dump($info->rootValue['parent']->children[0]);
$name = str_replace('String', '', strtr($info->fieldName, '_', '-'));
// Check if it's a subform field
$subfield = clone \ACF\Helpers\Yoo::getSubfield($args['field_id'], $args['context']);
// When we have a subform field, the $item is an array of values
if (!$subfield || !is_array($item))
{
if (!isset($item->id) || !($field = FieldsType::getField($name, $item, $args['context'])))
{
return;
}
}
else
{
// Set rawvalue
$subfield->rawvalue = isset($item["field{$args['field_id']}"]) ? $item["field{$args['field_id']}"] : '';
// Use the subform field
$field = $subfield;
}
$value = $field->rawvalue;
if (is_string($value))
{
if (!$value = json_decode($value, true))
{
return;
}
}
return $value;
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* @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
*/
namespace ACF\Helpers;
defined('_JEXEC') or die;
class Previewer
{
/**
* Returns the field previewer data.
*
* @return array
*/
public static function getFieldPreviewData($field = '')
{
if (empty($field))
{
return;
}
// Get path to file
$file = implode(DIRECTORY_SEPARATOR, [self::getJsonDirectory(), $field . '.json']);
if (!file_exists($file))
{
return;
}
return file_get_contents($file);
}
/**
* Returns the path to the fields previewer JSON directory.
*
* @return string
*/
public static function getJsonDirectory()
{
return implode(DIRECTORY_SEPARATOR, [JPATH_SITE, 'media', 'plg_system_acf', 'data', 'previewer']);
}
}

View File

@ -0,0 +1,87 @@
<?php
/**
* @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
*/
namespace ACF\Helpers;
defined('_JEXEC') or die;
use NRFramework\Functions;
use YOOtheme\Builder\Joomla\Fields\FieldsHelper;
use YOOtheme\Application as YooApplication;
use YOOtheme\Event;
class Yoo
{
public static function initFieldParser()
{
// Ensure YOOtheme Pro is ready
if (!class_exists(YooApplication::class, false))
{
return;
}
Event::on('source.com_fields.field', function($config, $field, $source, $context) {
// If it's not an ACF Field, return current config
if (substr($field->type, 0, 3) !== 'acf')
{
return $config;
}
// Get the helper class of the field
$helperClass = '\ACF\Helpers\Fields\\' . ucfirst(substr($field->type, 3));
// If it does not exist, return current config
if (!class_exists($helperClass))
{
return $config;
}
// If the method does not have a resolve method, return current config
if (!method_exists($helperClass, 'yooResolve'))
{
return $config;
}
$payload = [
'extensions' => [
'call' => [
'func' => $helperClass . '::yooResolve',
'args' => ['context' => $context, 'field_id' => $field->id]
]
],
] + $config;
// Get and set the type
$type = method_exists($helperClass, 'getYooType') ? $helperClass::getYooType($field, $source) : '';
if (!empty($type))
{
$payload['type'] = $type;
}
return $payload;
});
}
public static function getSubfield($id, $context)
{
static $fields = [];
if (!isset($fields[$context]))
{
$fields[$context] = [];
foreach (FieldsHelper::getFields($context, null, true) as $field)
{
$fields[$context][$field->id] = $field;
}
}
return !empty($fields[$context][$id]) ? $fields[$context][$id] : null;
}
}

View File

View File

@ -0,0 +1,58 @@
<?php
/**
* @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
*/
namespace ACF;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
class Item
{
/**
* Determines whether we're copying an item.
*
* @return bool
*/
public static function isCopying()
{
return self::isBatchCopying() || self::isSavingAsCopy();
}
/**
* Determines whether we're batch copying an item.
*
* @return bool
*/
public static function isBatchCopying()
{
$input = Factory::getApplication()->input;
$task = $input->getCmd('task', '');
$batchOptions = $input->post->get('batch', [], 'array');
$cid = $input->post->get('cid', [], 'array');
$isCopy = isset($batchOptions['move_copy']) && $batchOptions['move_copy'] === 'c';
return $task === 'batch' && is_array($cid) && count($cid) && $isCopy;
}
/**
* Determines whether we're copying an item using the "Save as Copy" button.
*
* @return bool
*/
public static function isSavingAsCopy()
{
$input = Factory::getApplication()->input;
$task = $input->getCmd('task', '');
$id = $input->getInt('id', 0);
$isCopying = $task === 'save2copy' && $id;
return $isCopying;
}
}

View File

@ -0,0 +1,148 @@
<?php
/**
* @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
*/
namespace ACF\Previewer;
defined('_JEXEC') or die;
class Countdown extends Field
{
/**
* The field framework widget name.
*
* @var string
*/
protected $field = 'Countdown';
/**
* The theme used.
*
* @var string
*/
private $theme;
public function __construct($data = [], $payload = [])
{
parent::__construct($data, $payload);
// Set theme
$this->theme = $this->getTheme();
}
/**
* Render the field.
*
* @return string
*/
public function onSetup()
{
$this->payload = [
// Field values
'countdown_type' => 'evergreen',
'timezone' => 'server',
'dynamic_days' => '1',
'dynamic_hours' => '12',
'dynamic_minutes' => '59',
'dynamic_seconds' => '59',
// Countdown End Action
'finish_text' => $this->fieldParams->get('finish_text', ''),
'redirect_url' => $this->fieldParams->get('redirect_url', ''),
'countdown_action' => 'restart',
// Preset
'theme' => $this->theme,
'format' => $this->fieldParams->get('format', ''),
// Unit Display
'days' => $this->fieldParams->get('days') === '1',
'days_label' => $this->fieldParams->get('days_label'),
'hours' => $this->fieldParams->get('hours') === '1',
'hours_label' => $this->fieldParams->get('hours_label'),
'minutes' => $this->fieldParams->get('minutes') === '1',
'minutes_label' => $this->fieldParams->get('minutes_label'),
'seconds' => $this->fieldParams->get('seconds') === '1',
'seconds_label' => $this->fieldParams->get('seconds_label'),
'separator' => $this->fieldParams->get('separator') === '1',
'double_zeroes_format' => $this->fieldParams->get('double_zeroes_format') === '1',
// Unit Item
'item_size' => $this->fieldParams->get('item_size_responsive.item_size'),
'item_padding' => $this->fieldParams->get('item_padding_control.item_padding'),
'gap' => $this->fieldParams->get('item_gap.gap'),
'item_border_style' => $this->fieldParams->get('border.style'),
'item_border_width' => $this->fieldParams->get('border.width'),
'item_border_color' => $this->fieldParams->get('border.color'),
'item_background_color' => $this->fieldParams->get('item_background_color'),
'item_border_radius' => $this->fieldParams->get('item_border_radius_control.item_border_radius'),
// Unit Digits Container
'digits_wrapper_min_width' => $this->fieldParams->get('digits_wrapper_custom_width') === '1' ? $this->fieldParams->get('digits_wrapper_min_width') : null,
'digits_wrapper_padding' => $this->fieldParams->get('digits_wrapper_padding_control.digits_wrapper_padding'),
'digits_wrapper_border_radius' => $this->fieldParams->get('digits_wrapper_border_radius_control.digits_wrapper_border_radius'),
'digits_wrapper_background_color' => $this->fieldParams->get('digits_wrapper_background_color'),
// Unit Digit
'digits_font_size' => $this->fieldParams->get('digits_font_size_control.digits_font_size'),
'digits_font_weight' => $this->fieldParams->get('digits_font_weight'),
'digit_min_width' => $this->fieldParams->get('digits_custom_width') === '1' ? $this->fieldParams->get('digits_min_width') : null,
'digits_padding' => $this->fieldParams->get('digits_padding_control.digits_padding'),
'digit_border_radius' => $this->fieldParams->get('digits_border_radius_control.digits_border_radius'),
'digits_gap' => $this->fieldParams->get('digits_gap_control.digits_gap'),
'digit_background_color' => $this->fieldParams->get('digit_background_color'),
'digit_text_color' => $this->fieldParams->get('digit_text_color'),
// Unit Label
'label_font_size' => $this->fieldParams->get('label_font_size_control.label_font_size'),
'label_font_weight' => $this->fieldParams->get('label_font_weight'),
'unit_label_margin_top' => $this->fieldParams->get('unit_label_margin_top'),
'unit_label_text_color' => $this->fieldParams->get('unit_label_text_color'),
];
$this->widget = new \NRFramework\Widgets\Countdown(json_decode(json_encode($this->payload), true));
}
/**
* Return all assets used by this field.
*
* @return void
*/
public function getAssets()
{
$exclude_breakpoints = [];
// If we are not viewing the fullscreen previewer,
// then get the widget's Custom CSS of the desktop
// due to the IFrame having small width and triggering the tablet/mobile CSS breakpoints
if (!$this->data->get('fullscreen'))
{
$exclude_breakpoints = ['tablet', 'mobile'];
}
return [
'css' => \NRFramework\Widgets\Countdown::getCSS($this->theme),
'js' => \NRFramework\Widgets\Countdown::getJS(),
'custom_css' => $this->widget->getWidgetCSS($exclude_breakpoints)
];
}
/**
* Get the theme.
*
* @return string
*/
private function getTheme()
{
$preset_source = $this->fieldParams->get('preset_source', 'preset');
$preset = $this->fieldParams->get('preset', '1');
// Determine theme
return $preset_source === 'custom' ? 'custom' : ($preset === '8' ? 'oneline' : 'default');
}
}

View File

@ -0,0 +1,103 @@
<?php
/**
* @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
*/
namespace ACF\Previewer;
defined('_JEXEC') or die;
class FAQ extends Field
{
/**
* The field framework widget name.
*
* @var string
*/
protected $field = 'FAQ';
/**
* Render the field.
*
* @return string
*/
public function onSetup()
{
$value = [
[
'question' => 'Who should use EngageBox?',
'answer' => 'EngageBox is the most powerful popup engine in the Joomla! market used by marketing agencies, bloggers, eCommerce websites, and all small businesses. If you want to grow your email list, improve your website conversions, and reduce cart abandonment, then you need EngageBox.'
],
[
'question' => 'What\'s required to use EngageBox?',
'answer' => 'EngageBox can be used in both Joomla 3 and Joomla 4. In detail, you will need an up-to-date version of Joomla 3.8.0 or higher, PHP 7.0.0 or higher, and MySQL 5 or higher.'
],
[
'question' => 'Do I need coding skills to use EngageBox?',
'answer' => 'Absolutely not! You can create and customize beautiful popups without any coding knowledge. We made it extremely user-friendly, so you can build a high-converting popup without hiring a developer.'
],
[
'question' => 'What type of conversions can I expect?',
'answer' => 'It will make a significant difference. Game-changing! Our average user sees over 500% increase in sales, customers base and growth in general.'
],
[
'question' => 'What if a visitor has a pop-up adblocker enabled?',
'answer' => 'Will still work! EngageBox produces popups in a way which can\'t be blocked by the browsers pop-up blocking feature or 3rd party extensions such as AdBlock or uBlock.'
],
];
$this->payload = [
'value' => $value,
'css_class' => ' template_' . $this->fieldParams->get('template'),
'columns' => (int) $this->fieldParams->get('columns', 1),
'item_gap' => $this->fieldParams->get('item_gap_control.item_gap', 20),
'column_gap' => $this->fieldParams->get('column_gap_control.column_gap', 20),
'item_background_color' => $this->fieldParams->get('background_color'),
'item_border_radius' => $this->fieldParams->get('border_radius_control.item_border_radius'),
'item_padding' => $this->fieldParams->get('padding_control.item_padding'),
'question_font_size' => $this->fieldParams->get('question_font_size_control.question_font_size'),
'question_text_color' => $this->fieldParams->get('question_text_color'),
'answer_font_size' => $this->fieldParams->get('answer_font_size_control.answer_font_size'),
'answer_text_color' => $this->fieldParams->get('answer_text_color'),
'generate_faq' => $this->fieldParams->get('generate_faq', '0') === '1',
'keep_one_question_open' => $this->fieldParams->get('keep_one_question_open', '0') === '1',
'separator' => $this->fieldParams->get('separator', '0') === '1',
'separator_color' => $this->fieldParams->get('separator_color'),
'initial_state' => $this->fieldParams->get('initial_state', 'first-open')
];
$show_toggle_icon = $this->fieldParams->get('show_toggle_icon', '1') === '1';
$this->payload['show_toggle_icon'] = $show_toggle_icon;
if ($show_toggle_icon)
{
$this->payload['icon'] = $this->fieldParams->get('icon', 'arrow');
$this->payload['icon_position'] = $this->fieldParams->get('icon_position', 'right');
}
$this->widget = new \NRFramework\Widgets\FAQ(json_decode(json_encode($this->payload), true));
}
/**
* Adds some extra CSS to the previewer's body.
*
* @return string
*/
protected function getFieldPreviewerCSS()
{
if ((int) $this->fieldParams->get('template') !== 4)
{
return;
}
return '
body {
background: #EBEBEB !important;
padding: 20px !important;
}
';
}
}

View File

@ -0,0 +1,235 @@
<?php
/**
* @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
*/
namespace ACF\Previewer;
defined('_JEXEC') or die;
use Joomla\Registry\Registry;
use Joomla\CMS\Uri\Uri;
class Field
{
/**
* The field framework widget name.
*
* @var string
*/
protected $field = '';
/**
* Field Editor Form Data.
*
* @var array
*/
protected $data = [];
/**
* Field Params.
*
* @var object
*/
protected $fieldParams = [];
/**
* The field payload used to render the field.
*
* @var array
*/
protected $payload;
/**
* The Framework Widget.
*
* @var Widget
*/
protected $widget = null;
public function __construct($data = [], $payload = [])
{
$this->data = new Registry($data);
$fieldParams = isset($data['fieldparams']) ? $data['fieldparams'] : [];
$this->fieldParams = new Registry($fieldParams);
if ($payload)
{
$this->payload = $payload;
}
}
/**
* Saves the field's JSON data for previewer to render it.
*
* @return void
*/
protected function saveJSON()
{
// Get path to file
$file = implode(DIRECTORY_SEPARATOR, [\ACF\Helpers\Previewer::getJsonDirectory(), $this->data->get('type') . '.json']);
// Save JSON file
file_put_contents($file, $this->getHTML());
}
/**
* Setup the field.
*
* @return string
*/
public function setup()
{
if (method_exists($this, 'onSetup'))
{
$this->onSetup();
}
$this->saveJSON();
}
/**
* Render the field.
*
* @return string
*/
public function render()
{
return $this->widget->render();
}
/**
* Field HTML output.
*
* @return string
*/
private function getHTML()
{
return '<html><head>' . $this->getHead() . '</head><body>' . $this->render() . '</body></html>';
}
/**
* Returns the head of the preview HTML.
*
* @return string
*/
private function getHead()
{
if (!$assets = $this->getAssets())
{
return;
}
// Add Reset CSS
$head = '<style>' . $this->getResetCSS() . '</style>';
// Add Custom CSS
if (isset($assets['custom_css']) && !empty($assets['custom_css']))
{
$head .= '<style>' . $assets['custom_css'] . '</style>';
}
$base_url = Uri::root();
// Add CSS
if (isset($assets['css']) && is_array($assets['css']) && count($assets['css']))
{
foreach ($assets['css'] as $css)
{
$css = str_replace('plg_system_nrframework/', 'plg_system_nrframework/css/', $css);
$link = $base_url . 'media/' . $css;
$head .= '<link href="' . $link . '" rel="stylesheet" />';
}
}
// Add Core JS
$head .= '<script src="' . $base_url . 'media/system/js/core.js"></script>';
// Add JS
if (isset($assets['js']) && is_array($assets['js']) && count($assets['js']))
{
foreach ($assets['js'] as $js)
{
$js = str_replace('plg_system_nrframework/', 'plg_system_nrframework/js/', $js);
$link = $base_url . 'media/' . $js;
$head .= '<script src="' . $link . '"></script>';
}
}
return $head;
}
/**
* Returns the field reset CSS.
*
* @return string
*/
private function getResetCSS()
{
$reset_css = '
body {
border: 0 !important;
background: #fff !important;
padding: 0 !important;
margin: 0 !important;
overflow-x: hidden !important;
font-family: Arial;
font-size: 16px;
}
';
return $reset_css . $this->getFieldPreviewerCSS();
}
/**
* Adds some extra CSS to the previewer's body.
*
* @return string
*/
protected function getFieldPreviewerCSS()
{
}
/**
* The CSS/JS assets that are required for the field to run.
*
* @return void
*/
public function getAssets()
{
return [
'css' => $this->getFieldCSS(),
'js' => $this->getFieldJS(),
'custom_css' => $this->widget->getOption('css_vars') . $this->widget->getOption('custom_css')
];
}
/**
* Returns the field CSS files.
*
* @return array
*/
private function getFieldCSS()
{
return $this->widget && method_exists($this->widget, 'getCSS') ? $this->widget->getCSS() : [];
}
/**
* Returns the field JS files.
*
* @return array
*/
private function getFieldJS()
{
return $this->widget && method_exists($this->widget, 'getJS') ? $this->widget->getJS() : [];
}
}

View File

472
plugins/system/acf/acf.php Normal file
View File

@ -0,0 +1,472 @@
<?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');
// 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('
<fieldset name="conditions">
<field name="wrongPluginOrder" type="note"
class="alert alert-warning"
description="ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER"
/>
</fieldset>
'));
}
}
}
// 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);
}
}

View File

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<extension version="3.4" type="plugin" group="system" method="upgrade">
<name>PLG_SYSTEM_ACF</name>
<description>PLG_SYSTEM_ACF_DESC</description>
<version>2.8.8</version>
<creationDate>May 2017</creationDate>
<copyright>Copyright © 2024 Tassos Marinos All Rights Reserved</copyright>
<license>http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL</license>
<author>Tassos Marinos</author>
<authorEmail>info@tassos.gr</authorEmail>
<authorUrl>http://www.tassos.gr</authorUrl>
<scriptfile>script.install.php</scriptfile>
<files>
<filename plugin="acf">acf.php</filename>
<filename>script.install.helper.php</filename>
<filename>version.php</filename>
<filename>autoload.php</filename>
<folder>ACF</folder>
<folder>media</folder>
<folder>layouts</folder>
<folder>helper</folder>
<folder>form</folder>
<folder>language</folder>
</files>
<updateservers>
<server type="extension" priority="1" name="Advanced Custom Fields">
http://www.tassos.gr/updates/advanced-custom-fields-pro.xml
</server>
</updateservers>
<config>
<fields name="params">
<fieldset name="basic" addfieldpath="plugins/system/acf/form/fields">
<field name="dashboard" type="nr_freetext"
path="/plugins/system/acf/layouts"
file="dashboard"
/>
</fieldset>
<fieldset name="settings" label="Settings" addfieldpath="plugins/system/nrframework/fields">
<field name="ass_well" type="nr_well"
label="NR_PUBLISHING_ASSIGNMENTS"
description="ACF_ASSIGNMENTS_DESC"
/>
<field name="assignments" type="radio"
class="btn-group btn-group-yesno"
label="JENABLED"
default="1">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="ass_well_end" type="nr_well"
end="1"
/>
</fieldset>
</fields>
</config>
<media folder="media" destination="plg_system_acf">
<folder>css</folder>
<folder>js</folder>
<folder>data</folder>
</media>
<!-- Watchful -->
<variant>pro</variant>
</extension>

View File

@ -0,0 +1,13 @@
<?php
/**
* @author 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' );
// Registers ACF's namespace
JLoader::registerNamespace('ACF', __DIR__ . '/ACF/', false, false, 'psr4');

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<form>
<fields name="params">
<fieldset name="conditions" label="NR_PUBLISHING_ASSIGNMENTS" addfieldpath="plugins/system/nrframework/fields">
<field name="rules" type="ConditionBuilder"
label="NR_PUBLISHING_ASSIGNMENTS"
hiddenLabel="true"
/>
</fieldset>
</fields>
</form>

View File

@ -0,0 +1,119 @@
<?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('Restricted access');
use Joomla\CMS\Form\Field\ListField;
use \NRFramework\Widgets\Helper;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
class JFormFieldACFFieldLayoutOverrides extends ListField
{
/**
* Method to get a list of options for a list input.
*
* @return array An array of options.
*/
protected function getOptions()
{
$layouts = [
'default' => 'JOPTION_USE_DEFAULT'
];
$field_type = (string) $this->element['field_type'];
$field_widget_name = (string) $this->element['widget_name'];
$override_widget_directory_name = $this->getOverrideWidgetDirectoryName($field_widget_name, $field_type);
if ($layout_overrides = Helper::getLayoutOverrides($override_widget_directory_name))
{
$layouts = array_merge($layouts, $layout_overrides);
}
foreach ($layouts as $key => $title)
{
$options[] = HTMLHelper::_('select.option', $key, Text::_($title));
}
return $options;
}
public function getInput()
{
$field_type = (string) $this->element['field_type'];
$field_widget_name = (string) $this->element['widget_name'];
$override_widget_directory_name = $this->getOverrideWidgetDirectoryName($field_widget_name, $field_type);
if (!$override_widget_directory_name)
{
return Text::_('ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST');
}
$original_path = implode(DIRECTORY_SEPARATOR, [JPATH_PLUGINS, 'system', 'nrframework', 'layouts', 'widgets', $override_widget_directory_name]). '/default.php';
$new_path = Helper::getLayoutOverridePath($override_widget_directory_name) . '/LAYOUTNAME.php';
$note = '<div class="acf-field-setting-note" style="padding-top:5px;">' . sprintf(Text::_('ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC'), Text::_('PLG_FIELDS_ACF' . $this->getHelpName($field_widget_name, $field_type) . '_LABEL'), $original_path, $new_path) . '</div>';
return parent::getInput() . $note;
}
/**
* Some widgets require a different directory to be used for layout overrides.
*
* @param string $field_widget_name The widget name
* @param string $field_type The field type
*
* @return string
*/
private function getOverrideWidgetDirectoryName($field_widget_name = null, $field_type = null)
{
if (!$field_widget_name || !$field_type)
{
return;
}
switch ($field_type)
{
case 'acfvideo':
$field_widget_name = strtolower($this->form->getData()->get('fieldparams.provider', ''));
break;
case 'acfgallery':
if ($this->form->getData()->get('fieldparams.style', '') === 'slideshow')
{
$field_widget_name = 'slideshow';
}
break;
}
return strtolower($field_widget_name);
}
private function getHelpName($field_widget_name = null, $field_type = null)
{
if (!$field_widget_name || !$field_type)
{
return;
}
switch ($field_type)
{
case 'acfaddress':
$field_widget_name = 'Address';
break;
case 'acfmap':
$field_widget_name = 'Map';
break;
}
return strtoupper($field_widget_name);
}
}

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<form>
<fields name="params">
<fieldset name="acf_options" label="ACF_ACF_OPTIONS">
<field name="acf_custom_css" type="editor"
label="ACF_CUSTOM_CSS"
description="ACF_CUSTOM_CSS_DESC"
editor="codemirror"
filter="raw"
/>
<field name="acf_layout_override" type="ACFFieldLayoutOverrides"
label="ACF_WIDGET_LAYOUT"
description="ACF_FIELD_LAYOUT_OVERRIDES"
/>
</fieldset>
</fields>
</form>

View File

@ -0,0 +1,63 @@
<?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
*/
use Joomla\CMS\Form\FormRule;
defined('_JEXEC') or die('Restricted access');
use Joomla\String\StringHelper;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
class JFormRuleACFGravatarValidator extends FormRule
{
/**
* Method to test the calendar value for a valid parts.
*
* @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object.
* @param mixed $value The form field value to validate.
* @param string $group The field name group control value. This acts as an array container for the field.
* For example if the field has name="foo" and the group value is set to "bar" then the
* full field name would end up being "bar[foo]".
* @param Registry $input An optional Registry object with the entire data set to validate against the entire form.
* @param Form $form The form object for which the field is being tested.
*
* @return boolean True if the value is valid, false otherwise.
*
* @since 3.7.0
*/
public function test(SimpleXMLElement $element, $value, $group = null, \Joomla\Registry\Registry $input = NULL, \Joomla\CMS\Form\Form $form = NULL)
{
// If the field is empty and not required, the field is valid.
$required = ((string) $element['required'] == 'true' || (string) $element['required'] == 'required');
if (!$required && empty($value))
{
return true;
}
// Allow Smile Pack Smart Tags
if (StringHelper::strpos($value, '{sp') !== false)
{
return true;
}
// Validate email
if (filter_var($value, FILTER_VALIDATE_EMAIL))
{
return true;
}
Factory::getApplication()->enqueueMessage(Text::_('ACF_INVALID_EMAIL'), 'error');
return false;
}
}

View File

@ -0,0 +1,56 @@
<?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
*/
use Joomla\CMS\Form\FormRule;
defined('_JEXEC') or die('Restricted access');
/**
* Form Rule class for the Joomla Platform.
*
* @since 1.7.0
*/
class JFormRuleACFRequired extends FormRule
{
/**
* Method to test the calendar value for a valid parts.
*
* @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object.
* @param mixed $value The form field value to validate.
* @param string $group The field name group control value. This acts as an array container for the field.
* For example if the field has name="foo" and the group value is set to "bar" then the
* full field name would end up being "bar[foo]".
* @param Registry $input An optional Registry object with the entire data set to validate against the entire form.
* @param Form $form The form object for which the field is being tested.
*
* @return boolean True if the value is valid, false otherwise.
*
* @since 3.7.0
*/
public function test(SimpleXMLElement $element, $value, $group = null, \Joomla\Registry\Registry $input = NULL, \Joomla\CMS\Form\Form $form = NULL)
{
// If the field is empty and not required, the field is valid.
$required = ((string) $element['required'] == 'true' || (string) $element['required'] == 'required');
if (!$required && empty($value))
{
return true;
}
if (!empty($value))
{
return true;
}
return false;
}
}

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);
}
}

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
ACF="Advanced Custom Fields"
PLG_SYSTEM_ACF="Sistema - Advanced Custom Fields (ACF)"
PLG_SYSTEM_ACF_DESC="Utilitza el connector Advanced Custom Fields per dotar-te de control total de les dades dels teus camps personalitzats Joomla!"
ACF_RETURN_VALUE="Valor de retorn"
ACF_RETURN_VALUE_DESC="Especifica el valor de retorn a la part pública"
; ACF_ASSIGNMENTS_DESC="If enabled, a tab called 'Display Conditions' will appear in the Field editing page. With the Display Conditions you can filter the fields displayed on the front-end by Menu Items, Date, Device, URLs, Domain Referrer, User Groups, Country and much more."
ACF_MISSING_FIELD="Trobes a faltar un camp personalitzat?"
ACF_MISSING_FIELD_DESC="Fes-m'ho saber i estaré encantat d'incloure'l a la col·lecció d'Advanced Custom Fields."
ACF_FIELDS_COLLECTION="Col·lecció de camps"
ACF_METADATA="Metadades"
ACF_CONTROLS="Controls"
ACF_CONTROLS_DESC="Especifica els controls de l'usuari que s'haurien de mostrar (com el botó de reproduir/pausa, etc)."
ACF_PRELOAD="Precàrrega"
ACF_PRELOAD_DESC="Especifica si (i com) s'hauria de carregar quan carrega la pàgina"
ACF_MUTED="Silenciat"
ACF_MUTED_DESC="Especifica si s'hauria de silenciar la sortida d'àudio"
ACF_LOOP="Bucle"
ACF_LOOP_DESC="Especifica si la reproducció ha de tornar a començar cada vegada que acaba"
ACF_AUTOPLAY="Reproducció automàtica"
ACF_AUTOPLAY_DESC="Especifica si començarà a reproduir-se l'arxiu multimèdia tan aviat com estigui disponible"
ACF_UNSUPPORTED_TAG="El teu navegador no soporta l'etiqueta %s."
ACF_WIDTH_DESC="Estableix l'amplada del reproductor"
ACF_HEIGHT_DESC="Estableix l'alçada del reproductor"
ACF_ALLOWFULLSCREEN="Permetre pantalla completa"
ACF_ALLOWFULLSCREEN_DESC="Permet que es reprodueixi el vídeo en pantalla completa."
ACF_FIXED="Fixat"
ACF_RESPONSIVE="Responsiu"
ACF_VIDEO_SIZE="Mida del vídeo"
ACF_VIDEO_SIZE_DESC="Estableix la mida del vídeo inserit.<br><br><strong>Fixa</strong>: El vídeo s'inserirà a una mida fixa.<br><strong>Responsiu</strong>: El vídeo s'inserirà de manera responsiva, per tant s'adaptarà a l'alçada i amplada del seu contenidor."
; ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! Content Page Types"
; ACF_FIELD_PREVIEWER="Field Previewer"
; ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Preview how this custom field will look like on your site."
; ACF_ACF_OPTIONS="ACF Options"
; ACF_CUSTOM_CSS="Custom CSS"
; ACF_CUSTOM_CSS_DESC="Apply custom CSS on your site when this custom field is displayed."
; ACF_FIELD_LAYOUT_OVERRIDES="Select which layout to use when this custom field is displayed on your site."
; ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="To create an override for <b>%s</b>, copy the <code>%s</code> layout file to <code>%s</code>.<br><br>You can read more here: <a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>How to create an alternative layout for Advanced Custom Fields</a>"
; ACF_WIDGET_LAYOUT="Widget Layout"
; ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="To ensure that the Display Conditions function correctly on the User Profile page, the 'System - Fields' plugin should be positioned before the 'System - Advanced Custom Fields (ACF)' plugin. By adjusting the plugin ordering as described, you'll resolve this warning."
; ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Please save the custom field first in order to select a layout."
; ACF_INVALID_EMAIL="Invalid email address"

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
ACF="Avanceret brugerdefinerede felter"
PLG_SYSTEM_ACF="System - Avancerede brugerdefinerede felter (ACF)"
PLG_SYSTEM_ACF_DESC="Anvend plugin'et Avancerede brugerdefinerede felter til at tage fuld kontorl over din Joomla brugerdefinerede feltdata."
ACF_RETURN_VALUE="Returværdi"
ACF_RETURN_VALUE_DESC="Angiv returværdien i frontend"
ACF_ASSIGNMENTS_DESC="Hvis aktiveret, så vil en fane med navnet 'Visningsbetingelser' blive vist op feltredigeringssiden. Med visningsbetingelser kan du filtrere felterne der vises i frontend efter menupunkter, dato, apparat, URLer, domænehenviser, brugergrupper, land og meget mere."
ACF_MISSING_FIELD="Mangler du et brugerdefineret felt?"
ACF_MISSING_FIELD_DESC="Lad mig endelig vide det og jeg vil være glad for at inkludere i Avancerede brugerdefinerede felter. "
ACF_FIELDS_COLLECTION="Feltsamling"
ACF_METADATA="Metadata"
ACF_CONTROLS="Knapper"
ACF_CONTROLS_DESC="Specificerer at afspiller-knapper skal vises (såsom en afspil/pause knap etc)."
ACF_PRELOAD="Præindlæs"
ACF_PRELOAD_DESC="Specificerer om og hvordan videoen skal indlæses når siden indlæser"
ACF_MUTED="Muted"
ACF_MUTED_DESC="Specificerer at audio outputtet fra videoen skal være muted"
ACF_LOOP="Loop"
ACF_LOOP_DESC="Specificerer at afspilleren vil starte forfra, hver gang den er færdig"
ACF_AUTOPLAY="Auto afspil"
ACF_AUTOPLAY_DESC="Specificerer at mediefilen vil starte med at afspille så snart den er klar"
ACF_UNSUPPORTED_TAG="Din browser understøtter ikke %s tagget."
ACF_WIDTH_DESC="Sætter bredden på afspilleren"
ACF_HEIGHT_DESC="Sætter højden på afspillerenthe height of the player"
ACF_ALLOWFULLSCREEN="Tillad fuld skærm"
ACF_ALLOWFULLSCREEN_DESC="Tillad at videoen afspilles i fuldskærmstilstand."
ACF_FIXED="Fast"
ACF_RESPONSIVE="Responsiv"
ACF_VIDEO_SIZE="Viedostørrelse"
ACF_VIDEO_SIZE_DESC="Angiv størrelsen på den indlejrede video.<br><br><strong>Fast</strong>: Video vil blive indlejret med en fast størrelse.<br><strong>Responsiv</strong>: Videon vil blive indlejret responsivt, så at størrelsen tilpasser sig til højden og bredden at dets beholder."
ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! indholdsside typer"
ACF_FIELD_PREVIEWER="Felt forhåndsviser"
ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Forhåndsvise hvordan dette brugerdefinerede felt vil se ud på dit websted."
ACF_ACF_OPTIONS="ACF indstillinger"
ACF_CUSTOM_CSS="Brugerdefineret CSS"
ACF_CUSTOM_CSS_DESC="Anvend brugerdefineret CSS på dit websted når dette brugerdefinerede felt vises."
ACF_FIELD_LAYOUT_OVERRIDES="Vælg hvilket layout der skal anvendes når dette brugerdefinerede felt bliver vist på dit websted."
ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="For at oprette en overskrivning for <b>%s</b>, så kopier layout filen <code>%s</code> til <code>%s</code>.<br><br>Du kan læse mere her: <a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>Hvordan oprettes et alternativt layout til Advanced Custom Fields</a>"
ACF_WIDGET_LAYOUT="Widget layout"
; ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="To ensure that the Display Conditions function correctly on the User Profile page, the 'System - Fields' plugin should be positioned before the 'System - Advanced Custom Fields (ACF)' plugin. By adjusting the plugin ordering as described, you'll resolve this warning."
; ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Please save the custom field first in order to select a layout."
; ACF_INVALID_EMAIL="Invalid email address"

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
ACF="Erweiterte benutzerdefinierte Felder"
PLG_SYSTEM_ACF="System - Erweiterte benutzerdefinierte Felder (ACF)"
PLG_SYSTEM_ACF_DESC="Verwenden Sie das Plugin\" Erweiterte benutzerdefinierte Felder \", um die vollständige Kontrolle über Ihre benutzerdefinierten Joomla-Felddaten zu erlangen."
ACF_RETURN_VALUE="Rückgabewert"
ACF_RETURN_VALUE_DESC="Rückgabewert im Frontend angeben"
; ACF_ASSIGNMENTS_DESC="If enabled, a tab called 'Display Conditions' will appear in the Field editing page. With the Display Conditions you can filter the fields displayed on the front-end by Menu Items, Date, Device, URLs, Domain Referrer, User Groups, Country and much more."
ACF_MISSING_FIELD="Vermissen Sie ein benutzerdefiniertes Feld?"
ACF_MISSING_FIELD_DESC="Bitte lassen Sie es mich wissen, und ich bin froh, die Sammlung\" Erweiterte benutzerdefinierte Felder \"hinzuzufügen."
ACF_FIELDS_COLLECTION="Feldsammlung"
ACF_METADATA="Metadaten"
ACF_CONTROLS="Steuerelemente"
ACF_CONTROLS_DESC="Gibt an, dass die Player-Steuerelemente angezeigt werden sollen (z. B. eine Wiedergabe- / Pausentaste usw.)."
ACF_PRELOAD="Vorladen"
ACF_PRELOAD_DESC="Gibt an, ob und wie das Video beim Laden der Seite geladen werden soll."
ACF_MUTED="Stumm geschaltet"
ACF_MUTED_DESC="Gibt an, dass die Audioausgabe des Videos stummgeschaltet werden soll"
ACF_LOOP="Schleife"
ACF_LOOP_DESC="Gibt an, dass der Player nach jedem Beenden erneut gestartet wird."
ACF_AUTOPLAY="Automatische Wiedergabe"
ACF_AUTOPLAY_DESC="Gibt an, dass die Mediendatei abgespielt wird, sobald sie fertig ist."
ACF_UNSUPPORTED_TAG="Ihr Browser unterstützt das %s-Tag nicht."
ACF_WIDTH_DESC="Legt die Breite des Players fest"
ACF_HEIGHT_DESC="Legt die Höhe des Players fest"
ACF_ALLOWFULLSCREEN="Vollbild zulassen"
ACF_ALLOWFULLSCREEN_DESC="Das Video kann im Vollbildmodus abgespielt werden."
ACF_FIXED="Behoben"
ACF_RESPONSIVE="Responsive"
ACF_VIDEO_SIZE="Videogröße"
ACF_VIDEO_SIZE_DESC="Legen Sie die Größe des eingebetteten Videos fest. <br> <br> <strong> Fest </strong>: Das Video wird in einer festen Größe eingebettet. <br> <strong> Responsive </strong>: Das Video wird reaktionsschnell eingebettet, sodass es sich an die Höhe und Breite seines Containers anpasst. "
; ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! Content Page Types"
; ACF_FIELD_PREVIEWER="Field Previewer"
; ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Preview how this custom field will look like on your site."
; ACF_ACF_OPTIONS="ACF Options"
; ACF_CUSTOM_CSS="Custom CSS"
; ACF_CUSTOM_CSS_DESC="Apply custom CSS on your site when this custom field is displayed."
; ACF_FIELD_LAYOUT_OVERRIDES="Select which layout to use when this custom field is displayed on your site."
; ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="To create an override for <b>%s</b>, copy the <code>%s</code> layout file to <code>%s</code>.<br><br>You can read more here: <a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>How to create an alternative layout for Advanced Custom Fields</a>"
; ACF_WIDGET_LAYOUT="Widget Layout"
; ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="To ensure that the Display Conditions function correctly on the User Profile page, the 'System - Fields' plugin should be positioned before the 'System - Advanced Custom Fields (ACF)' plugin. By adjusting the plugin ordering as described, you'll resolve this warning."
; ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Please save the custom field first in order to select a layout."
; ACF_INVALID_EMAIL="Invalid email address"

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
; ACF="Advanced Custom Fields"
; PLG_SYSTEM_ACF="System - Advanced Custom Fields (ACF)"
; PLG_SYSTEM_ACF_DESC="Use the Advanced Custom Fields plugin to take full control of your Joomla custom field data."
; ACF_RETURN_VALUE="Return Value"
; ACF_RETURN_VALUE_DESC="Specify the return value on front-end"
; ACF_ASSIGNMENTS_DESC="If enabled, a tab called 'Display Conditions' will appear in the Field editing page. With the Display Conditions you can filter the fields displayed on the front-end by Menu Items, Date, Device, URLs, Domain Referrer, User Groups, Country and much more."
; ACF_MISSING_FIELD="Are you missing a custom field?"
; ACF_MISSING_FIELD_DESC="Please, do let me know and I'll be glad to include it the Advanced Custom Fields collection. "
; ACF_FIELDS_COLLECTION="Fields Collection"
; ACF_METADATA="Metadata"
; ACF_CONTROLS="Controls"
; ACF_CONTROLS_DESC="Specifies that player controls should be displayed (such as a play/pause button etc)."
; ACF_PRELOAD="Preload"
; ACF_PRELOAD_DESC="Specifies if and how the video should be loaded when the page loads"
; ACF_MUTED="Muted"
; ACF_MUTED_DESC="Specifies that the audio output of the video should be muted"
; ACF_LOOP="Loop"
; ACF_LOOP_DESC="Specifies that the player will start over again, every time it is finished"
; ACF_AUTOPLAY="Auto Play"
; ACF_AUTOPLAY_DESC="Specifies that the media file will start playing as soon as it is ready"
; ACF_UNSUPPORTED_TAG="Your browser does not support the %s tag."
; ACF_WIDTH_DESC="Sets the width of the player"
; ACF_HEIGHT_DESC="Sets the height of the player"
; ACF_ALLOWFULLSCREEN="Allow Fullscreen"
; ACF_ALLOWFULLSCREEN_DESC="Allow the video to be played in fullscreen mode."
ACF_FIXED="Διορθώθηκε"
; ACF_RESPONSIVE="Responsive"
; ACF_VIDEO_SIZE="Video Size"
; ACF_VIDEO_SIZE_DESC="Set the size of the embedded video.<br><br><strong>Fixed</strong>: The video will be embedded at a fixed size.<br><strong>Responsive</strong>: The video will be embedded responsively, so it will adapt to the height and width of its container."
; ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! Content Page Types"
; ACF_FIELD_PREVIEWER="Field Previewer"
; ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Preview how this custom field will look like on your site."
; ACF_ACF_OPTIONS="ACF Options"
; ACF_CUSTOM_CSS="Custom CSS"
; ACF_CUSTOM_CSS_DESC="Apply custom CSS on your site when this custom field is displayed."
; ACF_FIELD_LAYOUT_OVERRIDES="Select which layout to use when this custom field is displayed on your site."
; ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="To create an override for <b>%s</b>, copy the <code>%s</code> layout file to <code>%s</code>.<br><br>You can read more here: <a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>How to create an alternative layout for Advanced Custom Fields</a>"
; ACF_WIDGET_LAYOUT="Widget Layout"
; ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="To ensure that the Display Conditions function correctly on the User Profile page, the 'System - Fields' plugin should be positioned before the 'System - Advanced Custom Fields (ACF)' plugin. By adjusting the plugin ordering as described, you'll resolve this warning."
; ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Please save the custom field first in order to select a layout."
; ACF_INVALID_EMAIL="Invalid email address"

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
ACF="Advanced Custom Fields"
PLG_SYSTEM_ACF="System - Advanced Custom Fields (ACF)"
PLG_SYSTEM_ACF_DESC="Use the Advanced Custom Fields plugin to take full control of your Joomla custom field data."
ACF_RETURN_VALUE="Return Value"
ACF_RETURN_VALUE_DESC="Specify the return value on front-end"
ACF_ASSIGNMENTS_DESC="If enabled, a tab called 'Display Conditions' will appear in the Field editing page. With the Display Conditions you can filter the fields displayed on the front-end by Menu Items, Date, Device, URLs, Domain Referrer, User Groups, Country and much more."
ACF_MISSING_FIELD="Are you missing a custom field?"
ACF_MISSING_FIELD_DESC="Please, do let me know and I'll be glad to include it the Advanced Custom Fields collection. "
ACF_FIELDS_COLLECTION="Fields Collection"
ACF_METADATA="Metadata"
ACF_CONTROLS="Controls"
ACF_CONTROLS_DESC="Specifies that player controls should be displayed (such as a play/pause button etc)."
ACF_PRELOAD="Preload"
ACF_PRELOAD_DESC="Specifies if and how the video should be loaded when the page loads"
ACF_MUTED="Muted"
ACF_MUTED_DESC="Specifies that the audio output of the video should be muted"
ACF_LOOP="Loop"
ACF_LOOP_DESC="Specifies that the player will start over again, every time it is finished"
ACF_AUTOPLAY="Auto Play"
ACF_AUTOPLAY_DESC="Specifies that the media file will start playing as soon as it is ready"
ACF_UNSUPPORTED_TAG="Your browser does not support the %s tag."
ACF_WIDTH_DESC="Sets the width of the player"
ACF_HEIGHT_DESC="Sets the height of the player"
ACF_ALLOWFULLSCREEN="Allow Fullscreen"
ACF_ALLOWFULLSCREEN_DESC="Allow the video to be played in fullscreen mode."
ACF_FIXED="Fixed"
ACF_RESPONSIVE="Responsive"
ACF_VIDEO_SIZE="Video Size"
ACF_VIDEO_SIZE_DESC="Set the size of the embedded video.<br /><br /><strong>Fixed</strong>: The video will be embedded at a fixed size.<br /><strong>Responsive</strong>: The video will be embedded responsively, so it will adapt to the height and width of its container."
ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! Content Page Types"
ACF_FIELD_PREVIEWER="Field Previewer"
ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Preview how this custom field will look like on your site."
ACF_ACF_OPTIONS="ACF Options"
ACF_CUSTOM_CSS="Custom CSS"
ACF_CUSTOM_CSS_DESC="Apply custom CSS on your site when this custom field is displayed."
ACF_FIELD_LAYOUT_OVERRIDES="Select which layout to use when this custom field is displayed on your site."
ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="To create an override for <b>%s</b>, copy the <code>%s</code> layout file to <code>%s</code>.<br/><br/>You can read more here: <a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>How to create an alternative layout for Advanced Custom Fields</a>"
ACF_WIDGET_LAYOUT="Widget Layout"
ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="To ensure that the Display Conditions function correctly on the User Profile page, the 'System - Fields' plugin should be positioned before the 'System - Advanced Custom Fields (ACF)' plugin. By adjusting the plugin ordering as described, you'll resolve this warning."
ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Please save the custom field first in order to select a layout."
ACF_INVALID_EMAIL="Invalid email address"

View File

@ -0,0 +1,9 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
PLG_SYSTEM_ACF="System - Advanced Custom Fields (ACF)"
PLG_SYSTEM_ACF_DESC="Use the Advanced Custom Fields plugin to take full control of your Joomla custom field data."

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
ACF="Campos Personalizados Avanzados"
PLG_SYSTEM_ACF="Sistema - Campos Personalizados Avanzados (ACF)"
PLG_SYSTEM_ACF_DESC="Utilice el complemento Campos Personalizados Avanzados para tomar el control total de los datos de sus campos personalizados de Joomla."
ACF_RETURN_VALUE="Valor de Retorno "
ACF_RETURN_VALUE_DESC="Especifique el valor de retorno en el front-end"
ACF_ASSIGNMENTS_DESC="Si está habilitado, aparecerá una pestaña llamada 'Condiciones de visualización' en la página de edición de campo. Con las Condiciones de visualización, puede filtrar los campos que se muestran en el front-end por Elementos de menú, Fecha, Dispositivo, URL, Referencia de dominio, Grupos de usuarios, País y mucho más."
ACF_MISSING_FIELD="¿Le falta un campo personalizado?"
ACF_MISSING_FIELD_DESC="Por favor, hágamelo saber y estaré encantado de incluirlo en la colección de campos personalizados avanzados."
ACF_FIELDS_COLLECTION="Colección de Campos"
ACF_METADATA="Metadatos"
ACF_CONTROLS="Controles"
ACF_CONTROLS_DESC="Especifica que se deben mostrar los controles del reproductor (como un botón de reproducción/pausa, etc.)."
ACF_PRELOAD="Precarga"
ACF_PRELOAD_DESC="Especifica si y cómo se debe cargar el video cuando se carga la página"
ACF_MUTED="Silenciar"
ACF_MUTED_DESC="Especifica que la salida de audio del video debe silenciarse"
ACF_LOOP="Bucle"
ACF_LOOP_DESC="Especifica que el reproductor comenzará de nuevo, cada vez que termine"
ACF_AUTOPLAY="Auto-reproducción"
ACF_AUTOPLAY_DESC="Especifica que el archivo multimedia comenzará a reproducirse tan pronto como esté listo"
ACF_UNSUPPORTED_TAG="Su navegador no admite la etiqueta %s."
ACF_WIDTH_DESC="Establece el ancho del reproductor"
ACF_HEIGHT_DESC="Establece la altura del reproductor."
ACF_ALLOWFULLSCREEN="Permitir pantalla completa"
ACF_ALLOWFULLSCREEN_DESC="Permita que el video se reproduzca en modo de pantalla completa."
ACF_FIXED="Fijo"
ACF_RESPONSIVE="Adaptativo"
ACF_VIDEO_SIZE="Tamaño del Video"
ACF_VIDEO_SIZE_DESC="Establezca el tamaño del video enbebido.<br><br><strong>Fijo</strong>:El video se incrustará en un tamaño fijo.<br><strong>Adaptativo</strong>: El video se incrustará de forma receptiva, por lo que se adaptará a la altura y el ancho de su contenedor."
ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! Tipos de Página de Contenido"
ACF_FIELD_PREVIEWER="Vista Previa del Campo"
ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Obtenga una vista previa de cómo se verá este campo personalizado en su sitio."
ACF_ACF_OPTIONS="Opciones de ACF"
ACF_CUSTOM_CSS="Personalizar CSS"
ACF_CUSTOM_CSS_DESC="Aplique CSS personalizado en su sitio cuando se muestre este campo personalizado."
ACF_FIELD_LAYOUT_OVERRIDES="Seleccione qué diseño usar cuando este campo personalizado se muestre en su sitio."
ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="Para crear una anulación para <b>%s</b>, copie el <code>%s</code> archivo de diseño para <code>%s</code>.<br><br>Puede leer más aquí:<a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>Cómo crear un diseño alternativo para campos personalizados avanzados</a>"
ACF_WIDGET_LAYOUT="Diseño de widgets"
ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="Para garantizar que las Condiciones de visualización funcionen correctamente en la página Perfil de usuario, el complemento 'Sistema - Campos' debe colocarse antes del complemento 'Sistema - Campos personalizados avanzados (ACF)'. Al ajustar el orden de los complementos como se describe, resolverá esta advertencia."
ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Primero guarde el campo personalizado para seleccionar un diseño."
ACF_INVALID_EMAIL="Dirección de correo electrónico no válida"

View File

@ -0,0 +1,9 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
PLG_SYSTEM_ACF="Sistema - Campos Personalizados Avanzados (ACF)"
PLG_SYSTEM_ACF_DESC="Utilice el complemento Campos Personalizados Avanzados para tomar el control total de los datos de sus campos personalizados de Joomla."

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
; ACF="Advanced Custom Fields"
; PLG_SYSTEM_ACF="System - Advanced Custom Fields (ACF)"
PLG_SYSTEM_ACF_DESC="Utilisez le plugin Advanced Custom Fields pour prendre le contrôle total de vos données de champ personnalisé Joomla."
ACF_RETURN_VALUE="Retourner la valeur"
ACF_RETURN_VALUE_DESC="Spécifier la valeur de retour sur le front-end"
; ACF_ASSIGNMENTS_DESC="If enabled, a tab called 'Display Conditions' will appear in the Field editing page. With the Display Conditions you can filter the fields displayed on the front-end by Menu Items, Date, Device, URLs, Domain Referrer, User Groups, Country and much more."
ACF_MISSING_FIELD="Il vous manque un champ personnalisé ?"
ACF_MISSING_FIELD_DESC="S'il vous plaît, faites-le moi savoir et je serai heureux de l'inclure dans la collection Advanced Custom Fields."
ACF_FIELDS_COLLECTION="Ensemble de champs"
ACF_METADATA="Méta-données"
ACF_CONTROLS="Commandes"
ACF_CONTROLS_DESC="Spécifie si les contrôles du lecteur doivent être affichés (tels que les boutons Lecture/Pause, etc)."
ACF_PRELOAD="Préchargement"
ACF_PRELOAD_DESC="Spécifie si et comment la vidéo est chargée une fois la page chargée"
ACF_MUTED="Muté"
ACF_MUTED_DESC="Spécifie que le son sortant de la vidéo est muté"
ACF_LOOP="Boucle"
ACF_LOOP_DESC="Spécifie que la lecture recommence a chaque fois qu'il a terminé"
ACF_AUTOPLAY="Lecture automatique"
ACF_AUTOPLAY_DESC="Spécifie que le fichier multimédia commencera à être lu dès qu'il sera prêt"
ACF_UNSUPPORTED_TAG="Votre navigateur ne supporte pas le tag %s."
ACF_WIDTH_DESC="Définit la largeur du lecteur"
ACF_HEIGHT_DESC="Définit la hauteur du lecteur"
ACF_ALLOWFULLSCREEN="Autoriser le plein écran"
ACF_ALLOWFULLSCREEN_DESC="Autorise la vidéo à être jouer en mode plein-écran."
; ACF_FIXED="Fixed"
; ACF_RESPONSIVE="Responsive"
; ACF_VIDEO_SIZE="Video Size"
; ACF_VIDEO_SIZE_DESC="Set the size of the embedded video.<br><br><strong>Fixed</strong>: The video will be embedded at a fixed size.<br><strong>Responsive</strong>: The video will be embedded responsively, so it will adapt to the height and width of its container."
; ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! Content Page Types"
; ACF_FIELD_PREVIEWER="Field Previewer"
; ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Preview how this custom field will look like on your site."
; ACF_ACF_OPTIONS="ACF Options"
; ACF_CUSTOM_CSS="Custom CSS"
; ACF_CUSTOM_CSS_DESC="Apply custom CSS on your site when this custom field is displayed."
; ACF_FIELD_LAYOUT_OVERRIDES="Select which layout to use when this custom field is displayed on your site."
; ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="To create an override for <b>%s</b>, copy the <code>%s</code> layout file to <code>%s</code>.<br><br>You can read more here: <a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>How to create an alternative layout for Advanced Custom Fields</a>"
; ACF_WIDGET_LAYOUT="Widget Layout"
; ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="To ensure that the Display Conditions function correctly on the User Profile page, the 'System - Fields' plugin should be positioned before the 'System - Advanced Custom Fields (ACF)' plugin. By adjusting the plugin ordering as described, you'll resolve this warning."
; ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Please save the custom field first in order to select a layout."
; ACF_INVALID_EMAIL="Invalid email address"

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
ACF="Advanced Custom Fields"
PLG_SYSTEM_ACF="Sistema - Advanced Custom Fields (ACF)"
PLG_SYSTEM_ACF_DESC="Utilizza il plugin Advanced Custom Fields per acquisire il pieno controllo dei dati dei campi personalizzati di Joomla."
ACF_RETURN_VALUE="Valore di ritorno"
ACF_RETURN_VALUE_DESC="Specifica il valore per il front-end"
; ACF_ASSIGNMENTS_DESC="If enabled, a tab called 'Display Conditions' will appear in the Field editing page. With the Display Conditions you can filter the fields displayed on the front-end by Menu Items, Date, Device, URLs, Domain Referrer, User Groups, Country and much more."
ACF_MISSING_FIELD="Non trovi un campo personalizzato?"
ACF_MISSING_FIELD_DESC="Per favore, fammelo sapere e sarò lieto di includerlo nella collezione di Advanced Custom Fields"
ACF_FIELDS_COLLECTION="Collezione di campi "
ACF_METADATA="Metadati"
ACF_CONTROLS="Controlli"
ACF_CONTROLS_DESC="Specifica che i controlli del lettore devono essere visualizzati (come il pulsante di riproduzione/pausa, ecc.)."
ACF_PRELOAD="Precarica"
ACF_PRELOAD_DESC="Specifica se e come il video deve essere caricato quando viene caricata la pagina"
ACF_MUTED="Audio disattivato"
ACF_MUTED_DESC="Specifica che l'uscita audio del video deve essere disattivata"
ACF_LOOP="Ciclo continuo"
ACF_LOOP_DESC="Specifica che il lettore ricomincerà da capo ogni volta che sarà terminato"
ACF_AUTOPLAY="Riproduzione automatica"
ACF_AUTOPLAY_DESC="Specifica che il file multimediale inizierà la riproduzione non appena sarà pronto"
ACF_UNSUPPORTED_TAG="Il tuo browser non supporta il tag %s."
ACF_WIDTH_DESC="Imposta la larghezza del lettore"
ACF_HEIGHT_DESC="Impsta l'altezza del lettore"
ACF_ALLOWFULLSCREEN="Permetti schermo intero"
ACF_ALLOWFULLSCREEN_DESC="Consenti la riproduzione del video a schermo intero."
ACF_FIXED="Fisso"
ACF_RESPONSIVE="Responsive"
ACF_VIDEO_SIZE="Dimensione video"
ACF_VIDEO_SIZE_DESC="Imposta la dimensione del video incorporato.<br><br><strong>Fisso</strong>: il video verrà incorporato a una dimensione fissa.<br><strong>Responsive</strong>: il video verrà incorporato in modo responsive, quindi si adatterà all'altezza e alla larghezza del suo contenitore."
; ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! Content Page Types"
; ACF_FIELD_PREVIEWER="Field Previewer"
; ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Preview how this custom field will look like on your site."
; ACF_ACF_OPTIONS="ACF Options"
; ACF_CUSTOM_CSS="Custom CSS"
; ACF_CUSTOM_CSS_DESC="Apply custom CSS on your site when this custom field is displayed."
; ACF_FIELD_LAYOUT_OVERRIDES="Select which layout to use when this custom field is displayed on your site."
; ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="To create an override for <b>%s</b>, copy the <code>%s</code> layout file to <code>%s</code>.<br><br>You can read more here: <a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>How to create an alternative layout for Advanced Custom Fields</a>"
; ACF_WIDGET_LAYOUT="Widget Layout"
; ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="To ensure that the Display Conditions function correctly on the User Profile page, the 'System - Fields' plugin should be positioned before the 'System - Advanced Custom Fields (ACF)' plugin. By adjusting the plugin ordering as described, you'll resolve this warning."
; ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Please save the custom field first in order to select a layout."
; ACF_INVALID_EMAIL="Invalid email address"

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
ACF="Advanced Custom Fields"
PLG_SYSTEM_ACF="Systeem - Advanced Custom Fields (ACF)"
PLG_SYSTEM_ACF_DESC="Gebruik de Advanced Custom Fields plugin om volledige controle te krijgen over de aangepaste veldgegevens van Joomla."
ACF_RETURN_VALUE="Winstwaarde"
ACF_RETURN_VALUE_DESC="Geef de retourwaarde op aan de front-end"
; ACF_ASSIGNMENTS_DESC="If enabled, a tab called 'Display Conditions' will appear in the Field editing page. With the Display Conditions you can filter the fields displayed on the front-end by Menu Items, Date, Device, URLs, Domain Referrer, User Groups, Country and much more."
ACF_MISSING_FIELD="Mist je nog een aangepast veld?"
ACF_MISSING_FIELD_DESC="Laat het me alsjeblieft weten en ik voeg het graag toe aan de Advanced Custom Fields-collectie."
ACF_FIELDS_COLLECTION="Velden Collectie"
ACF_METADATA="Metadata"
ACF_CONTROLS="Bediening"
ACF_CONTROLS_DESC="Specificeert welke spelerbedieningen zullen worden weergegeven (zoals een afspeel- / pauzeknop enz.)."
ACF_PRELOAD="Vooraf laden"
ACF_PRELOAD_DESC="Geeft aan of en hoe de video zal worden geladen wanneer de pagina wordt geladen"
ACF_MUTED="Gedempt"
ACF_MUTED_DESC="Geeft aan dat de audio-uitvoer van de video zal worden gedempt"
ACF_LOOP="Lus"
ACF_LOOP_DESC="Geeft aan dat de speler elke keer opnieuw zal beginnen als hij klaar is"
ACF_AUTOPLAY="Automatisch Afspelen"
ACF_AUTOPLAY_DESC="Geeft aan dat het mediabestand zal zodra hij gereed is worden afgespeeld "
ACF_UNSUPPORTED_TAG="Jouw browser ondersteunt de tag %s niet."
ACF_WIDTH_DESC="Stelt de breedte van de speler in"
ACF_HEIGHT_DESC="Stelt de hoogte van de speler in"
ACF_ALLOWFULLSCREEN="Volledig Scherm Toestaan"
ACF_ALLOWFULLSCREEN_DESC="Sta toe dat de video op volledig scherm wordt afgespeeld."
ACF_FIXED="Vastgezet"
ACF_RESPONSIVE="Responsive"
ACF_VIDEO_SIZE="Videoformaat"
ACF_VIDEO_SIZE_DESC="Stel de grootte van de ingesloten video in.<br><br><strong>Vast</strong>: de video wordt ingesloten op een vaste grootte.<br><strong>Responsive</strong>: De video wordt responsief ingesloten, zodat deze zich aanpast aan de hoogte en breedte van de container."
; ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! Content Page Types"
; ACF_FIELD_PREVIEWER="Field Previewer"
; ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Preview how this custom field will look like on your site."
; ACF_ACF_OPTIONS="ACF Options"
; ACF_CUSTOM_CSS="Custom CSS"
; ACF_CUSTOM_CSS_DESC="Apply custom CSS on your site when this custom field is displayed."
; ACF_FIELD_LAYOUT_OVERRIDES="Select which layout to use when this custom field is displayed on your site."
; ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="To create an override for <b>%s</b>, copy the <code>%s</code> layout file to <code>%s</code>.<br><br>You can read more here: <a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>How to create an alternative layout for Advanced Custom Fields</a>"
; ACF_WIDGET_LAYOUT="Widget Layout"
; ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="To ensure that the Display Conditions function correctly on the User Profile page, the 'System - Fields' plugin should be positioned before the 'System - Advanced Custom Fields (ACF)' plugin. By adjusting the plugin ordering as described, you'll resolve this warning."
; ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Please save the custom field first in order to select a layout."
; ACF_INVALID_EMAIL="Invalid email address"

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
ACF="Campos Personalizados Avançados"
PLG_SYSTEM_ACF="Sistema - Campos Personalizados Avançados (ACF)"
PLG_SYSTEM_ACF_DESC="Usa o plugin Advanced Custom Fields tomar o controle total de seus dados de campos personalizados do Joomla."
ACF_RETURN_VALUE="Valor de Retorno"
ACF_RETURN_VALUE_DESC="Especifique o valor de retorno no frontend."
ACF_ASSIGNMENTS_DESC="Se ativado, uma guia chamada 'Condições de Exibição' aparecerá na página de edição do campo. Com as Condições de Exibição você pode filtrar os campos exibidos no front-end por Itens de Menu, Data, Dispositivo, URLs, Referenciador de Domínio, Grupos de Usuários, País e muito mais."
ACF_MISSING_FIELD="Falta um campo personalizado?"
ACF_MISSING_FIELD_DESC="Por favor, deixe-me saber e eu ficarei feliz em incluí-lo na coleção do Advanced Custom Fields."
ACF_FIELDS_COLLECTION="Coleção de Campos"
ACF_METADATA="Metadata"
ACF_CONTROLS="Controles"
ACF_CONTROLS_DESC="Especifica que os controles do player devem ser exibidos (como um botão reproduzir/pausar, etc.)."
ACF_PRELOAD="Pré-carregar"
ACF_PRELOAD_DESC="Especifica se, e como o vídeo deve ser carregado quando a página for carregada"
ACF_MUTED="Silenciado"
ACF_MUTED_DESC="Especifica que a saída de áudio do vídeo deve ser silenciada"
ACF_LOOP="Infinito"
ACF_LOOP_DESC="Especifica que o player recomeçará sempre que terminar"
ACF_AUTOPLAY="Reprodução automática"
ACF_AUTOPLAY_DESC="Especifica que o arquivo de mídia começará a ser reproduzido assim que estiver pronto"
ACF_UNSUPPORTED_TAG="Seu navegador não suporta a %stag."
ACF_WIDTH_DESC="Define a largura do player"
ACF_HEIGHT_DESC="Define a altura do player"
ACF_ALLOWFULLSCREEN="Permitir tela cheia"
ACF_ALLOWFULLSCREEN_DESC="Permitir que o vídeo seja reproduzido em modo de tela cheia."
ACF_FIXED="Fixo"
ACF_RESPONSIVE="Responsivo"
ACF_VIDEO_SIZE="Tamanho do vídeo"
ACF_VIDEO_SIZE_DESC="Defina o tamanho do vídeo incorporado.<br><br><strong>Fixo</strong>: o vídeo será incorporado em um tamanho fixo.<br><strong>Responsivo</strong>: O vídeo será incorporado de forma responsiva, para que se adapte à altura e largura do contêiner."
ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! Tipos de páginas de conteúdo"
ACF_FIELD_PREVIEWER="Pré-visualizador de campo"
ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Visualizar a aparência desse campo personalizado no site."
ACF_ACF_OPTIONS="Opções ACF"
ACF_CUSTOM_CSS="CSS personalizado"
ACF_CUSTOM_CSS_DESC="Aplique CSS personalizado no site quando este campo personalizado for exibido."
ACF_FIELD_LAYOUT_OVERRIDES="Selecione qual layout usar quando este campo personalizado for exibido no site."
ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="Para criar uma substituição para<b>%s</b> , copie o <code>%s</code>arquivo de layout para <code>%s</code>. <br><br>Você pode ler mais aqui: <a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>Como criar um layout alternativo para Campos Personalizados Avançados</a>"
ACF_WIDGET_LAYOUT="Esquema de widgets"
; ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="To ensure that the Display Conditions function correctly on the User Profile page, the 'System - Fields' plugin should be positioned before the 'System - Advanced Custom Fields (ACF)' plugin. By adjusting the plugin ordering as described, you'll resolve this warning."
; ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Please save the custom field first in order to select a layout."
; ACF_INVALID_EMAIL="Invalid email address"

View File

@ -0,0 +1,37 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
ACF="Расширенные пользовательские поля "
PLG_SYSTEM_ACF="Система - Расширенные пользовательские поля (ACF)"
PLG_SYSTEM_ACF_DESC="Используйте плагин Advanced Custom Fields, чтобы получить полный контроль над данными пользовательских полей Joomla."
ACF_RETURN_VALUE="Возвращаемое значение"
ACF_RETURN_VALUE_DESC="Указать возвращаемое значение в интерфейсе"
ACF_ASSIGNMENTS="Назначения публикации"
ACF_ASSIGNMENTS_DESC="Если включено, на странице редактирования пользовательских полей появится новая вкладка под названием« Назначения публикации ». С помощью назначений публикации вы можете фильтровать поля, отображаемые в интерфейсе, по пунктам меню, дате, устройству, URL-адресам, рефереру домена. , Группы пользователей, Страна и многое другое. "
ACF_MISSING_FIELD="Вам не хватает настраиваемого поля?"
ACF_MISSING_FIELD_DESC="Пожалуйста, дайте мне знать, и я буду рад включить его в коллекцию Advanced Custom Fields."
ACF_FIELDS_COLLECTION="Коллекция полей"
ACF_METADATA="Метаданные"
ACF_CONTROLS="Управление"
ACF_CONTROLS_DESC="Указывает, что элементы управления плеером должны отображаться (например, кнопка воспроизведения / паузы и т. Д.)."
ACF_PRELOAD="Предзагрузка"
ACF_PRELOAD_DESC="Указывает, нужно ли и как загружать видео при загрузке страницы"
ACF_MUTED="Отключено"
ACF_MUTED_DESC="Указывает, что аудиовыход видео должен быть отключен"
ACF_LOOP="Цикл"
ACF_LOOP_DESC="Указывает, что игрок будет начинать сначала, каждый раз, когда он закончится"
ACF_AUTOPLAY="Автовоспроизведение"
ACF_AUTOPLAY_DESC="Указывает, что медиафайл начнет воспроизводиться, как только он будет готов"
ACF_UNSUPPORTED_TAG="Ваш браузер не поддерживает тег %s."
ACF_WIDTH_DESC="Устанавливает ширину плеера"
ACF_HEIGHT_DESC="Устанавливает высоту игрока"
ACF_ALLOWFULLSCREEN="Разрешить полный экран"
ACF_ALLOWFULLSCREEN_DESC="Разрешить воспроизведение видео в полноэкранном режиме."
ACF_FIXED="Фиксированный"
ACF_RESPONSIVE="Адаптивный"
ACF_VIDEO_SIZE="Размер видео"
ACF_VIDEO_SIZE_DESC="Установить размер встроенного видео. <br /> <br /> <strong> Исправлено </ strong>. Видео будет встроено в фиксированный размер. <br /> <strong> Отзывчивый </ strong> : Видео будет встроено быстро, поэтому оно будет адаптироваться к высоте и ширине контейнера. "

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
ACF="Advanced Custom Fields"
PLG_SYSTEM_ACF="System - Advanced Custom Fields (ACF)"
PLG_SYSTEM_ACF_DESC="Använd Advanced Custom Fields pluginen för att ta full kontroll över dina Joomla anpassade fältdata."
ACF_RETURN_VALUE="Returvärde"
ACF_RETURN_VALUE_DESC="Ange returvärdet i frontend."
; ACF_ASSIGNMENTS_DESC="If enabled, a tab called 'Display Conditions' will appear in the Field editing page. With the Display Conditions you can filter the fields displayed on the front-end by Menu Items, Date, Device, URLs, Domain Referrer, User Groups, Country and much more."
ACF_MISSING_FIELD="Saknar du ett anpassat fält?"
ACF_MISSING_FIELD_DESC="Snälla, låt mig veta så kommer jag gärna att inkludera den i Advanced Custom Fields-samlingen."
ACF_FIELDS_COLLECTION="Fält-samling"
ACF_METADATA="Metadata"
ACF_CONTROLS="Kontroller"
ACF_CONTROLS_DESC="Anger att spelarkontroller ska visas (t.ex. en uppspelning / paus-knapp osv.)."
ACF_PRELOAD="Förladdning"
ACF_PRELOAD_DESC="Anger om och hur videon ska laddas när sidan laddas."
ACF_MUTED="Tyst"
ACF_MUTED_DESC="Anger att ljudet på videon ska stängas av."
ACF_LOOP="Repetera"
ACF_LOOP_DESC="Anger att spelaren ska börja om varje gång den har spelat klart."
ACF_AUTOPLAY="Auto Play"
ACF_AUTOPLAY_DESC="Anger att mediefilen kommer att börja spelas så snart den är klar."
ACF_UNSUPPORTED_TAG="Din webbläsare stöder inte taggen %s."
ACF_WIDTH_DESC="Anger spelarens bredd"
ACF_HEIGHT_DESC="Anger spelarens höjd"
ACF_ALLOWFULLSCREEN="Tillåt helskärm"
ACF_ALLOWFULLSCREEN_DESC="Tillåt att videon spelas upp i helskärmsläge."
ACF_FIXED="Fast"
ACF_RESPONSIVE="Responsiv"
ACF_VIDEO_SIZE="Videons storlek"
ACF_VIDEO_SIZE_DESC="Ange storleken på den inbäddade videon.<br><br><strong>Fast</strong>: Videon kommer att bäddas in i en fast storlek.<br><strong>Responsiv</strong>: Videon kommer att bäddas in responsivt, så den kommer att anpassas till behållarens höjd och bredd."
; ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! Content Page Types"
; ACF_FIELD_PREVIEWER="Field Previewer"
; ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Preview how this custom field will look like on your site."
; ACF_ACF_OPTIONS="ACF Options"
; ACF_CUSTOM_CSS="Custom CSS"
; ACF_CUSTOM_CSS_DESC="Apply custom CSS on your site when this custom field is displayed."
; ACF_FIELD_LAYOUT_OVERRIDES="Select which layout to use when this custom field is displayed on your site."
; ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="To create an override for <b>%s</b>, copy the <code>%s</code> layout file to <code>%s</code>.<br><br>You can read more here: <a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>How to create an alternative layout for Advanced Custom Fields</a>"
; ACF_WIDGET_LAYOUT="Widget Layout"
; ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="To ensure that the Display Conditions function correctly on the User Profile page, the 'System - Fields' plugin should be positioned before the 'System - Advanced Custom Fields (ACF)' plugin. By adjusting the plugin ordering as described, you'll resolve this warning."
; ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Please save the custom field first in order to select a layout."
; ACF_INVALID_EMAIL="Invalid email address"

View File

@ -0,0 +1,9 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
PLG_SYSTEM_ACF="System - Advanced Custom Fields (ACF)"
PLG_SYSTEM_ACF_DESC="Använd Advanced Custom Fields pluginen för att ta full kontroll över dina Joomla anpassade fältdata."

View File

@ -0,0 +1,48 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
; ACF="Advanced Custom Fields"
; PLG_SYSTEM_ACF="System - Advanced Custom Fields (ACF)"
; PLG_SYSTEM_ACF_DESC="Use the Advanced Custom Fields plugin to take full control of your Joomla custom field data."
; ACF_RETURN_VALUE="Return Value"
ACF_RETURN_VALUE_DESC="Ön uçtaki dönüş değeri belirtin"
; ACF_ASSIGNMENTS_DESC="If enabled, a tab called 'Display Conditions' will appear in the Field editing page. With the Display Conditions you can filter the fields displayed on the front-end by Menu Items, Date, Device, URLs, Domain Referrer, User Groups, Country and much more."
; ACF_MISSING_FIELD="Are you missing a custom field?"
; ACF_MISSING_FIELD_DESC="Please, do let me know and I'll be glad to include it the Advanced Custom Fields collection. "
; ACF_FIELDS_COLLECTION="Fields Collection"
; ACF_METADATA="Metadata"
; ACF_CONTROLS="Controls"
; ACF_CONTROLS_DESC="Specifies that player controls should be displayed (such as a play/pause button etc)."
; ACF_PRELOAD="Preload"
; ACF_PRELOAD_DESC="Specifies if and how the video should be loaded when the page loads"
; ACF_MUTED="Muted"
; ACF_MUTED_DESC="Specifies that the audio output of the video should be muted"
; ACF_LOOP="Loop"
; ACF_LOOP_DESC="Specifies that the player will start over again, every time it is finished"
; ACF_AUTOPLAY="Auto Play"
; ACF_AUTOPLAY_DESC="Specifies that the media file will start playing as soon as it is ready"
; ACF_UNSUPPORTED_TAG="Your browser does not support the %s tag."
; ACF_WIDTH_DESC="Sets the width of the player"
; ACF_HEIGHT_DESC="Sets the height of the player"
; ACF_ALLOWFULLSCREEN="Allow Fullscreen"
; ACF_ALLOWFULLSCREEN_DESC="Allow the video to be played in fullscreen mode."
; ACF_FIXED="Fixed"
; ACF_RESPONSIVE="Responsive"
; ACF_VIDEO_SIZE="Video Size"
; ACF_VIDEO_SIZE_DESC="Set the size of the embedded video.<br><br><strong>Fixed</strong>: The video will be embedded at a fixed size.<br><strong>Responsive</strong>: The video will be embedded responsively, so it will adapt to the height and width of its container."
; ACF_ASSIGNMENT_CONTENT_PAGE_TYPES="Joomla! Content Page Types"
; ACF_FIELD_PREVIEWER="Field Previewer"
; ACF_FIELD_PREVIEWER_INFO_ICON_TITLE="Preview how this custom field will look like on your site."
; ACF_ACF_OPTIONS="ACF Options"
; ACF_CUSTOM_CSS="Custom CSS"
; ACF_CUSTOM_CSS_DESC="Apply custom CSS on your site when this custom field is displayed."
; ACF_FIELD_LAYOUT_OVERRIDES="Select which layout to use when this custom field is displayed on your site."
; ACF_OVERRIDE_WIDGET_BASED_FIELD_LAYOUT_DESC="To create an override for <b>%s</b>, copy the <code>%s</code> layout file to <code>%s</code>.<br><br>You can read more here: <a href='https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/how-to-create-an-alternative-layout-for-advanced-custom-fields' target='_blank'>How to create an alternative layout for Advanced Custom Fields</a>"
; ACF_WIDGET_LAYOUT="Widget Layout"
; ACF_USER_DISPLAY_CONDITIONS_WRONG_PLUGIN_ORDER="To ensure that the Display Conditions function correctly on the User Profile page, the 'System - Fields' plugin should be positioned before the 'System - Advanced Custom Fields (ACF)' plugin. By adjusting the plugin ordering as described, you'll resolve this warning."
; ACF_OVERRIDE_WIDGET_LAYOUT_PLEASE_SAVE_FIRST="Please save the custom field first in order to select a layout."
; ACF_INVALID_EMAIL="Invalid email address"

View File

@ -0,0 +1,37 @@
; @package Advanced Custom Fields
; @version 2.8.8 Pro
;
; @author Tassos Marinos - http://www.tassos.gr/joomla-extensions
; @copyright Copyright (c) 2019 Tassos Marinos. All rights reserved.
; @license http://www.tassos.gr
ACF="Розширені спеціальні поля"
PLG_SYSTEM_ACF="Система - розширені спеціальні поля (ACF)"
PLG_SYSTEM_ACF_DESC="Використовуйте плагін Advanced Custom Fields для повного контролю ваших даних спеціального поля Joomla."
ACF_RETURN_VALUE="Повернути значення"
ACF_RETURN_VALUE_DESC="Вкажіть повернене значення на передній частині"
ACF_ASSIGNMENTS="Видавничі завдання"
ACF_ASSIGNMENTS_DESC="Якщо це ввімкнено, на сторінці редагування спеціальних полів з'явиться нова вкладка"_QQ_" Публікаційні призначення "_QQ_". За допомогою завдань публікації ви можете відфільтрувати поля, відображені на передній панелі, за пунктами меню, датою, пристроєм, URL-адресами, доменним посиланням , Групи користувачів, країна та багато іншого "_QQ_""
ACF_MISSING_FIELD="Не вистачає спеціального поля?"
ACF_MISSING_FIELD_DESC="Будь ласка, дайте мені знати, і я буду рада включити його до колекції Advanced Custom Fields."
ACF_FIELDS_COLLECTION="Колекція полів"
ACF_METADATA="Метадані"
ACF_CONTROLS="Управління"
ACF_CONTROLS_DESC="Вказує, що слід відображати елементи керування програвачами (наприклад, кнопка відтворення / паузи тощо)."
ACF_PRELOAD="Попередня завантаження"
ACF_PRELOAD_DESC="Вказує, якщо і як слід завантажувати відео при завантаженні сторінки"
ACF_MUTED="Відключено"
ACF_MUTED_DESC="Вказує, що аудіо вихід відео має бути відключений"
ACF_LOOP="Цикл"
ACF_LOOP_DESC="Вказує, що гравець почнеться знову, щоразу, коли його закінчувати"
ACF_AUTOPLAY="Автоматичне відтворення"
ACF_AUTOPLAY_DESC="Вказує, що медіа-файл почне відтворюватися, як тільки він буде готовий"
ACF_UNSUPPORTED_TAG="Ваш браузер не підтримує тег %s."
ACF_WIDTH_DESC="Встановлює ширину програвача"
ACF_HEIGHT_DESC="Встановлює висоту гравця"
ACF_ALLOWFULLSCREEN="Дозволити повноекранний"
ACF_ALLOWFULLSCREEN_DESC="Дозволити відтворення відео в повноекранному режимі."
ACF_FIXED="Виправлено"
ACF_RESPONSIVE="Чуйний"
ACF_VIDEO_SIZE="Розмір відео"
ACF_VIDEO_SIZE_DESC="Встановити розмір вбудованого відео. <br /> <br /> <strong> Виправлено </strong>: відео буде вставлено у фіксованому розмірі. <br /> <strong> Чуйний </strong> : Відео буде вставлено чуйно, тож воно адаптується до висоти та ширини контейнера "_QQ_""

View File

@ -0,0 +1,129 @@
<?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;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Factory;
use Joomla\Registry\Registry;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Layout\FileLayout;
if (!@include_once(JPATH_PLUGINS . '/system/nrframework/autoload.php'))
{
throw new RuntimeException('Novarain Framework is not installed', 500);
}
if (defined('nrJ4'))
{
HTMLHelper::stylesheet('plg_system_nrframework/joomla4.css', ['relative' => true, 'version' => 'auto']);
} else
{
HTMLHelper::_('behavior.modal');
}
Factory::getDocument()->addStyleDeclaration('
.stars:hover {
text-decoration: none;
}
.icon-star {
color: #fcac0a;
width: ' . (defined('nrJ4') ? '14' : '7') . 'px;
}
');
/**
* Get list of all available fields
*
* @return array
*/
function getFieldsCollection()
{
// Load XML file
$xmlfile = __DIR__ . '/fieldscollection.xml';
if (!is_file($xmlfile))
{
return;
}
if (!$xmlItems = simplexml_load_file($xmlfile))
{
return;
}
$fields = array();
foreach ($xmlItems as $key => $item)
{
$item = (array) $item;
$item = new Registry($item["@attributes"]);
$extensionName = 'acf' . $item->get("name");
$extensionID = NRFramework\Functions::getExtensionID($extensionName, 'fields');
$backEndURL = "index.php?option=com_plugins&task=plugin.edit&extension_id=" . $extensionID;
$url = $item->get("proonly", null) ? NRFramework\Functions::getUTMURL($item->get("url", "https://www.tassos.gr/joomla-extensions/advanced-custom-fields")) : Uri::base() . $backEndURL;
$path = JPATH_PLUGINS . '/fields/acf' . $item->get("name");
NRFramework\Functions::loadLanguage('plg_fields_acf' . $item->get("name"), $path);
$obj = array(
"label" => isset($item['label']) ? $item['label'] : str_replace('ACF - ', '', Text::_('PLG_FIELDS_ACF' . strtoupper($item->get("name")) . '_LABEL')),
"description" => isset($item['description']) ? $item['description'] : Text::_('ACF_' . strtoupper($item->get("name")) . '_DESC'),
"backendurl" => Uri::base() . $backEndURL,
"extensionid" => $extensionID,
"proonly" => $item->get("proonly", null),
"comingsoon" => $item->get("comingsoon", false),
'docurl' => 'https://www.tassos.gr/joomla-extensions/advanced-custom-fields/docs/' . $item->get('doc')
);
$fields[] = $obj;
}
asort($fields);
$layout = new FileLayout('fieldscollection', __DIR__);
return $layout->render($fields);
}
?>
<div class="nr">
<div class="nr-well well">
<h4><?php echo Text::_("NR_INFORMATION") ?></h4>
<p>
<a target="_blank" href="https://www.tassos.gr/joomla-extensions/advanced-custom-fields">
<?php echo Text::_("ACF") ?>
<?php echo NRFramework\Functions::getExtensionVersion("plg_system_acf", true) ?>
</a>
</p>
<p><?php echo Text::_("NR_LIKE_THIS_EXTENSION") ?> <a target="_blank" href="https://extensions.joomla.org/extensions/extension/authoring-a-content/content-construction/advanced-custom-fields/"><?php echo Text::_("NR_LEAVE_A_REVIEW") ?></a>
<a class="stars" target="_blank" href="https://extensions.joomla.org/extensions/extension/authoring-a-content/content-construction/advanced-custom-fields/">
<span class="icon-star"></span>
<span class="icon-star"></span>
<span class="icon-star"></span>
<span class="icon-star"></span>
<span class="icon-star"></span>
</a>
</p>
<?php echo Text::_("NR_NEED_SUPPORT") ?>
<a target="_blank" href="http://www.tassos.gr/contact?extension=Advanced Custom Fields"><?php echo Text::_("NR_DROP_EMAIL") ?></a>
</div>
<!-- Fields Collection -->
<?php echo getFieldsCollection(); ?>
<hr>
<p><?php echo Text::sprintf('NR_COPYRIGHT', '&copy; ' . Date("Y")) ?></p>
</div>

View File

@ -0,0 +1,93 @@
<?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('JPATH_PLATFORM') or die;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
if (!defined('nrJ4'))
{
HTMLHelper::_('behavior.modal');
}
$modalRel = 'rel="{handler: \'iframe\', size: {x: 1000, y: 630}}"';
$product_url = 'https://www.tassos.gr/joomla-extensions/advanced-custom-fields';
?>
<div class="acft">
<table class="table table-striped">
<thead>
<tr>
<th><?php echo Text::_('ACF_FIELDS_COLLECTION') ?></th>
<th width="140px"></th>
</tr>
</thead>
<?php foreach ($displayData as $key => $field) { ?>
<tr>
<td class="acft-text">
<h4><?php echo $field['label'] ?></h4>
<?php echo $field['description'] ?>
</td>
<td class="acft-btn">
<div class="acft-btn">
<?php if ($field['comingsoon']) { ?>
<a class="btn" href="<?php echo $product_url ?>/roadmap" target="_blank">
On the roadmap
</a>
<?php } ?>
<?php if ($field["extensionid"]) { ?>
<a class="btn <?php echo !defined('nrJ4') ? 'modal' : '' ?> btn-outline-secondary btn-sm" <?php echo $modalRel; ?> href="<?php echo $field['backendurl'] ?>">
<span class="icon-options"></span>
</a>
<?php } ?>
<a class="btn btn-outline-secondary btn-sm" href="<?php echo $field['docurl'] ?>" target="_blank">
<span class="icon-help"></span>
</a>
</div>
</td>
</tr>
<?php } ?>
<tr>
<td>
<div><strong><?php echo Text::_("ACF_MISSING_FIELD") ?></strong></div>
<?php echo Text::_("ACF_MISSING_FIELD_DESC") ?>
</td>
<td class="acft-btn">
<a class="btn btn-primary" target="_blank" href="https://www.tassos.gr/contact?extension=Advanced Custom Fields">
<?php echo Text::_("NR_DROP_EMAIL")?>
</a>
</td>
</tr>
</table>
</div>
<style>
.acft-btn {
text-align: right !important;
white-space: nowrap;
}
.acft td, .acft th {
padding:13px;
vertical-align: middle;
}
.acft h4 {
margin:0 0 5px 0;
padding:0;
color:#3071a9;
}
</style>

View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="utf-8"?>
<fields>
<field name="email"
label="Email"
description="Safely display email addresses in the front-end that are unreadbable to spambots."
doc="the-email-field"
/>
<field name="gravatar"
doc="the-gravatar-field"
/>
<field name="country"
doc="the-country-field"
/>
<field name="currency"
doc="the-currency-field"
/>
<field name="url"
doc="the-url-field"
/>
<field name="convertforms"
doc="the-convert-forms-field"
/>
<field name="soundcloud"
doc="the-soundcloud-field"
/>
<field name="telephone"
doc="the-telephone-field"
/>
<field name="iframe"
doc="the-iframe-field"
/>
<field name="progressbar"
doc="the-progress-bar-field"
/>
<field name="truefalse"
doc="the-true-false-field"
/>
<field name="timepicker"
doc="the-timepicker-field"
/>
<field name="downloadbutton"
doc="the-download-button-field"
/>
<field name="html5audio"
doc="the-html5-audio-field"
/>
<field name="qrcode"
doc="the-qr-code-field"
/>
<field name="whatsappctc"
doc="the-whatsapp-click-to-chat-field"
/>
<field name="facebook"
doc="the-facebook-field"
/>
<field name="twitter"
doc="the-twitter-field"
/>
<field name="map"
doc="the-map-field"
/>
<field name="video"
doc="the-video-field"
/>
<!--
Note: Always set a fixed value in the Label and Description properties of
the Pro only fields as the Free version doesn't include them at all,
ending up with untranslated language strings
-->
<field name="address"
label="Address Autocomplete"
description="Display a map with location details such as address, country, city, postal code, state, etc..."
proonly="true"
doc="acf-address-field-get-instant-address-details"
/>
<field name="gallery"
label="Gallery"
description="Create image galleries to share group of pictures on your site."
proonly="true"
doc="the-gallery-field"
/>
<field name="upload"
label="File Upload"
description="Upload any file using a drag &amp; drop file uploader in the back-end and display the uploaded file as a link or image in the front-end."
proonly="true"
doc="how-to-add-a-file-upload-field-in-joomla-forms"
/>
<field name="module"
label="Module Loader"
description="Select any existing Joomla! Module in the back-end and render it in the front-end."
proonly="true"
doc="the-module-field"
/>
<field name="php"
label="PHP"
description="Execute PHP in a Joomla! Custom Field and display a dynamic value in the front-end."
proonly="true"
doc="how-to-run-php-code-in-a-joomla-custom-field"
/>
<field name="paypal"
label="PayPal"
description="Accept donations, allow your shoppers to buy products or subscribe to your services with the PayPal button."
proonly="true"
doc="joomla-paypal-custom-field"
/>
<field name="chainedfields"
label="Chained Fields"
description="Create select fields that dynamically change based on the previous selection."
proonly="true"
doc="create-chained-selects"
/>
<field name="countdown"
label="Countdown"
description="Use a countdown timer to create anticipation and scarcity around upcoming events, creating the feeling of scarcity, anticipation, and drive more sales."
proonly="true"
doc="how-to-add-a-countdown-timer-field"
/>
<field name="articles"
label="Articles"
description="Select and connect articles to each other."
proonly="true"
doc="articles"
/>
<field name="faq"
label="FAQ"
description="Add a Frequently Asked Questions section to your site."
proonly="true"
doc="create-faq-section-joomla"
/>
</fields>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
.acfupload,.cfup-file{font-size:14px}#attrib-conditions{padding:0}.acf-address-field-location-details input[type="text"]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:13px 8px;width:100%}#acfUploadItemEditModal input[type="text"]{width:100%;-webkit-box-sizing:border-box;box-sizing:border-box;height:auto}.acf-countdown-item-edit-wrapper .controls{margin:0 !important}.tf-phone-control{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);border-radius:3px;padding:4px 6px}

View File

@ -0,0 +1,3 @@
.nrtoggle{margin:6px 0}

View File

@ -0,0 +1,3 @@
.acf-responsive-embed{position:relative;padding-bottom:56.25%;height:0;overflow:hidden}.acf-responsive-embed iframe,.acf-responsive-embed object,.acf-responsive-embed embed{position:absolute;top:0;left:0;width:100%;height:100%}

View File

@ -0,0 +1,6 @@
# Block direct PHP access
<Files *.php>
deny from all
</Files>

View File

@ -0,0 +1 @@
<!DOCTYPE html><title></title>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
!function(window,document){"use strict";var helper={asyncScript:function(js_script){document.addEventListener("DOMContentLoaded",function(){window.addEventListener("load",function(){eval(js_script)})})},lazyloadIframes:function(){document.querySelectorAll("iframe.lazyload[data-src]").forEach(function(t){t.setAttribute("src",t.getAttribute("data-src")),t.removeAttribute("data-src")})}};window.ACFHelper=helper}(window,document);

View File

@ -0,0 +1,691 @@
<?php
/**
* Installer Script Helper
*
* @author Tassos Marinos <info@tassos.gr>
* @link http://www.tassos.gr
* @copyright Copyright © 2016 Tassos Marinos All Rights Reserved
* @license http://www.gnu.org/licenses/gpl-3.0.html GNU/GPL
*/
defined('_JEXEC') or die;
use Joomla\CMS\Installer\Installer;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
class PlgSystemAcfInstallerScriptHelper
{
public $name = '';
public $alias = '';
public $extname = '';
public $extension_type = '';
public $plugin_folder = 'system';
public $module_position = 'status';
public $client_id = 1;
public $install_type = 'install';
public $show_message = true;
public $autopublish = true;
public $db = null;
public $app = null;
public $installedVersion;
public function __construct(&$params)
{
$this->extname = $this->extname ?: $this->alias;
$this->db = Factory::getDbo();
$this->app = Factory::getApplication();
$this->installedVersion = $this->getVersion($this->getInstalledXMLFile());
}
/**
* Preflight event
*
* @param string
* @param JAdapterInstance
*
* @return boolean
*/
public function preflight($route, $adapter)
{
if (!in_array($route, array('install', 'update')))
{
return;
}
Factory::getLanguage()->load('plg_system_novaraininstaller', JPATH_PLUGINS . '/system/novaraininstaller');
if ($this->show_message && $this->isInstalled())
{
$this->install_type = 'update';
}
if ($this->onBeforeInstall() === false)
{
return false;
}
}
/**
* Preflight event
*
* @param string
* @param JAdapterInstance
*
* @return boolean
*/
public function postflight($route, $adapter)
{
Factory::getLanguage()->load($this->getPrefix() . '_' . $this->extname, $this->getMainFolder());
if (!in_array($route, array('install', 'update')))
{
return;
}
if ($this->onAfterInstall() === false)
{
return false;
}
if ($route == 'install' && $this->autopublish)
{
$this->publishExtension();
}
if ($this->show_message)
{
$this->addInstalledMessage();
}
Factory::getCache()->clean('com_plugins');
Factory::getCache()->clean('_system');
}
public function isInstalled()
{
if (!is_file($this->getInstalledXMLFile()))
{
return false;
}
$query = $this->db->getQuery(true)
->select('extension_id')
->from('#__extensions')
->where($this->db->quoteName('type') . ' = ' . $this->db->quote($this->extension_type))
->where($this->db->quoteName('element') . ' = ' . $this->db->quote($this->getElementName()));
$this->db->setQuery($query, 0, 1);
$result = $this->db->loadResult();
return empty($result) ? false : true;
}
public function getMainFolder()
{
switch ($this->extension_type)
{
case 'plugin' :
return JPATH_SITE . '/plugins/' . $this->plugin_folder . '/' . $this->extname;
case 'component' :
return JPATH_ADMINISTRATOR . '/components/com_' . $this->extname;
case 'module' :
return JPATH_ADMINISTRATOR . '/modules/mod_' . $this->extname;
case 'library' :
return JPATH_SITE . '/libraries/' . $this->extname;
}
}
public function getInstalledXMLFile()
{
return $this->getXMLFile($this->getMainFolder());
}
public function getCurrentXMLFile()
{
return $this->getXMLFile(__DIR__);
}
public function getXMLFile($folder)
{
switch ($this->extension_type)
{
case 'module' :
return $folder . '/mod_' . $this->extname . '.xml';
default :
return $folder . '/' . $this->extname . '.xml';
}
}
public function foldersExist($folders = array())
{
foreach ($folders as $folder)
{
if (is_dir($folder))
{
return true;
}
}
return false;
}
public function publishExtension()
{
switch ($this->extension_type)
{
case 'plugin' :
$this->publishPlugin();
case 'module' :
$this->publishModule();
}
}
public function publishPlugin()
{
$query = $this->db->getQuery(true)
->update('#__extensions')
->set($this->db->quoteName('enabled') . ' = 1')
->where($this->db->quoteName('type') . ' = ' . $this->db->quote('plugin'))
->where($this->db->quoteName('element') . ' = ' . $this->db->quote($this->extname))
->where($this->db->quoteName('folder') . ' = ' . $this->db->quote($this->plugin_folder));
$this->db->setQuery($query);
$this->db->execute();
}
public function publishModule()
{
// Get module id
$query = $this->db->getQuery(true)
->select('id')
->from('#__modules')
->where($this->db->quoteName('module') . ' = ' . $this->db->quote('mod_' . $this->extname))
->where($this->db->quoteName('client_id') . ' = ' . (int) $this->client_id);
$this->db->setQuery($query, 0, 1);
$id = $this->db->loadResult();
if (!$id)
{
return;
}
// check if module is already in the modules_menu table (meaning is is already saved)
$query->clear()
->select('moduleid')
->from('#__modules_menu')
->where($this->db->quoteName('moduleid') . ' = ' . (int) $id);
$this->db->setQuery($query, 0, 1);
$exists = $this->db->loadResult();
if ($exists)
{
return;
}
// Get highest ordering number in position
$query->clear()
->select('ordering')
->from('#__modules')
->where($this->db->quoteName('position') . ' = ' . $this->db->quote($this->module_position))
->where($this->db->quoteName('client_id') . ' = ' . (int) $this->client_id)
->order('ordering DESC');
$this->db->setQuery($query, 0, 1);
$ordering = $this->db->loadResult();
$ordering++;
// publish module and set ordering number
$query->clear()
->update('#__modules')
->set($this->db->quoteName('published') . ' = 1')
->set($this->db->quoteName('ordering') . ' = ' . (int) $ordering)
->set($this->db->quoteName('position') . ' = ' . $this->db->quote($this->module_position))
->where($this->db->quoteName('id') . ' = ' . (int) $id);
$this->db->setQuery($query);
$this->db->execute();
// add module to the modules_menu table
$query->clear()
->insert('#__modules_menu')
->columns(array($this->db->quoteName('moduleid'), $this->db->quoteName('menuid')))
->values((int) $id . ', 0');
$this->db->setQuery($query);
$this->db->execute();
}
public function addInstalledMessage()
{
Factory::getApplication()->enqueueMessage(
Text::sprintf(
Text::_($this->install_type == 'update' ? 'NRI_THE_EXTENSION_HAS_BEEN_UPDATED_SUCCESSFULLY' : 'NRI_THE_EXTENSION_HAS_BEEN_INSTALLED_SUCCESSFULLY'),
'<strong>' . Text::_($this->name) . '</strong>',
'<strong>' . $this->getVersion() . '</strong>',
$this->getFullType()
)
);
}
public function getPrefix()
{
switch ($this->extension_type)
{
case 'plugin';
return Text::_('plg_' . strtolower($this->plugin_folder));
case 'component':
return Text::_('com');
case 'module':
return Text::_('mod');
case 'library':
return Text::_('lib');
default:
return $this->extension_type;
}
}
public function getElementName($type = null, $extname = null)
{
$type = is_null($type) ? $this->extension_type : $type;
$extname = is_null($extname) ? $this->extname : $extname;
switch ($type)
{
case 'component' :
return 'com_' . $extname;
case 'module' :
return 'mod_' . $extname;
case 'plugin' :
default:
return $extname;
}
}
public function getFullType()
{
return Text::_('NRI_' . strtoupper($this->getPrefix()));
}
public function isPro()
{
$versionFile = __DIR__ . "/version.php";
// If version file does not exist we assume a PRO version
if (!is_file($versionFile))
{
return true;
}
// Load version file
require_once $versionFile;
return (bool) $NR_PRO;
}
public function getVersion($file = '')
{
$file = $file ?: $this->getCurrentXMLFile();
if (!is_file($file))
{
return '';
}
$xml = Installer::parseXMLInstallFile($file);
if (!$xml || !isset($xml['version']))
{
return '';
}
return $xml['version'];
}
/**
* Checks wether the extension can be installed or not
*
* @return boolean
*/
public function canInstall()
{
// The extension is not installed yet. Accept Install.
if (!$installed_version = $this->getVersion($this->getInstalledXMLFile()))
{
return true;
}
// Path to extension's version file
$versionFile = $this->getMainFolder() . "/version.php";
$NR_PRO = true;
// If version file does not exist we assume we have a PRO version installed
if (file_exists($versionFile))
{
require_once($versionFile);
}
// The free version is installed. Accept install.
if (!(bool)$NR_PRO)
{
return true;
}
// Current package is a PRO version. Accept install.
if ($this->isPro())
{
return true;
}
// User is trying to update from PRO version to FREE. Do not accept install.
Factory::getLanguage()->load($this->getPrefix() . '_' . $this->extname, __DIR__);
Factory::getApplication()->enqueueMessage(
Text::_('NRI_ERROR_PRO_TO_FREE'), 'error'
);
Factory::getApplication()->enqueueMessage(
html_entity_decode(
Text::sprintf(
'NRI_ERROR_UNINSTALL_FIRST',
'<a href="http://www.tassos.gr/joomla-extensions/' . $this->getUrlAlias() . '" target="_blank">',
'</a>',
Text::_($this->name)
)
), 'error'
);
return false;
}
/**
* Returns the URL alias of the extension.
*
* @return string
*/
private function getUrlAlias()
{
$alias = $this->alias;
switch ($alias)
{
case 'smilepack':
$alias = 'smile-pack';
break;
case 'convertforms':
$alias = 'convert-forms';
break;
case 'rstbox':
$alias = 'engagebox';
break;
case 'gsd':
$alias = 'google-structured-data';
break;
}
// ACF
if ($this->plugin_folder === 'fields' && ($alias === 'acf' || $this->startsWith($alias, 'acf')))
{
$alias = 'advanced-custom-fields';
}
return $alias;
}
/**
* Checks whether string starts with substring.
*
* @param string $string
* @param string $query
*
* @return bool
*/
public static function startsWith($string, $query)
{
return substr($string, 0, strlen($query)) === $query;
}
/**
* Checks if current version is newer than the installed one
* Used for Novarain Framework
*
* @return boolean [description]
*/
public function isNewer()
{
if (!$installed_version = $this->getVersion($this->getInstalledXMLFile()))
{
return true;
}
$package_version = $this->getVersion();
return version_compare($installed_version, $package_version, '<=');
}
/**
* Helper method triggered before installation
*
* @return bool
*/
public function onBeforeInstall()
{
if (!$this->canInstall())
{
return false;
}
}
/**
* Helper method triggered after installation
*/
public function onAfterInstall()
{
}
/**
* Delete files
*
* @param array $folders
*/
public function deleteFiles($files = array())
{
foreach ($files as $key => $file)
{
if (!is_file($file))
{
continue;
}
File::delete($file);
}
}
/**
* Deletes folders
*
* @param array $folders
*/
public function deleteFolders($folders = array())
{
foreach ($folders as $folder)
{
if (!is_dir($folder))
{
continue;
}
Folder::delete($folder);
}
}
public function dropIndex($table, $index)
{
$db = $this->db;
// Check if index exists first
$query = 'SHOW INDEX FROM ' . $db->quoteName('#__' . $table) . ' WHERE KEY_NAME = ' . $db->quote($index);
$db->setQuery($query);
$db->execute();
if (!$db->loadResult())
{
return;
}
// Remove index
$query = 'ALTER TABLE ' . $db->quoteName('#__' . $table) . ' DROP INDEX ' . $db->quoteName($index);
$db->setQuery($query);
$db->execute();
}
public function dropUnwantedTables($tables) {
if (!$tables) {
return;
}
foreach ($tables as $table) {
$query = "DROP TABLE IF EXISTS #__".$this->db->escape($table);
$this->db->setQuery($query);
$this->db->execute();
}
}
public function dropUnwantedColumns($table, $columns) {
if (!$columns || !$table) {
return;
}
$db = $this->db;
// Check if columns exists in database
function qt($n) {
return(Factory::getDBO()->quote($n));
}
$query = 'SHOW COLUMNS FROM #__'.$table.' WHERE Field IN ('.implode(",", array_map("qt", $columns)).')';
$db->setQuery($query);
$rows = $db->loadColumn(0);
// Abort if we don't have any rows
if (!$rows) {
return;
}
// Let's remove the columns
$q = "";
foreach ($rows as $key => $column) {
$comma = (($key+1) < count($rows)) ? "," : "";
$q .= "drop ".$this->db->escape($column).$comma;
}
$query = "alter table #__".$table." $q";
$db->setQuery($query);
$db->execute();
}
public function fetch($table, $columns = "*", $where = null, $singlerow = false) {
if (!$table) {
return;
}
$db = $this->db;
$query = $db->getQuery(true);
$query
->select($columns)
->from("#__$table");
if (isset($where)) {
$query->where("$where");
}
$db->setQuery($query);
return ($singlerow) ? $db->loadObject() : $db->loadObjectList();
}
/**
* Load the Novarain Framework
*
* @return boolean
*/
public function loadFramework()
{
if (is_file(JPATH_PLUGINS . '/system/nrframework/autoload.php'))
{
include_once JPATH_PLUGINS . '/system/nrframework/autoload.php';
}
}
/**
* Re-orders plugin after passed array of plugins
*
* @param string $plugin Plugin element name
* @param array $lowerPluginOrder Array of plugin element names
*
* @return boolean
*/
public function pluginOrderAfter($lowerPluginOrder)
{
if (!is_array($lowerPluginOrder) || !count($lowerPluginOrder))
{
return;
}
$db = $this->db;
// Get plugins max order
$query = $db->getQuery(true);
$query
->select($db->quoteName('b.ordering'))
->from($db->quoteName('#__extensions', 'b'))
->where($db->quoteName('b.element') . ' IN ("'.implode("\",\"",$lowerPluginOrder).'")')
->order('b.ordering desc');
$db->setQuery($query);
$maxOrder = $db->loadResult();
if (is_null($maxOrder))
{
return;
}
// Get plugin details
$query
->clear()
->select(array($db->quoteName('extension_id'), $db->quoteName('ordering')))
->from($db->quoteName('#__extensions'))
->where($db->quoteName('element') . ' = ' . $db->quote($this->alias));
$db->setQuery($query);
$pluginInfo = $db->loadObject();
if (!isset($pluginInfo->ordering) || $pluginInfo->ordering > $maxOrder)
{
return;
}
// Update the new plugin order
$object = new stdClass();
$object->extension_id = $pluginInfo->extension_id;
$object->ordering = ($maxOrder + 1);
try {
$db->updateObject('#__extensions', $object, 'extension_id');
} catch (Exception $e) {
return $e->getMessage();
}
}
}

View File

@ -0,0 +1,33 @@
<?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');
require_once __DIR__ . '/script.install.helper.php';
class PlgSystemACFInstallerScript extends PlgSystemACFInstallerScriptHelper
{
public $name = 'ACF';
public $alias = 'acf';
public $extension_type = 'plugin';
public function onAfterInstall()
{
if ($this->install_type == 'update')
{
require_once __DIR__ . '/helper/migrator.php';
$migrator = new ACFMigrator($this->installedVersion);
$migrator->do();
}
}
}

View File

@ -0,0 +1,16 @@
<?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');
$NR_PRO = "1";
$RELEASE_DATE = "2024-12-02";
?>

View File

@ -0,0 +1,108 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\AI\TextGeneration;
defined('_JEXEC') or die;
use Joomla\CMS\Http\HttpFactory;
class ImageToText
{
/**
* Generate a caption for an image
*
* @param string $imageUrl
*
* @return array
*/
public function generate($imageUrl = '')
{
if (!$imageUrl)
{
return [
'error' => true,
'message' => 'Image URL is required',
];
}
$apiKey = \NRFramework\Helpers\Settings::getValue('openai_api_key');
$apiEndpoint = 'https://api.openai.com/v1/chat/completions';
// Disable SSL verification for local files
$context = stream_context_create([
'ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
],
]);
$imageData = base64_encode(file_get_contents($imageUrl, false, $context));
$url = "data:image/jpeg;base64,{$imageData}";
$data = [
'model' => 'gpt-4o-mini',
'messages' => [
[
'role' => 'user',
'content' => [
[
'type' => 'text',
'text' => 'Describe this image with maximum 120 characters, spaces included.'
],
[
'type' => 'image_url',
'image_url' => [
'url' => $url,
],
],
],
],
],
'max_tokens' => 50,
];
$headers = [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $apiKey,
];
$error = false;
$message = '';
try {
$http = HttpFactory::getHttp();
$response = $http->post($apiEndpoint, json_encode($data), $headers);
if ($response->code == 200)
{
$result = json_decode($response->body);
$message = $result->choices[0]->message->content;
}
else
{
$error = true;
$decodedResponse = json_decode($response->body, true);
$message = isset($decodedResponse['error']['message']) ? $decodedResponse['error']['message'] : 'An error occurred while generating the caption.';
}
}
catch (\Exception $e)
{
$error = true;
$message = "Error: " . $e->getMessage();
}
return [
'error' => $error,
'message' => $message
];
}
}

View File

@ -0,0 +1,316 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework;
use NRFramework\Factory;
use NRFramework\Conditions\ConditionsHelper;
defined('_JEXEC') or die;
// @deprecated - Use \NRFramework\Condnitions\ConditionsHelper;
class Assignments
{
/**
* Assignment Type Aliases
*
* @var array
*
* @deprecated To be removed on Jan 1st 2023.
*/
public $typeAliases = array(
'device|devices' => 'Device',
'urls|url' => 'URL',
'os' => 'OS',
'browsers|browser' => 'Browser',
'referrer' => 'Referrer',
'php' => 'PHP',
'timeonsite' => 'TimeOnSite',
'pageviews|user_pageviews' => 'Pageviews',
'lang|language|languages' => 'Joomla\Language',
'usergroups|usergroup|user_groups' => 'Joomla\UserGroup',
'user_id|userid' => 'Joomla\UserID',
'menu' => 'Joomla\Menu',
'components|component' => 'Joomla\Component',
'datetime|daterange|date' => 'Date\Date',
'weekday|days|day' => 'Date\Day',
'months|month' => 'Date\Month',
'timerange|time' => 'Date\Time',
'acymailing' => 'AcyMailing',
'akeebasubs' => 'AkeebaSubs',
'engagebox|onotherbox' => 'EngageBox',
'convertforms' => 'ConvertForms',
'geo_country|country|countries' => 'Geo\Country',
'geo_continent|continent|continents' => 'Geo\Continent',
'geo_city|city|cities' => 'Geo\City',
'geo_region|region|regions' => 'Geo\Region',
'cookiename|cookie' => 'Cookie',
'ip_addresses|iprange|ip' => 'IP',
'k2_items|k2item' => 'Component\K2Item',
'k2_cats|k2category' => 'Component\K2Category',
'k2_tags|k2tag' => 'Component\K2Tag',
'k2_pagetypes|k2pagetype' => 'Component\K2Pagetype',
'contentcats|category' => 'Component\ContentCategory',
'contentarticles|article' => 'Component\ContentArticle',
'contentview' => 'Component\ContentView',
'eventbookingsingle' => 'Component\EventBookingSingle',
'eventbookingcategory' => 'Component\EventBookingCategory',
'j2storesingle' => 'Component\J2StoreSingle',
'j2storecategory' => 'Component\J2StoreCategory',
'hikashopsingle' => 'Component\HikashopSingle',
'hikashopcategory' => 'Component\HikashopCategory',
'sppagebuildersingle' => 'Component\SPPageBuilderSingle',
'sppagebuildercategory' => 'Component\SPPageBuilderCategory',
'virtuemartcategory' => 'Component\VirtueMartCategory',
'virtuemartsingle' => 'Component\VirtueMartSingle',
'jshoppingsingle' => 'Component\JShoppingSingle',
'jshoppingcategory' => 'Component\JShoppingCategory',
'rsblogsingle' => 'Component\RSBlogSingle',
'rsblogcategory' => 'Component\RSBlogCategory',
'rseventsprosingle' => 'Component\RSEventsProSingle',
'rseventsprocategory' => 'Component\RSEventsProCategory',
'easyblogcategory' => 'Component\EasyBlogCategory',
'easyblogsingle' => 'Component\EasyBlogSingle',
'zoosingle' => 'Component\ZooSingle',
'zoocategory' => 'Component\ZooCategory',
'eshopcategory' => 'Component\EshopCategory',
'eshopsingle' => 'Component\EshopSingle',
'jeventssingle' => 'Component\JEventsSingle',
'jeventscategory' => 'Component\JEventsCategory',
'djcatalog2category' => 'Component\DJCatalog2Category',
'djcatalog2single' => 'Component\DJCatalog2Single',
'quixsingle' => 'Component\QuixSingle',
'djclassifiedssingle' => 'Component\DJClassifiedsSingle',
'djclassifiedscategory' => 'Component\DJClassifiedsCategory',
'sobiprocategory' => 'Component\SobiProCategory',
'sobiprosingle' => 'Component\SobiProSingle',
'gridboxcategory' => 'Component\GridboxCategory',
'gridboxsingle' => 'Component\GridboxSingle',
'djeventscategory' => 'Component\DJEventsCategory',
'djeventssingle' => 'Component\DJEventsSingle',
'jcalprocategory' => 'Component\JCalProCategory',
'jcalprosingle' => 'Component\JCalProSingle',
'dpcalendarcategory' => 'Component\DPCalendarCategory',
'dpcalendarsingle' => 'Component\DPCalendarSingle',
'icagendacategory' => 'Component\ICagendaCategory',
'icagendasingle' => 'Component\ICagendaSingle',
'jbusinessdirectorybusinesscategory' => 'Component\JBusinessDirectoryBusinessCategory',
'jbusinessdirectorybusinesssingle' => 'Component\JBusinessDirectoryBusinessSingle',
'jbusinessdirectoryeventcategory' => 'Component\JBusinessDirectoryEventCategory',
'jbusinessdirectoryeventsingle' => 'Component\JBusinessDirectoryEventSingle',
'jbusinessdirectoryoffercategory' => 'Component\JBusinessDirectoryOfferCategory',
'jbusinessdirectoryoffersingle' => 'Component\JBusinessDirectoryOfferSingle',
'jreviewscategory' => 'Component\JReviewsCategory',
'jreviewssingle' => 'Component\JReviewsSingle'
);
/**
* Factory object
*
* @var \NRFramework\Factory
*/
protected $factory;
/**
* Class constructor
*/
public function __construct($factory = null)
{
$this->factory = is_null($factory) ? new Factory() : $factory;
}
/**
* Legacy method to check a set of rules.
*
* At the moment of writing this and the moment we're going to release a new version for EngageBox
* which is going to introduce the new ConditionBuilder field, ACF and GSD will still be using the passAll() method.
*
* This forces us to keep this method for backwards compatibiliy reasons.
* Additionally, it helps us to catch a special case where both ACF and GSD expect to pass all rules even if the array passed is null.
*
* @param array|object $assignments_info Array/Object containing assignment info
* @param string $match_method The matching method (and|or) - Deprecated
* @param bool $debug Set to true to request additional debug information about assignments
*
* @deprecated Use passSets() instead. To be removed on Jan 1st 2023
*/
public function passAll($assignments_info, $match_method = 'and')
{
$assignments = $this->prepareAssignments($assignments_info, $match_method);
$ch = new ConditionsHelper($this->factory);
$pass = $ch->passSets($assignments);
// If the checks return null, consider this as Success. This is required for both ACF and GSD.
return is_null($pass) ? true : $pass;
}
/**
* Returns the classname for a given assignment alias
*
* @param string $alias
* @return string|void
*
* @deprecated To be removed on Jan 1st 2023
*/
public function aliasToClassname($alias)
{
$alias = strtolower($alias);
foreach ($this->typeAliases as $aliases => $type)
{
if (strtolower($type) == $alias)
{
return $type;
}
$aliases = explode('|', strtolower($aliases));
if (in_array($alias, $aliases))
{
return $type;
}
}
return null;
}
/**
* Checks and prepares the given array of assignment information
*
* @param array $assignments_info
* @return array
*
* @deprecated To be removed on Jan 1st 2023
*/
protected function prepareAssignments($data, $matching_method = 'all')
{
if (is_object($data))
{
return $this->prepareAssignmentsFromObject($data, $matching_method);
}
if (!is_array($data) OR empty($data))
{
return;
}
$rules = array_pop($data);
if (!is_array($rules) OR empty($rules))
{
return;
}
foreach ($rules as &$rule)
{
if (is_array($rule))
{
foreach ($rule as &$_rule)
{
$_rule = $this->prepareAssignmentRule($_rule);
}
}
else
{
$rule = $this->prepareAssignmentRule($rule);
}
}
$data = [
[
'matching_method' => $matching_method == 'and' ? 'all' : 'any',
'rules' => $rules
]
];
return $data;
}
/**
* Prepares the assignment rule.
*
* @param object $rule
*
* @return object
*/
private function prepareAssignmentRule($rule)
{
return [
'name' => $this->aliasToClassname($rule->alias),
'operator' => (int) $rule->assignment_state == 1 ? 'includes' : 'not_includes',
'value' => isset($rule->value) ? $rule->value : null,
'params' => isset($rule->params) ? $rule->params : null,
];
}
/**
* Converts an object of assignment information to an array of groups
* Used by existing extensions
*
* @param object $assignments_info
* @param string $matching_method
*
* @deprecated To be removed on Jan 1st 2023
*/
public function prepareAssignmentsFromObject($assignments_info, $matching_method)
{
if (!isset($assignments_info->params))
{
return [];
}
$params = json_decode($assignments_info->params);
if (!is_object($params))
{
return [];
}
$assignments_info = [];
foreach ($this->typeAliases as $aliases => $type)
{
$aliases = explode('|', $aliases);
foreach ($aliases as $alias)
{
if (!isset($params->{'assign_' . $alias}) || !$params->{'assign_' . $alias})
{
continue;
}
// Discover assignment params
$assignment_params = new \stdClass();
foreach ($params as $key => $value)
{
if (strpos($key, "assign_" . $alias . "_param") !== false)
{
$key = str_replace("assign_" . $alias . "_param_", "", $key);
$assignment_params->$key = $value;
}
}
$assignments_info[] = [
'name' => $this->aliasToClassname($alias),
'operator' => (int) $params->{'assign_' . $alias} == 1 ? 'includes' : 'not_includes',
'value' => isset($params->{'assign_' . $alias . '_list'}) ? $params->{'assign_' . $alias . '_list'} : [],
'params' => $assignment_params
];
}
}
$data = [
[
'matching_method' => $matching_method == 'and' ? 'all' : 'any',
'rules' => $assignments_info
]
];
return $data;
}
}

View File

@ -0,0 +1,115 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
/**
* This file is deprecated. Use CacheManager instead of Cache.
*/
namespace NRFramework;
defined('_JEXEC') or die;
use \NRFramework\CacheManager;
use \Joomla\CMS\Factory;
/**
* Caching mechanism
*/
class Cache
{
/**
* Check if has alrady exists in memory
*
* @param string $hash The hash string
*
* @return boolean
*/
static public function has($hash)
{
$cache = CacheManager::getInstance(Factory::getCache('tassos', ''));
return $cache->has($hash);
}
/**
* Returns hash value
*
* @param string $hash The hash string
* @param string $clone Why the hell we clone objects here?
*
* @return mixed False on error, Object on success
*/
static public function get($hash, $clone = true)
{
$cache = CacheManager::getInstance(Factory::getCache('tassos', ''));
return $cache->get($hash, $clone);
}
/**
* Sets on memory the hash value
*
* @param string $hash The hash string
* @param mixed $data Can be string or object
*
* @return mixed
*/
static public function set($hash, $data)
{
$cache = CacheManager::getInstance(Factory::getCache('tassos', ''));
return $cache->set($hash, $data);
}
/**
* Reads hash value from memory or file
*
* @param string $hash The hash string
* @param boolean $force If true, the filesystem will be used as well on the /cache/ folder
*
* @return mixed The hash object valuw
*/
static public function read($hash, $force = false)
{
$cache = CacheManager::getInstance(Factory::getCache('tassos', ''));
return $cache->read($hash, $force);
}
/**
* Writes hash value in cache folder
*
* @param string $hash The hash string
* @param mixed $data Can be string or object
* @param integer $ttl Expiration duration in milliseconds
*
* @return mixed The hash object value
*/
static public function write($hash, $data, $ttl = 0)
{
$cache = CacheManager::getInstance(Factory::getCache('tassos', ''));
return $cache->write($hash, $data, $ttl);
}
/**
* Memoize a function to run once per runtime
*
* @param string $key The key to store the result of the callback
* @param callback $callback The callable anonymous function to call
*
* @return mixed
*/
static public function memo($key, callable $callback)
{
$hash = md5($key);
if (Cache::has($hash))
{
return Cache::get($hash);
}
return Cache::set($hash, $callback());
}
}

View File

@ -0,0 +1,143 @@
<?php
/**
* @author Tassos.gr <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework;
defined('_JEXEC') or die;
/**
* Cache Manager
*
* Singleton
*/
class CacheManager
{
/**
* 'static' cache array
* @var array
*/
protected $cache = [];
/**
* Cache mechanism object
* @var object
*/
protected $cache_mechanism = null;
/**
* Construct
*/
protected function __construct($cache_mechanism)
{
$this->cache_mechanism = $cache_mechanism;
}
static public function getInstance($cache_mechanism)
{
static $instance = null;
if ($instance === null)
{
$instance = new CacheManager($cache_mechanism);
}
return $instance;
}
/**
* Check if a hash already exists in memory
*
* @param string $hash The hash string
*
* @return boolean
*/
public function has($hash)
{
return isset($this->cache[$hash]);
}
/**
* Returns a hash's value
*
* @param string $hash The hash string
* @param string $clone Why the hell we clone objects here?
*
* @return mixed False on error, Object on success
*/
public function get($hash, $clone = true)
{
if (!$this->has($hash))
{
return false;
}
return is_object($this->cache[$hash]) && $clone ? clone $this->cache[$hash] : $this->cache[$hash];
}
/**
* Sets a hash value
*
* @param string $hash The hash string
* @param mixed $data Can be string or object
*
* @return mixed
*/
public function set($hash, $data)
{
$this->cache[$hash] = $data;
return $data;
}
/**
* Reads a hash value from memory or file
*
* @param string $hash The hash string
* @param boolean $force If true, the filesystem will be used as well on the /cache/ folder
*
* @return mixed The hash object value
*/
public function read($hash, $force = false)
{
if ($this->has($hash))
{
return $this->get($hash);
}
if ($force)
{
$this->cache_mechanism->setCaching(true);
}
return $this->cache_mechanism->get($hash);
}
/**
* Writes hash value in cache folder
*
* @param string $hash The hash string
* @param mixed $data Can be string or object
* @param integer $ttl Expiration duration in minutes. Default 1440 minutes = 1 day.
*
* @return mixed The hash object value
*/
public function write($hash, $data, $ttl = 1440)
{
if ($ttl > 0)
{
$this->cache_mechanism->setLifeTime($ttl);
}
$this->cache_mechanism->setCaching(true);
$this->cache_mechanism->store($data, $hash);
$this->set($hash, $data);
return $data;
}
}

View File

@ -0,0 +1,455 @@
<?php
/**
* @author Tassos Marinos <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions;
defined('_JEXEC') or die;
use Joomla\Registry\Registry;
use Joomla\String\StringHelper;
use Joomla\CMS\Language\Text;
/**
* Assignment Class
*/
class Condition
{
/**
* Application Object
*
* @var object
*/
protected $app;
/**
* Document Object
*
* @var object
*/
protected $doc;
/**
* Date Object
*
* @var object
*/
protected $date;
/**
* Database Object
*
* @var object
*/
protected $db;
/**
* User Object
*
* @var object
*/
protected $user;
/**
* Assignment Selection
*
* @var mixed
*/
protected $selection;
/**
* Assignment Parameters
*
* @var mixed
*/
protected $params;
/**
* Assignment State (Include|Exclude)
*
* @var string
*/
public $assignment;
/**
* Options
*
* @var object
*/
public $options;
/**
* Framework factory object
*
* @var object
*/
public $factory;
/**
* The default operator that will be used to compare haystack with needle.
*
* @var string
*/
protected $operator;
/**
* Class constructor
*
* @param array $options The rule options. Expected properties: selection, value, params
* @param object $factory The framework's factory class.
*/
public function __construct($options = null, $factory = null)
{
$this->factory = is_null($factory) ? new \NRFramework\Factory() : $factory;
// Set General Joomla Objects
$this->db = $this->factory->getDbo();
$this->app = $this->factory->getApplication();
$this->doc = $this->factory->getDocument();
$this->user = $this->factory->getUser();
$this->options = new Registry($options);
$this->setParams($this->options->get('params'));
$this->setOperator($this->options->get('operator', 'includesSome'));
// For performance reasons we might move this inside the pass() method
$this->setSelection($this->options->get('selection', ''));
}
/**
* Set the rule's user selected value
*
* @param mixed $selection
* @return object
*/
public function setSelection($selection)
{
$this->selection = $selection;
if (method_exists($this, 'prepareSelection'))
{
$this->selection = $this->prepareSelection();
}
return $this;
}
/**
* Undocumented function
*
* @return void
*/
public function getSelection()
{
return $this->selection;
}
/**
* Set the operator that will be used for the comparison
*
* @param string $operator
* @return object
*/
public function setOperator($operator)
{
$this->operator = $operator;
return $this;
}
/**
* Set the rule's parameters
*
* @param array $params
*/
public function setParams($params)
{
$this->params = new Registry($params);
}
public function getParams()
{
return $this->params;
}
/**
* Checks the validitity of two values based on the given operator.
*
* Consider converting this method as a Trait.
*
* @param mixed $value
* @param mixed $selection
* @param string $operator
* @param array $options ignoreCase: true,false
*
* @return bool
*/
public function passByOperator($value = null, $selection = null, $operator = null, $options = null)
{
$value = is_null($value) ? $this->value() : $value;
if (!is_null($selection))
{
$this->setSelection($selection);
}
$selection = $this->getSelection();
$options = new Registry($options);
$ignoreCase = $options->get('ignoreCase', true);
if (is_object($value))
{
$value = (array) $value;
}
if (is_object($selection))
{
$selection = (array) $selection;
}
if ($ignoreCase)
{
if (is_string($value))
{
$value = strtolower($value);
}
if (is_string($selection))
{
$selection = strtolower($selection);
}
if (is_array($value))
{
$value = array_map('strtolower', $value);
}
if (is_array($selection))
{
$selection = array_map(function($str)
{
return is_null($str) ? '' : strtolower($str);
}, $selection);
}
}
$operator = (is_null($operator) OR empty($operator)) ? $this->operator : $operator;
$pass = false;
switch ($operator)
{
case 'exists':
$pass = !is_null($value);
break;
// Determines whether haystack is empty. Accepts: array, string
case 'empty':
if (is_array($value))
{
$pass = empty($value);
}
if (is_string($value))
{
$pass = $value == '' || trim($value) == '';
}
if (is_bool($value))
{
$pass = !$value;
}
break;
case 'equals':
if (is_array($selection) || is_array($value))
{
$pass = $this->passByOperator($value, $selection, 'includesSome', $options);
}
else
{
$pass = $value == $selection;
}
break;
case 'contains':
if (is_string($value) && is_string($selection))
{
$pass = strlen($selection) > 0 && strpos($value, $selection) !== false;
}
break;
// Determine whether haystack is less than needle.
case 'less_than':
case 'lowerthan':
case 'lt':
$pass = $value < $selection;
break;
// Determine whether haystack is less than or equal to needle.
case 'less_than_or_equal_to':
case 'lowerthanequal':
case 'lte':
$pass = $value <= $selection;
break;
// Determine whether haystack is greater than needle.
case 'greater_than':
case 'greaterthan':
case 'gt':
$pass = $value > $selection;
break;
// Determine whether haystack is greater than or equal to needle.
case 'greater_than_or_equal_to':
case 'greterthanequal':
case 'gte':
$pass = $value >= $selection;
break;
// Determine whether haystack contains all elements in needle.
case 'includesAll':
case 'containsall':
$pass = count(array_intersect((array) $selection, (array) $value)) == count((array) $selection);
break;
// Determine whether haystack contains at least one element from needle.
case 'includesSome':
case 'containsany':
$pass = !empty(array_intersect((array) $value, (array) $selection));
break;
// Determine whether haystack contains at least one element from needle. Accepts; string, array.
case 'includes':
if (is_string($value) && $value != '' && is_string($selection) && $selection != '')
{
if (StringHelper::strpos($value, $selection) !== false)
{
$pass = true;
}
}
if (is_array($value) || is_array($selection))
{
$pass = $this->passByOperator($value, $selection, 'includesSome', $options);
}
break;
// Determine whether haystack starts with needle. Accepts: string
case 'starts_with':
$pass = StringHelper::substr($value, 0, StringHelper::strlen($selection)) === $selection;
break;
// Determine whether haystack ends with needle. Accepts: string
case 'ends_with':
$pass = StringHelper::substr($value, -StringHelper::strlen($selection)) === $selection;
break;
// Determine whether value is in given range
case 'range':
$value1 = isset($selection['value1']) ? (float) $selection['value1'] : false;
$value2 = isset($selection['value2']) ? (float) $selection['value2'] : false;
$pass = $value1 && $value2 ? (($value >= $value1) && ($value <= $value2)) : false;
break;
// Determine whether haystack equals to needle. Accepts any object.
default:
$pass = $value == $selection;
}
return $pass;
}
/**
* Base assignment check
*
* @return bool
*/
public function pass()
{
return $this->passByOperator();
}
/**
* Returns all parent rows
*
* This method doesn't belong here. Move it to Functions.php.
*
* @param integer $id Row primary key
* @param string $table Table name
* @param string $parent Parent column name
* @param string $child Child column name
*
* @return array Array with IDs
*/
public function getParentIds($id = 0, $table = 'menu', $parent = 'parent_id', $child = 'id')
{
if (!$id)
{
return [];
}
$cache = $this->factory->getCache();
$hash = md5('getParentIds_' . $id . '_' . $table . '_' . $parent . '_' . $child);
if ($cache->has($hash))
{
return $cache->get($hash);
}
$parent_ids = array();
while ($id)
{
$query = $this->db->getQuery(true)
->select('t.' . $parent)
->from('#__' . $table . ' as t')
->where('t.' . $child . ' = ' . (int) $id);
$this->db->setQuery($query);
$id = $this->db->loadResult();
// Break if no parent is found or parent already found before for some reason
if (!$id || in_array($id, $parent_ids))
{
break;
}
$parent_ids[] = $id;
}
return $cache->set($hash, $parent_ids);
}
/**
* A one-line text that describes the current value detected by the rule. Eg: The current time is %s.
*
* @return string
*/
public function getValueHint()
{
$value = $this->value();
// If the rule returns an array, use the 1st one.
$value = is_array($value) ? $value[0] : $value;
return Text::sprintf('NR_DISPLAY_CONDITIONS_HINT_' . strtoupper($this->getName()), ucfirst(strtolower($value)));
}
/**
* Return the rule name
*
* @return string
*/
protected function getName()
{
$classParts = explode('\\', get_called_class());
return array_pop($classParts);
}
}

View File

@ -0,0 +1,393 @@
<?php
/**
* @author Tassos.gr <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions;
defined('_JEXEC') or die;
use Joomla\CMS\Layout\LayoutHelper;
use NRFramework\Conditions\ConditionsHelper;
use NRFramework\Extension;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Form\Form;
class ConditionBuilder
{
public static function pass($rules)
{
$rules = self::prepareRules($rules);
if (empty($rules))
{
return true;
}
return ConditionsHelper::getInstance()->passSets($rules);
}
/**
* Prepare rules object to run checks
*
* @return void
*/
public static function prepareRules($rules = [])
{
if (!is_array($rules))
{
return [];
}
$rules_ = [];
foreach ($rules as $key => $group)
{
if (isset($group['enabled']) AND !(bool) $group['enabled'])
{
continue;
}
// A group without rules, doesn't make sense.
if (!isset($group['rules']) OR (isset($group['rules']) AND empty($group['rules'])))
{
continue;
}
$validRules = [];
foreach ($group['rules'] as $rule)
{
// Make sure rule has a name.
if (!isset($rule['name']) OR (isset($rule['name']) AND empty($rule['name'])))
{
continue;
}
// Rule is invalid if both value and params properties are empty
if (!isset($rule['value']) && !isset($rule['params']))
{
continue;
}
// Skip disabled rules
if (isset($rule['enabled']) && !(bool) $rule['enabled'])
{
continue;
}
// We don't need this property.
unset($rule['enabled']);
// Prepare rule value if necessary
if (isset($rule['value']))
{
$rule['value'] = self::prepareTFRepeaterValue($rule['value']);
}
// Verify operator
if (!isset($rule['operator']) OR (isset($rule['operator']) && empty($rule['operator'])))
{
$rule['operator'] = isset($rule['params']['operator']) ? $rule['params']['operator'] : '';
}
$validRules[] = $rule;
}
if (count($validRules) > 0)
{
$group['rules'] = $validRules;
if (!isset($group['matching_method']) OR (isset($group['matching_method']) AND empty($group['matching_method'])))
{
$group['matching_method'] = 'all';
}
unset($group['enabled']);
$rules_[] = $group;
}
}
return $rules_;
}
/**
* Parse the value of the TF Repeater Input field.
*
* @param array $selection
*
* @return mixed
*/
public static function prepareTFRepeaterValue($selection)
{
// Only proceed when we have an array of arrays selection.
if (!is_array($selection))
{
return $selection;
}
$first = array_values($selection)[0];
if (!is_array($first))
{
return $selection;
}
if (!isset($first['value']))
{
return $selection;
}
$new_selection = [];
foreach ($selection as $value)
{
/**
* We expect a `value` key for TFInputRepeater fields or a key,value pair
* for plain arrays.
*/
if (!isset($value['value']))
{
/**
* If no value exists, it means that the passed $assignment->selection is a key,value pair array so we use the value
* as our returned selection.
*
* This happens when we pass a key,value pair array as $assignment->selection when we expect a TFInputRepeater value
* so we need to take this into consideration.
*/
$new_selection[] = $value;
continue;
}
// value must not be empty
if (is_scalar($value['value']) && empty(trim($value['value'])))
{
continue;
}
$new_selection[] = count($value) === 1 ? $value['value'] : $value;
}
return $new_selection;
}
/**
* Returns the TGeoIP plugin modal.
*
* @return string
*/
public static function getGeoModal()
{
// Do not proceed if the database is up-to-date
if (!\NRFramework\Extension::geoPluginNeedsUpdate())
{
return;
}
HTMLHelper::_('bootstrap.modal');
$modalName = 'tf-geodbchecker-modal';
// The TGeoIP Plugin URL
$url = Uri::base(true) . '/index.php?option=com_plugins&view=plugin&tmpl=component&layout=modal&extension_id=' . \NRFramework\Functions::getExtensionID('tgeoip', 'system');
$options = [
'title' => Text::_('NR_EDIT'),
'url' => $url,
'height' => '400px',
'backdrop' => 'static',
'bodyHeight' => '70',
'modalWidth' => '70',
'footer' => '<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" data-dismiss="modal" aria-hidden="true">'
. Text::_('JLIB_HTML_BEHAVIOR_CLOSE') . '</button>
<button type="button" class="btn btn-success" aria-hidden="true"
onclick="jQuery(\'#' . $modalName . ' iframe\').contents().find(\'#applyBtn\').click();">'
. Text::_('JAPPLY') . '</button>',
];
return HTMLHelper::_('bootstrap.renderModal', $modalName, $options);
}
/**
* Prepares the given rules list.
*
* @param array $list
*
* @return array
*/
public static function prepareXmlRulesList($list)
{
if (is_array($list))
{
$list = implode(',', array_map('trim', $list));
}
else if (is_string($list))
{
$list = str_replace(' ', '', $list);
}
return $list;
}
/**
* Adds a new condition item or group.
*
* @param string $controlGroup The name of the input used to store the data.
* @param string $groupKey The group index ID.
* @param string $conditionKey The added condition item index ID.
* @param array $condition The condition name we are adding.
* @param string $include_rules The list of included conditions that override the available conditions.
* @param string $exclude_rules The list of excluded conditions that override the available conditions.
* @param bool $exclude_rules_pro Whether the excluded rules should appear as Pro missing features.
*
* @return string
*/
public static function add($controlGroup, $groupKey, $conditionKey, $condition = null, $include_rules = [], $exclude_rules = [], $exclude_rules_pro = false)
{
$controlGroup_ = $controlGroup . "[$groupKey][rules][$conditionKey]"; // @Todo - rename input namespace to 'conditions'
$form = self::getForm('conditionbuilder/base.xml', $controlGroup_, $condition);
$form->setFieldAttribute('name', 'include_rules', is_array($include_rules) ? implode(',', $include_rules) : $include_rules);
$form->setFieldAttribute('name', 'exclude_rules', is_array($exclude_rules) ? implode(',', $exclude_rules) : $exclude_rules);
$form->setFieldAttribute('name', 'exclude_rules_pro', $exclude_rules_pro);
$options = [
'name' => $controlGroup_,
'enabled' => !isset($condition['enabled']) ? true : (string) $condition['enabled'] == '1',
'toolbar' => $form,
'groupKey' => $groupKey,
'conditionKey' => $conditionKey,
'options' => ''
];
if (isset($condition['name']))
{
$optionsHTML = self::renderOptions($condition['name'], $controlGroup_, $condition);
$options['condition_name'] = $condition['name'];
$options['options'] = $optionsHTML;
}
return self::getLayout('conditionbuilder_row', $options);
}
/**
* Render condition item settings.
*
* @param string $name The name of the condition item.
* @param string $controlGroup The name of the input used to store the data.
* @param object $formData The data that will be bound to the form.
*
* @return string
*/
public static function renderOptions($name, $controlGroup = null, $formData = null)
{
if (!$form = self::getForm('conditions/' . strtolower(str_replace('\\', '/', $name)) . '.xml', $controlGroup, $formData))
{
return;
}
$form->setFieldAttribute('note', 'ruleName', $name);
return $form->renderFieldset('general');
}
/**
* Handles loading condition builder given a payload.
*
* @param array $payload
*
* @return string
*/
public static function initLoad($payload = [])
{
if (!$payload)
{
return;
}
if (!isset($payload['data']) &&
!isset($payload['name']))
{
return;
}
if (!$data = json_decode($payload['data']))
{
return;
}
// transform object to assosiative array
$data = json_decode(json_encode($data), true);
// html of condition builder
$html = '';
$include_rules = isset($payload['include_rules']) ? $payload['include_rules'] : [];
$exclude_rules = isset($payload['exclude_rules']) ? $payload['exclude_rules'] : [];
$exclude_rules_pro = isset($payload['exclude_rules_pro']) ? $payload['exclude_rules_pro'] : false;
foreach ($data as $groupKey => $groupConditions)
{
$payload = [
'name' => $payload['name'],
'groupKey' => $groupKey,
'groupConditions' => $groupConditions,
'include_rules' => $include_rules,
'exclude_rules' => $exclude_rules,
'exclude_rules_pro' => $exclude_rules_pro
];
$html .= self::getLayout('conditionbuilder_group', $payload);
}
return $html;
}
/**
* Render a layout given its name and payload.
*
* @param string $name
* @param array $payload
*
* @return string
*/
public static function getLayout($name, $payload)
{
return LayoutHelper::render($name, $payload, JPATH_PLUGINS . '/system/nrframework/layouts');
}
/**
* Returns the form by binding given data.
*
* @param string $name
* @param string $controlGroup
* @param array $data
*
* @return object
*/
private static function getForm($name, $controlGroup, $data = null)
{
if (!file_exists(JPATH_PLUGINS . '/system/nrframework/xml/' . $name))
{
return;
}
$form = new Form('cb', ['control' => $controlGroup]);
$form->addFieldPath(JPATH_PLUGINS . '/system/nrframework/fields');
$form->loadFile(JPATH_PLUGINS . '/system/nrframework/xml/' . $name);
if (!is_null($data))
{
$form->bind($data);
}
return $form;
}
}

View File

@ -0,0 +1,97 @@
<?php
/**
* @author Tassos.gr <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions;
defined('_JEXEC') or die;
use NRFramework\Conditions\Condition;
class AcyMailing extends Condition
{
/**
* Returns the assignment's value
*
* @return array AcyMailing lists
*/
public function value()
{
return $this->getSubscribedLists();
}
/**
* Returns all AcyMailing lists the user is subscribed to
*
* @return array AcyMailing lists
*/
private function getSubscribedLists()
{
if (!$user = $this->user->id)
{
return false;
}
// Get a db connection.
$db = $this->db;
// Create a new query object.
$query = $db->getQuery(true);
$lists = [];
// Read AcyMailing v5 lists
if (\NRFramework\Extension::isInstalled('com_acymailing'))
{
$query
->select(array('list.listid'))
->from($db->quoteName('#__acymailing_listsub', 'list'))
->join('INNER', $db->quoteName('#__acymailing_subscriber', 'sub') . ' ON (' . $db->quoteName('list.subid') . '=' . $db->quoteName('sub.subid') . ')')
->where($db->quoteName('list.status') . ' = 1')
->where($db->quoteName('sub.userid') . ' = ' . $user)
->where($db->quoteName('sub.confirmed') . ' = 1')
->where($db->quoteName('sub.enabled') . ' = 1');
// Reset the query using our newly populated query object.
$db->setQuery($query);
if ($cols = $db->loadColumn())
{
$lists = array_merge($lists, $cols);
}
}
// Read AcyMailing > v5 lists
if (\NRFramework\Extension::isInstalled('com_acym'))
{
// Create a new query object.
$query = $db->getQuery(true);
$query
->select(['list.id'])
->from($db->quoteName('#__acym_user_has_list', 'userlist'))
->join('INNER', $db->quoteName('#__acym_list', 'list') . ' ON (' . $db->quoteName('list.id') . '=' . $db->quoteName('userlist.list_id') . ')')
->join('INNER', $db->quoteName('#__acym_user', 'user') . ' ON (' . $db->quoteName('user.id') . '=' . $db->quoteName('userlist.user_id') . ')')
->where($db->quoteName('user.cms_id') . ' = ' . $user)
->where($db->quoteName('userlist.status') . ' = 1')
->where($db->quoteName('userlist.unsubscribe_date') . ' IS NULL');
// Reset the query using our newly populated query object.
$db->setQuery($query);
$cols = $db->loadColumn();
foreach ($cols as $value)
{
$lists[] = '6:' . $value;
}
}
return $lists;
}
}

View File

@ -0,0 +1,71 @@
<?php
/**
* @author Tassos.gr <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions;
defined('_JEXEC') or die;
use NRFramework\Conditions\Condition;
class AkeebaSubs extends Condition
{
/**
* Returns the assignment's value
*
* @return array Akeeba Subscriptions
*/
public function value()
{
return $this->getlevels();
}
/**
* Returns all user's active subscriptions
*
* @param int $userid User's id
*
* @return array Akeeba Subscriptions
*/
private function getLevels()
{
if (!$user = $this->user->id)
{
return false;
}
if (!defined('FOF30_INCLUDED') && !@include_once(JPATH_LIBRARIES . '/fof30/include.php'))
{
return false;
}
// Get the Akeeba Subscriptions container. Also includes the autoloader.
$container = \FOF30\Container\Container::getInstance('com_akeebasubs');
$subscriptionsModel = $container->factory->model('Subscriptions')->tmpInstance();
$items = $subscriptionsModel
->user_id($user)
->enabled(1)
->get();
if (!$items->count())
{
return false;
}
$levels = array();
foreach ($items as $subscription)
{
$levels[] = $subscription->akeebasubs_level_id;
}
return array_unique($levels);
}
}

View File

@ -0,0 +1,27 @@
<?php
/**
* @author Tassos.gr <info@tassos.gr>
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions;
defined('_JEXEC') or die;
use NRFramework\Conditions\Condition;
class Browser extends Condition
{
/**
* Returns the assignment's value
*
* @return string Browser name
*/
public function value()
{
return $this->factory->getBrowser()['name'];
}
}

View File

@ -0,0 +1,249 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
use NRFramework\Conditions\Condition;
use NRFramework\Functions;
/**
* Base class used by component-based assignments. Class properties defaults to com_content.
*/
abstract class ComponentBase extends Condition
{
/**
* The component's Category Page view name
*
* @var string
*/
protected $viewCategory = 'category';
/**
* The component's Single Page view name
*
* @var string
*/
protected $viewSingle = 'article';
/**
* The component's option name
*
* @var string
*/
protected $component_option = 'com_content';
/**
* Request information
*
* @var mixed
*/
protected $request = null;
/**
* Class Constructor
*
* @param object $options
* @param object $factory
*/
public function __construct($options = null, $factory = null)
{
parent::__construct($options, $factory);
$request = new \stdClass;
$request->view = $this->app->input->get('view');
$request->task = $this->app->input->get('task');
$request->option = $this->app->input->get('option');
$request->layout = $this->app->input->get('layout');
$request->id = $this->app->input->getInt('id');
// Check if request is forwarded
if ($context = $this->app->input->get('forward_context'))
{
if (isset($context['request']))
{
$request = (object) $context['request'];
}
}
$this->request = $request;
}
/**
* Returns the assignment's value
*
* @return array Category IDs
*/
public function value()
{
return $this->getCategoryIds();
}
/**
* Indicates whether the current view concerns a Category view
*
* @return boolean
*/
protected function isCategoryPage()
{
return ($this->request->view == $this->viewCategory);
}
/**
* Indicates whether the current view concerncs a Single Page view
*
* @return boolean
*/
public function isSinglePage()
{
return ($this->request->view == $this->viewSingle);
}
/**
* Check if we are in the right context and we're manipulating the correct component
*
* @return bool
*/
protected function passContext()
{
return ($this->request->option == $this->component_option);
}
/**
* Returns category IDs based
*
* @return array
*/
protected function getCategoryIDs()
{
$id = $this->request->id;
// Make sure we have an ID.
if (empty($id))
{
return;
}
// If this is a Category page, return the Category ID from the Query String
if ($this->isCategoryPage())
{
return (array) $id;
}
// If this is a Single Page, return all assosiated Category IDs.
if ($this->isSinglePage())
{
return $this->getSinglePageCategories($id);
}
}
/**
* Checks whether the current page is within the selected categories
*
* @param string $ref_table The referenced table
* @param string $ref_parent_column The name of the parent column in the referenced table
*
* @return boolean
*/
protected function passCategories($ref_table = 'categories', $ref_parent_column = 'parent_id')
{
if (empty($this->selection) || !$this->passContext())
{
return false;
}
// Include Children switch: 0 = No, 1 = Yes, 2 = Child Only
$inc_children = $this->params->get('inc_children');
// Setup supported views
$view_single = $this->params->get('view_single', true);
$view_category = $this->params->get('view_category', false);
// Check if we are in a valid context
if (!($view_category && $this->isCategoryPage()) && !($view_single && $this->isSinglePage()))
{
return false;
}
// Start Checks
$pass = false;
// Get current page assosiated category IDs. It can be a single ID of the current Category view or multiple IDs assosiated to active item.
$catids = $this->getCategoryIDs();
$catids = is_array($catids) ? $catids : (array) $catids;
foreach ($catids as $catid)
{
$pass = in_array($catid, $this->selection);
if ($pass)
{
// If inc_children is either disabled or set to 'Also on Childs', there's no need for further checks.
// The condition is already passed.
if (in_array($this->params->get('inc_children'), [0, 1]))
{
break;
}
// We are here because we need childs only. Disable pass and continue checking parent IDs.
$pass = false;
}
// Pass check for child items
if (!$pass && $this->params->get('inc_children'))
{
$parent_ids = $this->getParentIDs($catid, $ref_table, $ref_parent_column);
foreach ($parent_ids as $id)
{
if (in_array($id, $this->selection))
{
$pass = true;
break 2;
}
}
unset($parent_ids);
}
}
return $pass;
}
/**
* Check whether this page passes the validation
*
* @return void
*/
protected function passSinglePage()
{
// Make sure we are in the right context
if (empty($this->selection) || !$this->passContext() || !$this->isSinglePage())
{
return false;
}
if (!is_array($this->selection))
{
$this->selection = Functions::makeArray($this->selection);
}
return parent::pass();
}
/**
* Get single page's assosiated categories
*
* @param Integer The Single Page id
* @return array
*/
abstract protected function getSinglePageCategories($id);
}

View File

@ -0,0 +1,40 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class ContentArticle extends ContentBase
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['article'];
/**
* Pass check for Joomla! Articles
*
* @return bool
*/
public function pass()
{
return $this->passSinglePage();
}
/**
* Returns the assignment's value
*
* @return int Article ID
*/
public function value()
{
return $this->request->id;
}
}

View File

@ -0,0 +1,120 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;
class ContentBase extends ComponentBase
{
/**
* Get single page's assosiated categories
*
* @param integer The Single Page id
*
* @return integer
*/
protected function getSinglePageCategories($id)
{
// If the article is not assigned to any menu item, the cat id should be available in the query string. Let's check it.
if ($requestCatID = $this->app->input->getInt('catid', null))
{
return $requestCatID;
}
// Apparently, the catid is not available in the Query String. Let's ask Article model.
$item = $this->getItem($id);
if (is_object($item) && isset($item->catid))
{
return $item->catid;
}
}
/**
* Load a Joomla article data object.
*
* @return object
*/
public function getItem($id = null)
{
$id = is_null($id) ? $this->request->id : $id;
// Sanity check
if (is_null($id))
{
return;
}
$hash = md5('contentItem' . $id);
$cache = $this->factory->getCache();
if ($cache->has($hash))
{
return $cache->get($hash);
}
// Prevent "Article not found" error on J3.
if (!defined('nrJ4'))
{
$db = Factory::getDbo();
$query = $db->getQuery(true)
->select($db->quoteName('id'))
->from($db->quoteName('#__content'))
->where($db->quoteName('id') . ' = ' . $db->q((int) $id));
$db->setQuery($query);
if (!$db->loadResult())
{
return $cache->set($hash, null);
}
}
// Use try catch to prevent fatal errors in case the article is not found
try
{
$model = $this->getArticleModel();
$item = $model->getItem($id);
if ($item)
{
$item->images = is_string($item->images) ? json_decode($item->images) : $item->images;
$item->urls = is_string($item->urls) ? json_decode($item->urls) : $item->urls;
$item->attribs = is_string($item->attribs) ? json_decode($item->attribs) : $item->attribs;
}
return $cache->set($hash, $item);
} catch (\Throwable $th)
{
return null;
}
}
/**
* Return the Article's model.
*
* @return object
*/
private function getArticleModel()
{
if (defined('nrJ4'))
{
$mvcFactory = Factory::getApplication()->bootComponent('com_content')->getMVCFactory();
return $mvcFactory->createModel('Article', 'Administrator');
}
// Joomla 3
BaseDatabaseModel::addIncludePath(JPATH_SITE . '/components/com_content/models');
return BaseDatabaseModel::getInstance('Article', 'ContentModel');
}
}

View File

@ -0,0 +1,30 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class ContentCategory extends ContentBase
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['category'];
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passCategories();
}
}

View File

@ -0,0 +1,44 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class ContentView extends ContentBase
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['contentview'];
/**
* Pass check for Joomla! Articles
*
* @return bool
* @return bool
*/
public function pass()
{
// Make sure we are in the right context
if (empty($this->selection) || !$this->passContext())
{
return false;
}
// In the Joomla Content component, the 'view' query parameter equals to 'category' in both Category List and Category Blog views.
// In order to distinguish them we are using the 'layout' parameter as well.
if ($this->request->view == 'category' && $this->request->layout)
{
$this->request->view .= '_' . $this->request->layout;
}
return $this->passByOperator($this->request->view, $this->selection, 'includes');
}
}

View File

@ -0,0 +1,57 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DJCatalog2Base extends ComponentBase
{
/**
* The component's Single Page view name
*
* @var string
*/
protected $viewSingle = 'item';
/**
* The component's Category Page view name
*
* @var string
*/
protected $viewCategory = 'items';
/**
* The component's option name
*
* @var string
*/
protected $component_option = 'com_djcatalog2';
/**
* Get single page's assosiated categories
*
* @param Integer The Single Page id
*
* @return array
*/
protected function getSinglePageCategories($id)
{
$db = $this->db;
$query = $db->getQuery(true)
->select($db->quoteName('category_id'))
->from($db->quoteName('#__djc2_items_categories'))
->where($db->quoteName('item_id') . '=' . $db->q($id));
$db->setQuery($query);
return $db->loadColumn();
}
}

View File

@ -0,0 +1,30 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DJCatalog2Category extends DJCatalog2Base
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['djcatalog2.category'];
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passCategories('djc2_categories');
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DJCatalog2Single extends DJCatalog2Base
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['djcatalog2.single'];
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passSinglePage();
}
/**
* Returns the assignment's value
*
* @return int
*/
public function value()
{
return $this->request->id;
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DJClassifiedsBase extends ComponentBase
{
/**
* The component's Single Page view name
*
* @var string
*/
protected $viewSingle = 'item';
/**
* The component's option name
*
* @var string
*/
protected $component_option = 'com_djclassifieds';
/**
* Get single page's assosiated categories
*
* @param Integer The Single Page id
*
* @return array
*/
protected function getSinglePageCategories($id)
{
$db = $this->db;
$query = $db->getQuery(true)
->select('cat_id')
->from('#__djcf_items')
->where($db->quoteName('id') . '=' . $db->q($id));
$db->setQuery($query);
return $db->loadColumn();
}
}

View File

@ -0,0 +1,31 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DJClassifiedsCategory extends DJClassifiedsBase
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['djclassifieds.category'];
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passCategories('djcf_categories', 'parent_id');
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DJClassifiedsSingle extends DJClassifiedsBase
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['djclassifieds.single'];
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passSinglePage();
}
/**
* Returns the assignment's value
*
* @return int
*/
public function value()
{
return $this->request->id;
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DJEventsBase extends ComponentBase
{
/**
* The component's Single Page view name
*
* @var string
*/
protected $viewSingle = 'event';
/**
* The component's option name
*
* @var string
*/
protected $component_option = 'com_djevents';
/**
* Get single page's assosiated categories
*
* @param Integer The Single Page id
*
* @return array
*/
protected function getSinglePageCategories($id)
{
$db = $this->db;
$query = $db->getQuery(true)
->select($db->quoteName('cat_id'))
->from('#__djev_events')
->where($db->quoteName('id') . '=' . $db->q($id));
$db->setQuery($query);
return $db->loadColumn();
}
}

View File

@ -0,0 +1,31 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DJEventsCategory extends DJEventsBase
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['djevents.category'];
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passCategories('djev_cats', 'parent_id');
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DJEventsSingle extends DJEventsBase
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['djevents.single'];
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passSinglePage();
}
/**
* Returns the assignment's value
*
* @return int
*/
public function value()
{
return $this->request->id;
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DPCalendarBase extends ComponentBase
{
/**
* The component's Single Page view name
*
* @var string
*/
protected $viewSingle = 'event';
/**
* The component's option name
*
* @var string
*/
protected $component_option = 'com_dpcalendar';
/**
* Get single page's assosiated categories
*
* @param Integer The Single Page id
*
* @return array
*/
protected function getSinglePageCategories($id)
{
$db = $this->db;
$query = $db->getQuery(true)
->select($db->quoteName('catid'))
->from('#__dpcalendar_events')
->where($db->quoteName('id') . '=' . $db->q($id));
$db->setQuery($query);
return $db->loadColumn();
}
}

View File

@ -0,0 +1,26 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DPCalendarCategory extends DPCalendarBase
{
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passCategories('categories', 'parent_id');
}
}

View File

@ -0,0 +1,35 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class DPCalendarSingle extends DPCalendarBase
{
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passSinglePage();
}
/**
* Returns the assignment's value
*
* @return int
*/
public function value()
{
return $this->request->id;
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class EasyBlogBase extends ComponentBase
{
/**
* The component's Single Page view name
*
* @var string
*/
protected $viewSingle = 'entry';
/**
* The component's option name
*
* @var string
*/
protected $component_option = 'com_easyblog';
/**
* Get single page's assosiated categories
*
* @param Integer The Single Page id
*
* @return array
*/
protected function getSinglePageCategories($id)
{
$db = $this->db;
$query = $db->getQuery(true)
->select('category_id')
->from('#__easyblog_post')
->where($db->quoteName('id') . '=' . $db->q($id));
$db->setQuery($query);
return $db->loadColumn();
}
}

View File

@ -0,0 +1,31 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class EasyBlogCategory extends EasyBlogBase
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['easyblog.category'];
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passCategories('easyblog_category', 'parent_id');
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class EasyBlogSingle extends EasyBlogBase
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['easyblog.single'];
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passSinglePage();
}
/**
* Returns the assignment's value
*
* @return int
*/
public function value()
{
return $this->request->id;
}
}

View File

@ -0,0 +1,400 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
use Joomla\CMS\Factory;
class EcommerceBase extends ComponentBase
{
/**
* Pass method for "Amount In Cart" condition.
*
* @return bool
*/
public function passAmountInCart()
{
// Whether we exclude shipping cost
$exclude_shipping_cost = $this->params->get('exclude_shipping_cost', '0') === '1';
$shipping_total = 0;
$amount = 0;
switch ($this->params->get('total', 'total'))
{
case 'total':
$amount = $this->getCartTotal();
if ($exclude_shipping_cost)
{
$shipping_total = -$this->getShippingTotal();
}
break;
case 'subtotal':
$amount = $this->getCartSubtotal();
if (!$exclude_shipping_cost)
{
$shipping_total = $this->getShippingTotal();
}
break;
}
// Calculate final amount
$amount = $amount + $shipping_total;
$operator = $this->options->get('operator', 'equal');
$selection = (float) $this->selection;
// Range selection
if ($operator === 'range')
{
$selection = [
'value1' => $selection,
'value2' => (float) $this->options->get('params.value2', false)
];
}
return $this->passByOperator($amount, $selection, $operator);
}
/**
* Pass method for "Products In Cart" condition.
*
* @param string $cart_product_item_id_key
*
* @return bool
*/
protected function passProductsInCart($cart_product_item_id_key = ['id'], $product_prop_key = 'quantity')
{
// Get cart products
if (!$cartProducts = $this->getCartProducts())
{
return false;
}
// Get condition products
if (!$conditionProducts = $this->selection)
{
return false;
}
if (!is_array($conditionProducts))
{
return false;
}
// Ensure all condition's products exist in the cart
$foundCartProducts = array_filter(
$cartProducts,
function ($prod) use ($conditionProducts, $cart_product_item_id_key, $product_prop_key)
{
$prod = (array) $prod;
// Check the ID first
foreach ($cart_product_item_id_key as $id_key)
{
$valid = array_filter($conditionProducts, function($item) use ($prod, $id_key) {
return isset($item['value']) && (int) $item['value'] === (int) $prod[$id_key];
});
if ($valid)
{
break;
}
}
// If not valid, abort
if (!$valid)
{
return;
}
// Get valid product
$valid_product = reset($valid);
// Ensure product has property
$product_property_value = isset($prod[$product_prop_key]) ? (int) $prod[$product_prop_key] : false;
if (!$product_property_value)
{
return $valid;
}
// We need an operator other than "any"
if (!isset($valid_product['operator']) || $valid_product['operator'] === 'any')
{
return $valid;
}
// Ensure value 1 is valid
$product_value1 = isset($valid_product['value1']) ? (int) $valid_product['value1'] : false;
if (!$product_value1)
{
return $valid;
}
$product_value2 = isset($valid_product['value2']) ? (int) $valid_product['value2'] : false;
// Default selection
$selection = $product_value1;
// Range selection
if ($valid_product['operator'] === 'range')
{
$selection = [
'value1' => $product_value1,
'value2' => $product_value2
];
}
return $this->passByOperator($product_property_value, $selection, $valid_product['operator']);
}
);
return count($foundCartProducts);
}
/**
* Pass method for "Last Purchase Date" condition.
*
* @return bool
*/
protected function passLastPurchaseDate()
{
if (!$user = Factory::getUser())
{
return;
}
if (!$user->id)
{
return;
}
if (!$purchase_date = $this->getLastPurchaseDate($user->id))
{
return;
}
$purchaseDate = new \DateTime('@' . $purchase_date);
$purchaseDate->setTimezone(new \DateTimeZone('UTC'));
$purchaseDate->setTime(0,0);
$currentDate = new \DateTime('now', new \DateTimeZone('UTC'));
$pass = false;
$operator = $this->options->get('params.operator', 'within_hours');
switch ($operator)
{
case 'within_hours':
case 'within_days':
case 'within_weeks':
case 'within_months':
if (!$within_value = intval($this->options->get('params.within_value')))
{
return;
}
$period = str_replace('within_', '', $operator);
$timeframe = strtoupper($period[0]);
// Hours requires a "T"
if ($timeframe === 'H')
{
$within_value = 'T' . $within_value;
}
$interval = new \DateInterval("P{$within_value}{$timeframe}");
$purchaseDateXDaysAgo = (clone $purchaseDate)->add($interval);
$interval->invert = 1; // Set invert to 1 to indicate past time
$pass = $purchaseDateXDaysAgo >= $currentDate;
break;
case 'equal':
if (!$this->selection)
{
return;
}
$selectionDate = new \DateTime($this->selection, new \DateTimeZone('UTC'));
$pass = $purchaseDate->format('Y-m-d') === $selectionDate->format('Y-m-d');
break;
case 'before':
if (!$this->selection)
{
return;
}
$selectionDate = new \DateTime($this->selection, new \DateTimeZone('UTC'));
$pass = $purchaseDate < $selectionDate;
break;
case 'after':
if (!$this->selection)
{
return;
}
$selectionDate = new \DateTime($this->selection, new \DateTimeZone('UTC'));
$pass = $purchaseDate > $selectionDate;
break;
case 'range':
if (!$secondDate = $this->options->get('params.value2'))
{
return;
}
if (!$this->selection)
{
return;
}
$startDate = new \DateTime($this->selection, new \DateTimeZone('UTC'));
$endDate = new \DateTime($secondDate, new \DateTimeZone('UTC'));
$pass = $purchaseDate >= $startDate && $purchaseDate <= $endDate;
break;
}
return $pass;
}
/**
* Pass method for "Current Product Price" condition.
*
* @return bool
*/
public function passCurrentProductPrice()
{
// Ensure we are viewing a product page
if (!$this->isSinglePage())
{
return;
}
if (!$this->selection)
{
return;
}
// Get current product data
if (!$product_data = $this->getCurrentProductData())
{
return;
}
// Get value 1
$selection = (float) $this->options->get('selection');
// Range selection
if ($this->operator === 'range')
{
$value2 = (float) $this->options->get('params.value2');
$selection = [
'value1' => $selection,
'value2' => $value2
];
}
return $this->passByOperator($product_data['price'], $selection, $this->operator);
}
/**
* Pass method for "Current Product Stock" condition.
*
* @return bool
*/
public function passCurrentProductStock()
{
// Ensure we are viewing a product page
if (!$this->isSinglePage())
{
return;
}
if (!$this->selection)
{
return;
}
$current_product_id = $this->request->id;
if (!$product_stock = $this->getProductStock($current_product_id))
{
return;
}
// Get value 1
$selection = (int) $this->options->get('selection');
// Range selection
if ($this->operator === 'range')
{
$value2 = (int) $this->options->get('params.value2');
$selection = [
'value1' => $selection,
'value2' => $value2
];
}
return $this->passByOperator($product_stock, $selection, $this->operator);
}
protected function getPreparedSelection()
{
$selection = $this->getSelection();
if (!is_array($selection))
{
return $selection;
}
foreach ($selection as &$value)
{
if (!is_array($value))
{
continue;
}
$params = isset($value['params']) ? $value['params'] : [];
if ($params)
{
if (isset($params['value']))
{
$params['value1'] = $params['value'];
}
unset($params['value']);
unset($value['params']);
}
$value = array_merge($value, $params);
}
return $selection;
}
/**
* Get single page's assosiated categories
*
* @param Integer The Single Page id
*
* @return array
*/
protected function getSinglePageCategories($id) {}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class EshopBase extends ComponentBase
{
/**
* The component's Single Page view name
*
* @var string
*/
protected $viewSingle = 'product';
/**
* The component's option name
*
* @var string
*/
protected $component_option = 'com_eshop';
/**
* Get single page's assosiated categories
*
* @param Integer The Single Page id
*
* @return array
*/
protected function getSinglePageCategories($id)
{
$db = $this->db;
$query = $db->getQuery(true)
->select('category_id')
->from('#__eshop_productcategories')
->where($db->quoteName('product_id') . '=' . $db->q($id));
$db->setQuery($query);
return $db->loadColumn();
}
}

View File

@ -0,0 +1,31 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class EshopCategory extends EshopBase
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['eshop.category'];
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passCategories('eshop_categories', 'category_parent_id');
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class EshopSingle extends EshopBase
{
/**
* Shortcode aliases for this Condition
*/
public static $shortcode_aliases = ['eshop.single'];
/**
* Pass check
*
* @return bool
*/
public function pass()
{
return $this->passSinglePage();
}
/**
* Returns the assignment's value
*
* @return int
*/
public function value()
{
return $this->request->id;
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* @author Tassos.gr
* @link https://www.tassos.gr
* @copyright Copyright © 2024 Tassos All Rights Reserved
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
*/
namespace NRFramework\Conditions\Conditions\Component;
defined('_JEXEC') or die;
class EventBookingBase extends ComponentBase
{
/**
* The component's Single Page view name
*
* @var string
*/
protected $viewSingle = 'event';
/**
* The component's option name
*
* @var string
*/
protected $component_option = 'com_eventbooking';
/**
* Get single page's assosiated categories
*
* @param Integer The Single Page id
*
* @return array
*/
protected function getSinglePageCategories($id)
{
$db = $this->db;
$query = $db->getQuery(true)
->select('category_id')
->from('#__eb_event_categories')
->where($db->quoteName('event_id') . '=' . $db->q($id));
$db->setQuery($query);
return $db->loadColumn();
}
}

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