Skip to content

Commit e571b68

Browse files
rework acf fields processing (WP-991)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ea58048 commit e571b68

8 files changed

Lines changed: 108 additions & 230 deletions

File tree

inc/Smartling/Base/SmartlingCoreDownloadTrait.php

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public function downloadTranslationBySubmission(SubmissionEntity $entity): void
5858
$entity->getFileUri(),
5959
])
6060
);
61-
$data = (string)$this->getApiWrapper()->downloadFile($entity);
61+
$data = $this->getApiWrapper()->downloadFile($entity);
6262
$msg = vsprintf('Downloaded file for submission id = \'%s\'. Dump: %s', [$entity->getId(),
6363
base64_encode($data)]);
6464
$this->getLogger()->debug($msg);
@@ -74,9 +74,7 @@ public function downloadTranslationBySubmission(SubmissionEntity $entity): void
7474
$entity->getTargetLocale(),
7575
])
7676
);
77-
if (count($this->acfDynamicSupport->getDefinitions()) === 0) {
78-
$this->acfDynamicSupport->run();
79-
}
77+
$this->acfDynamicSupport->runIfRequired();
8078
$this->applyXML($entity, $data, $this->xmlHelper, $this->postContentHelper);
8179
LiveNotificationController::pushNotification(
8280
$this
@@ -122,12 +120,12 @@ public function downloadTranslationBySubmission(SubmissionEntity $entity): void
122120
}
123121
}
124122

125-
public function downloadTranslationBySubmissionId($id)
123+
public function downloadTranslationBySubmissionId($id): void
126124
{
127125
do_action(ExportedAPI::ACTION_SMARTLING_DOWNLOAD_TRANSLATION, $this->loadSubmissionEntityById($id));
128126
}
129127

130-
public function downloadTranslation($contentType, $sourceBlog, $sourceEntity, $targetBlog, $targetEntity = null)
128+
public function downloadTranslation($contentType, $sourceBlog, $sourceEntity, $targetBlog, $targetEntity = null): void
131129
{
132130
$submission = $this->getTranslationHelper()
133131
->prepareSubmission($contentType, $sourceBlog, $sourceEntity, $targetBlog, $targetEntity);

inc/Smartling/Extensions/Acf/AcfDynamicSupport.php

Lines changed: 56 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
use Smartling\Base\ExportedAPI;
66
use Smartling\Bootstrap;
7-
use Smartling\Exception\SmartlingConfigException;
87
use Smartling\Exception\SmartlingDirectRunRuntimeException;
98
use Smartling\Extensions\AcfOptionPages\ContentTypeAcfOption;
109
use Smartling\Helpers\ArrayHelper;
@@ -31,7 +30,7 @@ class AcfDynamicSupport
3130
public const REFERENCED_TYPE_POST = 'post';
3231
public const REFERENCED_TYPE_TAXONOMY = 'taxonomy';
3332

34-
public static array $acfReverseDefinitionAction = [];
33+
private array $filterConfigurations = [];
3534

3635
private ?array $definitions = null;
3736

@@ -47,20 +46,6 @@ public function getDefinitions(): array
4746
return $this->definitions ?? [];
4847
}
4948

