Source: php/sync/class-unsync.php

  1. <?php
  2. /**
  3. * Unsync class for the Cloudinary plugin.
  4. *
  5. * @package Cloudinary
  6. */
  7. namespace Cloudinary\Sync;
  8. use Cloudinary\Plugin;
  9. use Cloudinary\Sync;
  10. use Cloudinary\Media;
  11. use Cloudinary\Sync\Storage;
  12. use WP_Post;
  13. /**
  14. * Class Unsync
  15. */
  16. class Unsync {
  17. /**
  18. * Holds the plugin instance.
  19. *
  20. * @var Plugin Instance of the global plugin.
  21. */
  22. public $plugin;
  23. /**
  24. * Holds the Media instance.
  25. *
  26. * @var Media
  27. */
  28. protected $media;
  29. /**
  30. * Holds the Sync instance.
  31. *
  32. * @var Sync
  33. */
  34. protected $sync;
  35. /**
  36. * Holds the Storage instance.
  37. *
  38. * @var Storage
  39. */
  40. protected $storage;
  41. /**
  42. * Unsync constructor.
  43. *
  44. * @param Plugin $plugin Global instance of the main plugin.
  45. */
  46. public function __construct( Plugin $plugin ) {
  47. $this->plugin = $plugin;
  48. }
  49. /**
  50. * Holds the unsync action keys.
  51. */
  52. const UNSYNC_ACTION = 'cloudinary-unsync';
  53. /**
  54. * Holds the unsync/resync toggle action keys.
  55. */
  56. const UNSYNC_TOGGLE = 'cloudinary-sync-toggle';
  57. /**
  58. * Register any hooks that this component needs.
  59. */
  60. public function setup() {
  61. $this->media = $this->plugin->get_component( 'media' );
  62. $this->sync = $this->plugin->get_component( 'sync' );
  63. $this->storage = $this->plugin->get_component( 'storage' );
  64. if ( 'off' === $this->plugin->settings->get_value( 'auto_sync' ) ) {
  65. add_action( 'attachment_submitbox_misc_actions', array( $this, 'single_action' ), 11 );
  66. add_filter( 'handle_bulk_actions-upload', array( $this, 'handle_bulk_actions' ), 11, 3 );
  67. add_filter( 'media_row_actions', array( $this, 'add_inline_action' ), 10, 2 );
  68. add_filter( 'bulk_actions-upload', array( $this, 'add_bulk_actions' ) );
  69. }
  70. }
  71. /**
  72. * Adds the deliver checkbox on the single image edit screen.
  73. *
  74. * @param WP_Post $attachment The attachment post object.
  75. */
  76. public function single_action( $attachment ) {
  77. // Set url for action handling.
  78. $action_url = add_query_arg(
  79. array(
  80. 'action' => self::UNSYNC_TOGGLE,
  81. 'media[]' => $attachment->ID,
  82. '_wpnonce' => wp_create_nonce( 'bulk-media' ),
  83. ),
  84. 'upload.php'
  85. );
  86. $link_text = $this->sync->been_synced( $attachment->ID ) ? $this->get_action_text() : __( 'Sync with Cloudinary', 'cloudinary' );
  87. $status = $this->sync->filter_media_states( array(), $attachment );
  88. ?>
  89. <div class="misc-pub-section misc-pub-sync-unsync">
  90. <?php if ( ! empty( $status ) ) : ?>
  91. <?php echo esc_html( array_shift( $status ) ); ?>
  92. <?php else : ?>
  93. <a href="<?php echo esc_url( $action_url ); ?>"><?php echo esc_html( $link_text ); ?></a>
  94. <?php endif; ?>
  95. </div>
  96. <?php
  97. }
  98. /**
  99. * Handles bulk actions for attachments.
  100. *
  101. * @param string $location The location to redirect after.
  102. * @param string $action The action to handle.
  103. * @param array $post_ids Post ID's to action.
  104. *
  105. * @return string
  106. */
  107. public function handle_bulk_actions( $location, $action, $post_ids ) {
  108. $actions = array(
  109. self::UNSYNC_ACTION,
  110. self::UNSYNC_TOGGLE,
  111. );
  112. if ( in_array( $action, $actions, true ) ) {
  113. switch ( $action ) {
  114. case self::UNSYNC_ACTION:
  115. $post_ids = array_filter( $post_ids, array( $this->sync, 'been_synced' ) );
  116. foreach ( $post_ids as $id ) {
  117. $this->unsync_attachment( $id );
  118. }
  119. break;
  120. case self::UNSYNC_TOGGLE:
  121. $attachment_id = array_shift( $post_ids );
  122. if ( $this->sync->been_synced( $attachment_id ) ) {
  123. $this->unsync_attachment( $attachment_id );
  124. } else {
  125. $this->sync->add_to_sync( $attachment_id );
  126. }
  127. $location = get_edit_post_link( $attachment_id, 'edit' );
  128. break;
  129. }
  130. /**
  131. * Action to flush delivery caches.
  132. *
  133. * @hook cloudinary_flush_cache
  134. * @since 3.0.0
  135. */
  136. do_action( 'cloudinary_flush_cache' );
  137. }
  138. return $location;
  139. }
  140. /**
  141. * Add an inline action for manual sync.
  142. *
  143. * @param array $actions All actions.
  144. * @param \WP_Post $post The current post object.
  145. *
  146. * @return array
  147. */
  148. public function add_inline_action( $actions, $post ) {
  149. if ( $this->sync->been_synced( $post->ID ) ) {
  150. // Set url for action handling.
  151. $action_url = add_query_arg(
  152. array(
  153. 'action' => self::UNSYNC_ACTION,
  154. 'media[]' => $post->ID,
  155. '_wpnonce' => wp_create_nonce( 'bulk-media' ),
  156. ),
  157. 'upload.php'
  158. );
  159. // Add link th actions.
  160. $actions[ self::UNSYNC_ACTION ] = sprintf(
  161. '<a href="%1$s" aria-label="%2$s">%2$s</a>',
  162. $action_url,
  163. $this->get_action_text()
  164. );
  165. }
  166. return $actions;
  167. }
  168. /**
  169. * Add bulk actions.
  170. *
  171. * @param array $actions Current actions to add to.
  172. *
  173. * @return array
  174. */
  175. public function add_bulk_actions( $actions ) {
  176. $new_action = array(
  177. self::UNSYNC_ACTION => $this->get_action_text(),
  178. );
  179. $actions = array_merge( $new_action, $actions );
  180. return $actions;
  181. }
  182. /**
  183. * Get the action text.
  184. *
  185. * @return string
  186. */
  187. protected function get_action_text() {
  188. return __( 'Unsync from Cloudinary', 'cloudinary' );
  189. }
  190. /**
  191. * Unsync an attachment from cloudinary.
  192. *
  193. * @param int $attachment_id The attachment to unsync.
  194. */
  195. public function unsync_attachment( $attachment_id ) {
  196. $this->sync->set_pending( $attachment_id );
  197. $cloudinary_id = $this->media->get_cloudinary_id( $attachment_id );
  198. $url = $this->media->cloudinary_url( $attachment_id, 'raw', array(), $cloudinary_id, true );
  199. $url = remove_query_arg( '_i', $url );
  200. $storage = $this->media->get_post_meta( $attachment_id, Sync::META_KEYS['storage'], true );
  201. if ( 'cld' === $storage || 'dual_low' === $storage ) {
  202. if ( 'dual_low' === $storage ) {
  203. $this->storage->remove_local_assets( $attachment_id );
  204. }
  205. $file_maybe = get_attached_file( $attachment_id );
  206. if ( ! file_exists( $file_maybe ) ) {
  207. remove_filter( 'wp_unique_filename', array( $this->storage, 'unique_filename' ), 10 );
  208. $date = get_post_datetime( $attachment_id );
  209. $download = $this->sync->managers['download']->download_asset( $attachment_id, $url, $date->format( 'Y/m' ) );
  210. add_filter( 'wp_unique_filename', array( $this->storage, 'unique_filename' ), 10, 3 );
  211. if ( is_wp_error( $download ) ) {
  212. wp_die( esc_html( $download->get_error_message() ) );
  213. }
  214. }
  215. }
  216. // Remove meta data.
  217. $sync_key = $this->media->get_public_id_from_url( $url, true );
  218. $public_id = $this->media->get_public_id( $attachment_id );
  219. // Delete sync keys.
  220. delete_post_meta( $attachment_id, '_' . md5( $sync_key ), true );
  221. delete_post_meta( $attachment_id, '_' . md5( 'base_' . $public_id ), true );
  222. foreach ( Sync::META_KEYS as $key ) {
  223. delete_post_meta( $attachment_id, $key );
  224. }
  225. $this->sync->set_signature_item( $attachment_id, 'file' );
  226. /**
  227. * Action unsyncing an attachment.
  228. *
  229. * @hook cloudinary_unsync_asset
  230. * @since 3.0.0
  231. *
  232. * @param $attachment_id {int} The attachment ID.
  233. */
  234. do_action( 'cloudinary_unsync_asset', $attachment_id );
  235. }
  236. }