1716 lines
54 KiB
PHP
1716 lines
54 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace DeliciousBrains\WP_Offload_Media\Integrations;
|
||
|
|
|
||
|
|
use AS3CF_Error;
|
||
|
|
use AS3CF_Utils;
|
||
|
|
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
||
|
|
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
||
|
|
use DeliciousBrains\WP_Offload_Media\Items\Remove_Provider_Handler;
|
||
|
|
use DeliciousBrains\WP_Offload_Media\Items\Upload_Handler;
|
||
|
|
use Exception;
|
||
|
|
use WP_Error;
|
||
|
|
use WP_Post;
|
||
|
|
|
||
|
|
class Media_Library extends Integration {
|
||
|
|
/**
|
||
|
|
* Is the current process deleting an attachment?
|
||
|
|
*
|
||
|
|
* @var bool
|
||
|
|
*/
|
||
|
|
private $deleting_attachment = false;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Keep track of items that are being updated multiple times in one request. I.e. when WP
|
||
|
|
* calls wp_update_attachment_metadata repeatedly during thumbnail generation
|
||
|
|
*
|
||
|
|
* @var array
|
||
|
|
*/
|
||
|
|
protected $items_in_progress = array();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Keep track of items that has been replaced by an edit image operation
|
||
|
|
*
|
||
|
|
* @var array
|
||
|
|
*/
|
||
|
|
protected $replaced_object_keys = array();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Keep track of context when rendering media library actions.
|
||
|
|
*
|
||
|
|
* @var string
|
||
|
|
*/
|
||
|
|
protected $render_context = 'list';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Init Media Library integration.
|
||
|
|
*/
|
||
|
|
public function init() {
|
||
|
|
Media_Library_Item::init_cache();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @inheritDoc
|
||
|
|
*/
|
||
|
|
public function setup() {
|
||
|
|
// Filter from WordPress media library handling, plugin needs to be set up
|
||
|
|
add_filter( 'wp_unique_filename', array( $this, 'wp_unique_filename' ), 10, 3 );
|
||
|
|
add_filter( 'wp_update_attachment_metadata', array( $this, 'wp_update_attachment_metadata' ), 110, 2 );
|
||
|
|
add_filter( 'pre_delete_attachment', array( $this, 'pre_delete_attachment' ), 20 );
|
||
|
|
add_filter( 'delete_attachment', array( $this, 'delete_attachment' ), 20 );
|
||
|
|
add_action( 'delete_post', array( $this, 'delete_post' ) );
|
||
|
|
add_filter( 'update_attached_file', array( $this, 'update_attached_file' ), 100, 2 );
|
||
|
|
add_filter( 'update_post_metadata', array( $this, 'update_post_metadata' ), 100, 5 );
|
||
|
|
|
||
|
|
// Attachment screens/modals
|
||
|
|
add_action( 'load-upload.php', array( $this, 'load_media_assets' ), 11 );
|
||
|
|
add_action( 'admin_enqueue_scripts', array( $this, 'load_attachment_assets' ), 11 );
|
||
|
|
add_action( 'add_meta_boxes', array( $this, 'attachment_provider_meta_box' ) );
|
||
|
|
|
||
|
|
// AJAX
|
||
|
|
add_action( 'wp_ajax_as3cf_get_attachment_provider_details', array( $this, 'ajax_get_attachment_provider_details' ) );
|
||
|
|
|
||
|
|
// Rewriting URLs, doesn't depend on plugin being set up
|
||
|
|
add_filter( 'wp_get_attachment_url', array( $this, 'wp_get_attachment_url' ), 99, 2 );
|
||
|
|
add_filter( 'wp_get_attachment_image_attributes', array( $this, 'wp_get_attachment_image_attributes' ), 99, 3 );
|
||
|
|
add_filter( 'get_image_tag', array( $this, 'maybe_encode_get_image_tag' ), 99, 6 );
|
||
|
|
add_filter( 'wp_get_attachment_image_src', array( $this, 'maybe_encode_wp_get_attachment_image_src' ), 99, 4 );
|
||
|
|
add_filter( 'wp_prepare_attachment_for_js', array( $this, 'maybe_encode_wp_prepare_attachment_for_js' ), 99, 3 );
|
||
|
|
add_filter( 'image_get_intermediate_size', array( $this, 'maybe_encode_image_get_intermediate_size' ), 99, 3 );
|
||
|
|
add_filter( 'get_attached_file', array( $this, 'get_attached_file' ), 10, 2 );
|
||
|
|
add_filter( 'wp_get_original_image_path', array( $this, 'get_attached_file' ), 10, 2 );
|
||
|
|
add_filter( 'wp_audio_shortcode', array( $this, 'wp_media_shortcode' ), 100, 5 );
|
||
|
|
add_filter( 'wp_video_shortcode', array( $this, 'wp_media_shortcode' ), 100, 5 );
|
||
|
|
|
||
|
|
// Srcset handling
|
||
|
|
add_filter( 'wp_image_file_matches_image_meta', array( $this, 'image_file_matches_image_meta' ), 10, 4 );
|
||
|
|
|
||
|
|
// Internal filters and actions
|
||
|
|
add_filter( 'as3cf_get_provider_url_for_item_source', array( $this, 'filter_get_provider_url_for_item_source' ), 10, 3 );
|
||
|
|
add_filter( 'as3cf_get_local_url_for_item_source', array( $this, 'filter_get_local_url_for_item_source' ), 10, 3 );
|
||
|
|
add_filter( 'as3cf_get_size_string_from_url_for_item_source', array( $this, 'get_size_string_from_url_for_item_source' ), 10, 3 );
|
||
|
|
add_filter( 'as3cf_get_item_secure_url', array( $this, 'get_item_secure_url' ), 10, 5 );
|
||
|
|
add_filter( 'as3cf_get_item_url', array( $this, 'get_item_url' ), 10, 5 );
|
||
|
|
add_filter( 'as3cf_remove_local_files', array( $this, 'filter_remove_local_files' ), 10, 3 );
|
||
|
|
add_filter( 'as3cf_remove_source_files_from_provider', array( $this, 'filter_remove_source_files_from_provider' ), 10, 3 );
|
||
|
|
add_action( 'as3cf_post_upload_item', array( $this, 'post_upload_item' ), 10, 1 );
|
||
|
|
add_filter( 'as3cf_pre_handle_item_' . Upload_Handler::get_item_handler_key_name(), array( $this, 'pre_handle_item_upload' ), 10, 3 );
|
||
|
|
add_filter( 'as3cf_upload_object_key_as_private', array( $this, 'filter_upload_object_key_as_private' ), 10, 3 );
|
||
|
|
add_action( 'as3cf_pre_upload_object', array( $this, 'action_pre_upload_object' ), 10, 2 );
|
||
|
|
|
||
|
|
if ( self::wp_check_filetype_broken() ) {
|
||
|
|
add_filter( 'shortcode_atts_audio', array( $this, 'filter_shortcode_atts' ), 10, 4 );
|
||
|
|
add_filter( 'shortcode_atts_video', array( $this, 'filter_shortcode_atts' ), 10, 4 );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Is installed?
|
||
|
|
*
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public static function is_installed(): bool {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Handles the upload of the attachment to provider when an attachment is updated.
|
||
|
|
*
|
||
|
|
* @handles wp_update_attachment_metadata
|
||
|
|
*
|
||
|
|
* @param array $data meta data for attachment
|
||
|
|
* @param int $post_id
|
||
|
|
*
|
||
|
|
* @return array|WP_Error
|
||
|
|
* @throws Exception
|
||
|
|
*/
|
||
|
|
public function wp_update_attachment_metadata( $data, $post_id ) {
|
||
|
|
if ( ! $this->as3cf->is_plugin_setup( true ) ) {
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Some other filter may already have corrupted $data
|
||
|
|
if ( is_wp_error( $data ) ) {
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Protect against updates of partially formed metadata since WordPress 5.3.
|
||
|
|
// Checks whether new upload currently is expected to have subsizes during upload,
|
||
|
|
// and if so, are any of its currently missing sizes part of the set.
|
||
|
|
if (
|
||
|
|
! empty( $data ) &&
|
||
|
|
function_exists( 'wp_get_registered_image_subsizes' ) &&
|
||
|
|
function_exists( 'wp_get_missing_image_subsizes' ) &&
|
||
|
|
wp_attachment_is_image( $post_id )
|
||
|
|
) {
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Plugin compat may require that we wait for wp_generate_attachment_metadata
|
||
|
|
* to be run before proceeding with uploading. I.e. Regenerate Thumbnails requires this.
|
||
|
|
*
|
||
|
|
* @param bool $wait True if we should wait AND generate_attachment_metadata hasn't run yet
|
||
|
|
*/
|
||
|
|
if ( apply_filters( 'as3cf_wait_for_generate_attachment_metadata', false ) ) {
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
// There is no unified way of checking whether subsizes are expected, so we have to duplicate WordPress code here.
|
||
|
|
$new_sizes = wp_get_registered_image_subsizes();
|
||
|
|
$new_sizes = apply_filters( 'intermediate_image_sizes_advanced', $new_sizes, $data, $post_id );
|
||
|
|
|
||
|
|
// If an image has been rotated, remove original image from metadata so that
|
||
|
|
// `wp_get_missing_image_subsizes()` doesn't use non-rotated image for
|
||
|
|
// generating missing thumbnail sizes.
|
||
|
|
// Also, some images, particularly SVGs, don't create thumbnails but do have
|
||
|
|
// metadata for them. At the time `wp_get_missing_image_subsizes()` checks
|
||
|
|
// the saved metadata, it isn't there, but we already have it.
|
||
|
|
$func = function ( $value, $object_id, $meta_key, $single, $meta_type ) use ( $post_id, $data ) {
|
||
|
|
if ( ! empty( $value['image_meta']['orientation'] ) ) {
|
||
|
|
unset( $value['original_image'] );
|
||
|
|
}
|
||
|
|
if ( ! empty( $data['image_meta']['orientation'] ) ) {
|
||
|
|
unset( $data['original_image'] );
|
||
|
|
}
|
||
|
|
|
||
|
|
if (
|
||
|
|
is_null( $value ) &&
|
||
|
|
$object_id === $post_id &&
|
||
|
|
'_wp_attachment_metadata' === $meta_key &&
|
||
|
|
$single &&
|
||
|
|
'post' === $meta_type
|
||
|
|
) {
|
||
|
|
// For some reason the filter is expected return an array of values
|
||
|
|
// as if not doing a single record.
|
||
|
|
return array( $data );
|
||
|
|
}
|
||
|
|
|
||
|
|
return $value;
|
||
|
|
};
|
||
|
|
|
||
|
|
add_filter( 'get_post_metadata', $func, 10, 5 );
|
||
|
|
$missing_sizes = wp_get_missing_image_subsizes( $post_id );
|
||
|
|
remove_filter( 'get_post_metadata', $func );
|
||
|
|
|
||
|
|
// If any registered thumbnails smaller than the original are missing,
|
||
|
|
// and current filters still expect those sizes, wait until they're all ready.
|
||
|
|
if (
|
||
|
|
! empty( $new_sizes ) &&
|
||
|
|
! empty( $missing_sizes ) &&
|
||
|
|
! empty( array_intersect_key( $missing_sizes, $new_sizes ) )
|
||
|
|
) {
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Is this a new item that we're already started working on in this request?
|
||
|
|
if ( ! empty( $this->items_in_progress[ $post_id ] ) ) {
|
||
|
|
$as3cf_item = $this->items_in_progress[ $post_id ];
|
||
|
|
}
|
||
|
|
|
||
|
|
// Is this an update for an existing item.
|
||
|
|
if ( empty( $as3cf_item ) || is_wp_error( $as3cf_item ) ) {
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
||
|
|
}
|
||
|
|
|
||
|
|
// Abort if not already uploaded to provider and the copy setting is off.
|
||
|
|
if ( ! $as3cf_item && ! $this->as3cf->get_setting( 'copy-to-s3' ) ) {
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( empty( $as3cf_item ) ) {
|
||
|
|
$as3cf_item = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Allows implementors to cancel uploading a Media Library item for any reason.
|
||
|
|
*
|
||
|
|
* This filter is triggered by updates to an attachment's metadata.
|
||
|
|
* To potentially cancel an upload started by any method,
|
||
|
|
* please use the 'as3cf_pre_upload_item' filter.
|
||
|
|
*
|
||
|
|
* @param bool $cancel True if the upload should be cancelled
|
||
|
|
* @param array $data Array describing the object being uploaded
|
||
|
|
* @param int $post_id Attachment's ID
|
||
|
|
* @param Media_Library_Item $as3cf_item The Media Library Item object if previously offloaded
|
||
|
|
*
|
||
|
|
* @see as3cf_pre_upload_item
|
||
|
|
*/
|
||
|
|
$cancel = apply_filters( 'as3cf_pre_update_attachment_metadata', false, $data, $post_id, $as3cf_item );
|
||
|
|
if ( false !== $cancel ) {
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
$offloaded_files = array();
|
||
|
|
|
||
|
|
// If we still don't have a valid item, create one from scratch.
|
||
|
|
if ( empty( $as3cf_item ) || is_wp_error( $as3cf_item ) ) {
|
||
|
|
$as3cf_item = Media_Library_Item::create_from_source_id( $post_id );
|
||
|
|
} else {
|
||
|
|
$offloaded_files = $as3cf_item->offloaded_files();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Did we get a WP_Error?
|
||
|
|
if ( is_wp_error( $as3cf_item ) ) {
|
||
|
|
AS3CF_Error::Log( $as3cf_item->get_error_message() );
|
||
|
|
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Or didn't we get anything at all?
|
||
|
|
if ( empty( $as3cf_item ) ) {
|
||
|
|
$message = sprintf( __( "Can't create item from media library item %d", 'amazon-s3-and-cloudfront' ), $post_id );
|
||
|
|
AS3CF_Error::Log( $message );
|
||
|
|
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Update item's expected objects from attachment's new metadata.
|
||
|
|
$this->update_item_from_new_metadata( $as3cf_item, $data );
|
||
|
|
|
||
|
|
$this->upload_item( $as3cf_item, $offloaded_files );
|
||
|
|
$this->items_in_progress[ $post_id ] = $as3cf_item;
|
||
|
|
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Upload item.
|
||
|
|
*
|
||
|
|
* @param Media_Library_Item $as3cf_item
|
||
|
|
* @param array $offloaded_files An array of files previously offloaded for the item.
|
||
|
|
*/
|
||
|
|
protected function upload_item( Media_Library_Item $as3cf_item, array $offloaded_files ) {
|
||
|
|
$upload_handler = $this->as3cf->get_item_handler( Upload_Handler::get_item_handler_key_name() );
|
||
|
|
$upload_handler->handle( $as3cf_item, array( 'offloaded_files' => $offloaded_files ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Handle update_post_metadata for some media library related keys
|
||
|
|
*
|
||
|
|
* @handles update_post_metadata
|
||
|
|
*
|
||
|
|
* @param bool $check
|
||
|
|
* @param int $object_id
|
||
|
|
* @param string $meta_key
|
||
|
|
* @param mixed $meta_value
|
||
|
|
* @param mixed $prev_value
|
||
|
|
*/
|
||
|
|
public function update_post_metadata( $check, $object_id, $meta_key, $meta_value, $prev_value ) {
|
||
|
|
if ( '_wp_attachment_backup_sizes' === $meta_key ) {
|
||
|
|
if ( $this->as3cf->is_plugin_setup( true ) ) {
|
||
|
|
$this->update_attachment_backup_sizes( $object_id, $meta_value );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $check;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Handle updated attachment_backup_sizes.
|
||
|
|
*
|
||
|
|
* @param int $post_id
|
||
|
|
* @param array $sizes
|
||
|
|
*/
|
||
|
|
protected function update_attachment_backup_sizes( $post_id, $sizes ) {
|
||
|
|
// This item should already be known in this request, if not bail out
|
||
|
|
if ( empty( $this->items_in_progress[ $post_id ] ) ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// We should also have recorded some replaced keys in this request, if not bail
|
||
|
|
if ( empty( $this->replaced_object_keys[ $post_id ] ) ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @var Media_Library_Item $as3cf_item */
|
||
|
|
$as3cf_item = $this->items_in_progress[ $post_id ];
|
||
|
|
$existing_objects = $as3cf_item->objects();
|
||
|
|
|
||
|
|
foreach ( array_keys( $sizes ) as $key ) {
|
||
|
|
if ( ! isset( $existing_objects[ $key ] ) ) {
|
||
|
|
$parts = explode( '-', $key );
|
||
|
|
$size = join( '-', array_slice( $parts, 0, -1 ) );
|
||
|
|
if ( 'full' === $size ) {
|
||
|
|
$size = Item::primary_object_key();
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( isset( $this->replaced_object_keys[ $post_id ][ $size ] ) ) {
|
||
|
|
$existing_objects[ $key ] = $this->replaced_object_keys[ $post_id ][ $size ];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$as3cf_item->set_objects( $existing_objects );
|
||
|
|
$as3cf_item->save();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Filters the result when generating a unique file name.
|
||
|
|
*
|
||
|
|
* @param string $filename Unique file name.
|
||
|
|
* @param string $ext File extension, eg. ".png".
|
||
|
|
* @param string $dir Directory path.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
* @since 4.5.0
|
||
|
|
*/
|
||
|
|
public function wp_unique_filename( $filename, $ext, $dir ) {
|
||
|
|
// Get Post ID if uploaded in post screen.
|
||
|
|
$post_id = filter_input( INPUT_POST, 'post_id', FILTER_VALIDATE_INT );
|
||
|
|
|
||
|
|
return $this->filter_unique_filename( $filename, $ext, $dir, $post_id );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create unique names for file to be uploaded to AWS.
|
||
|
|
* This only applies when the remove local file option is enabled.
|
||
|
|
*
|
||
|
|
* @param string $filename Unique file name.
|
||
|
|
* @param string $ext File extension, eg. ".png".
|
||
|
|
* @param string $dir Directory path.
|
||
|
|
* @param int $post_id Attachment's parent Post ID.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function filter_unique_filename( $filename, $ext, $dir, $post_id = null ) {
|
||
|
|
if ( ! $this->as3cf->is_plugin_setup( true ) ) {
|
||
|
|
return $filename;
|
||
|
|
}
|
||
|
|
|
||
|
|
// sanitize the file name before we begin processing
|
||
|
|
$filename = sanitize_file_name( $filename );
|
||
|
|
$ext = strtolower( $ext );
|
||
|
|
$name = wp_basename( $filename, $ext );
|
||
|
|
|
||
|
|
// Edge case: if file is named '.ext', treat as an empty name.
|
||
|
|
if ( $name === $ext ) {
|
||
|
|
$name = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
// Rebuild filename with lowercase extension as provider will have converted extension on upload.
|
||
|
|
$filename = $name . $ext;
|
||
|
|
$time = current_time( 'mysql' );
|
||
|
|
|
||
|
|
// Get time if uploaded in post screen.
|
||
|
|
if ( ! empty( $post_id ) ) {
|
||
|
|
$time = $this->get_post_time( $post_id );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( ! $this->as3cf->does_file_exist( $filename, $time ) ) {
|
||
|
|
// File doesn't exist locally or on provider, return it.
|
||
|
|
return $filename;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this->as3cf->generate_unique_filename( $name, $ext, $time );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Allow processes to update the file on provider via update_attached_file()
|
||
|
|
*
|
||
|
|
* @param string $file
|
||
|
|
* @param int $attachment_id
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function update_attached_file( $file, $attachment_id ) {
|
||
|
|
if ( ! $this->as3cf->is_plugin_setup( true ) ) {
|
||
|
|
return $file;
|
||
|
|
}
|
||
|
|
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
||
|
|
|
||
|
|
if ( ! $as3cf_item ) {
|
||
|
|
return $file;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Allow processes to update the file on provider via update_attached_file()
|
||
|
|
*
|
||
|
|
* @param string $file File name/path
|
||
|
|
* @param int $attachment_id Attachment id
|
||
|
|
* @param Media_Library_Item $as3cf_item The item object
|
||
|
|
*/
|
||
|
|
return apply_filters( 'as3cf_update_attached_file', $file, $attachment_id, $as3cf_item );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Removes an attachment and intermediate image size files from provider
|
||
|
|
*
|
||
|
|
* @param int $post_id
|
||
|
|
*/
|
||
|
|
public function delete_attachment( $post_id ) {
|
||
|
|
if ( ! $this->as3cf->is_plugin_setup( true ) ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
||
|
|
|
||
|
|
if ( ! $as3cf_item ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( ! $as3cf_item->served_by_provider( true ) ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Remove the objects from the provider
|
||
|
|
$remove_provider_handler = $this->as3cf->get_item_handler( Remove_Provider_Handler::get_item_handler_key_name() );
|
||
|
|
$remove_provider_handler->handle( $as3cf_item, array( 'verify_exists_on_local' => false ) );
|
||
|
|
$as3cf_item->delete();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Update an existing item's expected objects from attachment's new metadata.
|
||
|
|
*
|
||
|
|
* @param Media_Library_Item $as3cf_item
|
||
|
|
* @param array $metadata
|
||
|
|
*/
|
||
|
|
protected function update_item_from_new_metadata( $as3cf_item, $metadata ) {
|
||
|
|
if ( empty( $metadata ) || ! is_array( $metadata ) ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
$files = AS3CF_Utils::get_attachment_file_paths( $as3cf_item->source_id(), false, $metadata );
|
||
|
|
$existing_basename = wp_basename( $as3cf_item->path() );
|
||
|
|
$existing_objects = $as3cf_item->objects();
|
||
|
|
|
||
|
|
if ( ! isset( $this->replaced_object_keys[ $as3cf_item->source_id() ] ) ) {
|
||
|
|
$this->replaced_object_keys[ $as3cf_item->source_id() ] = array();
|
||
|
|
}
|
||
|
|
|
||
|
|
foreach ( $files as $object_key => $file ) {
|
||
|
|
$new_filename = wp_basename( $file );
|
||
|
|
|
||
|
|
if ( ! empty( $existing_objects[ $object_key ]['source_file'] ) && $existing_objects[ $object_key ]['source_file'] !== $new_filename ) {
|
||
|
|
$this->replaced_object_keys[ $as3cf_item->source_id() ][ $object_key ] = $existing_objects[ $object_key ];
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( Item::primary_object_key() === $object_key && $existing_basename !== $new_filename ) {
|
||
|
|
$as3cf_item->set_path( str_replace( $existing_basename, $new_filename, $as3cf_item->path() ) );
|
||
|
|
$as3cf_item->set_source_path( str_replace( $existing_basename, $new_filename, $as3cf_item->source_path() ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
$existing_objects[ $object_key ] = array(
|
||
|
|
'source_file' => $new_filename,
|
||
|
|
'is_private' => isset( $existing_objects[ $object_key ]['is_private'] ) ? $existing_objects[ $object_key ]['is_private'] : false,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
$extra_info = $as3cf_item->extra_info();
|
||
|
|
$extra_info['objects'] = $existing_objects;
|
||
|
|
$as3cf_item->set_extra_info( $extra_info );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Load media assets.
|
||
|
|
*/
|
||
|
|
public function load_media_assets() {
|
||
|
|
$this->as3cf->enqueue_style( 'as3cf-media-styles', 'assets/css/media', array( 'as3cf-modal' ) );
|
||
|
|
$this->as3cf->enqueue_script( 'as3cf-media-script', 'assets/js/media', array(
|
||
|
|
'jquery',
|
||
|
|
'media-views',
|
||
|
|
'media-grid',
|
||
|
|
'wp-util',
|
||
|
|
) );
|
||
|
|
|
||
|
|
wp_localize_script( 'as3cf-media-script', 'as3cf_media', array(
|
||
|
|
'strings' => $this->get_media_action_strings(),
|
||
|
|
'nonces' => array(
|
||
|
|
'get_attachment_provider_details' => wp_create_nonce( 'get-attachment-s3-details' ),
|
||
|
|
),
|
||
|
|
) );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Load the attachment assets only when editing an attachment
|
||
|
|
*
|
||
|
|
* @param string $hook_suffix
|
||
|
|
*/
|
||
|
|
public function load_attachment_assets( $hook_suffix ) {
|
||
|
|
global $post;
|
||
|
|
if ( 'post.php' !== $hook_suffix || 'attachment' !== $post->post_type ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->as3cf->enqueue_style( 'as3cf-pro-attachment-styles', 'assets/css/attachment', array( 'as3cf-modal' ) );
|
||
|
|
|
||
|
|
do_action( 'as3cf_load_attachment_assets' );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Add the S3 meta box to the attachment screen
|
||
|
|
*/
|
||
|
|
public function attachment_provider_meta_box() {
|
||
|
|
add_meta_box(
|
||
|
|
's3-actions',
|
||
|
|
__( 'Offload', 'amazon-s3-and-cloudfront' ),
|
||
|
|
array( $this, 'attachment_provider_actions_meta_box' ),
|
||
|
|
'attachment',
|
||
|
|
'side',
|
||
|
|
'core'
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Handle retrieving the provider details for attachment modals.
|
||
|
|
*/
|
||
|
|
public function ajax_get_attachment_provider_details() {
|
||
|
|
if ( ! isset( $_POST['id'] ) ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
check_ajax_referer( 'get-attachment-s3-details', '_nonce' );
|
||
|
|
|
||
|
|
$id = intval( $_POST['id'] );
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $id );
|
||
|
|
$served_by_provider = false;
|
||
|
|
|
||
|
|
if ( ! empty( $as3cf_item ) ) {
|
||
|
|
$served_by_provider = $as3cf_item->served_by_provider( true );
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->render_context = 'grid';
|
||
|
|
|
||
|
|
// get the actions available for the attachment
|
||
|
|
$data = array(
|
||
|
|
'links' => $this->add_media_row_actions( array(), $id ),
|
||
|
|
'provider_object' => $this->get_formatted_provider_info( $id ),
|
||
|
|
'acl_toggle' => $this->verify_media_actions() && $served_by_provider,
|
||
|
|
);
|
||
|
|
|
||
|
|
wp_send_json_success( $data );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Conditionally adds copy, remove and download S3 action links for an
|
||
|
|
* attachment on the Media library list view
|
||
|
|
*
|
||
|
|
* @param array $actions
|
||
|
|
* @param WP_Post|int $post
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function add_media_row_actions( array $actions, $post ) {
|
||
|
|
return $actions;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get a list of available media actions which can be performed according to plugin and user capability requirements.
|
||
|
|
*
|
||
|
|
* @param string|null $scope
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function get_available_media_actions( $scope = '' ) {
|
||
|
|
return array();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Render the S3 attachment meta box
|
||
|
|
*/
|
||
|
|
public function attachment_provider_actions_meta_box() {
|
||
|
|
global $post;
|
||
|
|
$file = get_attached_file( $post->ID, true );
|
||
|
|
|
||
|
|
$args = array(
|
||
|
|
'provider_object' => $this->get_formatted_provider_info( $post->ID ),
|
||
|
|
'post' => $post,
|
||
|
|
'local_file_exists' => file_exists( $file ),
|
||
|
|
'available_actions' => $this->get_available_media_actions( 'singular' ),
|
||
|
|
'sendback' => 'post.php?post=' . $post->ID . '&action=edit',
|
||
|
|
);
|
||
|
|
|
||
|
|
$this->as3cf->render_view( 'attachment-metabox', $args );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get attachment url
|
||
|
|
*
|
||
|
|
* @param string $url
|
||
|
|
* @param int $post_id
|
||
|
|
*
|
||
|
|
* @return bool|mixed|WP_Error
|
||
|
|
*/
|
||
|
|
public function wp_get_attachment_url( $url, $post_id ) {
|
||
|
|
if ( $this->as3cf->plugin_compat->is_customizer_crop_action() ) {
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
||
|
|
if ( empty( $as3cf_item ) || ! $as3cf_item->served_by_provider() ) {
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
$size = $as3cf_item->get_object_key_from_filename( $url );
|
||
|
|
$new_url = $as3cf_item->get_provider_url( $size );
|
||
|
|
|
||
|
|
if ( is_wp_error( $new_url ) || false === $new_url ) {
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Old naming convention, will be deprecated soon
|
||
|
|
$new_url = apply_filters( 'wps3_get_attachment_url', $new_url, $post_id, $this );
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Filter the rewritten provider URL for a Media Library Item (attachment)
|
||
|
|
*
|
||
|
|
* @param string $url The URL
|
||
|
|
* @param int $post_id Attachment post id
|
||
|
|
*/
|
||
|
|
return apply_filters( 'as3cf_wp_get_attachment_url', $new_url, $post_id );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Return a formatted provider info array with display friendly defaults
|
||
|
|
*
|
||
|
|
* @param int $id
|
||
|
|
*
|
||
|
|
* @return bool|array
|
||
|
|
*/
|
||
|
|
public function get_formatted_provider_info( int $id ) {
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $id );
|
||
|
|
|
||
|
|
if ( ! $as3cf_item ) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
$provider_object = $as3cf_item->key_values();
|
||
|
|
$storage_provider = $this->as3cf->get_storage_provider_instance( $provider_object['provider'] );
|
||
|
|
|
||
|
|
// Backwards compatibility.
|
||
|
|
$provider_object['key'] = $provider_object['path'];
|
||
|
|
$provider_object['url'] = $as3cf_item->get_provider_url();
|
||
|
|
|
||
|
|
$acl = $as3cf_item->is_private() ? $storage_provider->get_private_acl() : $storage_provider->get_default_acl();
|
||
|
|
$acl_info = array(
|
||
|
|
'acl' => $acl,
|
||
|
|
'name' => $this->as3cf->get_acl_display_name( $acl ),
|
||
|
|
'title' => $this->get_media_action_strings( 'change_to_private' ),
|
||
|
|
);
|
||
|
|
|
||
|
|
if ( $as3cf_item->is_private() ) {
|
||
|
|
$acl_info['title'] = $this->get_media_action_strings( 'change_to_public' );
|
||
|
|
}
|
||
|
|
|
||
|
|
$provider_object['acl'] = $acl_info;
|
||
|
|
$provider_object['region'] = $storage_provider->get_region_name( $provider_object['region'] );
|
||
|
|
$provider_object['provider_name'] = $this->as3cf->get_provider_service_name( $provider_object['provider'] );
|
||
|
|
|
||
|
|
return $provider_object;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Filters the list of attachment image attributes.
|
||
|
|
*
|
||
|
|
* @param array $attr Attributes for the image markup.
|
||
|
|
* @param WP_Post $attachment Image attachment post.
|
||
|
|
* @param string|array $size Requested size. Image size or array of width and height values (in that order).
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function wp_get_attachment_image_attributes( $attr, $attachment, $size ) {
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment->ID );
|
||
|
|
if ( ! $as3cf_item || ! $as3cf_item->served_by_provider() ) {
|
||
|
|
return $attr;
|
||
|
|
}
|
||
|
|
|
||
|
|
$size = $this->maybe_convert_size_to_string( $attachment->ID, $size );
|
||
|
|
|
||
|
|
// image_downsize incorrectly substitutes size filename into full URL for src attribute instead of clobbering.
|
||
|
|
// So we need to fix up the src attribute if a size is being used.
|
||
|
|
if ( ! empty( $size ) && ! empty( $attr['src'] ) ) {
|
||
|
|
$attr['src'] = $as3cf_item->get_provider_url( $size );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Filtered list of attachment image attributes.
|
||
|
|
*
|
||
|
|
* @param array $attr Attributes for the image markup.
|
||
|
|
* @param WP_Post $attachment Image attachment post.
|
||
|
|
* @param string $size Requested size.
|
||
|
|
* @param Media_Library_Item $as3cf_item
|
||
|
|
*/
|
||
|
|
return apply_filters( 'as3cf_wp_get_attachment_image_attributes', $attr, $attachment, $size, $as3cf_item );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Maybe encode attachment URLs when retrieving the image tag
|
||
|
|
*
|
||
|
|
* @param string $html
|
||
|
|
* @param int $id
|
||
|
|
* @param string $alt
|
||
|
|
* @param string $title
|
||
|
|
* @param string $align
|
||
|
|
* @param string $size
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function maybe_encode_get_image_tag( $html, $id, $alt, $title, $align, $size ) {
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $id );
|
||
|
|
if ( ! $as3cf_item || ! $as3cf_item->served_by_provider() ) {
|
||
|
|
return $html;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( ! is_string( $html ) ) {
|
||
|
|
return $html;
|
||
|
|
}
|
||
|
|
|
||
|
|
preg_match( '@\ssrc=[\'\"]([^\'\"]*)[\'\"]@', $html, $matches );
|
||
|
|
|
||
|
|
if ( ! isset( $matches[1] ) ) {
|
||
|
|
// Can't establish img src
|
||
|
|
return $html;
|
||
|
|
}
|
||
|
|
|
||
|
|
$img_src = $matches[1];
|
||
|
|
$new_img_src = $this->maybe_sign_intermediate_size( $img_src, $id, $size, $as3cf_item );
|
||
|
|
$new_img_src = AS3CF_Utils::encode_filename_in_path( $new_img_src );
|
||
|
|
|
||
|
|
return str_replace( $img_src, $new_img_src, $html );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Maybe encode URLs for images that represent an attachment
|
||
|
|
*
|
||
|
|
* @param array|bool $image
|
||
|
|
* @param int $attachment_id
|
||
|
|
* @param string|array $size
|
||
|
|
* @param bool $icon
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function maybe_encode_wp_get_attachment_image_src( $image, $attachment_id, $size, $icon ) {
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
||
|
|
if ( ! $as3cf_item || ! $as3cf_item->served_by_provider() ) {
|
||
|
|
return $image;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( isset( $image[0] ) ) {
|
||
|
|
$url = $this->maybe_sign_intermediate_size( $image[0], $attachment_id, $size, $as3cf_item );
|
||
|
|
$url = AS3CF_Utils::encode_filename_in_path( $url );
|
||
|
|
|
||
|
|
$image[0] = $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $image;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Maybe encode URLs when outputting attachments in the media grid
|
||
|
|
*
|
||
|
|
* @param array $response
|
||
|
|
* @param int|object $attachment
|
||
|
|
* @param array $meta
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function maybe_encode_wp_prepare_attachment_for_js( $response, $attachment, $meta ) {
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment->ID );
|
||
|
|
if ( empty( $as3cf_item ) || ! $as3cf_item->served_by_provider() ) {
|
||
|
|
return $response;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( isset( $response['url'] ) ) {
|
||
|
|
$response['url'] = AS3CF_Utils::encode_filename_in_path( $response['url'] );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( isset( $response['sizes'] ) && is_array( $response['sizes'] ) ) {
|
||
|
|
foreach ( $response['sizes'] as $size => $value ) {
|
||
|
|
$url = $this->maybe_sign_intermediate_size( $value['url'], $attachment->ID, $size, $as3cf_item, true );
|
||
|
|
$url = AS3CF_Utils::encode_filename_in_path( $url );
|
||
|
|
|
||
|
|
$response['sizes'][ $size ]['url'] = $url;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $response;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Maybe encode URLs when retrieving intermediate sizes.
|
||
|
|
*
|
||
|
|
* @param array $data
|
||
|
|
* @param int $post_id
|
||
|
|
* @param string|array $size
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function maybe_encode_image_get_intermediate_size( $data, $post_id, $size ) {
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
||
|
|
if ( ! $as3cf_item || ! $as3cf_item->served_by_provider() ) {
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( isset( $data['url'] ) ) {
|
||
|
|
$url = $this->maybe_sign_intermediate_size( $data['url'], $post_id, $size, $as3cf_item );
|
||
|
|
$url = AS3CF_Utils::encode_filename_in_path( $url );
|
||
|
|
|
||
|
|
$data['url'] = $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Sign intermediate size.
|
||
|
|
*
|
||
|
|
* @param string $url
|
||
|
|
* @param int $attachment_id
|
||
|
|
* @param string|array $size
|
||
|
|
* @param bool|Media_Library_Item $as3cf_item
|
||
|
|
* @param bool $force_rewrite If size not signed, make sure correct URL is being used anyway.
|
||
|
|
*
|
||
|
|
* @return string|WP_Error
|
||
|
|
*/
|
||
|
|
protected function maybe_sign_intermediate_size( $url, $attachment_id, $size, $as3cf_item = false, $force_rewrite = false ) {
|
||
|
|
if ( ! $as3cf_item ) {
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
||
|
|
}
|
||
|
|
|
||
|
|
$size = $this->maybe_convert_size_to_string( $attachment_id, $size );
|
||
|
|
|
||
|
|
if ( $force_rewrite || $as3cf_item->is_private( $size ) ) {
|
||
|
|
// Private file, add AWS signature if required
|
||
|
|
return $as3cf_item->get_provider_url( $size );
|
||
|
|
}
|
||
|
|
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Return the provider URL when the local file is missing
|
||
|
|
* unless we know who the calling process is, and we are happy
|
||
|
|
* to copy the file back to the server to be used.
|
||
|
|
*
|
||
|
|
* @handles get_attached_file
|
||
|
|
* @handles wp_get_original_image_path
|
||
|
|
*
|
||
|
|
* @param string $file
|
||
|
|
* @param int $attachment_id
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function get_attached_file( $file, $attachment_id ) {
|
||
|
|
// During the deletion of an attachment, stream wrapper URLs should not be returned.
|
||
|
|
if ( $this->deleting_attachment ) {
|
||
|
|
return $file;
|
||
|
|
}
|
||
|
|
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
||
|
|
if ( ! empty( $as3cf_item ) && ! $as3cf_item->served_by_provider() ) {
|
||
|
|
$as3cf_item = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( file_exists( $file ) || ! $as3cf_item ) {
|
||
|
|
if ( $as3cf_item ) {
|
||
|
|
/**
|
||
|
|
* This filter gives filter implementors a chance to copy back siblings for
|
||
|
|
* a local file even if the main already exists locally.
|
||
|
|
*
|
||
|
|
* @param string $url Item URL
|
||
|
|
* @param string $file Local file path
|
||
|
|
* @param int $attachment_id Attachment post id
|
||
|
|
* @param Media_Library_Item $as3cf_item The Item object
|
||
|
|
*/
|
||
|
|
return apply_filters( 'as3cf_get_attached_file_noop', $file, $file, $attachment_id, $as3cf_item );
|
||
|
|
} else {
|
||
|
|
return $file;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$url = $as3cf_item->get_provider_url();
|
||
|
|
if ( false === $url || is_wp_error( $url ) ) {
|
||
|
|
return $file;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* This filter gives filter implementors a chance to copy back missing item files
|
||
|
|
* from the provider before WordPress returns the file name/path for it. Defaults to
|
||
|
|
* returning the remote URL.
|
||
|
|
*
|
||
|
|
* @param string $url Item URL
|
||
|
|
* @param string $file Local file path
|
||
|
|
* @param int $attachment_id Attachment post id
|
||
|
|
* @param Media_Library_Item $as3cf_item The Item object
|
||
|
|
*/
|
||
|
|
return apply_filters( 'as3cf_get_attached_file', $url, $file, $attachment_id, $as3cf_item );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Filters the audio & video shortcodes output to remove "&_=NN" params from source.src as it breaks signed URLs.
|
||
|
|
*
|
||
|
|
* @param string $html Shortcode HTML output.
|
||
|
|
* @param array $atts Array of shortcode attributes.
|
||
|
|
* @param string $media Media file.
|
||
|
|
* @param int $post_id Post ID.
|
||
|
|
* @param string $library Media library used for the shortcode.
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*
|
||
|
|
* Note: Depends on 30377.4.diff from https://core.trac.wordpress.org/ticket/30377
|
||
|
|
*/
|
||
|
|
public function wp_media_shortcode( $html, $atts, $media, $post_id, $library ) {
|
||
|
|
return preg_replace( '/&_=[0-9]+/', '', $html );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Check we can do the media actions
|
||
|
|
*
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public function verify_media_actions() {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get all strings or a specific string used for the media actions
|
||
|
|
*
|
||
|
|
* @param null|string $string
|
||
|
|
*
|
||
|
|
* @return array|string
|
||
|
|
*/
|
||
|
|
public function get_media_action_strings( $string = null ) {
|
||
|
|
$not_verified_value = __( 'No', 'amazon-s3-and-cloudfront' );
|
||
|
|
$not_verified_value .= ' ';
|
||
|
|
$not_verified_value .= $this->as3cf->more_info_link( '/wp-offload-media/doc/add-metadata-tool/', 'os3+attachment+metabox', 'analyze-and-repair', 'More Info', '(', ')' );
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Returns all strings used to render meta boxes on the WordPress Media Library edit page
|
||
|
|
*
|
||
|
|
* @param array $strings Associative array of strings
|
||
|
|
*/
|
||
|
|
$strings = apply_filters( 'as3cf_media_action_strings', array(
|
||
|
|
'provider' => _x( 'Storage Provider', 'Storage provider key name', 'amazon-s3-and-cloudfront' ),
|
||
|
|
'provider_name' => _x( 'Storage Provider', 'Storage provider name', 'amazon-s3-and-cloudfront' ),
|
||
|
|
'bucket' => _x( 'Bucket', 'Bucket name', 'amazon-s3-and-cloudfront' ),
|
||
|
|
'key' => _x( 'Path', 'Path to file in bucket', 'amazon-s3-and-cloudfront' ),
|
||
|
|
'region' => _x( 'Region', 'Location of bucket', 'amazon-s3-and-cloudfront' ),
|
||
|
|
'acl' => _x( 'Access', 'Access control list of the file in bucket', 'amazon-s3-and-cloudfront' ),
|
||
|
|
'url' => __( 'URL', 'amazon-s3-and-cloudfront' ),
|
||
|
|
'is_verified' => _x( 'Verified', 'Whether or not metadata has been verified', 'amazon-s3-and-cloudfront' ),
|
||
|
|
'not_verified' => $not_verified_value,
|
||
|
|
) );
|
||
|
|
|
||
|
|
if ( ! is_null( $string ) ) {
|
||
|
|
return isset( $strings[ $string ] ) ? $strings[ $string ] : '';
|
||
|
|
}
|
||
|
|
|
||
|
|
return $strings;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Remove 'filesize' from attachment's metadata if appropriate, also our total filesize record.
|
||
|
|
*
|
||
|
|
* @param int $post_id Attachment's post_id.
|
||
|
|
* @param array $data Attachment's metadata.
|
||
|
|
* @param bool $update_metadata Update the metadata record now? Defaults to true.
|
||
|
|
*
|
||
|
|
* @return array Attachment's cleaned up metadata.
|
||
|
|
*/
|
||
|
|
public function maybe_cleanup_filesize_metadata( $post_id, $data, $update_metadata = true ) {
|
||
|
|
if ( ! is_int( $post_id ) || empty( $post_id ) || empty( $data ) || ! is_array( $data ) ) {
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Audio and video have a filesize added to metadata by default, but images and anything else don't.
|
||
|
|
* Note: Could have used `wp_generate_attachment_metadata` here to test whether default metadata has 'filesize',
|
||
|
|
* but it not only has side effects it also does a lot of work considering it's not a huge deal for this entry to hang around.
|
||
|
|
*/
|
||
|
|
if (
|
||
|
|
empty( $data['mime_type'] ) ||
|
||
|
|
0 === strpos( $data['mime_type'], 'image/' ) ||
|
||
|
|
! ( 0 === strpos( $data['mime_type'], 'audio/' ) || 0 === strpos( $data['mime_type'], 'video/' ) )
|
||
|
|
) {
|
||
|
|
unset( $data['filesize'] );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( $update_metadata ) {
|
||
|
|
if ( empty( $data ) ) {
|
||
|
|
delete_post_meta( $post_id, '_wp_attachment_metadata' );
|
||
|
|
} else {
|
||
|
|
update_post_meta( $post_id, '_wp_attachment_metadata', $data );
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
delete_post_meta( $post_id, 'as3cf_filesize_total' );
|
||
|
|
|
||
|
|
return $data;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get ACL value string.
|
||
|
|
*
|
||
|
|
* @param array $acl
|
||
|
|
* @param int $post_id
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function get_acl_value_string( $acl, $post_id ) {
|
||
|
|
return $acl['name'];
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Determines if the image metadata is for the image source file.
|
||
|
|
*
|
||
|
|
* @handles wp_image_file_matches_image_meta
|
||
|
|
*
|
||
|
|
* @param bool $match
|
||
|
|
* @param string $image_location
|
||
|
|
* @param array $image_meta
|
||
|
|
* @param int $source_id
|
||
|
|
*
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public function image_file_matches_image_meta( $match, $image_location, $image_meta, $source_id ) {
|
||
|
|
// If already matched or the URL is local, there's nothing for us to do.
|
||
|
|
if ( $match || $this->as3cf->filter_local->url_needs_replacing( $image_location ) ) {
|
||
|
|
return $match;
|
||
|
|
}
|
||
|
|
|
||
|
|
$item = array(
|
||
|
|
'id' => $source_id,
|
||
|
|
'source_type' => Media_Library_Item::source_type(),
|
||
|
|
);
|
||
|
|
|
||
|
|
return $this->as3cf->filter_provider->item_matches_src( $item, $image_location );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the local URL for a Media Library Item
|
||
|
|
*
|
||
|
|
* @handles as3cf_get_local_url_for_item_source
|
||
|
|
*
|
||
|
|
* @param string $url Url
|
||
|
|
* @param array $item_source The item source descriptor array
|
||
|
|
* @param string $size Name of requested size
|
||
|
|
*
|
||
|
|
* @return string|false
|
||
|
|
*/
|
||
|
|
public function filter_get_local_url_for_item_source( $url, $item_source, $size ) {
|
||
|
|
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $item_source['id'] );
|
||
|
|
if ( ! empty( $as3cf_item ) ) {
|
||
|
|
return $as3cf_item->get_local_url( $size );
|
||
|
|
}
|
||
|
|
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the remote URL for a Media Library Item
|
||
|
|
*
|
||
|
|
* @handles as3cf_get_provider_url_for_item_source
|
||
|
|
*
|
||
|
|
* @param string $url Url
|
||
|
|
* @param array $item_source The item source descriptor array
|
||
|
|
* @param string $size Name of requested size
|
||
|
|
*
|
||
|
|
* @return string|false
|
||
|
|
*/
|
||
|
|
public function filter_get_provider_url_for_item_source( $url, $item_source, $size ) {
|
||
|
|
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
$as3cf_item = Media_Library_Item::get_by_source_id( $item_source['id'] );
|
||
|
|
if ( empty( $as3cf_item ) || ! $as3cf_item->served_by_provider() ) {
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
$url = $as3cf_item->get_provider_url( $size );
|
||
|
|
|
||
|
|
if ( is_wp_error( $url ) ) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the size from a URL for media library item types
|
||
|
|
*
|
||
|
|
* @handles as3cf_get_size_string_from_url_for_item_source
|
||
|
|
*
|
||
|
|
* @param string $size
|
||
|
|
* @param string $url
|
||
|
|
* @param array $item_source
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function get_size_string_from_url_for_item_source( $size, $url, $item_source ) {
|
||
|
|
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
||
|
|
return $size;
|
||
|
|
}
|
||
|
|
|
||
|
|
$meta = get_post_meta( $item_source['id'], '_wp_attachment_metadata', true );
|
||
|
|
|
||
|
|
if ( empty( $meta['sizes'] ) ) {
|
||
|
|
// No alternative sizes available, return
|
||
|
|
return $size;
|
||
|
|
}
|
||
|
|
|
||
|
|
$basename = AS3CF_Utils::encode_filename_in_path( wp_basename( $this->as3cf->maybe_remove_query_string( $url ) ) );
|
||
|
|
|
||
|
|
foreach ( $meta['sizes'] as $size_name => $file ) {
|
||
|
|
if ( $basename === AS3CF_Utils::encode_filename_in_path( $file['file'] ) ) {
|
||
|
|
return $size_name;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $size;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get attachment id from remote URL.
|
||
|
|
*
|
||
|
|
* @param string $url
|
||
|
|
*
|
||
|
|
* @return bool|int
|
||
|
|
*/
|
||
|
|
public function get_attachment_id_from_provider_url( $url ) {
|
||
|
|
$item_source = $this->as3cf->filter_provider->get_item_source_from_url( $url );
|
||
|
|
|
||
|
|
if ( ! Item::is_empty_item_source( $item_source ) && Media_Library_Item::source_type() === $item_source['source_type'] ) {
|
||
|
|
return $item_source['id'];
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get attachment id from local URL.
|
||
|
|
*
|
||
|
|
* @param string $url
|
||
|
|
*
|
||
|
|
* @return bool|int
|
||
|
|
*/
|
||
|
|
public function get_attachment_id_from_local_url( $url ) {
|
||
|
|
$item_source = $this->as3cf->filter_local->get_item_source_from_url( $url );
|
||
|
|
|
||
|
|
if ( ! Item::is_empty_item_source( $item_source ) && Media_Library_Item::source_type() === $item_source['source_type'] ) {
|
||
|
|
return $item_source['id'];
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get post time
|
||
|
|
*
|
||
|
|
* @param int $post_id
|
||
|
|
*
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
private function get_post_time( $post_id ) {
|
||
|
|
$time = current_time( 'mysql' );
|
||
|
|
|
||
|
|
if ( ! $post = get_post( $post_id ) ) {
|
||
|
|
return $time;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( substr( $post->post_date, 0, 4 ) > 0 ) {
|
||
|
|
$time = $post->post_date;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $time;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Maybe convert size to string
|
||
|
|
*
|
||
|
|
* @param int $attachment_id
|
||
|
|
* @param mixed $size
|
||
|
|
*
|
||
|
|
* @return null|string
|
||
|
|
*/
|
||
|
|
private function maybe_convert_size_to_string( $attachment_id, $size ) {
|
||
|
|
if ( is_array( $size ) ) {
|
||
|
|
return $this->convert_dimensions_to_size_name( $attachment_id, $size );
|
||
|
|
}
|
||
|
|
|
||
|
|
return $size;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Convert dimensions to size.
|
||
|
|
*
|
||
|
|
* @param int $attachment_id
|
||
|
|
* @param array $dimensions
|
||
|
|
*
|
||
|
|
* @return null|string
|
||
|
|
*/
|
||
|
|
private function convert_dimensions_to_size_name( int $attachment_id, array $dimensions ) {
|
||
|
|
$w = ( isset( $dimensions[0] ) && (int) $dimensions[0] > 0 ) ? (int) $dimensions[0] : 1;
|
||
|
|
$h = ( isset( $dimensions[1] ) && (int) $dimensions[1] > 0 ) ? (int) $dimensions[1] : 1;
|
||
|
|
$original_aspect_ratio = $w / $h;
|
||
|
|
$meta = wp_get_attachment_metadata( $attachment_id );
|
||
|
|
|
||
|
|
if ( ! isset( $meta['sizes'] ) || empty( $meta['sizes'] ) ) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
$sizes = $meta['sizes'];
|
||
|
|
uasort( $sizes, function ( $a, $b ) {
|
||
|
|
// Order by image area.
|
||
|
|
return ( (int) $a['width'] * (int) $a['height'] ) - ( (int) $b['width'] * (int) $b['height'] );
|
||
|
|
} );
|
||
|
|
|
||
|
|
$nearest_matches = array();
|
||
|
|
|
||
|
|
foreach ( $sizes as $size => $value ) {
|
||
|
|
if ( $w > (int) $value['width'] || $h > (int) $value['height'] ) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$aspect_ratio = 0;
|
||
|
|
if ( (int) $value['height'] > 0 ) {
|
||
|
|
$aspect_ratio = (int) $value['width'] / (int) $value['height'];
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( $aspect_ratio === $original_aspect_ratio ) {
|
||
|
|
return $size;
|
||
|
|
}
|
||
|
|
|
||
|
|
$nearest_matches[] = $size;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Return nearest match.
|
||
|
|
if ( ! empty( $nearest_matches ) ) {
|
||
|
|
return $nearest_matches[0];
|
||
|
|
}
|
||
|
|
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Has the given attachment been uploaded by this instance?
|
||
|
|
*
|
||
|
|
* @param int $source_id
|
||
|
|
*
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public function item_just_uploaded( $source_id ) {
|
||
|
|
if ( is_int( $source_id ) && isset( $this->items_in_progress[ $source_id ] ) ) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Call legacy attachment specific version of the as3cf_get_item_secure_url filter.
|
||
|
|
*
|
||
|
|
* @param string $url The URL
|
||
|
|
* @param Item $as3cf_item The Item object
|
||
|
|
* @param array $item_source The item source descriptor array
|
||
|
|
* @param int $timestamp Expiry timestamp
|
||
|
|
* @param array $headers Optional extra http headers
|
||
|
|
*
|
||
|
|
* @handles as3cf_get_item_secure_url
|
||
|
|
*
|
||
|
|
* @return string|mixed
|
||
|
|
*/
|
||
|
|
public function get_item_secure_url( $url, $as3cf_item, $item_source, $timestamp, $headers ) {
|
||
|
|
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Filters the secure url for an attachment
|
||
|
|
*
|
||
|
|
* @param string $url The URL
|
||
|
|
* @param Item $as3cf_item The Item object
|
||
|
|
* @param int $id The attachment id
|
||
|
|
* @param int $timestamp Expiry timestamp
|
||
|
|
* @param array $headers Optional extra http headers
|
||
|
|
*
|
||
|
|
* @deprecated 2.6.0 Please use filter "as3cf_get_item_secure_url" instead.
|
||
|
|
*/
|
||
|
|
return apply_filters( 'as3cf_get_attachment_secure_url', $url, $as3cf_item, $item_source['id'], $timestamp, $headers );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Call legacy attachment specific version of the as3cf_get_item_url filter.
|
||
|
|
*
|
||
|
|
* @param string $url The URL
|
||
|
|
* @param Item $as3cf_item The Item object
|
||
|
|
* @param array $item_source The item source descriptor array
|
||
|
|
* @param int $timestamp Expiry timestamp
|
||
|
|
* @param array $headers Optional extra http headers
|
||
|
|
*
|
||
|
|
* @handles as3cf_get_item_url
|
||
|
|
*
|
||
|
|
* @return string|mixed
|
||
|
|
*/
|
||
|
|
public function get_item_url( $url, $as3cf_item, $item_source, $timestamp, $headers ) {
|
||
|
|
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
||
|
|
return $url;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Filters the url for an attachment
|
||
|
|
*
|
||
|
|
* @param string $url The URL
|
||
|
|
* @param Item $as3cf_item The Item object
|
||
|
|
* @param int $id The attachment id
|
||
|
|
* @param int $timestamp Expiry timestamp
|
||
|
|
* @param array $headers Optional extra http headers
|
||
|
|
*
|
||
|
|
* @deprecated 2.6.0 Please use filter "as3cf_get_item_url" instead.
|
||
|
|
*/
|
||
|
|
return apply_filters( 'as3cf_get_attachment_url', $url, $as3cf_item, $item_source['id'], $timestamp, $headers );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Call legacy attachment specific version of the as3cf_remove_source_files_from_provider filter.
|
||
|
|
*
|
||
|
|
* @param array $paths Array of local paths to be removed from provider
|
||
|
|
* @param Item $as3cf_item The Item object
|
||
|
|
* @param array $item_source The item source descriptor array
|
||
|
|
*
|
||
|
|
* @handles as3cf_remove_source_files_from_provider
|
||
|
|
*
|
||
|
|
* @return array|mixed
|
||
|
|
*/
|
||
|
|
public function filter_remove_source_files_from_provider( $paths, Item $as3cf_item, $item_source ) {
|
||
|
|
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
||
|
|
return $paths;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Filters which provider files to remove
|
||
|
|
*
|
||
|
|
* @param array $paths Array of local paths to be removed from provider
|
||
|
|
* @param int $id Item attachment id
|
||
|
|
* @param Item $as3cf_item The Item
|
||
|
|
* @param bool $include_backups Also include backup files?
|
||
|
|
*
|
||
|
|
* @deprecated 2.6.0 Please use filter "as3cf_remove_source_files_from_provider" instead.
|
||
|
|
*/
|
||
|
|
return apply_filters( 'as3cf_remove_attachment_paths', $paths, $item_source['id'], $as3cf_item, true );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Calls legacy attachment specific version of as3cf_remove_local_files filter.
|
||
|
|
*
|
||
|
|
* @param array $files_to_remove Array of paths to be removed
|
||
|
|
* @param Item $as3cf_item The Item object
|
||
|
|
* @param array $item_source The item source descriptor array
|
||
|
|
*
|
||
|
|
* @handles as3cf_remove_local_files
|
||
|
|
*
|
||
|
|
* @return array|mixed
|
||
|
|
*/
|
||
|
|
public function filter_remove_local_files( $files_to_remove, $as3cf_item, $item_source ) {
|
||
|
|
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
||
|
|
return $files_to_remove;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Filters which local files should be removed.
|
||
|
|
*
|
||
|
|
* @param array $paths Paths that will be removed
|
||
|
|
* @param int $id Attachment id
|
||
|
|
* @param string $source_path Path to primary file
|
||
|
|
*
|
||
|
|
* @deprecated 2.6.0 Please use filter "as3cf_remove_local_files" instead.
|
||
|
|
*/
|
||
|
|
return apply_filters( 'as3cf_upload_attachment_local_files_to_remove', $files_to_remove, $item_source['id'], $as3cf_item->full_source_path( Item::primary_object_key() ) );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Handle post upload duties if uploaded item is a media-library item.
|
||
|
|
*
|
||
|
|
* @handles as3cf_post_upload_item
|
||
|
|
*
|
||
|
|
* @param Media_Library_Item $as3cf_item
|
||
|
|
*/
|
||
|
|
public function post_upload_item( $as3cf_item ) {
|
||
|
|
if ( Media_Library_Item::source_type() !== $as3cf_item->source_type() ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Make sure duplicates are marked as offloaded too.
|
||
|
|
$as3cf_item->offload_duplicate_items();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fires after an attachment has been uploaded to the provider.
|
||
|
|
*
|
||
|
|
* @param int $id Attachment id
|
||
|
|
* @param Item $as3cf_item The item that was just uploaded
|
||
|
|
*
|
||
|
|
* @deprecated 2.6.0 Please use action "as3cf_post_upload_item" instead.
|
||
|
|
*/
|
||
|
|
do_action( 'as3cf_post_upload_attachment', $as3cf_item->source_id(), $as3cf_item );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Call legacy media library specific filter for cancelling an upload.
|
||
|
|
*
|
||
|
|
* @param bool $cancel Should the action on the item be cancelled?
|
||
|
|
* @param Item $as3cf_item The item that the action is being handled for.
|
||
|
|
* @param array $options Handler dependent options that may have been set for the action.
|
||
|
|
*
|
||
|
|
* @handles as3cf_pre_handle_item_upload
|
||
|
|
*
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public function pre_handle_item_upload( $cancel, $as3cf_item, array $options ) {
|
||
|
|
if ( Media_Library_Item::source_type() !== $as3cf_item->source_type() ) {
|
||
|
|
return $cancel;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get unfiltered attachment metadata to pass into legacy filter.
|
||
|
|
$metadata = wp_get_attachment_metadata( $as3cf_item->source_id(), true );
|
||
|
|
if ( is_wp_error( $metadata ) ) {
|
||
|
|
return $metadata;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Allow provider upload to be cancelled for any reason.
|
||
|
|
*
|
||
|
|
* @param bool $cancel Should the upload for the attachment be cancelled?
|
||
|
|
* @param int $id Attachment id
|
||
|
|
* @param array $metadata Attachment metadata
|
||
|
|
*
|
||
|
|
* @deprecated 2.6.0 Please use filter "as3cf_pre_upload_item" instead.
|
||
|
|
*/
|
||
|
|
return apply_filters( 'as3cf_pre_upload_attachment', $cancel, $as3cf_item->source_id(), $metadata );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Call legacy filter for determining private status on an item's individual object_key.
|
||
|
|
*
|
||
|
|
* @param bool $is_private
|
||
|
|
* @param string $object_key
|
||
|
|
* @param Item $as3cf_item
|
||
|
|
*
|
||
|
|
* @handles as3cf_upload_object_key_as_private
|
||
|
|
*
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public function filter_upload_object_key_as_private( $is_private, $object_key, $as3cf_item ) {
|
||
|
|
if ( Media_Library_Item::source_type() !== $as3cf_item->source_type() ) {
|
||
|
|
return $is_private;
|
||
|
|
}
|
||
|
|
|
||
|
|
$metadata = wp_get_attachment_metadata( $as3cf_item->source_id(), true );
|
||
|
|
$default_acl = $this->as3cf->get_storage_provider()->get_default_acl();
|
||
|
|
$private_acl = $this->as3cf->get_storage_provider()->get_private_acl();
|
||
|
|
$acl = true === $is_private ? $private_acl : $default_acl;
|
||
|
|
|
||
|
|
if ( Item::primary_object_key() === $object_key ) {
|
||
|
|
$file_name = wp_basename( $as3cf_item->source_path() );
|
||
|
|
$file_type = wp_check_filetype_and_ext( $as3cf_item->source_path(), $file_name );
|
||
|
|
|
||
|
|
// Old naming convention, will be removed soon.
|
||
|
|
$acl = apply_filters( 'wps3_upload_acl', $acl, $file_type['type'], $metadata, $as3cf_item->source_id(), $this->as3cf );
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Determine canned ACL for an item's original (full size) file about to be uploaded to provider.
|
||
|
|
*
|
||
|
|
* @param string $acl The canned ACL for the provider.
|
||
|
|
* @param array $metadata The attachment's metadata.
|
||
|
|
* @param int $id The attachment's ID.
|
||
|
|
*
|
||
|
|
* @deprecated 2.6.0 Please use filter "as3cf_upload_object_key_as_private" instead.
|
||
|
|
*/
|
||
|
|
$acl = apply_filters( 'as3cf_upload_acl', $acl, $metadata, $as3cf_item->source_id() );
|
||
|
|
} else {
|
||
|
|
/**
|
||
|
|
* Determine ACL for an item's individual thumbnail size about to be uploaded to provider.
|
||
|
|
*
|
||
|
|
* @param string $acl The canned ACL for the provider.
|
||
|
|
* @param string $size Size name for file (thumbnail, medium, large).
|
||
|
|
* @param int $id The attachment's ID.
|
||
|
|
* @param array $data The attachment's metadata.
|
||
|
|
*
|
||
|
|
* @deprecated 2.6.0 Please use filter "as3cf_upload_object_key_as_private" instead.
|
||
|
|
*/
|
||
|
|
$acl = apply_filters( 'as3cf_upload_acl_sizes', $acl, $object_key, $as3cf_item->source_id(), $metadata );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( ! empty( $acl ) && $private_acl === $acl ) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $is_private;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Fire legacy action just before a Media Library Item is offloaded.
|
||
|
|
*
|
||
|
|
* @handles as3cf_pre_upload_object
|
||
|
|
*
|
||
|
|
* @param Item $as3cf_item
|
||
|
|
* @param array $args
|
||
|
|
*/
|
||
|
|
public function action_pre_upload_object( $as3cf_item, $args ) {
|
||
|
|
if ( Media_Library_Item::source_type() !== $as3cf_item->source_type() ) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Actions fires when an Item's original file might be offloaded.
|
||
|
|
*
|
||
|
|
* This action gives notice that an Item is being processed for upload to a bucket,
|
||
|
|
* and the given arguments represent the original file's potential offload location.
|
||
|
|
* However, if the current process is for picking up extra files associated with the item,
|
||
|
|
* the indicated original file may not actually be offloaded if it does not exist
|
||
|
|
* on the server but has already been offloaded.
|
||
|
|
*
|
||
|
|
* @param int $id The attachment id.
|
||
|
|
* @param Media_Library_Item $as3cf_item The Item whose files are being offloaded.
|
||
|
|
* @param string $path The path to the item.
|
||
|
|
* @param array $args The arguments that could be used to offload the original file.
|
||
|
|
*
|
||
|
|
* @deprecated 2.6.0 Please use action "as3cf_pre_upload_object" instead.
|
||
|
|
*/
|
||
|
|
do_action( 'as3cf_upload_attachment_pre_remove', $as3cf_item->source_id(), $as3cf_item, $as3cf_item->normalized_path_dir(), $args );
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Takes notice that an attachment is about to be deleted and prepares for it.
|
||
|
|
*
|
||
|
|
* @handles pre_delete_attachment
|
||
|
|
*
|
||
|
|
* @param bool|null $delete Whether to go forward with deletion.
|
||
|
|
*
|
||
|
|
* @return bool|null
|
||
|
|
*/
|
||
|
|
public function pre_delete_attachment( $delete ) {
|
||
|
|
if ( is_null( $delete ) ) {
|
||
|
|
$this->deleting_attachment = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $delete;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Takes notice that an attachment has been deleted and undoes previous preparations for the event.
|
||
|
|
*
|
||
|
|
* @handles delete_post
|
||
|
|
*
|
||
|
|
* Note: delete_post is used as there is a potential that deleted_post is not reached.
|
||
|
|
*/
|
||
|
|
public function delete_post() {
|
||
|
|
$this->deleting_attachment = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Has WP Core fixed wp_check_filetype when URL has params yet?
|
||
|
|
*
|
||
|
|
* @see https://core.trac.wordpress.org/ticket/30377
|
||
|
|
* @see https://github.com/aaemnnosttv/fix-wp-media-shortcodes-with-params/blob/master/fix-wp-media-shortcodes-with-params.php
|
||
|
|
*
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
public static function wp_check_filetype_broken() {
|
||
|
|
$normal_file = wp_check_filetype( 'file.mp4', array( 'mp4' => 'video/mp4' ) );
|
||
|
|
$querys_file = wp_check_filetype( 'file.mp4?param=1', array( 'mp4' => 'video/mp4' ) );
|
||
|
|
|
||
|
|
return $normal_file !== $querys_file;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Filters shortcode attributes to temporarily add file extension to end of URL params.
|
||
|
|
*
|
||
|
|
* The temporary extension is removed once wp_check_filetype has been used.
|
||
|
|
*
|
||
|
|
* The function compensates for when query args or fragments are included in the URL,
|
||
|
|
* which makes wp_check_filetype fail to see the extension of the file.
|
||
|
|
*
|
||
|
|
* @see https://core.trac.wordpress.org/ticket/30377
|
||
|
|
* @see https://github.com/aaemnnosttv/fix-wp-media-shortcodes-with-params/blob/master/fix-wp-media-shortcodes-with-params.php
|
||
|
|
*
|
||
|
|
* @param array $out The output array of shortcode attributes.
|
||
|
|
* @param array $pairs The supported attributes and their defaults.
|
||
|
|
* @param array $atts The user defined shortcode attributes.
|
||
|
|
* @param string $shortcode The shortcode name.
|
||
|
|
*
|
||
|
|
* @return array
|
||
|
|
*/
|
||
|
|
public function filter_shortcode_atts( $out, $pairs, $atts, $shortcode ) {
|
||
|
|
$get_media_extensions = "wp_get_{$shortcode}_extensions";
|
||
|
|
|
||
|
|
if ( ! function_exists( $get_media_extensions ) ) {
|
||
|
|
return $out;
|
||
|
|
}
|
||
|
|
|
||
|
|
$default_types = $get_media_extensions();
|
||
|
|
|
||
|
|
if ( empty( $default_types ) || ! is_array( $default_types ) ) {
|
||
|
|
return $out;
|
||
|
|
}
|
||
|
|
|
||
|
|
// URLs can be in src or type specific fallback attributes.
|
||
|
|
array_unshift( $default_types, 'src' );
|
||
|
|
|
||
|
|
$fixes = array();
|
||
|
|
|
||
|
|
foreach ( $default_types as $type ) {
|
||
|
|
if ( empty( $out[ $type ] ) ) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( false !== strpos( $out[ $type ], '&as3cf-fix-wp-check-file-type-ext=.' ) ) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( AS3CF_Utils::is_url( $out[ $type ] ) ) {
|
||
|
|
$url = $out[ $type ];
|
||
|
|
$parts = wp_parse_url( $url );
|
||
|
|
|
||
|
|
if (
|
||
|
|
empty( $parts['path'] ) ||
|
||
|
|
( empty( $parts['query'] ) && empty( $parts['fragment'] ) )
|
||
|
|
) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$ext = pathinfo( $parts['path'], PATHINFO_EXTENSION );
|
||
|
|
|
||
|
|
if ( empty( $ext ) ) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$scheme = empty( $parts['scheme'] ) ? '' : $parts['scheme'] . '://';
|
||
|
|
$user = empty( $parts['user'] ) ? '' : $parts['user'];
|
||
|
|
$pass = ! empty( $user ) && ! empty( $parts['pass'] ) ? ':' . $parts['pass'] : '';
|
||
|
|
$auth = ! empty( $user ) ? $user . $pass . '@' : '';
|
||
|
|
$host = empty( $parts['host'] ) ? '' : $parts['host'];
|
||
|
|
$port = ! empty( $host ) && ! empty( $parts['port'] ) ? ':' . $parts['port'] : '';
|
||
|
|
$path = $parts['path'];
|
||
|
|
$query = empty( $parts['query'] ) ? '?as3cf-fix-wp-check-file-type=true' : '?' . $parts['query'];
|
||
|
|
|
||
|
|
if ( ! empty( $parts['fragment'] ) ) {
|
||
|
|
$query .= '&as3cf-fix-wp-check-file-type-fragment=' . $parts['fragment'];
|
||
|
|
}
|
||
|
|
|
||
|
|
$query .= '&as3cf-fix-wp-check-file-type-ext=.' . $ext;
|
||
|
|
|
||
|
|
$out[ $type ] = $scheme . $auth . $host . $port . $path . $query;
|
||
|
|
$fixes[] = $ext;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( $fixes ) {
|
||
|
|
add_filter( "wp_{$shortcode}_shortcode", function ( $html ) use ( $fixes ) {
|
||
|
|
$html = str_replace( '?as3cf-fix-wp-check-file-type=true', '', $html );
|
||
|
|
|
||
|
|
foreach ( $fixes as $ext ) {
|
||
|
|
$html = str_replace( '&as3cf-fix-wp-check-file-type-ext=.' . $ext, '', $html );
|
||
|
|
}
|
||
|
|
|
||
|
|
return str_replace( '&as3cf-fix-wp-check-file-type-fragment=', '#', $html );
|
||
|
|
} );
|
||
|
|
}
|
||
|
|
|
||
|
|
return $out;
|
||
|
|
}
|
||
|
|
}
|