50-
/**
51-
* @throws SmartlingConfigException
52-
*/
53-
private function getAcf(): mixed
54-
{
55-
global $acf;
56-
57-
if (!isset($acf)) {
58-
throw new SmartlingConfigException('ACF plugin is not installed or activated.');
59-
}
60-
61-
return $acf;
62-
}
63-
6449
public function __construct(
6550
private ArrayHelper $arrayHelper,
6651
private SettingsManager $settingsManager,
@@ -108,7 +93,7 @@ private function getBlogListForSearch(): array
10893
/**
10994
* @throws SmartlingDirectRunRuntimeException
11095
*/
111-
private function getDatabaseDefinitions(): array
96+
private function loadDefinitions(): array
11297
{
11398
$defs = [];
11499
$this->getLogger()->debug('Looking for ACF definitions via ACF API');
@@ -130,177 +115,78 @@ private function getDatabaseDefinitions(): array
130115
return $defs;
131116
}
132117

133-
private function collectAcfDefinitions(): array
118+
public function getFilterConfiguration(string $key): ?array
134119
{
135-
$defs = [];
136-
foreach (acf_get_field_groups() as $group) {
137-
$defs[$group['key']] = [
138-
'global_type' => 'group',
139-
'active' => $group['active'] ?? 1,
140-
];
141-
$stack = [$group];
142-
while (null !== ($parent = array_shift($stack))) {
143-
foreach (acf_get_fields($parent) as $field) {
144-
if (!is_array($field) || !isset($field['key'], $field['type'])) {
145-
continue;
146-
}
147-
$defs[$field['key']] = ['global_type' => 'field', 'type' => $field['type']];
148-
if ('clone' === $field['type']) {
149-
if (array_key_exists('clone', $field)) {
150-
$defs[$field['key']]['clone'] = $field['clone'];
151-
} else {
152-
$this->getLogger()->debug('ACF field fieldType="clone" has no target. ' . json_encode($field));
153-
}
154-
}
155-
if (in_array($field['type'], ['repeater', 'group', 'flexible_content'], true)) {
156-
$stack[] = $field;
157-
}
158-
}
159-
}
160-
}
161-
162-
return $defs;
120+
return $this->filterConfigurations[$key] ?? null;
163121
}
164122

165-
public function getReferencedType(string $type): string
166-
{
167-
return match ($type) {
168-
'image', 'image_aspect_ratio_crop', 'file', 'gallery' => self::REFERENCED_TYPE_MEDIA,
169-
'post_object', 'page_link', 'relationship' => self::REFERENCED_TYPE_POST,
170-
'taxonomy' => self::REFERENCED_TYPE_TAXONOMY,
171-
default => self::REFERENCED_TYPE_NONE,
172-
};
173-
}
174-
175-
protected function extractGroupsDefinitions(array $groups): array
123+
private function collectAcfDefinitions(): array
176124
{
177125
$defs = [];
178-
foreach ($groups as $group) {
126+
foreach (acf_get_raw_field_groups() as $group) {
127+
if (!is_array($group) || !isset($group['key'], $group['ID'])) {
128+
continue;
129+
}
179130
$defs[$group['key']] = [
180131
'global_type' => 'group',
132+
'active' => $group['active'] ?? 1,
181133
];
182-
if (array_key_exists('active', $group)) {
183-
$defs[$group['key']]['active'] = $group['active'];
134+
foreach (acf_get_raw_fields($group['ID']) as $field) {
135+
$this->addAcfFieldToDefs($field, $defs);
184136
}
185137
}
186138

187139
return $defs;
188140
}
189141

190-
protected function extractFieldDefinitions(array $fields): array
142+
private function addAcfFieldToDefs(mixed $field, array &$defs): void
191143
{
192-
$defs = [];
193-
194-
foreach ($fields as $field) {
195-
$defs[$field['key']] = [
196-
'global_type' => 'field',
197-
'type' => $field['type'],
198-
'name' => $field['name'],
199-
'parent' => $field['parent'],
200-
];
201-
202-
if ('clone' === $field['type']) {
144+
if (!is_array($field) || !isset($field['key'], $field['type'])) {
145+
return;
146+
}
147+
$defs[$field['key']] = ['global_type' => 'field', 'type' => $field['type']];
148+
if ('clone' === $field['type']) {
149+
if (array_key_exists('clone', $field)) {
203150
$defs[$field['key']]['clone'] = $field['clone'];
151+
} else {
152+
$this->getLogger()->debug('ACF field fieldType="clone" has no target. ' . json_encode($field));
204153
}
205154
}
206-
207-
return $defs;
208-
}
209-
210-
/**
211-
* Get local definitions for ACF Pro ver < 5.7.12
212-
*/
213-
private function getLocalDefinitionsOld(): array
214-
{
215-
$defs = [];
216-
try {
217-
$acf = (array)$this->getAcf();
218-
} catch (SmartlingConfigException $e) {
219-
$this->getLogger()->warning($e->getMessage());
220-
$this->getLogger()->warning('Unable to load old type local ACF definitions.');
221-
222-
return $defs;
155+
if (!in_array($field['type'], ['repeater', 'group', 'flexible_content'], true)) {
156+
return;
223157
}
224-
225-
if (array_key_exists('local', $acf)) {
226-
if ($acf['local'] instanceof \acf_local) {
227-
$local = $acf['local'];
228-
229-
$defs = array_merge($defs, $this->extractGroupsDefinitions($local->groups));
230-
$defs = array_merge($defs, $this->extractFieldDefinitions($local->fields));
231-
158+
if (isset($field['ID']) && (int)$field['ID'] > 0) {
159+
foreach (acf_get_raw_fields((int)$field['ID']) as $child) {
160+
$this->addAcfFieldToDefs($child, $defs);
232161
}
233162
}
234-
235-
return $defs;
236-
}
237-
238-
protected function validateAcfStores(): bool
239-
{
240-
global $acf_stores;
241-
242-
return is_array($acf_stores)
243-
&& array_key_exists('local-groups', $acf_stores)
244-
&& ($acf_stores['local-groups'] instanceof \ACF_Data)
245-
&& array_key_exists('local-fields', $acf_stores)
246-
&& ($acf_stores['local-fields'] instanceof \ACF_Data);
247-
}
248-
249-
/**
250-
* Get local definitions for ACF Pro ver 5.7.12+
251-
*/
252-
private function getLocalDefinitionsNew(): array
253-
{
254-
$defs = [];
255-
256-
if ($this->validateAcfStores()) {
257-
global $acf_stores;
258-
259-
$defs = array_merge($defs, $this->extractGroupsDefinitions($acf_stores['local-groups']->get_data()));
260-
$defs = array_merge($defs, $this->extractFieldDefinitions($acf_stores['local-fields']->get_data()));
261-
262-
} else {
263-
$this->getLogger()->warning('Unable to load new type local ACF definitions.');
264-
}
265-
266-
return $defs;
267-
}
268-
269-
/**
270-
* Reads local (PHP and JSON) ACF Definitions
271-
*/
272-
private function getLocalDefinitions(): array
273-
{
274-
$defs = $this->getLocalDefinitionsOld();
275-
276-
if (empty($defs)) {
277-
$defs = $this->getLocalDefinitionsNew();
278-
}
279-
280-
return $defs;
281-
}
282-
283-
private function verifyDefinitions(array $localDefinitions, array $dbDefinitions): bool
284-
{
285-
foreach ($dbDefinitions as $key => $definition) {
286-
if (!array_key_exists($key, $localDefinitions)) {
287-
return false;
163+
if (isset($field['sub_fields']) && is_array($field['sub_fields'])) {
164+
foreach ($field['sub_fields'] as $child) {
165+
$this->addAcfFieldToDefs($child, $defs);
288166
}
289-
290-
if ($definition['global_type'] === 'field') {
291-
$local = $localDefinitions[$key];
292-
if ($local['type'] !== $definition['type']) {
293-
// ACF Option Pages has internal issue in definition, so skip it:
294-
if ('group_572b269b668a4' !== $local['parent']) {
295-
return false;
167+
}
168+
if (isset($field['layouts']) && is_array($field['layouts'])) {
169+
foreach ($field['layouts'] as $layout) {
170+
if (is_array($layout) && isset($layout['sub_fields']) && is_array($layout['sub_fields'])) {
171+
foreach ($layout['sub_fields'] as $child) {
172+
$this->addAcfFieldToDefs($child, $defs);
296173
}
297174
}
298175
}
299176
}
177+
}
300178

301-
return true;
179+
public function getReferencedType(string $type): string
180+
{
181+
return match ($type) {
182+
'image', 'image_aspect_ratio_crop', 'file', 'gallery' => self::REFERENCED_TYPE_MEDIA,
183+
'post_object', 'page_link', 'relationship' => self::REFERENCED_TYPE_POST,
184+
'taxonomy' => self::REFERENCED_TYPE_TAXONOMY,
185+
default => self::REFERENCED_TYPE_NONE,
186+
};
302187
}
303188

189+
304190
private function tryRegisterACFOptions(): void
305191
{
306192
$this->getLogger()->debug('Checking if ACF Option Pages presents...');
@@ -399,31 +285,16 @@ private function tryRegisterACF(): void
399285
$this->getLogger()->debug('Checking if ACF presents...');
400286
if ($this->isAcfActive()) {
401287
$this->getLogger()->debug('ACF detected.');
402-
$localDefinitions = $this->getLocalDefinitions();
403-
404288
try {
405-
$dbDefinitions = $this->getDatabaseDefinitions();
289+
$this->definitions = $this->loadDefinitions();
406290
} catch (SmartlingDirectRunRuntimeException $e) {
407-
$dbDefinitions = [];
291+
$this->definitions = [];
408292
DiagnosticsHelper::addDiagnosticsMessage(
409-
'Failed to get ACF definitions from database.' .
293+
'Failed to get ACF definitions. ' .
410294
'Please ensure that WordPress network is set up properly.<br>' .
411295
"Exception message: {$e->getMessage()}"
412296
);
413297
}
414-
415-
if (false === $this->verifyDefinitions($localDefinitions, $dbDefinitions)) {
416-
$url = admin_url('edit.php?post_type=acf-field-group&page=acf-tools');
417-
$msg = [
418-
'ACF Configuration has been changed.',
419-
'Please update groups and fields definitions for all sites (As PHP generated code).',
420-
vsprintf('Use <strong><a href="%s">this</a></strong> page to generate export code and add it to your theme or extra plugin.',
421-
[$url]),
422-
];
423-
DiagnosticsHelper::addDiagnosticsMessage(implode('<br/>', $msg));
424-
}
425-
426-
$this->definitions = array_merge($localDefinitions, $dbDefinitions);
427298
$this->buildRules();
428299
$this->prepareFilters();
429300
} else {
@@ -437,6 +308,13 @@ public function run(): void
437308
$this->tryRegisterACF();
438309
}
439310

311+
public function runIfRequired(): void
312+
{
313+
if (count($this->getDefinitions()) === 0) {
314+
$this->run();
315+
}
316+
}
317+
440318
private function prepareFilters(): void
441319
{
442320
$rules = [];
@@ -468,7 +346,7 @@ private function prepareFilters(): void
468346
}
469347
}
470348

471-
static::$acfReverseDefinitionAction = $rules;
349+
$this->filterConfigurations = $rules;
472350
}
473351

474352
public function getReplacerIdForField(array $attributes, string $key): ?string

0 commit comments

Comments
 (0)