PluginProbe ʕ •ᴥ•ʔ
Admin and Site Enhancements (ASE) / 8.2.2
Admin and Site Enhancements (ASE) v8.2.2
9.1.0 9.0.2 9.0.1 9.0.0 8.9.2 8.9.1 8.9.0 8.8.8 8.8.7 8.8.6 8.8.5 8.8.4 8.8.3 8.8.2 8.8.1 8.8.0 8.7.3 8.7.2 8.7.1 8.2.1 8.2.2 8.2.3 8.3.0 8.3.1 8.3.2 8.4.0 8.4.1 8.4.2 8.5.0 8.5.1 8.5.2 8.6.0 8.6.1 8.6.2 8.7.0 5.0.1 5.0.2 5.0.2.1 5.0.2.2 5.0.2.3 5.0.2.4 5.1.0 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.8.0 5.8.1 6.0.0 6.0.3 6.0.4 6.0.5 6.0.5.1 6.0.6 6.0.7 6.0.8.1 6.1.0 6.1.3 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.3.0 6.3.1 6.3.2 6.4.0 6.5.0 6.5.1 6.6.0 6.7.0 6.8.0 6.8.2 6.8.3 6.9.0 6.9.1 6.9.10 6.9.11 6.9.12 6.9.13.1 6.9.13.2 6.9.2 6.9.3 6.9.4 6.9.5 6.9.6 6.9.7 6.9.8 6.9.9 7.0.0 7.0.2 7.0.2.1 7.0.2.2 7.0.2.3 7.0.3 7.1.0 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2.0 7.2.1 7.3.0 7.3.1 7.3.2 7.3.3 7.4.0 7.4.2 7.4.4 7.4.5 7.4.6 7.4.7 7.4.8 7.5.0 7.5.1 7.5.2 7.5.3 7.5.4 7.6.0 7.6.1 7.6.1.1 7.6.10 7.6.11 7.6.2 7.6.3 7.6.4 7.6.5 7.6.6 7.6.7 7.6.7.1 7.6.8 7.6.9 7.7.0 7.8.0 7.8.1 7.8.10 7.8.11 7.8.12 7.8.13 7.8.14 7.8.15 7.8.16 7.8.17 7.8.18 7.8.2 7.8.3 7.8.4 7.8.5 7.8.5.1 7.8.6 7.8.7 7.8.8 7.8.9 7.9.0 7.9.1 7.9.10 7.9.11 7.9.2 7.9.3 7.9.4 7.9.5 7.9.6 7.9.7 7.9.8 7.9.9 8.0.0 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.0.6 8.0.7 8.0.8 8.1.0 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 1.9.0 2.0.0 2.1.0 2.2.0 2.3.0 2.4.0 2.5.0 2.6.0 2.7.0 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.2.0 3.3.0 3.4.0 3.5.0 3.6.1 3.7.0 3.8.0 3.9.0 3.9.1 3.9.2 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.9.0 4.9.1 4.9.2 4.9.3 5.0.0
admin-site-enhancements / classes / class-media-replacement.php
admin-site-enhancements / classes Last commit date
class-activation.php 7 months ago class-admin-menu-organizer.php 7 months ago class-admin-menu-svg-icon-mask.php 7 months ago class-auto-publish-posts-with-missed-schedule.php 7 months ago class-avif-upload.php 7 months ago class-captcha-protection.php 7 months ago class-change-login-url.php 7 months ago class-cleanup-admin-bar.php 7 months ago class-common-methods.php 7 months ago class-content-duplication.php 7 months ago class-content-order.php 7 months ago class-custom-admin-footer-text.php 7 months ago class-custom-body-class.php 7 months ago class-custom-css.php 7 months ago class-custom-nav-menu-items-in-new-tab.php 7 months ago class-deactivation.php 7 months ago class-disable-author-archives.php 7 months ago class-disable-comments.php 7 months ago class-disable-dashboard-widgets.php 7 months ago class-disable-embeds.php 7 months ago class-disable-feeds.php 7 months ago class-disable-gutenberg.php 7 months ago class-disable-rest-api.php 7 months ago class-disable-smaller-components.php 7 months ago class-disable-updates.php 7 months ago class-disable-xml-rpc.php 7 months ago class-display-system-summary.php 7 months ago class-email-address-obfuscator.php 7 months ago class-email-delivery.php 7 months ago class-enhance-list-tables.php 7 months ago class-external-permalinks.php 7 months ago class-heartbeat-control.php 7 months ago class-hide-admin-bar.php 7 months ago class-hide-admin-notices.php 7 months ago class-image-sizes-panel.php 7 months ago class-image-upload-control.php 7 months ago class-insert-head-body-footer-code.php 7 months ago class-last-login-column.php 7 months ago class-limit-login-attempts.php 7 months ago class-login-id-type.php 7 months ago class-login-logout-menu.php 7 months ago class-maintenance-mode.php 7 months ago class-manage-ads-appads-txt.php 7 months ago class-manage-robots-txt.php 7 months ago class-media-replacement.php 7 months ago class-multiple-user-roles.php 7 months ago class-obfuscate-author-slugs.php 7 months ago class-open-external-links-in-new-tab.php 7 months ago class-password-protection.php 7 months ago class-redirect-after-login.php 7 months ago class-redirect-after-logout.php 7 months ago class-redirect-fourofour.php 7 months ago class-registration-date-column.php 7 months ago class-revisions-control.php 7 months ago class-search-engines-visibility.php 7 months ago class-settings-fields-render.php 7 months ago class-settings-sanitization.php 7 months ago class-settings-sections-fields.php 7 months ago class-show-custom-taxonomy-filters.php 7 months ago class-site-identity-on-login-page.php 7 months ago class-svg-upload.php 7 months ago class-various-admin-ui-enhancements.php 7 months ago class-view-admin-as-role.php 7 months ago class-wider-admin-menu.php 7 months ago class-wp-config-transformer.php 7 months ago
class-media-replacement.php
392 lines
1 <?php
2
3 namespace ASENHA\Classes;
4
5 /**
6 * Class for Media Replacement module
7 *
8 * @since 6.9.5
9 */
10 class Media_Replacement {
11
12 /**
13 * Modify the 'Edit' link to be 'Edit or Replace'
14 *
15 */
16 public function modify_media_list_table_edit_link( $actions, $post ) {
17
18 $new_actions = array();
19
20 foreach( $actions as $key => $value ) {
21
22 if ( $key == 'edit' ) {
23
24 $new_actions['edit'] = '<a href="' . get_edit_post_link( $post ) . '" aria-label="Edit or Replace">Edit or Replace</a>';
25
26 } else {
27
28 $new_actions[$key] = $value;
29
30 }
31
32 }
33
34 return $new_actions;
35
36 }
37
38 /**
39 * Add media replacement button in the edit screen of media/attachment
40 *
41 * @since 1.1.0
42 */
43 public function add_media_replacement_button( $fields, $post ) {
44 global $pagenow, $typenow;
45
46 // Do not do this on post creation and editing screen
47 // May cause media frame layout / display issues
48 if ( 'attachment' == $typenow ||
49 ( 'attachment' != $typenow && 'post-new.php' != $pagenow && 'post.php' != $pagenow )
50 ) {
51 $original_attachment_id = '';
52 $image_mime_type = '';
53 if ( is_object( $post ) ) {
54 $original_attachment_id = $post->ID;
55 if ( property_exists( $post, 'post_mime_type' ) ) {
56 $image_mime_type = $post->post_mime_type;
57 }
58 }
59
60 // Enqueues all scripts, styles, settings, and templates necessary to use all media JS APIs.
61 // Reference: https://codex.wordpress.org/Javascript_Reference/wp.media
62 wp_enqueue_media();
63
64 // Add new field to attachment fields for the media replace functionality
65 $fields['asenha-media-replace'] = array();
66 $fields['asenha-media-replace']['label'] = '';
67 $fields['asenha-media-replace']['input'] = 'html';
68 $fields['asenha-media-replace']['html'] = '
69 <div id="media-replace-div' . '" class="postbox attachment-id-' . $original_attachment_id . '" data-original-image-id="' . $original_attachment_id . '">
70 <div class="postbox-header">
71 <h2 class="hndle ui-sortable-handle">' . __( 'Replace Media', 'admin-site-enhancements' ) . '</h2>
72 </div>
73 <div class="inside">
74 <button type="button" id="asenha-media-replace" class="button-secondary button-large asenha-media-replace-button" data-old-image-mime-type="' . $image_mime_type . '" onclick="replaceMedia(\'' . $original_attachment_id . '\',\'' . $image_mime_type . '\');">' . __( 'Select New Media File', 'admin-site-enhancements' ) . '</button>
75 <input type="hidden" id="new-attachment-id-' . $original_attachment_id . '" name="new-attachment-id-' . $original_attachment_id . '" />
76 <div class="asenha-media-replace-notes"><p>' . __( 'The current file will be replaced with the uploaded / selected file (of the same type) while retaining the current ID, publish date and file name. Thus, no existing links will break.', 'admin-site-enhancements' ) . '</p></div>
77 </div>
78 </div>
79 ';
80 }
81
82 return $fields;
83
84 }
85
86 public function attachment_for_js( $image_url, $attachment_id ) {
87 // vi( $image_url );
88 // vi( $attachment_id );
89 }
90
91 /**
92 * Replace existing media with the newly updated file
93 *
94 * @link https://plugins.trac.wordpress.org/browser/replace-image/tags/1.1.7/hm-replace-image.php#L55
95 * @since 1.1.0
96 */
97 public function replace_media( $old_attachment_id ) {
98 // vi( $old_attachment_id, '', 'replace_media has been triggered via edit_attachment_hook' );
99
100 // Get the new attachment/media ID, meta and mime type
101 if ( isset( $_POST['new-attachment-id-'.$old_attachment_id] ) && ! empty( $_POST['new-attachment-id-'.$old_attachment_id] ) ) {
102 $new_attachment_id = intval( sanitize_text_field( $_POST['new-attachment-id-'.$old_attachment_id] ) );
103 // vi( $new_attachment_id, '', '$new_attachment_id is detected in replace_media' );
104
105 // Verify the user has permission to delete the new attachment (source file for replacement)
106 // This prevents unauthorized users from using another user's attachment as a replacement source
107 // which would result in that attachment being deleted
108 if ( ! current_user_can( 'delete_post', $new_attachment_id ) ) {
109 return;
110 }
111
112 $old_post_meta = get_post( $old_attachment_id, ARRAY_A );
113 $old_post_mime = $old_post_meta['post_mime_type']; // e.g. 'image/jpeg'
114 // vi( $old_post_mime, '', 'old_post_mime is detected in replace_media' );
115
116 $new_post_meta = get_post( $new_attachment_id, ARRAY_A );
117 $new_post_mime = $new_post_meta['post_mime_type']; // e.g. 'image/jpeg'
118 // vi( $new_post_mime, '', 'new_post_mime is detected in replace_media' );
119
120 // Check if the media file ID selected via the media frame and passed on to the #new-attachment-id hidden field
121 // Ensure the mime type matches too
122 if ( ( ! empty( $new_attachment_id ) ) && is_numeric( $new_attachment_id ) && ( $old_post_mime == $new_post_mime ) ) {
123 // vi( $new_attachment_id, '', 'We are processing the replacement of the old image.' );
124
125 $new_attachment_meta = wp_get_attachment_metadata( $new_attachment_id );
126
127 // If original file is larger than 2560 pixel
128 // https://make.wordpress.org/core/2019/10/09/introducing-handling-of-big-images-in-wordpress-5-3/
129 if ( is_array( $new_attachment_meta ) && array_key_exists( 'original_image', $new_attachment_meta ) ) {
130
131 // Get the original media file path
132 $new_media_file_path = wp_get_original_image_path( $new_attachment_id );
133
134 } else {
135
136 // Get the path to newly uploaded media file. An image file name may end with '-scaled'.
137 $new_attachment_file = get_post_meta( $new_attachment_id, '_wp_attached_file', true );
138 $upload_dir = wp_upload_dir();
139 $new_media_file_path = $upload_dir['basedir'] . '/' . $new_attachment_file;
140
141 }
142
143 // Check if the new media file exist / was successfully uploaded
144 if ( ! is_file( $new_media_file_path ) ) {
145 return false;
146 }
147
148 // Delete existing/old media files. Post and post meta entries for it are still there in the database.
149 $this->delete_media_files( $old_attachment_id );
150
151 // If original file is larger than 2560 pixel
152 // https://make.wordpress.org/core/2019/10/09/introducing-handling-of-big-images-in-wordpress-5-3/
153 if ( is_array( $new_attachment_meta ) && array_key_exists( 'original_image', $new_attachment_meta ) ) {
154
155 // Get the original media file path
156 $old_media_file_path = wp_get_original_image_path( $old_attachment_id );
157
158 } else {
159
160 // Get the path to the old/existing media file that will be replaced and deleted. An image file name may end with '-scaled'.
161 $old_attachment_file = get_post_meta( $old_attachment_id, '_wp_attached_file', true );
162 $old_media_file_path = $upload_dir['basedir'] . '/' . $old_attachment_file;
163
164 }
165
166 // Check if the directory path to the old media file is still intact
167 if ( ! file_exists( dirname( $old_media_file_path ) ) ) {
168
169 // Recreate the directory path
170 mkdir( dirname( $old_media_file_path ), 0755, true );
171
172 }
173
174 // Copy the new media file into the old media file's path
175 copy( $new_media_file_path, $old_media_file_path );
176
177 // Regenerate attachment meta data and image sub-sizes from the new media file that was just copied to the old path
178 $old_media_post_meta_updated = wp_generate_attachment_metadata( $old_attachment_id, $old_media_file_path );
179
180 // Update new media file's meta data with the ones from the old media. i.e. new media file will carry over the post ID and post meta of the old media file. i.e. only the files are replaced for the old media's ID and post meta in the database.
181 wp_update_attachment_metadata( $old_attachment_id, $old_media_post_meta_updated );
182
183 // Delete the newly uploaded media file and it's sub-sizes, and also delete post and post meta entries for it in the database.
184 wp_delete_attachment( $new_attachment_id, true );
185
186 // Add old attachment ID to recently replaced media option. This will be used for cache busting to ensure the new replacement images are immediately loaded in the browser / wp-admin
187 $options_extra = get_option( ASENHA_SLUG_U . '_extra', array() );
188 $recently_replaced_media = isset( $options_extra['recently_replaced_media'] ) ? $options_extra['recently_replaced_media'] : array();
189 $max_media_number_to_cache_bust = 5;
190 // vi( $recently_replaced_media, '', 'before' );
191 if ( count( $recently_replaced_media ) >= $max_media_number_to_cache_bust ) {
192 // Remove first/oldest attachment ID
193 array_shift( $recently_replaced_media );
194 }
195 $recently_replaced_media[] = $old_attachment_id;
196 $recently_replaced_media = array_unique( $recently_replaced_media );
197 // vi( $recently_replaced_media, '', 'after' );
198 $options_extra['recently_replaced_media'] = $recently_replaced_media;
199 update_option( ASENHA_SLUG_U . '_extra', $options_extra, true );
200 sleep(2);
201 }
202 }
203 }
204
205 /**
206 * Delete the existing/old media files when performing media replacement
207 *
208 * @link https://plugins.trac.wordpress.org/browser/replace-image/tags/1.1.7/hm-replace-image.php#L80
209 * @since 1.1.0
210 */
211 public function delete_media_files( $post_id ) {
212
213 $attachment_meta = wp_get_attachment_metadata( $post_id );
214
215 // Will get '-scaled' version if it exists, e.g. /path/to/uploads/year/month/file-name.jpg
216 $attachment_file_path = get_attached_file( $post_id );
217
218 // e.g. file-name.jpg
219 $attachment_file_basename = basename( $attachment_file_path );
220
221 // Delete intermediate images if there are any
222
223 if ( isset( $attachment_meta['sizes'] ) && is_array( $attachment_meta['sizes'] ) ) {
224
225 foreach( $attachment_meta['sizes'] as $size => $size_info) {
226
227 // /path/to/uploads/year/month/file-name.jpg --> /path/to/uploads/year/month/file-name-1024x768.jpg
228 $intermediate_file_path = str_replace( $attachment_file_basename, $size_info['file'], $attachment_file_path );
229 wp_delete_file( $intermediate_file_path );
230
231 }
232
233 }
234
235 // Delete the attachment file, which maybe the '-scaled' version
236 wp_delete_file( $attachment_file_path );
237
238 // If original file is larger than 2560 pixel
239 // https://make.wordpress.org/core/2019/10/09/introducing-handling-of-big-images-in-wordpress-5-3/
240 $attachment_original_file_path = wp_get_original_image_path( $post_id );
241
242 // Maybe delete the original file if it's an image file, and the original file path exists / was found
243 if ( $attachment_original_file_path ) {
244 wp_delete_file( $attachment_original_file_path );
245 }
246
247 }
248
249 /**
250 * Customize the attachment updated message
251 *
252 * @link https://github.com/WordPress/wordpress-develop/blob/6.0.2/src/wp-admin/edit-form-advanced.php#L180
253 * @since 1.1.0
254 */
255 public function attachment_updated_custom_message( $messages ) {
256
257 $new_messages = array();
258
259 foreach( $messages as $post_type => $messages_array ) {
260
261 if ( $post_type == 'attachment' ) {
262
263 // Message ID for successful edit/update of an attachment is 4. e.g. /wp-admin/post.php?post=a&action=edit&classic-editor&message=4 Customize it here.
264 $messages_array[4] = 'Media file updated. You may need to <a href="https://fabricdigital.co.nz/blog/how-to-hard-refresh-your-browser-and-clear-cache" target="_blank">hard refresh</a> your browser to see the updated media preview image below.';
265
266 }
267
268 $new_messages[$post_type] = $messages_array;
269
270 }
271
272 return $new_messages;
273
274 }
275
276 /**
277 * Append cache busting parameter to the end of image srcset
278 *
279 * @since 5.7.0
280 */
281 public function append_cache_busting_param_to_image_srcset( $sources, $size_array, $image_src, $image_meta, $attachment_id ) {
282 $options_extra = get_option( ASENHA_SLUG_U . '_extra', array() );
283 $recently_replaced_media = isset( $options_extra['recently_replaced_media'] ) ? $options_extra['recently_replaced_media'] : array();
284 $attachment_mime_type = get_post_mime_type( $attachment_id );
285
286 if ( in_array( $attachment_id, $recently_replaced_media )
287 && false !== strpos( $attachment_mime_type, 'image' )
288 ) {
289 foreach ( $sources as $size => $source ) {
290 $source['url'] .= $this->maybe_append_timestamp_parameter( $source['url'] );
291 $sources[$size] = $source;
292 // vi( $source, '', 'cache busting added via append_cache_busting_param_to_image_srcset' );
293 }
294 }
295 return $sources;
296 }
297
298 /**
299 * Append cache busting parameter to the end of image src
300 *
301 * @since 5.7.0
302 */
303 public function append_cache_busting_param_to_attachment_image_src( $image, $attachment_id ) {
304 $options_extra = get_option( ASENHA_SLUG_U . '_extra', array() );
305 $recently_replaced_media = isset( $options_extra['recently_replaced_media'] ) ? $options_extra['recently_replaced_media'] : array();
306 $attachment_mime_type = get_post_mime_type( $attachment_id );
307
308 if ( ! empty( $image[0] )
309 && in_array( $attachment_id, $recently_replaced_media )
310 && false !== strpos( $attachment_mime_type, 'image' )
311 ) {
312 $image[0] .= $this->maybe_append_timestamp_parameter( $image[0] );
313 // vi( $image, '', 'cache busting added via append_cache_busting_param_to_attachment_image_src' );
314 }
315
316 return $image;
317 }
318
319 /**
320 * Append cache busting parameter to image src for js
321 *
322 * @since 5.7.0
323 */
324 public function append_cache_busting_param_to_attachment_for_js( $response, $attachment ) {
325 $options_extra = get_option( ASENHA_SLUG_U . '_extra', array() );
326 $recently_replaced_media = isset( $options_extra['recently_replaced_media'] ) ? $options_extra['recently_replaced_media'] : array();
327 $attachment_mime_type = get_post_mime_type( $attachment->ID );
328
329 if ( in_array( $attachment->ID, $recently_replaced_media )
330 // && false !== strpos( $attachment_mime_type, 'image' )
331 ) {
332 if ( false !== strpos( $response['url'], '?' ) ) {
333 $response['url'] .= $this->maybe_append_timestamp_parameter( $response['url'] );
334 // vi( $response, '', 'cache busting added via append_cache_busting_param_to_attachment_for_js' );
335 }
336 if ( isset( $response['sizes'] ) ) {
337 foreach ( $response['sizes'] as $size_name => $size ) {
338 $response['sizes'][$size_name]['url'] .= $this->maybe_append_timestamp_parameter( $size['url'] );
339 // vi( $response, '', 'cache busting added via append_cache_busting_param_to_attachment_for_js' );
340 }
341 }
342 }
343
344 return $response;
345 }
346
347 /**
348 * Append cache busting parameter to attachment URL
349 *
350 * @since 6.8.2
351 */
352 public function append_cache_busting_param_to_attachment_url( $url, $attachment_id ) {
353 $options_extra = get_option( ASENHA_SLUG_U . '_extra', array() );
354 $recently_replaced_media = isset( $options_extra['recently_replaced_media'] ) ? $options_extra['recently_replaced_media'] : array();
355 $attachment_mime_type = get_post_mime_type( $attachment_id );
356
357 if ( in_array( $attachment_id, $recently_replaced_media )
358 // && false !== strpos( $attachment_mime_type, 'image' )
359 ) {
360 $url .= $this->maybe_append_timestamp_parameter( $url );
361 // vi( $url, '', 'cache busting added via append_cache_busting_param_to_attachment_url' );
362 }
363
364 return $url;
365 }
366
367 /**
368 * Maybe append timestamp parameter
369 *
370 * @since 7.7
371 */
372 public function maybe_append_timestamp_parameter( $url ) {
373 $parts = parse_url( $url );
374 $additional_url_parameter = '';
375
376 if ( isset( $parts['query'] ) ) {
377 parse_str( $parts['query'], $query );
378
379 if ( isset( $query['t'] ) && ! empty( $query['t'] ) ) {
380 // Do not add another timestamp parameter
381 } else {
382 $additional_url_parameter = ( false === strpos( $url, '?' ) ? '?' : '&' ) . 't=' . time();
383 }
384
385 } else {
386 $additional_url_parameter = ( false === strpos( $url, '?' ) ? '?' : '&' ) . 't=' . time();
387 }
388
389 return $additional_url_parameter;
390 }
391
392 }