PluginProbe ʕ •ᴥ•ʔ
Admin Columns / 7.1.4
Admin Columns v7.1.4
7.1.4 7.0.19 2.3.5 2.4 2.4.1 2.4.10 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.6.1 2.5.6.2 2.5.6.3 2.5.6.4 3.0 3.0.1 3.0.2 3.0.3 3.0.5 3.0.7 3.1 3.1.1 3.1.10 3.1.2 3.1.3 3.1.5 3.2.3 3.2.7 3.3.1 3.4.1 3.4.6 3.4.8 4.0.1 4.0.3 4.1.6 4.2.2 4.2.5 4.3 4.3.2 4.4.1 4.4.4 4.4.5 4.5.5 4.6.1 4.7.18 4.7.19 4.7.20 4.7.7 7.0.13 7.0.14 7.0.16 trunk 1.0 1.1 1.1.3 1.2 1.2.1 1.3 1.3.1 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.5.1 1.4.6 1.4.6.1 1.4.6.2 1.4.6.3 1.4.6.4 1.4.7 1.4.8 1.4.9 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.2 2.2.1 2.2.1.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.5.1 2.2.6 2.2.6.1 2.2.6.2 2.2.6.3 2.2.6.4 2.2.7 2.2.8 2.2.8.1 2.2.9 2.3.1 2.3.2 2.3.3
codepress-admin-columns / classes / Acf / FieldGroupCache.php
codepress-admin-columns / classes / Acf Last commit date
FieldGroup 2 days ago RequestHandler 2 days ago Service 2 days ago AcfColumnFactory.php 2 days ago ColumnMatcher.php 2 days ago FieldGroupCache.php 2 days ago
FieldGroupCache.php
276 lines
1 <?php
2
3 declare(strict_types=1);
4
5 namespace AC\Acf;
6
7 use AC\Acf\FieldGroup\Location;
8 use AC\Acf\FieldGroup\Query;
9 use AC\Acf\FieldGroup\QueryFactory;
10 use AC\Registerable;
11 use AC\TableIdsFactory;
12 use AC\TableScreen;
13 use AC\TableScreenFactory;
14 use AC\Type\TableId;
15
16 /**
17 * Central cache for ACF field group data: field counts per table screen
18 * and the group-to-table-screen mapping. Stored as transients (1 week TTL)
19 * and invalidated automatically when ACF field groups are created, updated,
20 * trashed, or restored.
21 */
22 class FieldGroupCache implements Registerable
23 {
24 private const TRANSIENT_KEY = '_ac_acf_field_counts';
25 private const TRANSIENT_KEY_TABLE_SCREENS = '_ac_acf_group_table_screens';
26 private const TRANSIENT_KEY_META_KEYS_BY_TYPE = '_ac_acf_meta_keys_by_type';
27 private const TTL_SECONDS = WEEK_IN_SECONDS;
28
29 private QueryFactory $query_factory;
30
31 private TableIdsFactory $table_ids_factory;
32
33 private TableScreenFactory $table_screen_factory;
34
35 public function __construct(
36 QueryFactory $query_factory,
37 TableIdsFactory $table_ids_factory,
38 TableScreenFactory $table_screen_factory
39 ) {
40 $this->query_factory = $query_factory;
41 $this->table_ids_factory = $table_ids_factory;
42 $this->table_screen_factory = $table_screen_factory;
43 }
44
45 public function register(): void
46 {
47 add_action('save_post_acf-field-group', [$this, 'invalidate']);
48 add_action('trashed_post', [$this, 'invalidate_field_group']);
49 add_action('untrashed_post', [$this, 'invalidate_field_group']);
50 add_action('deleted_post', [$this, 'invalidate_field_group']);
51 }
52
53 public function invalidate_field_group(int $post_id): void
54 {
55 if ('acf-field-group' === get_post_type($post_id)) {
56 $this->invalidate();
57 }
58 }
59
60 public function get_count_for_post_type(string $post_type): int
61 {
62 return $this->get_count_for_query($post_type, new Location\Post($post_type));
63 }
64
65 /**
66 * @return TableScreen[]
67 */
68 public function get_table_screens_for_group(int $id): array
69 {
70 $map = $this->get_group_table_screen_map();
71
72 if (! isset($map[$id])) {
73 return [];
74 }
75
76 $table_screens = [];
77
78 foreach ($map[$id] as $table_id) {
79 $table_id = new TableId($table_id);
80
81 if ($this->table_screen_factory->can_create($table_id)) {
82 $table_screens[] = $this->table_screen_factory->create($table_id);
83 }
84 }
85
86 return $table_screens;
87 }
88
89 /**
90 * @return array<int, string[]> Group ID => list of table ID strings
91 */
92 private function get_group_table_screen_map(): array
93 {
94 $map = get_transient(self::TRANSIENT_KEY_TABLE_SCREENS);
95
96 if (is_array($map)) {
97 return $map;
98 }
99
100 if (! $this->is_acf_available()) {
101 return [];
102 }
103
104 $map = [];
105
106 foreach ($this->table_ids_factory->create() as $table_id) {
107 if (! $this->table_screen_factory->can_create($table_id)) {
108 continue;
109 }
110
111 $table_screen = $this->table_screen_factory->create($table_id);
112 $query = $this->query_factory->create($table_screen);
113
114 if (! $query) {
115 continue;
116 }
117
118 foreach ($query->get_groups() as $group) {
119 $group_id = (int)($group['ID'] ?? 0);
120
121 if ($group_id <= 0) {
122 continue;
123 }
124
125 if (! isset($map[$group_id])) {
126 $map[$group_id] = [];
127 }
128
129 $table_id_string = (string)$table_id;
130
131 if (! in_array($table_id_string, $map[$group_id], true)) {
132 $map[$group_id][] = $table_id_string;
133 }
134 }
135 }
136
137 set_transient(self::TRANSIENT_KEY_TABLE_SCREENS, $map, self::TTL_SECONDS);
138
139 return $map;
140 }
141
142 public function get_count_for_table_screen(TableScreen $table_screen): int
143 {
144 $query = $this->query_factory->create($table_screen);
145
146 if (! $query) {
147 return 0;
148 }
149
150 return $this->get_count_for_query((string)$table_screen->get_id(), $query);
151 }
152
153 /**
154 * @return array<string, string[]> field type => list of meta_keys (field names)
155 */
156 public function get_meta_keys_grouped_by_type(): array
157 {
158 $cached = get_transient(self::TRANSIENT_KEY_META_KEYS_BY_TYPE);
159
160 if (is_array($cached)) {
161 return $cached;
162 }
163
164 if (! $this->is_acf_available()) {
165 return [];
166 }
167
168 $result = [];
169 $seen_groups = [];
170
171 foreach ($this->table_ids_factory->create() as $table_id) {
172 if (! $this->table_screen_factory->can_create($table_id)) {
173 continue;
174 }
175
176 $table_screen = $this->table_screen_factory->create($table_id);
177 $query = $this->query_factory->create($table_screen);
178
179 if (! $query) {
180 continue;
181 }
182
183 foreach ($query->get_groups() as $group) {
184 $group_key = (string)($group['key'] ?? '');
185
186 if ('' === $group_key || isset($seen_groups[$group_key])) {
187 continue;
188 }
189
190 $seen_groups[$group_key] = true;
191
192 $fields = acf_get_fields($group_key);
193
194 if (! is_array($fields)) {
195 continue;
196 }
197
198 foreach ($fields as $field) {
199 if (! is_array($field) || empty($field['name']) || empty($field['type'])) {
200 continue;
201 }
202
203 $type = (string)$field['type'];
204 $name = (string)$field['name'];
205
206 if (! isset($result[$type])) {
207 $result[$type] = [];
208 }
209
210 if (! in_array($name, $result[$type], true)) {
211 $result[$type][] = $name;
212 }
213 }
214 }
215 }
216
217 set_transient(self::TRANSIENT_KEY_META_KEYS_BY_TYPE, $result, self::TTL_SECONDS);
218
219 return $result;
220 }
221
222 private function is_acf_available(): bool
223 {
224 return function_exists('acf_get_field_groups')
225 && function_exists('acf_get_fields')
226 && function_exists('acf_get_store');
227 }
228
229 private function get_count_for_query(string $cache_key, Query $query): int
230 {
231 if (! $this->is_acf_available()) {
232 return 0;
233 }
234
235 $counts = get_transient(self::TRANSIENT_KEY);
236
237 if (! is_array($counts)) {
238 $counts = [];
239 }
240
241 if (array_key_exists($cache_key, $counts)) {
242 return $counts[$cache_key];
243 }
244
245 $count = $this->count_fields($query);
246 $counts[$cache_key] = $count;
247
248 set_transient(self::TRANSIENT_KEY, $counts, self::TTL_SECONDS);
249
250 return $count;
251 }
252
253 public function invalidate(): void
254 {
255 delete_transient(self::TRANSIENT_KEY);
256 delete_transient(self::TRANSIENT_KEY_TABLE_SCREENS);
257 delete_transient(self::TRANSIENT_KEY_META_KEYS_BY_TYPE);
258 }
259
260 private function count_fields(Query $query): int
261 {
262 $count = 0;
263
264 foreach ($query->get_groups() as $group) {
265 $fields = acf_get_fields($group['key']);
266
267 if (is_array($fields)) {
268 $count += count($fields);
269 }
270 }
271
272 return $count;
273 }
274
275 }
276