/taxonomy-to-post_type-sync.class.php

https://github.com/mjangda/taxonomy-to-post_type-sync · PHP · 333 lines · 220 code · 85 blank · 28 comment · 38 complexity · 687334befaf9ef1454269e80ac73da43 MD5 · raw file

  1. <?php
  2. class Tax2PostTypeSync {
  3. var $doing_sync = false;
  4. var $sync_relationships = array();
  5. var $sync_post_types = array();
  6. var $sync_taxonomies = array();
  7. function __construct() {
  8. $this->init_sync_relationships();
  9. // Add save-sync actions
  10. add_action( 'save_post', array( $this, 'sync_save_post_callback' ), 11, 2 );
  11. add_action( 'edit_term', array( $this, 'sync_edit_term_callback' ), 11, 3 );
  12. add_action( 'create_term', array( $this, 'sync_edit_term_callback' ), 11, 3 );
  13. // Handle term delete
  14. add_action( 'delete_term', array( $this, 'sync_delete_term_callback' ), 11, 3 );
  15. // Handle post delete
  16. add_action( 'before_delete_post', array( $this, 'sync_delete_post_callback' ), 11 );
  17. }
  18. function init_sync_relationships() {
  19. if( ! is_array( $this->sync_relationships ) )
  20. $this->sync_relationships = array();
  21. }
  22. function get_sync_relationships() {
  23. if( empty( $this->sync_relationships ) )
  24. $this->sync_relationships = $this->init_sync_relationships();
  25. return $this->sync_relationships;
  26. }
  27. function register_sync( $post_type, $taxonomy ) {
  28. // Check that valid post_type and valid taxonomy
  29. if( ! post_type_exists( $post_type ) || ! taxonomy_exists( $taxonomy ) ) {
  30. _doing_it_wrong( __FUNCTION__, sprintf( __( 'Post Type (%1$s) or Taxonomy (%2$s) don\'t exist!', 'tax_to_posttype_sync' ), $post_type, $taxonomy ) );
  31. return;
  32. }
  33. // Link the taxonomy to the post_type
  34. register_taxonomy_for_object_type( $taxonomy, $post_type );
  35. $this->sync_relationships[] = array(
  36. 'post_type' => $post_type,
  37. 'taxonomy' => $taxonomy,
  38. );
  39. $this->sync_post_type_relationships[$post_type] = $taxonomy;
  40. $this->sync_taxonomy_relationships[$taxonomy] = $post_type;
  41. }
  42. function get_post_type_sync( $post_type ) {
  43. if( isset( $this->sync_post_type_relationships[$post_type] ) )
  44. return $this->sync_post_type_relationships[$post_type];
  45. return false;
  46. }
  47. function get_taxonomy_sync( $taxonomy ) {
  48. if( isset( $this->sync_taxonomy_relationships[$taxonomy] ) )
  49. return $this->sync_taxonomy_relationships[$taxonomy];
  50. return false;
  51. }
  52. function sync_save_post_callback( $post_id, $post ) {
  53. if( $this->doing_sync() )
  54. return;
  55. if( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
  56. return;
  57. if( $post->post_status == 'auto-draft' )
  58. return;
  59. // Check if sync enabled
  60. $post_type = $post->post_type;
  61. $taxonomy = $this->get_post_type_sync( $post_type );
  62. if( ! $taxonomy )
  63. return;
  64. $this->do_sync();
  65. $this->sync_post_to_term( $post_id, $post, $post_type, $taxonomy );
  66. $this->done_sync();
  67. }
  68. function sync_post_to_term( $post_id, $post, $post_type, $taxonomy ) {
  69. $title = $post->post_title;
  70. $slug = $post->post_name;
  71. if( empty( $slug ) )
  72. $slug = sanitize_title( $title );
  73. if( empty( $slug ) )
  74. return;
  75. $term = null;
  76. // Check if we have a synced term already
  77. $term = $this->get_synced_term( $post_id, $post_type );
  78. // We don't, so check to see if the term exists
  79. if( ! $term )
  80. $term = get_term_by( 'slug', $slug, $taxonomy );
  81. if( $term ) {
  82. // Update the existing term
  83. $term_save = wp_update_term( $term->term_id, $taxonomy, array(
  84. 'name' => $title,
  85. 'slug' => $slug,
  86. ) );
  87. } else {
  88. if( empty( $title ) )
  89. $title = $slug;
  90. // Create a new term
  91. $term_save = wp_insert_term( $title, $taxonomy, array(
  92. 'slug' => $slug
  93. ) );
  94. }
  95. // Watch for is_wp_error( $term )
  96. if( $term_save && is_wp_error( $term_save ) ) {
  97. error_log( sprintf( __( 'Uh oh! %1$s failed! Details: %2$s' ), __FUNCTION__, var_export( $term_save, true ) ) );
  98. return;
  99. }
  100. // Store our post-term sync relationship
  101. $this->sync_post_term_relationship( $post_id, $post_type, $term_save['term_id'], $taxonomy );
  102. }
  103. function sync_delete_post_callback( $post_id ) {
  104. if( $this->doing_sync() )
  105. return;
  106. $post = get_post( $post_id );
  107. // Check if sync enabled
  108. $post_type = $post->post_type;
  109. $taxonomy = $this->get_post_type_sync( $post_type );
  110. if( ! $taxonomy )
  111. return;
  112. $this->do_sync();
  113. // Delete matching term
  114. $term = $this->get_synced_term( $post_id, $post_type );
  115. if( $term )
  116. wp_delete_term( $term->term_id, $taxonomy );
  117. $this->done_sync();
  118. }
  119. function sync_edit_term_callback( $term_id, $tt_id, $taxonomy ) {
  120. if( $this->doing_sync() )
  121. return;
  122. // Check if sync enabled
  123. $post_type = $this->get_taxonomy_sync( $taxonomy );
  124. if( ! $post_type )
  125. return;
  126. $term = get_term( $term_id, $taxonomy );
  127. $this->do_sync();
  128. $this->sync_term_to_post( $term_id, $term, $taxonomy, $post_type );
  129. $this->done_sync();
  130. }
  131. function sync_term_to_post( $term_id, $term, $taxonomy, $post_type ) {
  132. $slug = $term->slug;
  133. $title = $term->name;
  134. // Get synced post
  135. $post = $this->get_synced_post( $term->term_id, $taxonomy );
  136. // If a synced post doesn't exist, try to find one matching the post_name
  137. if( ! $post ) {
  138. $post = $this->get_post_by_slug( $slug, $post_type );
  139. // We still don't have a post, so let's create one
  140. if( ! $post ) {
  141. $post_id = wp_insert_post( array(
  142. 'post_title' => $title,
  143. 'post_name' => $slug,
  144. 'post_type' => $post_type,
  145. 'post_status' => 'publish',
  146. ) );
  147. } else {
  148. $post_id = $post->ID;
  149. }
  150. // Store our post-term sync relationship
  151. $this->sync_post_term_relationship( $post_id, $post_type, $term->term_id, $taxonomy );
  152. } else {
  153. wp_update_post( array(
  154. 'ID' => $post->ID,
  155. 'post_title' => $title,
  156. 'post_name' => $slug,
  157. 'post_type' => $post_type,
  158. 'post_status' => 'publish',
  159. ) );
  160. }
  161. // Now, let's hook into the post-term update hook and update /actually/ update our post
  162. // TODO: Hook into into the right callback
  163. add_action( 'edited_term', array( $this, 'sync_edit_term_callback' ), 11, 3 );
  164. }
  165. function sync_delete_term_callback( $term, $tt_id, $taxonomy ) {
  166. if( $this->doing_sync() )
  167. return;
  168. // Check if sync enabled
  169. $post_type = $this->get_taxonomy_sync( $taxonomy );
  170. if( ! $post_type )
  171. return;
  172. $this->do_sync();
  173. // Get matching post and delete
  174. $post = $this->get_synced_post( $term, $taxonomy );
  175. if( $post )
  176. wp_delete_post( $post->ID, true ); // force delete
  177. $this->done_sync();
  178. }
  179. function sync_post_term_relationship( $post_id, $post_type, $term_id, $taxonomy ) {
  180. wp_set_object_terms( $post_id, (int)$term_id, $taxonomy );
  181. }
  182. function get_synced_term( $post_id, $post_type ) {
  183. // In case we get passed in a whole post object
  184. if ( is_object( $post_id ) )
  185. $post_id = $post_id->ID;
  186. $taxonomy = $this->get_post_type_sync( $post_type );
  187. $terms = wp_get_object_terms( $post_id, $taxonomy );
  188. if( ! empty( $terms ) && ! is_wp_error( $terms ) )
  189. return $terms[0];
  190. return false;
  191. }
  192. function get_synced_post( $term_id, $taxonomy ) {
  193. // In case the term object was passed in
  194. if ( is_object( $term_id ) )
  195. $term_id = $term_id->term_id;
  196. $post_type = $this->get_taxonomy_sync( $taxonomy );
  197. $posts = get_posts( array(
  198. 'posts_per_page' => 1,
  199. 'post_type' => $post_type,
  200. 'post_status' => 'any',
  201. 'tax_query' => array(
  202. array(
  203. 'taxonomy' => $taxonomy,
  204. 'field' => 'id',
  205. 'terms' => $term_id
  206. ),
  207. ),
  208. ) );
  209. if( ! empty( $posts ) )
  210. return $posts[0];
  211. return false;
  212. }
  213. function get_post_by_slug( $slug, $post_type ) {
  214. $posts = get_posts( array(
  215. 'posts_per_page' => 1,
  216. 'name' => $slug,
  217. 'post_type' => $post_type,
  218. 'post_status' => 'any',
  219. ) );
  220. if( ! empty( $posts ) )
  221. return $posts[0];
  222. return false;
  223. }
  224. // We use the following helper functions to avoid getting into recursive problems
  225. // i.e. from save_post, calling wp_update_term, which fires edited_terms, which calls wp_update_post, which fires save_post etc.
  226. private function doing_sync() {
  227. return $this->doing_sync;
  228. }
  229. private function do_sync() {
  230. $this->doing_sync = true;
  231. }
  232. private function done_sync() {
  233. $this->doing_sync = false;
  234. }
  235. }
  236. // Public wrapper functions
  237. function x_register_sync( $post_type, $taxonomy ) {
  238. global $tax_to_posttype_sync;
  239. $tax_to_posttype_sync->register_sync( $post_type, $taxonomy );
  240. }
  241. function x_get_synced_term( $post_id, $post_type ) {
  242. global $tax_to_posttype_sync;
  243. return $tax_to_posttype_sync->get_synced_term( $post_id, $post_type );
  244. }
  245. function x_get_synced_post( $term_id, $taxonomy ) {
  246. global $tax_to_posttype_sync;
  247. return $tax_to_posttype_sync->get_synced_post( $term_id, $taxonomy );
  248. }