Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/common field group fixes #1285

Merged
merged 23 commits into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,9 @@ public function testfilterFieldValueReturnsMainBlogValueIfOptionKeyIsListed(): v
->willReturn('main_blog_value');

$this->assertEquals(
'main_blog_value',
'main_blog_value',
$this->instance->filterFieldValue('local_value', 'option', ['key' => 'field_1', 'name' => 'field_name'])
);


}

//Test that filterFieldValue should return local value if option key does not exists in fields to filter
Expand All @@ -116,7 +114,7 @@ public function testfilterFieldValueReturnsLocalBlogValueIfOptionKeyIsNotListed(
->method('getFieldFromSite');

$this->assertEquals(
'local_value',
'local_value',
$this->instance->filterFieldValue('local_value', 'option', ['key' => 'field_3', 'name' => 'field_name'])
);
}
Expand All @@ -130,9 +128,8 @@ public function testfilterFieldValueReturnsLocalBlogValueIfIdNotOptioOrOptions()
->method('getFieldFromSite');

$this->assertEquals(
'local_value',
'local_value',
$this->instance->filterFieldValue('local_value', 15, ['key' => 'field_1', 'name' => 'field_name'])
);
}

}
174 changes: 130 additions & 44 deletions library/CommonFieldGroups/FilterGetFieldToRetriveCommonValues.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,21 @@
use Municipio\CommonFieldGroups\CommonFieldGroupsConfigInterface;
use Municipio\Helper\SiteSwitcher\SiteSwitcherInterface;

/**
* FilterGetFieldToRetriveCommonValues
*
* This class is responsible for filtering fields to retrieve common values.
*
* This class will need some extensive refactoring in the future. Also tests will need to be written.
* The debug function will be removed after release validation.
*
* @category Municipio
*/

