Нет описания

Posts.php 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. <?php
  2. /*******************************************************************************
  3. * Copyright (c) 2019, Code Atlantic LLC
  4. ******************************************************************************/
  5. if ( ! defined( 'ABSPATH' ) ) {
  6. exit;
  7. }
  8. /**
  9. * Implements a batch processor for migrating existing posts to new data structure.
  10. *
  11. * @since 1.7.0
  12. *
  13. * @see PUM_Abstract_Upgrade
  14. * @see PUM_Interface_Batch_PrefetchProcess
  15. * @see PUM_Interface_Upgrade_Posts
  16. */
  17. abstract class PUM_Abstract_Upgrade_Posts extends PUM_Abstract_Upgrade implements PUM_Interface_Upgrade_Posts {
  18. /**
  19. * Batch process ID.
  20. *
  21. * @var string
  22. */
  23. public $batch_id;
  24. /**
  25. * Post type.
  26. *
  27. * @var string
  28. */
  29. public $post_type = 'post';
  30. /**
  31. * Post status to update.
  32. *
  33. * @var array
  34. */
  35. public $post_status = array( 'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', 'trash' );
  36. /**
  37. * Number of posts to migrate per step.
  38. *
  39. * @var int
  40. */
  41. public $per_step = 1;
  42. /**
  43. * @var array
  44. */
  45. public $post_ids;
  46. /**
  47. * @var array
  48. */
  49. public $completed_post_ids;
  50. /**
  51. * Allows disabling of the post_id array query prefetch for stepping.
  52. *
  53. * When true will prefetch all post_ids from the query and cache them, stepping through that array. WP_Query is only called once.
  54. *
  55. * When false the stepping will occur via a new WP_Query with pagination.
  56. *
  57. * True is useful if you are querying on data that will be changed during processing.
  58. *
  59. * False is useful if there may be a massive amount of post data to migrate.
  60. * False is not useful when the query args are targeting data that will be changed.
  61. * Ex: Query all posts with old_meta, then during each step moving old_meta to new_meta.
  62. * In this example, the second query will not include posts updated in the first step, but then also sets an offset skipping posts that need update still.
  63. *
  64. * @var bool
  65. */
  66. public $prefetch_ids = true;
  67. public function init( $data = null ) {
  68. }
  69. public function pre_fetch() {
  70. $total_to_migrate = $this->get_total_count();
  71. if ( ! $total_to_migrate ) {
  72. $posts = $this->get_posts( array(
  73. 'fields' => 'ids',
  74. 'posts_per_page' => - 1,
  75. ) );
  76. $posts = wp_parse_id_list( $posts );
  77. $total_to_migrate = count( $posts );
  78. if ( $this->prefetch_ids ) {
  79. $this->set_post_ids( $posts );
  80. }
  81. $this->set_total_count( $total_to_migrate );
  82. }
  83. }
  84. /**
  85. * Gets the results of a custom post query.
  86. *
  87. * @param array $args
  88. *
  89. * @return array
  90. */
  91. public function get_posts( $args = array() ) {
  92. return get_posts( $this->query_args( $args ) );
  93. }
  94. /**
  95. * Generates an array of query args for this upgrade.
  96. *
  97. * @uses self::custom_query_args();
  98. *
  99. * @param array $args
  100. *
  101. * @return array
  102. */
  103. public function query_args( $args = array() ) {
  104. $defaults = wp_parse_args( $this->custom_query_args(), array(
  105. 'post_status' => $this->post_status,
  106. 'post_type' => $this->post_type,
  107. ) );
  108. return wp_parse_args( $args, $defaults );
  109. }
  110. /**
  111. * @return array
  112. */
  113. public function custom_query_args() {
  114. return array();
  115. }
  116. /**
  117. * Executes a single step in the batch process.
  118. *
  119. * @return int|string|WP_Error Next step number, 'done', or a WP_Error object.
  120. */
  121. public function process_step() {
  122. $completed_post_ids = $this->get_completed_post_ids();
  123. if ( $this->prefetch_ids ) {
  124. $all_posts = $this->get_post_ids();
  125. $remaining_post_ids = array_diff( $all_posts, $completed_post_ids );
  126. $posts = array_slice( $remaining_post_ids, 0, $this->per_step );
  127. } else {
  128. $posts = $this->get_posts( array(
  129. 'fields' => 'ids',
  130. 'posts_per_page' => $this->per_step,
  131. 'offset' => $this->get_offset(),
  132. 'orderby' => 'ID',
  133. 'order' => 'ASC',
  134. ) );
  135. }
  136. if ( empty( $posts ) ) {
  137. return 'done';
  138. }
  139. foreach ( $posts as $post_id ) {
  140. $this->process_post( $post_id );
  141. $completed_post_ids[] = $post_id;
  142. }
  143. // Deduplicate.
  144. $completed_post_ids = wp_parse_id_list( $completed_post_ids );
  145. $this->set_completed_post_ids( $completed_post_ids );
  146. $this->set_current_count( count( $completed_post_ids ) );
  147. return ++ $this->step;
  148. }
  149. /**
  150. * Retrieves a message for the given code.
  151. *
  152. * @param string $code Message code.
  153. *
  154. * @return string Message.
  155. */
  156. public function get_message( $code ) {
  157. $post_type = get_post_type_object( $this->post_type );
  158. $labels = get_post_type_labels( $post_type );
  159. $singular = strtolower( $labels->singular_name );
  160. $plural = strtolower( $labels->name );
  161. switch ( $code ) {
  162. case 'start':
  163. $total_count = $this->get_total_count();
  164. $message = sprintf( _n( 'Updating %d %2$s.', 'Updating %d %3$s.', $total_count, 'popup-maker' ), number_format_i18n( $total_count ), $singular, $plural );
  165. break;
  166. case 'done':
  167. $final_count = $this->get_current_count();
  168. $message = sprintf( _n( '%s %2$s was updated successfully.', '%s %3$s were updated successfully.', $final_count, 'popup-maker' ), number_format_i18n( $final_count ), $singular, $plural );
  169. break;
  170. default:
  171. $message = '';
  172. break;
  173. }
  174. return $message;
  175. }
  176. /**
  177. * Process needed upgrades on each post.
  178. *
  179. * @param int $post_id
  180. */
  181. abstract public function process_post( $post_id = 0 );
  182. /**
  183. * Full list of post_ids to be processed.
  184. *
  185. * @return array|bool Default false.
  186. */
  187. protected function get_post_ids() {
  188. if ( ! isset( $this->post_ids ) || ! $this->post_ids ) {
  189. $this->post_ids = PUM_DataStorage::get( "{$this->batch_id}_post_ids", false );
  190. if ( is_array( $this->post_ids ) ) {
  191. $this->post_ids = wp_parse_id_list( $this->post_ids );
  192. }
  193. }
  194. return $this->post_ids;
  195. }
  196. /**
  197. * Sets list of post_ids to be processed.
  198. *
  199. * @param array $post_ids Full list of post_ids to be processed.
  200. */
  201. protected function set_post_ids( $post_ids = array() ) {
  202. $this->post_ids = $post_ids;
  203. PUM_DataStorage::write( "{$this->batch_id}_post_ids", $post_ids );
  204. }
  205. /**
  206. * Deletes the stored data for this process.
  207. */
  208. protected function delete_post_ids() {
  209. $this->post_ids = false;
  210. PUM_DataStorage::delete( "{$this->batch_id}_post_ids" );
  211. }
  212. /**
  213. * Full list of completed_post_ids to be processed.
  214. *
  215. * @return array|bool Default false.
  216. */
  217. protected function get_completed_post_ids() {
  218. if ( ! isset( $this->completed_post_ids ) || ! $this->completed_post_ids ) {
  219. $completed_post_ids = PUM_DataStorage::get( "{$this->batch_id}_completed_post_ids", array() );
  220. $this->completed_post_ids = wp_parse_id_list( $completed_post_ids );
  221. }
  222. return $this->completed_post_ids;
  223. }
  224. /**
  225. * Sets list of completed_post_ids to be processed.
  226. *
  227. * @param array $completed_post_ids Full list of post_ids to be processed.
  228. */
  229. protected function set_completed_post_ids( $completed_post_ids = array() ) {
  230. $this->completed_post_ids = wp_parse_id_list( $completed_post_ids );
  231. PUM_DataStorage::write( "{$this->batch_id}_completed_post_ids", $completed_post_ids );
  232. }
  233. /**
  234. * Deletes the stored data for this process.
  235. */
  236. protected function delete_completed_post_ids() {
  237. $this->completed_post_ids = false;
  238. PUM_DataStorage::delete( "{$this->batch_id}_completed_post_ids" );
  239. }
  240. }