PageRenderTime 66ms CodeModel.GetById 37ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/pods/classes/PodsTermSplitting.php

https://gitlab.com/najomie/ljm
PHP | 515 lines | 301 code | 111 blank | 103 comment | 28 complexity | a5b38604c9328b9d211f37549ca139e0 MD5 | raw file
  1. <?php
  2. /**
  3. * @package Pods
  4. */
  5. class Pods_Term_Splitting {
  6. /** @var int ID of the formerly shared term */
  7. private $term_id;
  8. /** @var int ID of the new term created for the $term_taxonomy_id */
  9. private $new_term_id;
  10. /** @var string Taxonomy for the split term */
  11. private $taxonomy;
  12. /** @var string */
  13. private $progress_option_name;
  14. /** @var array */
  15. private $previous_progress = array();
  16. /**
  17. * @param int $term_id ID of the formerly shared term.
  18. * @param int $new_term_id ID of the new term created for the $term_taxonomy_id.
  19. * @param string $taxonomy Taxonomy for the split term.
  20. */
  21. public function __construct( $term_id, $new_term_id, $taxonomy ) {
  22. $this->term_id = $term_id;
  23. $this->new_term_id = $new_term_id;
  24. $this->taxonomy = $taxonomy;
  25. $this->progress_option_name = "_pods_term_split_{$term_id}_{$taxonomy}";
  26. }
  27. /**
  28. *
  29. */
  30. public function split_shared_term() {
  31. // Stash any previous progress
  32. $this->previous_progress = $this->get_progress();
  33. if ( empty( $this->previous_progress ) ) {
  34. $this->append_progress( 'started' );
  35. $this->append_progress( "new term ID: {$this->new_term_id}" );
  36. }
  37. // Get the Pod information if the taxonomy is a Pod
  38. $taxonomy_pod = $this->get_pod_info();
  39. // Is the taxonomy a Pod?
  40. if ( is_array( $taxonomy_pod ) ) {
  41. $this->update_podsrel_taxonomy( $taxonomy_pod[ 'id' ] );
  42. // Update the Pods table if the taxonomy is a table based Pod
  43. if ( 'table' == $taxonomy_pod[ 'storage' ] ) {
  44. $this->update_pod_table( $taxonomy_pod[ 'pod_table' ] );
  45. }
  46. }
  47. // Track down all fields related to the target taxonomy and update stored term IDs as necessary
  48. $this->update_relationships_to_term();
  49. // Clean up
  50. $this->delete_progress();
  51. }
  52. /**
  53. * Return the Pod information for the specified taxonomy, or null if the taxonomy isn't a Pod
  54. *
  55. * @return array|bool|mixed|null
  56. */
  57. private function get_pod_info() {
  58. $pod_info = null;
  59. if ( pods_api()->pod_exists( $this->taxonomy ) ) {
  60. // Load the taxonomy Pod
  61. $params = array(
  62. 'name' => $this->taxonomy,
  63. 'table_info' => true
  64. );
  65. $pod_info = pods_api()->load_pod( $params, false );
  66. }
  67. return $pod_info;
  68. }
  69. /**
  70. * @param int $pod_id
  71. */
  72. private function update_podsrel_taxonomy( $pod_id ) {
  73. /** @global wpdb $wpdb */
  74. global $wpdb;
  75. $task = "update_podsrel_taxonomy_{$pod_id}";
  76. if ( ! $this->have_done( $task ) ) {
  77. // UPDATE {$wpdb->prefix}podsrel SET item_id = {$new_term_id} WHERE pod_id = {$pod_id} AND item_id = {$term_id}
  78. $table = "{$wpdb->prefix}podsrel";
  79. $data = array( 'item_id' => $this->new_term_id );
  80. $where = array(
  81. 'pod_id' => $pod_id,
  82. 'item_id' => $this->term_id
  83. );
  84. $format = '%d';
  85. $where_format = '%d';
  86. $wpdb->update( $table, $data, $where, $format, $where_format );
  87. $this->append_progress( $task );
  88. }
  89. }
  90. /**
  91. * @param string $pod_table
  92. */
  93. private function update_pod_table( $pod_table ) {
  94. /** @global wpdb $wpdb */
  95. global $wpdb;
  96. $task = "update_pod_table_{$pod_table}";
  97. if ( ! $this->have_done( $task ) ) {
  98. // Prime the values and update
  99. $data = array( 'id' => $this->new_term_id );
  100. $where = array( 'id' => $this->term_id );
  101. $format = '%d';
  102. $where_format = '%d';
  103. $wpdb->update( $pod_table, $data, $where, $format, $where_format );
  104. $this->append_progress( $task );
  105. }
  106. }
  107. /**
  108. * Track down all fields related to the target taxonomy and update stored term IDs as necessary
  109. */
  110. private function update_relationships_to_term() {
  111. // Loop through all Pods
  112. $all_pods = pods_api()->load_pods();
  113. if ( ! is_array( $all_pods ) ) {
  114. return;
  115. }
  116. foreach ( $all_pods as $this_pod_id => $this_pod ) {
  117. // Loop through all fields in this Pod
  118. foreach ( $this_pod[ 'fields' ] as $this_field_name => $this_field ) {
  119. // Ignore everything except relationship fields to this taxonomy
  120. if ( 'pick' != $this_field[ 'type' ] || 'taxonomy' != $this_field[ 'pick_object' ] || $this->taxonomy != $this_field[ 'pick_val' ] ) {
  121. continue;
  122. }
  123. // Update the term ID in podsrel everywhere it is the value for this field
  124. $this->update_podsrel_related_term( $this_field[ 'id' ] );
  125. // Fix-up any special-case relationships that store term IDs in their own meta table and/or serialized
  126. switch ( $this_pod[ 'type' ] ) {
  127. case 'post_type':
  128. $this->update_postmeta( $this_pod[ 'name' ], $this_field_name );
  129. break;
  130. case 'comment':
  131. $this->update_commentmeta( $this_field_name );
  132. break;
  133. case 'user':
  134. $this->update_usermeta( $this_field_name );
  135. break;
  136. case 'settings':
  137. $this->update_setting_meta( $this_pod[ 'name' ], $this_field_name );
  138. break;
  139. }
  140. }
  141. }
  142. }
  143. /**
  144. * @param int $field_id
  145. */
  146. private function update_podsrel_related_term( $field_id ) {
  147. /** @global wpdb $wpdb */
  148. global $wpdb;
  149. $task = "update_podsrel_related_term_{$field_id}";
  150. if ( ! $this->have_done( $task ) ) {
  151. // UPDATE {$wpdb->prefix}podsrel SET related_item_id = {$new_term_id} WHERE field_id = {$field_id} AND related_item_id = {$term_id}
  152. $table = "{$wpdb->prefix}podsrel";
  153. $data = array(
  154. 'related_item_id' => $this->new_term_id
  155. );
  156. $where = array(
  157. 'field_id' => $field_id,
  158. 'related_item_id' => $this->term_id
  159. );
  160. $format = '%d';
  161. $where_format = '%d';
  162. $wpdb->update( $table, $data, $where, $format, $where_format );
  163. $this->append_progress( $task );
  164. }
  165. }
  166. /**
  167. * Called for all fields related to the target taxonomy that are in a post_type
  168. *
  169. * @param string $pod_name
  170. * @param string $field_name
  171. */
  172. private function update_postmeta( $pod_name, $field_name ) {
  173. /** @global wpdb $wpdb */
  174. global $wpdb;
  175. // Fix up the unserialized data
  176. $task = "update_postmeta_{$pod_name}_{$field_name}_unserialized";
  177. if ( ! $this->have_done( $task ) ) {
  178. $wpdb->query( $wpdb->prepare(
  179. "
  180. UPDATE
  181. {$wpdb->postmeta} AS meta
  182. LEFT JOIN {$wpdb->posts} AS t
  183. ON meta.post_id = t.ID
  184. SET
  185. meta_value = %s
  186. WHERE
  187. meta_key = %s
  188. AND meta_value = %s
  189. AND t.post_type = %s
  190. ",
  191. $this->new_term_id,
  192. $field_name,
  193. $this->term_id,
  194. $pod_name
  195. ) );
  196. $this->append_progress( $task );
  197. }
  198. // Fix up the serialized data
  199. $task = "update_postmeta_{$pod_name}_{$field_name}_serialized";
  200. if ( ! $this->have_done( $task ) ) {
  201. $meta_key = sprintf( '_pods_%s', $field_name );
  202. $target_serialized = sprintf( ';i:%s;', $this->term_id );
  203. $replace_serialized = sprintf( ';i:%s;', $this->new_term_id );
  204. $wpdb->query( $wpdb->prepare(
  205. "
  206. UPDATE
  207. {$wpdb->postmeta} AS meta
  208. LEFT JOIN {$wpdb->posts} AS t
  209. ON meta.post_id = t.ID
  210. SET
  211. meta.meta_value = REPLACE( meta.meta_value, %s, %s )
  212. WHERE
  213. meta.meta_key = %s
  214. AND t.post_type = %s
  215. AND meta_value LIKE '%%%s%%'
  216. ",
  217. $target_serialized,
  218. $replace_serialized,
  219. $meta_key,
  220. $pod_name,
  221. pods_sanitize_like( $target_serialized )
  222. ) );
  223. $this->append_progress( $task );
  224. }
  225. }
  226. /**
  227. * Called for all fields related to the target taxonomy that are in a comment Pod
  228. *
  229. * @param string $field_name
  230. */
  231. private function update_commentmeta( $field_name ) {
  232. /** @global wpdb $wpdb */
  233. global $wpdb;
  234. // Fix up the unserialized data
  235. $task = "update_commentmeta_{$field_name}_unserialized";
  236. if ( ! $this->have_done( $task ) ) {
  237. $table = $wpdb->commentmeta;
  238. $data = array( 'meta_value' => $this->new_term_id );
  239. $where = array(
  240. 'meta_key' => $field_name,
  241. 'meta_value' => $this->term_id
  242. );
  243. $format = '%s';
  244. $where_format = array( '%s', '%s' );
  245. $wpdb->update( $table, $data, $where, $format, $where_format );
  246. $this->append_progress( $task );
  247. }
  248. // Fix up the serialized data
  249. $task = "update_commentmeta_{$field_name}_serialized";
  250. if ( ! $this->have_done( $task ) ) {
  251. $meta_key = sprintf( '_pods_%s', $field_name );
  252. $target_serialized = sprintf( ';i:%s;', $this->term_id );
  253. $replace_serialized = sprintf( ';i:%s;', $this->new_term_id );
  254. $wpdb->query( $wpdb->prepare(
  255. "
  256. UPDATE
  257. {$wpdb->commentmeta}
  258. SET
  259. meta_value = REPLACE( meta_value, %s, %s )
  260. WHERE
  261. meta_key = %s
  262. AND meta_value LIKE '%%%s%%'
  263. ",
  264. $target_serialized,
  265. $replace_serialized,
  266. $meta_key,
  267. pods_sanitize_like( $target_serialized )
  268. ) );
  269. $this->append_progress( $task );
  270. }
  271. }
  272. /**
  273. * Called for all fields related to the target taxonomy that are in a user Pod
  274. *
  275. * @param string $field_name
  276. */
  277. private function update_usermeta( $field_name ) {
  278. /** @global wpdb $wpdb */
  279. global $wpdb;
  280. // Fix up the unserialized data
  281. $task = "update_usermeta_{$field_name}_unserialized";
  282. if ( ! $this->have_done( $task ) ) {
  283. $table = $wpdb->usermeta;
  284. $data = array( 'meta_value' => $this->new_term_id );
  285. $where = array(
  286. 'meta_key' => $field_name,
  287. 'meta_value' => $this->term_id
  288. );
  289. $format = '%s';
  290. $where_format = array( '%s', '%s' );
  291. $wpdb->update( $table, $data, $where, $format, $where_format );
  292. $this->append_progress( $task );
  293. }
  294. // Fix up the serialized data
  295. $task = "update_usermeta_{$field_name}_serialized";
  296. if ( ! $this->have_done( $task ) ) {
  297. $meta_key = sprintf( '_pods_%s', $field_name );
  298. $target_serialized = sprintf( ';i:%s;', $this->term_id );
  299. $replace_serialized = sprintf( ';i:%s;', $this->new_term_id );
  300. $wpdb->query( $wpdb->prepare(
  301. "
  302. UPDATE
  303. {$wpdb->usermeta}
  304. SET
  305. meta_value = REPLACE( meta_value, %s, %s )
  306. WHERE
  307. meta_key = %s
  308. AND meta_value LIKE '%%%s%%'
  309. ",
  310. $target_serialized,
  311. $replace_serialized,
  312. $meta_key,
  313. pods_sanitize_like( $target_serialized )
  314. ) );
  315. $this->append_progress( $task );
  316. }
  317. }
  318. /**
  319. * Called for all fields related to the target taxonomy that are in a user Pod
  320. *
  321. * @param string $pod_name
  322. * @param string $field_name
  323. */
  324. private function update_setting_meta( $pod_name, $field_name ) {
  325. /** @global wpdb $wpdb */
  326. global $wpdb;
  327. $option_name = "{$pod_name}_{$field_name}";
  328. // Fix up the unserialized data
  329. $task = "update_setting_meta_{$pod_name}_{$field_name}_unserialized";
  330. if ( ! $this->have_done( $task ) ) {
  331. // UPDATE {$wpdb->options} SET option_value = '{$new_term_id}' WHERE option_name = '{$pod_name}_{$field_name}' AND option_value = '{$term_id}'
  332. $table = $wpdb->options;
  333. $data = array( 'option_value' => $this->new_term_id );
  334. $where = array(
  335. 'option_name' => $option_name,
  336. 'option_value' => $this->term_id
  337. );
  338. $format = '%s';
  339. $where_format = array( '%s', '%s' );
  340. $wpdb->update( $table, $data, $where, $format, $where_format );
  341. $this->append_progress( $task );
  342. }
  343. // Fix up the serialized data
  344. $task = "update_setting_meta_{$pod_name}_{$field_name}_serialized";
  345. if ( ! $this->have_done( $task ) ) {
  346. $target_serialized = sprintf( ';i:%s;', $this->term_id );
  347. $replace_serialized = sprintf( ';i:%s;', $this->new_term_id );
  348. $wpdb->query( $wpdb->prepare(
  349. "
  350. UPDATE
  351. {$wpdb->options}
  352. SET
  353. option_value = REPLACE( option_value, %s, %s )
  354. WHERE
  355. option_name = %s
  356. AND option_value LIKE '%%%s%%'
  357. ",
  358. $target_serialized,
  359. $replace_serialized,
  360. $option_name,
  361. pods_sanitize_like( $target_serialized )
  362. ) );
  363. $this->append_progress( $task );
  364. }
  365. }
  366. /**
  367. * @param string $task_name
  368. *
  369. * @return bool
  370. */
  371. private function have_done( $task_name ) {
  372. return in_array( $task_name, $this->previous_progress );
  373. }
  374. /**
  375. * @return array
  376. */
  377. private function get_progress() {
  378. return get_option( $this->progress_option_name, array() );
  379. }
  380. /**
  381. * @param $data
  382. */
  383. private function append_progress( $data ) {
  384. // Get the current progress array
  385. $current_progress = $this->get_progress();
  386. if ( ! is_array( $current_progress ) ) {
  387. $current_progress = array();
  388. }
  389. // Tack on the new data
  390. $updated_progress = array_merge( $current_progress, array( $data ) );
  391. // Note: we don't want autoload set and you cannot specify autoload via update_option
  392. if ( ! empty( $current_progress ) && is_array( $current_progress ) ) {
  393. update_option( $this->progress_option_name, $updated_progress );
  394. } else {
  395. add_option( $this->progress_option_name, $updated_progress, '', false );
  396. }
  397. }
  398. /**
  399. *
  400. */
  401. private function delete_progress() {
  402. delete_option( $this->progress_option_name );
  403. }
  404. }