diff --git a/src/CoreBundle/Contao/Hooks/ContentElementCallback.php b/src/CoreBundle/Contao/Hooks/ContentElementCallback.php index 0a370a7dc..13c024b14 100644 --- a/src/CoreBundle/Contao/Hooks/ContentElementCallback.php +++ b/src/CoreBundle/Contao/Hooks/ContentElementCallback.php @@ -45,7 +45,14 @@ class ContentElementCallback extends AbstractContentElementAndModuleCallback */ public function buildFilterParameterList(DC_Table $dataContainer) { - parent::buildFilterParamsFor($dataContainer, 'metamodel_content'); + if ( + null === ($currentRecord = $dataContainer->getCurrentRecord()) + || $currentRecord['type'] !== 'metamodel_content' + ) { + return; + } + + $this->buildFilterParamsFor($dataContainer, 'metamodel_content'); } /** diff --git a/src/CoreBundle/Contao/Hooks/FilterContentElementCallback.php b/src/CoreBundle/Contao/Hooks/FilterContentElementCallback.php new file mode 100644 index 000000000..274ffef58 --- /dev/null +++ b/src/CoreBundle/Contao/Hooks/FilterContentElementCallback.php @@ -0,0 +1,48 @@ + + * @copyright 2012-2025 The MetaModels team. + * @license https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later + * @filesource + */ + +namespace MetaModels\CoreBundle\Contao\Hooks; + +use Contao\DC_Table; + +/** + * This class provides callbacks for tl_content. + */ +final class FilterContentElementCallback extends AbstractContentElementAndModuleCallback +{ + /** + * The table name. + * + * @var string + */ + protected static $tableName = 'tl_content'; + + /** Called from tl_content.onload_callback. */ + public function buildFilterParameterList(DC_Table $dataContainer): void + { + if ( + null === ($currentRecord = $dataContainer->getCurrentRecord()) + || $currentRecord['type'] !== 'metamodels_frontendfilter' + ) { + return; + } + + $this->buildFilterParamsFor($dataContainer, 'metamodels_frontendfilter'); + } +} diff --git a/src/CoreBundle/Contao/Hooks/FilterModuleCallback.php b/src/CoreBundle/Contao/Hooks/FilterModuleCallback.php new file mode 100644 index 000000000..b08d5f7ce --- /dev/null +++ b/src/CoreBundle/Contao/Hooks/FilterModuleCallback.php @@ -0,0 +1,48 @@ + + * @copyright 2012-2025 The MetaModels team. + * @license https://github.com/MetaModels/core/blob/master/LICENSE LGPL-3.0-or-later + * @filesource + */ + +namespace MetaModels\CoreBundle\Contao\Hooks; + +use Contao\DC_Table; + +/** + * This class provides callbacks for tl_module. + */ +final class FilterModuleCallback extends AbstractContentElementAndModuleCallback +{ + /** + * The table name. + * + * @var string + */ + protected static $tableName = 'tl_module'; + + /** Called from tl_module.onload_callback. */ + public function buildFilterParameterList(DC_Table $dataContainer): void + { + if ( + null === ($currentRecord = $dataContainer->getCurrentRecord()) + || $currentRecord['type'] !== 'metamodels_frontendfilter' + ) { + return; + } + + $this->buildFilterParamsFor($dataContainer, 'metamodels_frontendfilter'); + } +} diff --git a/src/CoreBundle/Contao/Hooks/ModuleCallback.php b/src/CoreBundle/Contao/Hooks/ModuleCallback.php index 87d88d890..a21e83d39 100644 --- a/src/CoreBundle/Contao/Hooks/ModuleCallback.php +++ b/src/CoreBundle/Contao/Hooks/ModuleCallback.php @@ -43,6 +43,13 @@ class ModuleCallback extends AbstractContentElementAndModuleCallback */ public function buildFilterParameterList(DC_Table $dataContainer) { + if ( + null === ($currentRecord = $dataContainer->getCurrentRecord()) + || $currentRecord['type'] !== 'metamodel_list' + ) { + return; + } + parent::buildFilterParamsFor($dataContainer, 'metamodel_list'); } diff --git a/src/CoreBundle/Resources/config/hooks.yml b/src/CoreBundle/Resources/config/hooks.yml index 2b7dbe781..7c392872a 100644 --- a/src/CoreBundle/Resources/config/hooks.yml +++ b/src/CoreBundle/Resources/config/hooks.yml @@ -34,6 +34,30 @@ services: - '@translator' public: true + MetaModels\CoreBundle\Contao\Hooks\FilterContentElementCallback: + arguments: + - '@metamodels.assets.icon_builder' + - '@metamodels.backend.url-builder-factory' + - '@metamodels.factory' + - '@metamodels.filter_setting_factory' + - '@database_connection' + - '@metamodels.template_list' + - '@request_stack' + - '@translator' + public: true + + MetaModels\CoreBundle\Contao\Hooks\FilterModuleCallback: + arguments: + - '@metamodels.assets.icon_builder' + - '@metamodels.backend.url-builder-factory' + - '@metamodels.factory' + - '@metamodels.filter_setting_factory' + - '@database_connection' + - '@metamodels.template_list' + - '@request_stack' + - '@translator' + public: true + MetaModels\CoreBundle\EventListener\GetSearchablePagesListener: arguments: - '@database_connection' diff --git a/src/CoreBundle/Resources/contao/dca/tl_content.php b/src/CoreBundle/Resources/contao/dca/tl_content.php index 34c0fd5d0..7985b3300 100755 --- a/src/CoreBundle/Resources/contao/dca/tl_content.php +++ b/src/CoreBundle/Resources/contao/dca/tl_content.php @@ -24,9 +24,12 @@ */ use MetaModels\CoreBundle\Contao\Hooks\ContentElementCallback; +use MetaModels\CoreBundle\Contao\Hooks\FilterContentElementCallback; $GLOBALS['TL_DCA']['tl_content']['config']['onload_callback'][] = [ContentElementCallback::class, 'buildFilterParameterList']; +$GLOBALS['TL_DCA']['tl_content']['config']['onload_callback'][] = + [FilterContentElementCallback::class, 'buildFilterParameterList']; $GLOBALS['TL_DCA']['tl_content']['palettes']['metamodel_content'] = '{type_legend},type,headline;' . @@ -45,8 +48,8 @@ $GLOBALS['TL_DCA']['tl_content']['palettes']['metamodels_frontendfilter'] = '{type_legend},type,headline;' . - '{mm_filter_legend},metamodel,metamodel_filtering,metamodel_fef_template,metamodel_fef_params,' . - 'metamodel_fef_autosubmit,metamodel_fef_hideclearfilter,metamodel_available_values,' . + '{mm_filter_legend},metamodel,metamodel_filtering,metamodel_fef_template,metamodel_filterparams,' . + 'metamodel_fef_params,metamodel_fef_autosubmit,metamodel_fef_hideclearfilter,metamodel_available_values,' . 'metamodel_jumpTo,metamodel_fef_id,metamodel_fef_urlfragment;' . '{protected_legend:hide},protected;' . '{expert_legend:hide},guests,cssID,space;' . diff --git a/src/CoreBundle/Resources/contao/dca/tl_module.php b/src/CoreBundle/Resources/contao/dca/tl_module.php index 9552c1264..e3120623c 100755 --- a/src/CoreBundle/Resources/contao/dca/tl_module.php +++ b/src/CoreBundle/Resources/contao/dca/tl_module.php @@ -24,8 +24,11 @@ */ use MetaModels\CoreBundle\Contao\Hooks\ModuleCallback; +use MetaModels\CoreBundle\Contao\Hooks\FilterModuleCallback; $GLOBALS['TL_DCA']['tl_module']['config']['onload_callback'][] = [ModuleCallback::class, 'buildFilterParameterList']; +$GLOBALS['TL_DCA']['tl_module']['config']['onload_callback'][] = + [FilterModuleCallback::class, 'buildFilterParameterList']; $GLOBALS['TL_DCA']['tl_module']['palettes']['metamodel_list'] = '{title_legend},name,headline,type;' . @@ -43,8 +46,8 @@ $GLOBALS['TL_DCA']['tl_module']['palettes']['metamodels_frontendfilter'] = '{title_legend},name,headline,type;' . - '{mm_filter_legend},metamodel,metamodel_filtering,metamodel_fef_template,metamodel_fef_params,' . - 'metamodel_fef_autosubmit,metamodel_fef_hideclearfilter,metamodel_available_values,' . + '{mm_filter_legend},metamodel,metamodel_filtering,metamodel_fef_template,metamodel_filterparams,' . + 'metamodel_fef_params,metamodel_fef_autosubmit,metamodel_fef_hideclearfilter,metamodel_available_values,' . 'metamodel_jumpTo,metamodel_fef_id,metamodel_fef_urlfragment;' . '{protected_legend:hide},protected;' . '{expert_legend:hide},guests,cssID,space'; diff --git a/src/FrontendIntegration/FrontendFilter.php b/src/FrontendIntegration/FrontendFilter.php index 23029c476..d2f1c2114 100644 --- a/src/FrontendIntegration/FrontendFilter.php +++ b/src/FrontendIntegration/FrontendFilter.php @@ -28,6 +28,7 @@ namespace MetaModels\FrontendIntegration; +use Contao\StringUtil; use ContaoCommunityAlliance\Contao\Bindings\ContaoEvents; use ContaoCommunityAlliance\Contao\Bindings\Events\Controller\RedirectEvent; use Contao\CoreBundle\Csrf\ContaoCsrfTokenManager; @@ -427,8 +428,11 @@ protected function getFilters() } } + $values = \array_merge($all->getSlugParameters(), $all->getGetParameters()); + $baseParameters = $this->getBaseParameters($values); + $arrWidgets = $filterSetting->getParameterFilterWidgets( - \array_merge($all->getSlugParameters(), $all->getGetParameters()), + \array_merge($values, $baseParameters), $jumpToInformation, $filterOptions ); @@ -622,4 +626,50 @@ public function generateClearAll($strContent, $strTemplate) return $strContent; } + + private function getBaseParameters(array $values): array + { + /** @psalm-suppress UndefinedMagicPropertyFetch */ + if ([] === ($presets = StringUtil::deserialize($this->objFilterConfig->metamodel_filterparams, true))) { + return []; + } + + if (null === ($filterSetting = $this->objFilterConfig->getFilterCollection())) { + throw new RuntimeException( + 'Error: no filter object defined, call setFilterSettings() before setFilterParameters().' + ); + } + + $presetNames = $filterSetting->getParameters(); + $filterParamKeys = \array_keys($filterSetting->getParameterFilterNames()); + + $processed = []; + + // We have to use all the preset values we want first. + foreach ($presets as $presetName => $presetValues) { + if (\in_array($presetName, $presetNames, true)) { + $processed[$presetName] = $presetValues['value']; + } + } + + // Now we have to use all FE filter params, that are either: + // * not contained within the presets + // * or are overridable. + foreach ($filterParamKeys as $filterParameterKey) { + // Unknown parameter? - next, please. + if (!\array_key_exists($filterParameterKey, $values)) { + continue; + } + + // Not a preset or allowed to override? - use value. + if ( + (!\array_key_exists($filterParameterKey, $presets)) + || (bool) $presets[$filterParameterKey]['use_get'] + ) { + $processed[$filterParameterKey] = $values[$filterParameterKey]; + } + } + + return $processed; + } }