PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 2.8.23.4
Pods – Custom Content Types and Fields v2.8.23.4
2.8.23.4 2.9.19.4 3.0.10.4 3.1.4.2 3.2.8.3 3.3.9.1 trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / classes / PodsTermSplitting.php
pods / classes Last commit date
cli 2 weeks ago fields 2 weeks ago widgets 2 weeks ago Pods.php 2 weeks ago PodsAPI.php 2 weeks ago PodsAdmin.php 2 weeks ago PodsArray.php 2 weeks ago PodsComponent.php 2 weeks ago PodsComponents.php 2 weeks ago PodsData.php 2 weeks ago PodsField.php 2 weeks ago PodsForm.php 2 weeks ago PodsI18n.php 2 weeks ago PodsInit.php 2 weeks ago PodsMeta.php 2 weeks ago PodsMigrate.php 2 weeks ago PodsRESTFields.php 2 weeks ago PodsRESTHandlers.php 2 weeks ago PodsTermSplitting.php 2 weeks ago PodsUI.php 2 weeks ago PodsView.php 2 weeks ago
PodsTermSplitting.php
504 lines
1 <?php
2
3 /**
4 * @package Pods
5 */
6 class Pods_Term_Splitting {
7
8 /** @var int ID of the formerly shared term */
9 private $term_id;
10
11 /** @var int ID of the new term created for the $term_taxonomy_id */
12 private $new_term_id;
13
14 /** @var string Taxonomy for the split term */
15 private $taxonomy;
16
17 /** @var string */
18 private $progress_option_name;
19
20 /** @var array */
21 private $previous_progress = [];
22
23 /**
24 * @param int $term_id ID of the formerly shared term.
25 * @param int $new_term_id ID of the new term created for the $term_taxonomy_id.
26 * @param string $taxonomy Taxonomy for the split term.
27 */
28 public function __construct( $term_id, $new_term_id, $taxonomy ) {
29 $this->term_id = $term_id;
30 $this->new_term_id = $new_term_id;
31 $this->taxonomy = $taxonomy;
32
33 $this->progress_option_name = "_pods_term_split_{$term_id}_{$taxonomy}";
34 }
35
36 /**
37 *
38 */
39 public function split_shared_term() {
40 // Stash any previous progress
41 $this->previous_progress = $this->get_progress();
42
43 if ( empty( $this->previous_progress ) ) {
44 $this->append_progress( 'started' );
45 $this->append_progress( "new term ID: {$this->new_term_id}" );
46 }
47
48 // Get the Pod information if the taxonomy is a Pod
49 $taxonomy_pod = $this->get_pod_info();
50
51 // Is the taxonomy a Pod?
52 if ( is_array( $taxonomy_pod ) || $taxonomy_pod instanceof Pods\Whatsit ) {
53 $this->update_podsrel_taxonomy( $taxonomy_pod['id'] );
54
55 // Update the Pods table if the taxonomy is a table based Pod
56 if ( 'table' === $taxonomy_pod['storage'] ) {
57 $this->update_pod_table( $taxonomy_pod['pod_table'] );
58 }
59 }
60
61 // Track down all fields related to the target taxonomy and update stored term IDs as necessary
62 $this->update_relationships_to_term();
63
64 // Clean up
65 $this->delete_progress();
66 }
67
68 /**
69 * Return the Pod information for the specified taxonomy, or null if the taxonomy isn't a Pod
70 *
71 * @return array|bool|mixed|null
72 */
73 private function get_pod_info() {
74 $pod_info = null;
75
76 try {
77 $api = pods_api();
78
79 if ( $api->pod_exists( [ 'name' => $this->taxonomy ] ) ) {
80 // Load the taxonomy Pod
81 $params = [
82 'name' => $this->taxonomy,
83 ];
84
85 $pod_info = $api->load_pod( $params, false );
86 }
87 } catch ( Exception $exception ) {
88 // Do nothing.
89 }
90
91 return $pod_info;
92 }
93
94 /**
95 * @param int $pod_id
96 */
97 private function update_podsrel_taxonomy( $pod_id ) {
98 /** @var wpdb $wpdb */
99 global $wpdb;
100
101 $task = "update_podsrel_taxonomy_{$pod_id}";
102
103 if ( ! $this->have_done( $task ) ) {
104 if ( pods_podsrel_enabled() ) {
105 // UPDATE {$wpdb->prefix}podsrel SET item_id = {$new_term_id} WHERE pod_id = {$pod_id} AND item_id = {$term_id}
106 $table = "{$wpdb->prefix}podsrel";
107
108 $data = [
109 'item_id' => $this->new_term_id,
110 ];
111
112 $where = [
113 'pod_id' => $pod_id,
114 'item_id' => $this->term_id,
115 ];
116
117 $format = '%d';
118 $where_format = '%d';
119
120 $wpdb->update( $table, $data, $where, $format, $where_format );
121 }
122
123 /**
124 * Allow hooking into the term splitting process for taxonomy.
125 *
126 * @since 2.8.0
127 *
128 * @param int $pod_id The pod ID for the taxonomy.
129 * @param int $term_id The current term ID being split.
130 * @param int $new_term_id The new term ID.
131 * @param string $task The task being done.
132 */
133 do_action( 'pods_term_splitting_update_taxonomy', $pod_id, $this->term_id, $this->new_term_id, $task );
134
135 $this->append_progress( $task );
136 }
137 }
138
139 /**
140 * @param string $pod_table
141 */
142 private function update_pod_table( $pod_table ) {
143 /** @var wpdb $wpdb */
144 global $wpdb;
145
146 $task = "update_pod_table_{$pod_table}";
147
148 if ( ! $this->have_done( $task ) ) {
149 // Prime the values and update
150 $data = [
151 'id' => $this->new_term_id,
152 ];
153
154 $where = [
155 'id' => $this->term_id,
156 ];
157
158 $format = '%d';
159 $where_format = '%d';
160
161 $wpdb->update( $pod_table, $data, $where, $format, $where_format );
162
163 $this->append_progress( $task );
164 }
165 }
166
167 /**
168 * Track down all fields related to the target taxonomy and update stored term IDs as necessary
169 */
170 private function update_relationships_to_term() {
171 // Loop through all Pods
172 try {
173 $all_pods = pods_api()->load_pods();
174 } catch ( Exception $exception ) {
175 return;
176 }
177
178 if ( ! is_array( $all_pods ) ) {
179 return;
180 }
181
182 foreach ( $all_pods as $this_pod_id => $this_pod ) {
183 // Loop through all fields in this Pod
184 foreach ( $this_pod['fields'] as $this_field_name => $this_field ) {
185 // Ignore everything except relationship fields to this taxonomy
186 if ( 'pick' !== $this_field['type'] || 'taxonomy' !== $this_field['pick_object'] || $this->taxonomy !== $this_field['pick_val'] ) {
187 continue;
188 }
189
190 // Update the term ID in podsrel everywhere it is the value for this field
191 $this->update_podsrel_related_term( $this_field['id'] );
192
193 // Fix-up any special-case relationships that store term IDs in their own meta table and/or serialized
194 switch ( $this_pod['type'] ) {
195 case 'post_type':
196 $this->update_postmeta( $this_pod['name'], $this_field_name );
197 break;
198
199 case 'comment':
200 $this->update_commentmeta( $this_field_name );
201 break;
202
203 case 'user':
204 $this->update_usermeta( $this_field_name );
205 break;
206
207 case 'settings':
208 $this->update_setting_meta( $this_pod['name'], $this_field_name );
209 break;
210 }
211 }//end foreach
212 }//end foreach
213
214 }
215
216 /**
217 * @param int $field_id
218 */
219 private function update_podsrel_related_term( $field_id ) {
220 /** @var wpdb $wpdb */
221 global $wpdb;
222
223 $task = "update_podsrel_related_term_{$field_id}";
224
225 if ( ! $this->have_done( $task ) ) {
226 if ( pods_podsrel_enabled() ) {
227 // UPDATE {$wpdb->prefix}podsrel SET related_item_id = {$new_term_id} WHERE field_id = {$field_id} AND related_item_id = {$term_id}
228 $table = "{$wpdb->prefix}podsrel";
229
230 $data = [
231 'related_item_id' => $this->new_term_id,
232 ];
233
234 $where = [
235 'field_id' => $field_id,
236 'related_item_id' => $this->term_id,
237 ];
238
239 $format = '%d';
240 $where_format = '%d';
241
242 $wpdb->update( $table, $data, $where, $format, $where_format );
243 }
244
245 /**
246 * Allow hooking into the term splitting process for taxonomy by related term.
247 *
248 * @since 2.8.0
249 *
250 * @param int $field_id The field ID for the relationship.
251 * @param int $term_id The current term ID being split.
252 * @param int $new_term_id The new term ID.
253 * @param string $task The task being done.
254 */
255 do_action( 'pods_term_splitting_update_related_term', $field_id, $this->term_id, $this->new_term_id, $task );
256
257 $this->append_progress( $task );
258 }
259 }
260
261 /**
262 * Called for all fields related to the target taxonomy that are in a post_type
263 *
264 * @param string $pod_name
265 * @param string $field_name
266 */
267 private function update_postmeta( $pod_name, $field_name ) {
268 /** @var wpdb $wpdb */
269 global $wpdb;
270
271 // Fix up the unserialized data
272 $task = "update_postmeta_{$pod_name}_{$field_name}_unserialized";
273 if ( ! $this->have_done( $task ) ) {
274 $wpdb->query( $wpdb->prepare( "
275 UPDATE
276 {$wpdb->postmeta} AS meta
277 LEFT JOIN {$wpdb->posts} AS t
278 ON meta.post_id = t.ID
279 SET
280 meta_value = %s
281 WHERE
282 meta_key = %s
283 AND meta_value = %s
284 AND t.post_type = %s
285 ", $this->new_term_id, $field_name, $this->term_id, $pod_name ) );
286
287 $this->append_progress( $task );
288 }//end if
289
290 // Fix up the serialized data
291 $task = "update_postmeta_{$pod_name}_{$field_name}_serialized";
292 if ( ! $this->have_done( $task ) ) {
293 $meta_key = sprintf( '_pods_%s', $field_name );
294 $target_serialized = sprintf( ';i:%s;', $this->term_id );
295 $replace_serialized = sprintf( ';i:%s;', $this->new_term_id );
296
297 $wpdb->query( $wpdb->prepare( "
298 UPDATE
299 {$wpdb->postmeta} AS meta
300 LEFT JOIN {$wpdb->posts} AS t
301 ON meta.post_id = t.ID
302 SET
303 meta.meta_value = REPLACE( meta.meta_value, %s, %s )
304 WHERE
305 meta.meta_key = %s
306 AND t.post_type = %s
307 AND meta_value LIKE '%%%s%%'
308 ", $target_serialized, $replace_serialized, $meta_key, $pod_name, pods_sanitize_like( $target_serialized ) ) );
309
310 $this->append_progress( $task );
311 }//end if
312
313 }
314
315 /**
316 * Called for all fields related to the target taxonomy that are in a comment Pod
317 *
318 * @param string $field_name
319 */
320 private function update_commentmeta( $field_name ) {
321 /** @var wpdb $wpdb */
322 global $wpdb;
323
324 // Fix up the unserialized data
325 $task = "update_commentmeta_{$field_name}_unserialized";
326 if ( ! $this->have_done( $task ) ) {
327 $table = $wpdb->commentmeta;
328 $data = [ 'meta_value' => $this->new_term_id ];
329 $where = [
330 'meta_key' => $field_name,
331 'meta_value' => $this->term_id,
332 ];
333 $format = '%s';
334 $where_format = [ '%s', '%s' ];
335 $wpdb->update( $table, $data, $where, $format, $where_format );
336
337 $this->append_progress( $task );
338 }
339
340 // Fix up the serialized data
341 $task = "update_commentmeta_{$field_name}_serialized";
342 if ( ! $this->have_done( $task ) ) {
343 $meta_key = sprintf( '_pods_%s', $field_name );
344 $target_serialized = sprintf( ';i:%s;', $this->term_id );
345 $replace_serialized = sprintf( ';i:%s;', $this->new_term_id );
346
347 $wpdb->query( $wpdb->prepare( "
348 UPDATE
349 {$wpdb->commentmeta}
350 SET
351 meta_value = REPLACE( meta_value, %s, %s )
352 WHERE
353 meta_key = %s
354 AND meta_value LIKE '%%%s%%'
355 ", $target_serialized, $replace_serialized, $meta_key, pods_sanitize_like( $target_serialized ) ) );
356
357 $this->append_progress( $task );
358 }//end if
359
360 }
361
362 /**
363 * Called for all fields related to the target taxonomy that are in a user Pod
364 *
365 * @param string $field_name
366 */
367 private function update_usermeta( $field_name ) {
368 /** @var wpdb $wpdb */
369 global $wpdb;
370
371 // Fix up the unserialized data
372 $task = "update_usermeta_{$field_name}_unserialized";
373 if ( ! $this->have_done( $task ) ) {
374 $table = $wpdb->usermeta;
375 $data = [ 'meta_value' => $this->new_term_id ];
376 $where = [
377 'meta_key' => $field_name,
378 'meta_value' => $this->term_id,
379 ];
380 $format = '%s';
381 $where_format = [ '%s', '%s' ];
382 $wpdb->update( $table, $data, $where, $format, $where_format );
383
384 $this->append_progress( $task );
385 }
386
387 // Fix up the serialized data
388 $task = "update_usermeta_{$field_name}_serialized";
389 if ( ! $this->have_done( $task ) ) {
390 $meta_key = sprintf( '_pods_%s', $field_name );
391 $target_serialized = sprintf( ';i:%s;', $this->term_id );
392 $replace_serialized = sprintf( ';i:%s;', $this->new_term_id );
393
394 $wpdb->query( $wpdb->prepare( "
395 UPDATE
396 {$wpdb->usermeta}
397 SET
398 meta_value = REPLACE( meta_value, %s, %s )
399 WHERE
400 meta_key = %s
401 AND meta_value LIKE '%%%s%%'
402 ", $target_serialized, $replace_serialized, $meta_key, pods_sanitize_like( $target_serialized ) ) );
403
404 $this->append_progress( $task );
405 }//end if
406
407 }
408
409 /**
410 * Called for all fields related to the target taxonomy that are in a user Pod
411 *
412 * @param string $pod_name
413 * @param string $field_name
414 */
415 private function update_setting_meta( $pod_name, $field_name ) {
416 /** @var wpdb $wpdb */
417 global $wpdb;
418
419 $option_name = "{$pod_name}_{$field_name}";
420
421 // Fix up the unserialized data
422 $task = "update_setting_meta_{$pod_name}_{$field_name}_unserialized";
423 if ( ! $this->have_done( $task ) ) {
424 // UPDATE {$wpdb->options} SET option_value = '{$new_term_id}' WHERE option_name = '{$pod_name}_{$field_name}' AND option_value = '{$term_id}'
425 $table = $wpdb->options;
426 $data = [ 'option_value' => $this->new_term_id ];
427 $where = [
428 'option_name' => $option_name,
429 'option_value' => $this->term_id,
430 ];
431 $format = '%s';
432 $where_format = [ '%s', '%s' ];
433 $wpdb->update( $table, $data, $where, $format, $where_format );
434
435 $this->append_progress( $task );
436 }
437
438 // Fix up the serialized data
439 $task = "update_setting_meta_{$pod_name}_{$field_name}_serialized";
440 if ( ! $this->have_done( $task ) ) {
441 $target_serialized = sprintf( ';i:%s;', $this->term_id );
442 $replace_serialized = sprintf( ';i:%s;', $this->new_term_id );
443
444 $wpdb->query( $wpdb->prepare( "
445 UPDATE
446 {$wpdb->options}
447 SET
448 option_value = REPLACE( option_value, %s, %s )
449 WHERE
450 option_name = %s
451 AND option_value LIKE '%%%s%%'
452 ", $target_serialized, $replace_serialized, $option_name, pods_sanitize_like( $target_serialized ) ) );
453
454 $this->append_progress( $task );
455 }//end if
456
457 }
458
459 /**
460 * @param string $task_name
461 *
462 * @return bool
463 */
464 private function have_done( $task_name ) {
465 return in_array( $task_name, $this->previous_progress, true );
466 }
467
468 /**
469 * @return array
470 */
471 private function get_progress() {
472 return get_option( $this->progress_option_name, [] );
473 }
474
475 /**
476 * @param $data
477 */
478 private function append_progress( $data ) {
479 // Get the current progress array
480 $current_progress = $this->get_progress();
481 if ( ! is_array( $current_progress ) ) {
482 $current_progress = [];
483 }
484
485 // Tack on the new data
486 $updated_progress = array_merge( $current_progress, [ $data ] );
487
488 // Note: we don't want autoload set and you cannot specify autoload via update_option
489 if ( ! empty( $current_progress ) && is_array( $current_progress ) ) {
490 update_option( $this->progress_option_name, $updated_progress );
491 } else {
492 add_option( $this->progress_option_name, $updated_progress, '', false );
493 }
494 }
495
496 /**
497 *
498 */
499 private function delete_progress() {
500 delete_option( $this->progress_option_name );
501 }
502
503 }
504