class FilterGetFieldToRetriveCommonValues implements Hookable
{
public array $fieldsToFilter = [];
private array $fieldsToFilter = [];
private array $fieldsKeyValueStore = [];

public function __construct(
private WpService $wpService,
Expand All @@ -21,88 +33,162 @@ public function __construct(
) {
}

/**
* Add hooks
*
* @return void
*/
public function addHooks(): void
{
if($this->wpService->isMainSite()) {
if ($this->wpService->isMainSite()) {
return;
}
$this->wpService->addFilter('init', [$this, 'populateFieldsToFilter'], 10, 3);
$this->wpService->addFilter('acf/load_value', [$this, 'filterFieldValue'], 10, 3);
$this->wpService->addAction('init', [$this, 'initializeFieldsToFilter']);
}

/**
* Initialize fields to filter
*
* @param array $queryParams
* @return void
*/
public function initializeFieldsToFilter(): void
{
$this->populateFieldsToFilter();
$this->populateFieldValues();
$this->applyFiltersToFields();
}

/**
* Populates the $fieldsToFilter array dynamically from ACF field groups provided in the config.
* Populate fields to filter
*
* @return void
*/
public function populateFieldsToFilter(): void
private function populateFieldsToFilter(): void
{
$acfGroupKeys = $this->config->getAcfFieldGroupsToFilter();

foreach ($acfGroupKeys as $groupData) {
foreach ($groupData as $groupId) {
$this->fieldsToFilter = array_merge(
$this->fieldsToFilter,
$this->getFieldKeysForGroup($groupId) ?: []
);
$fields = $this->getFieldsForGroup($groupId);
$this->fieldsToFilter = array_merge($this->fieldsToFilter, $fields);
}
}
$this->fieldsToFilter = array_unique($this->fieldsToFilter);
}

/**
* Retrieves the field keys for a specific ACF field group by its ID.
* Populate field values
*
* @param string $groupId The ACF field group ID.
* @return array The field keys in the group.
* @return void
*/
public function getFieldKeysForGroup(string $groupId): array
private function populateFieldValues(): void
{
//TODO: Remove when acf function is delcared in service
$func = $this->acfService->acfGetFields ?? 'acf_get_fields';

// Call the function and return the field keys
return array_map(fn($field) => $field['name'], $func($groupId) ?: []);
$this->siteSwitcher->runInSite(
$this->wpService->getMainSiteId(),
function () {
foreach ($this->fieldsToFilter as $field) {
$this->fetchFieldValue($field);
}
}
);
}

/**
* Filters the ACF field value based on predefined conditions.
* Fetch field value
*
* @param mixed $localValue The current value of the field.
* @param int $postId The ID of the post being edited.
* @param string $field The field object being loaded.
* @return mixed The filtered value for the field.
* @param array $field
* @return void
*/
public function filterFieldValue(mixed $localValue, null|string|int $id, array $field)
private function fetchFieldValue(array $field): void
{

if(!in_array($id, ['option', 'options'])) {
return $localValue;
$baseKey = $field['name'];
$optionKey = "options_" . $field['name'];
$acfFieldMetaKey = "_options_" . $field['name'];

// Fetch main value and ACF metadata key
$this->fieldsKeyValueStore[$optionKey] = $this->wpService->getOption($optionKey);
$this->fieldsKeyValueStore[$acfFieldMetaKey] = $this->wpService->getOption($acfFieldMetaKey);

// Handle true/false fields (convert to bool)
if ($field['type'] === "true_false" && is_numeric($this->fieldsKeyValueStore[$optionKey])) {
$this->fieldsKeyValueStore[$optionKey] = (bool) $this->fieldsKeyValueStore[$optionKey];
}

if($this->wpService->isMainSite()) {
return $localValue;
// Handle subfields for repeaters or similar structures
if (!empty($field['sub_fields']) && is_numeric($this->fieldsKeyValueStore[$optionKey])) {
$this->wpService->addFilter('acf/pre_format_value', function ($null, $value, $postId, $field, $escape_html) use ($baseKey) {
if (!in_array($postId, ['options', 'option'])) {
return $null;
}
if ($field['name'] == $baseKey) {
return $value;
}
return $null;
}, 10, 5);

$this->processSubFields($field, $optionKey);
}
}

if (in_array($field['name'], $this->fieldsToFilter)) {
return $this->getFieldValueFromMainBlog($field['name']);
/**
* Process subfields for repeaters or similar structures
*
* @param array $field
* @param string $optionKey
* @return void
*/
private function processSubFields(array $field, string $optionKey): void
{
$fieldArray = [];
$numberOfEntries = (int)$this->fieldsKeyValueStore[$optionKey];

foreach ($field['sub_fields'] as $subField) {
for ($i = 0; $i < $numberOfEntries; $i++) {
$subFieldKey = $optionKey . "_" . $i . "_" . $subField['name'];
$subFieldValue = $this->wpService->getOption($subFieldKey);
$fieldArray[$i][$subField['name']] = $subFieldValue;

$this->fieldsKeyValueStore[$subFieldKey] = $subFieldValue;
}
}
return $localValue;

$this->fieldsKeyValueStore[$optionKey] = $fieldArray;
}

/**
* Fetches the field value from the main blog using the SiteSwitcher.
* Apply filters to fields
*
* @param string $optionKey The key of the field.
* @param mixed $default The default value if the field does not exist.
* @return mixed The field value.
* @return void
*/
protected function getFieldValueFromMainBlog(string $optionKey): mixed
private function applyFiltersToFields(): void
{
return $this->siteSwitcher->getFieldFromSite(
$this->wpService->getMainSiteId(),
$optionKey
);
foreach ($this->fieldsKeyValueStore as $fieldKey => $fieldValue) {
$this->wpService->addFilter(
'pre_option_' . $fieldKey,
fn() => $fieldValue
);

// Apply ACF-specific filters for unprefixed keys
if (!str_starts_with($fieldKey, '_')) {
$this->wpService->addFilter(
'acf/pre_load_value',
fn($localValue, $postId, $field) => ('options_' . $field['name'] === $fieldKey ? $fieldValue : $localValue),
10,
3
);
}
}
}

/**
* Get acf fields for a specific group
*
* @param string $groupId
* @return array
*/
private function getFieldsForGroup(string $groupId): array
{
$fetchFields = $this->acfService->acfGetFields ?? 'acf_get_fields';
return $fetchFields($groupId) ?: [];
}
}
Loading