Version Description
= 2.6 = This is a major upgrade that updates the format of information stored about offloaded Media Library items. Once upgraded you will not be able to downgrade without restoring data from a backup. This version requires PHP 5.6+
= 2.3 = This is a major upgrade that switches to using a custom table for storing data about offloaded Media Library items. Once upgraded you will not be able to downgrade without restoring data from a backup.
= 2.0 = This is a major upgrade that introduces support for DigitalOcean Spaces, renames the plugin to WP Offload Media Lite, and coincidentally upgrades some of its database settings. You may not be able to downgrade to WP Offload S3 Lite 1.x after upgrading to WP Offload Media Lite 2.0+.
= 1.1 = This is a major change, which ensures S3 URLs are no longer saved in post content. Instead, local URLs are filtered on page generation and replaced with the S3 version. If you depend on the S3 URLs being stored in post content you will need to make modifications to support this version.
= 0.6 = This version requires PHP 5.3.3+ and the Amazon Web Services plugin
Release Info
Developer | deliciousbrains |
Plugin | WP Offload S3 Lite |
Version | 2.6.0 |
Comparing to | |
See all releases |
Code changes from version 2.5.5 to 2.6.0
- README.md +18 -4
- classes/amazon-s3-and-cloudfront.php +367 -1900
- classes/as3cf-filter.php +106 -145
- classes/as3cf-plugin-compatibility.php +119 -149
- classes/as3cf-utils.php +48 -110
- classes/filters/as3cf-local-to-s3.php +155 -29
- classes/filters/as3cf-s3-to-local.php +73 -53
- classes/integrations/core.php +43 -0
- classes/integrations/integration-manager.php +81 -0
- classes/integrations/integration.php +37 -0
- classes/integrations/media-library.php +1551 -0
- classes/items/download-handler.php +169 -0
- classes/items/item-handler.php +247 -0
- classes/items/item.php +965 -89
- classes/items/manifest.php +10 -0
- classes/items/media-library-item.php +384 -275
- classes/items/remove-local-handler.php +209 -0
- classes/items/remove-provider-handler.php +141 -0
- classes/items/upload-handler.php +449 -0
- classes/providers/storage/storage-provider.php +4 -3
- classes/upgrades/upgrade-edd-replace-urls.php +8 -1
- classes/upgrades/upgrade-file-sizes.php +12 -11
- classes/upgrades/upgrade-filter-post.php +18 -15
- classes/upgrades/upgrade-item-extra-data.php +152 -0
- classes/upgrades/upgrade-items-table.php +9 -10
- classes/upgrades/upgrade-meta-wp-error.php +7 -7
- classes/upgrades/upgrade-region-meta.php +8 -8
- classes/upgrades/upgrade-tools-errors.php +105 -0
- classes/upgrades/upgrade.php +10 -9
- include/functions.php +9 -7
- languages/amazon-s3-and-cloudfront-en.pot +233 -170
- readme.txt +17 -3
- view/attachment-metabox.php +23 -16
- wordpress-s3.php +3 -3
@@ -2,9 +2,9 @@
|
|
2 |
**Contributors:** bradt, deliciousbrains, ianmjones
|
3 |
**Tags:** uploads, amazon, s3, amazon s3, digitalocean, digitalocean spaces, google cloud storage, gcs, mirror, admin, media, cdn, cloudfront
|
4 |
**Requires at least:** 4.9
|
5 |
-
**Tested up to:** 5.
|
6 |
-
**Requires PHP:** 5.
|
7 |
-
**Stable tag:** 2.
|
8 |
**License:** GPLv3
|
9 |
|
10 |
Copies files to Amazon S3, DigitalOcean Spaces or Google Cloud Storage as they are uploaded to the Media Library. Optionally configure Amazon CloudFront or another CDN for faster delivery.
|
@@ -13,7 +13,7 @@ Copies files to Amazon S3, DigitalOcean Spaces or Google Cloud Storage as they a
|
|
13 |
|
14 |
FORMERLY WP OFFLOAD S3 LITE
|
15 |
|
16 |
-
https://www.youtube.com/watch?v=
|
17 |
|
18 |
This plugin automatically copies images, videos, documents, and any other media added through WordPress' media uploader to [Amazon S3](http://aws.amazon.com/s3/), [DigitalOcean Spaces](https://www.digitalocean.com/products/spaces/) or [Google Cloud Storage](https://cloud.google.com/storage/). It then automatically replaces the URL to each media file with their respective Amazon S3, DigitalOcean Spaces or Google Cloud Storage URL or, if you have configured [Amazon CloudFront](http://aws.amazon.com/cloudfront/) or another CDN with or without a custom domain, that URL instead. Image thumbnails are also copied to the bucket and delivered through the correct remote URL.
|
19 |
|
@@ -75,6 +75,10 @@ If you upgrade to the pro version of [WP Offload Media](https://deliciousbrains.
|
|
75 |
|
76 |
## Upgrade Notice ##
|
77 |
|
|
|
|
|
|
|
|
|
78 |
### 2.3 ###
|
79 |
This is a major upgrade that switches to using a custom table for storing data about offloaded Media Library items. Once upgraded you will not be able to downgrade without restoring data from a backup.
|
80 |
|
@@ -89,6 +93,16 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
|
|
89 |
|
90 |
## Changelog ##
|
91 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
### WP Offload Media Lite 2.5.5 - 2021-07-19 ###
|
93 |
* Bug fix: Signed GCS URLs broken when updating a post
|
94 |
* Bug fix: Incorrect mime type set on scaled image's bucket object when thumbnail format differs from original file's format
|
2 |
**Contributors:** bradt, deliciousbrains, ianmjones
|
3 |
**Tags:** uploads, amazon, s3, amazon s3, digitalocean, digitalocean spaces, google cloud storage, gcs, mirror, admin, media, cdn, cloudfront
|
4 |
**Requires at least:** 4.9
|
5 |
+
**Tested up to:** 5.9
|
6 |
+
**Requires PHP:** 5.6
|
7 |
+
**Stable tag:** 2.6.0
|
8 |
**License:** GPLv3
|
9 |
|
10 |
Copies files to Amazon S3, DigitalOcean Spaces or Google Cloud Storage as they are uploaded to the Media Library. Optionally configure Amazon CloudFront or another CDN for faster delivery.
|
13 |
|
14 |
FORMERLY WP OFFLOAD S3 LITE
|
15 |
|
16 |
+
https://www.youtube.com/watch?v=I-wTMXMeFu4
|
17 |
|
18 |
This plugin automatically copies images, videos, documents, and any other media added through WordPress' media uploader to [Amazon S3](http://aws.amazon.com/s3/), [DigitalOcean Spaces](https://www.digitalocean.com/products/spaces/) or [Google Cloud Storage](https://cloud.google.com/storage/). It then automatically replaces the URL to each media file with their respective Amazon S3, DigitalOcean Spaces or Google Cloud Storage URL or, if you have configured [Amazon CloudFront](http://aws.amazon.com/cloudfront/) or another CDN with or without a custom domain, that URL instead. Image thumbnails are also copied to the bucket and delivered through the correct remote URL.
|
19 |
|
75 |
|
76 |
## Upgrade Notice ##
|
77 |
|
78 |
+
### 2.6 ###
|
79 |
+
This is a major upgrade that updates the format of information stored about offloaded Media Library items. Once upgraded you will not be able to downgrade without restoring data from a backup.
|
80 |
+
This version requires PHP 5.6+
|
81 |
+
|
82 |
### 2.3 ###
|
83 |
This is a major upgrade that switches to using a custom table for storing data about offloaded Media Library items. Once upgraded you will not be able to downgrade without restoring data from a backup.
|
84 |
|
93 |
|
94 |
## Changelog ##
|
95 |
|
96 |
+
### WP Offload Media Lite 2.6 - 2022-03-09 ###
|
97 |
+
* [Release Summary Blog Post](https://deliciousbrains.com/wp-offload-media-2-6-released/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
|
98 |
+
* New: WP Offload Media is now compatible with WordPress 5.9 and Full Site Editing
|
99 |
+
* Improvement: Offloaded thumbnail sizes are now tracked for better handling of changes to registered sizes
|
100 |
+
* Improvement: Offloads and other storage provider actions are faster
|
101 |
+
* Bug fix: URL rewriting now works in the Full Site Editor
|
102 |
+
* Bug fix: Offloaded images are now shown when re-editing a Block Template or Template Part
|
103 |
+
* Bug fix: URL rewriting now works for Widgets migrated to a Widget Sidebar Block
|
104 |
+
* Bug fix: Objects are no longer left in the bucket when deleting a Media Library item with many changes to its thumbnail sizes
|
105 |
+
|
106 |
### WP Offload Media Lite 2.5.5 - 2021-07-19 ###
|
107 |
* Bug fix: Signed GCS URLs broken when updating a post
|
108 |
* Bug fix: Incorrect mime type set on scaled image's bucket object when thumbnail format differs from original file's format
|
@@ -1,7 +1,15 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
use DeliciousBrains\WP_Offload_Media\
|
|
|
|
|
|
|
4 |
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
|
|
|
|
|
|
|
|
|
|
5 |
use DeliciousBrains\WP_Offload_Media\Providers\Delivery\Another_CDN;
|
6 |
use DeliciousBrains\WP_Offload_Media\Providers\Delivery\AWS_CloudFront;
|
7 |
use DeliciousBrains\WP_Offload_Media\Providers\Delivery\Cloudflare;
|
@@ -23,9 +31,11 @@ use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Content_Replace_URLs;
|
|
23 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_EDD_Replace_URLs;
|
24 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_File_Sizes;
|
25 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Filter_Post_Excerpt;
|
|
|
26 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Items_Table;
|
27 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Meta_WP_Error;
|
28 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Region_Meta;
|
|
|
29 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_WPOS3_To_AS3CF;
|
30 |
|
31 |
class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
@@ -120,6 +130,11 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
120 |
*/
|
121 |
protected static $delivery_provider_classes = array();
|
122 |
|
|
|
|
|
|
|
|
|
|
|
123 |
/**
|
124 |
* @var AS3CF_Plugin_Compatibility
|
125 |
*/
|
@@ -137,7 +152,21 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
137 |
'WPOS3_SETTINGS',
|
138 |
);
|
139 |
|
140 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
|
142 |
/**
|
143 |
* @param string $plugin_file_path
|
@@ -145,7 +174,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
145 |
*
|
146 |
* @throws Exception
|
147 |
*/
|
148 |
-
function __construct( $plugin_file_path, $slug = null ) {
|
149 |
$this->plugin_slug = ( is_null( $slug ) ) ? 'amazon-s3-and-cloudfront' : $slug;
|
150 |
|
151 |
parent::__construct( $plugin_file_path );
|
@@ -162,7 +191,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
162 |
*
|
163 |
* @throws Exception
|
164 |
*/
|
165 |
-
function init( $plugin_file_path ) {
|
166 |
$this->plugin_title = __( 'Offload Media Lite', 'amazon-s3-and-cloudfront' );
|
167 |
$this->plugin_menu_title = __( 'Offload Media Lite', 'amazon-s3-and-cloudfront' );
|
168 |
|
@@ -186,8 +215,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
186 |
Storage::get_provider_key_name() => 'DeliciousBrains\WP_Offload_Media\Providers\Delivery\Storage',
|
187 |
) );
|
188 |
|
189 |
-
Media_Library_Item::init_cache();
|
190 |
-
|
191 |
$this->set_storage_provider();
|
192 |
$this->set_delivery_provider();
|
193 |
|
@@ -202,6 +229,8 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
202 |
new Upgrade_Filter_Post_Excerpt( $this );
|
203 |
new Upgrade_WPOS3_To_AS3CF( $this );
|
204 |
new Upgrade_Items_Table( $this );
|
|
|
|
|
205 |
|
206 |
// Plugin setup
|
207 |
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
|
@@ -210,38 +239,18 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
210 |
add_filter( 'plugin_action_links', array( $this, 'plugin_actions_settings_link' ), 10, 2 );
|
211 |
add_filter( 'network_admin_plugin_action_links', array( $this, 'plugin_actions_settings_link' ), 10, 2 );
|
212 |
add_filter( 'pre_get_space_used', array( $this, 'multisite_get_space_used' ) );
|
|
|
213 |
// display a notice when either lite or pro is automatically deactivated
|
214 |
add_action( 'pre_current_active_plugins', array( $this, 'plugin_deactivated_notice' ) );
|
215 |
add_action( 'as3cf_plugin_load', array( $this, 'remove_access_keys_if_constants_set' ) );
|
216 |
|
217 |
-
// Attachment screens/modals
|
218 |
-
add_action( 'load-upload.php', array( $this, 'load_media_assets' ), 11 );
|
219 |
-
add_action( 'admin_enqueue_scripts', array( $this, 'load_attachment_assets' ), 11 );
|
220 |
-
add_action( 'add_meta_boxes', array( $this, 'attachment_provider_meta_box' ) );
|
221 |
-
|
222 |
// UI AJAX
|
223 |
add_action( 'wp_ajax_as3cf-get-buckets', array( $this, 'ajax_get_buckets' ) );
|
224 |
add_action( 'wp_ajax_as3cf-get-url-preview', array( $this, 'ajax_get_url_preview' ) );
|
225 |
-
add_action( 'wp_ajax_as3cf_get_attachment_provider_details', array( $this, 'ajax_get_attachment_provider_details' ) );
|
226 |
add_action( 'wp_ajax_as3cf-get-diagnostic-info', array( $this, 'ajax_get_diagnostic_info' ) );
|
227 |
|
228 |
-
//
|
229 |
-
|
230 |
-
add_filter( 'wp_get_attachment_image_attributes', array( $this, 'wp_get_attachment_image_attributes' ), 99, 3 );
|
231 |
-
add_filter( 'get_image_tag', array( $this, 'maybe_encode_get_image_tag' ), 99, 6 );
|
232 |
-
add_filter( 'wp_get_attachment_image_src', array( $this, 'maybe_encode_wp_get_attachment_image_src' ), 99, 4 );
|
233 |
-
add_filter( 'wp_prepare_attachment_for_js', array( $this, 'maybe_encode_wp_prepare_attachment_for_js', ), 99, 3 );
|
234 |
-
add_filter( 'image_get_intermediate_size', array( $this, 'maybe_encode_image_get_intermediate_size' ), 99, 3 );
|
235 |
-
add_filter( 'get_attached_file', array( $this, 'get_attached_file' ), 10, 2 );
|
236 |
-
add_filter( 'wp_get_original_image_path', array( $this, 'get_attached_file' ), 10, 2 );
|
237 |
-
add_filter( 'wp_audio_shortcode', array( $this, 'wp_media_shortcode' ), 100, 5 );
|
238 |
-
add_filter( 'wp_video_shortcode', array( $this, 'wp_media_shortcode' ), 100, 5 );
|
239 |
-
|
240 |
-
// Communication with provider, plugin needs to be setup
|
241 |
-
add_filter( 'wp_unique_filename', array( $this, 'wp_unique_filename' ), 10, 3 );
|
242 |
-
add_filter( 'wp_update_attachment_metadata', array( $this, 'wp_update_attachment_metadata' ), 110, 2 );
|
243 |
-
add_filter( 'delete_attachment', array( $this, 'delete_attachment' ), 20 );
|
244 |
-
add_filter( 'update_attached_file', array( $this, 'update_attached_file' ), 100, 2 );
|
245 |
|
246 |
// Listen for settings changes
|
247 |
if ( false !== static::settings_constant() ) {
|
@@ -267,6 +276,31 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
267 |
$this->register_delivery_provider_assets();
|
268 |
}
|
269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
270 |
/**
|
271 |
* @return Storage_Provider
|
272 |
*/
|
@@ -419,6 +453,15 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
419 |
return empty( $class ) ? __( 'Unknown', 'amazon-s3-and-cloudfront' ) : $class::get_provider_service_name();
|
420 |
}
|
421 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
422 |
/**
|
423 |
* Get the plugin title to be used in page headings
|
424 |
*
|
@@ -1047,7 +1090,12 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1047 |
*
|
1048 |
* @return array
|
1049 |
*/
|
1050 |
-
function get_allowed_mime_types() {
|
|
|
|
|
|
|
|
|
|
|
1051 |
return apply_filters( 'as3cf_allowed_mime_types', get_allowed_mime_types() );
|
1052 |
}
|
1053 |
|
@@ -1125,18 +1173,18 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1125 |
*
|
1126 |
* @return string
|
1127 |
*/
|
1128 |
-
function get_url_preview( $escape = true, $suffix = 'photo.jpg' ) {
|
1129 |
$as3cf_item = new Media_Library_Item(
|
1130 |
$this->get_storage_provider()->get_provider_key_name(),
|
1131 |
$this->get_setting( 'region' ),
|
1132 |
$this->get_setting( 'bucket' ),
|
1133 |
-
AS3CF_Utils::trailingslash_prefix( $this->
|
1134 |
false,
|
1135 |
null,
|
1136 |
-
|
1137 |
);
|
1138 |
|
1139 |
-
$url = $
|
1140 |
|
1141 |
if ( is_wp_error( $url ) ) {
|
1142 |
return '';
|
@@ -1200,1538 +1248,213 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
1200 |
}
|
1201 |
|
1202 |
/**
|
1203 |
-
*
|
1204 |
-
*
|
1205 |
-
* @param string $region
|
1206 |
-
* @param string $bucket
|
1207 |
-
* @param array $objects
|
1208 |
-
* @param bool $log_error
|
1209 |
-
* @param bool $return_on_error
|
1210 |
-
* @param bool $force_new_provider_client if we are deleting in bulk, force new provider client
|
1211 |
-
* to cope with possible different regions
|
1212 |
*
|
1213 |
-
* @return
|
1214 |
*/
|
1215 |
-
function
|
1216 |
-
|
|
|
|
|
|
|
|
|
1217 |
|
1218 |
-
|
1219 |
-
|
1220 |
-
$this->get_provider_client( $region, $force_new_provider_client )->delete_objects( array(
|
1221 |
-
'Bucket' => $bucket,
|
1222 |
-
'Objects' => $chunk,
|
1223 |
-
) );
|
1224 |
-
}
|
1225 |
-
} catch ( Exception $e ) {
|
1226 |
-
if ( $log_error ) {
|
1227 |
-
AS3CF_Error::log( 'Error removing files from bucket: ' . $e->getMessage() );
|
1228 |
-
}
|
1229 |
|
1230 |
-
|
1231 |
-
|
1232 |
|
1233 |
-
return
|
1234 |
}
|
1235 |
|
1236 |
/**
|
1237 |
-
*
|
1238 |
*
|
1239 |
-
* @param
|
1240 |
-
* @param
|
1241 |
-
*
|
1242 |
-
* @
|
1243 |
-
* @param bool $return_on_error
|
1244 |
-
* @param bool $force_new_provider_client if we are deleting in bulk, force new provider client
|
1245 |
-
* to cope with possible different regions
|
1246 |
*/
|
1247 |
-
function
|
1248 |
-
|
1249 |
-
|
1250 |
-
$paths = AS3CF_Utils::get_attachment_file_paths( $post_id, false, false, $include_backups );
|
1251 |
-
$paths = apply_filters( 'as3cf_remove_attachment_paths', $paths, $post_id, $as3cf_item, $include_backups );
|
1252 |
-
|
1253 |
-
// If another item in current site shares full size *local* paths, only remove remote files not referenced by duplicates.
|
1254 |
-
// We reference local paths as they should be reflected one way or another remotely, including backups.
|
1255 |
-
$fullsize_paths = AS3CF_Utils::fullsize_paths( $paths );
|
1256 |
-
$as3cf_items_with_paths = Media_Library_Item::get_by_source_path( $fullsize_paths, array( $post_id ), false );
|
1257 |
-
|
1258 |
-
$duplicate_paths = array();
|
1259 |
-
|
1260 |
-
foreach ( $as3cf_items_with_paths as $as3cf_item_with_path ) {
|
1261 |
-
/* @var Media_Library_Item $as3cf_item_with_path */
|
1262 |
-
$duplicate_paths += array_values( AS3CF_Utils::get_attachment_file_paths( $as3cf_item_with_path->source_id(), false, false, $include_backups ) );
|
1263 |
-
}
|
1264 |
-
|
1265 |
-
if ( ! empty( $duplicate_paths ) ) {
|
1266 |
-
$paths = array_diff( $paths, $duplicate_paths );
|
1267 |
-
}
|
1268 |
-
|
1269 |
-
// Nothing to do, shortcut out.
|
1270 |
-
if ( empty( $paths ) ) {
|
1271 |
-
return;
|
1272 |
}
|
1273 |
|
1274 |
-
$
|
1275 |
-
|
1276 |
-
|
1277 |
-
foreach ( $paths_to_remove as $size => $path ) {
|
1278 |
-
$objects_to_remove[] = array(
|
1279 |
-
'Key' => $as3cf_item->key( wp_basename( $path ) ),
|
1280 |
-
);
|
1281 |
}
|
1282 |
|
1283 |
-
|
1284 |
-
$this->delete_objects( $as3cf_item->region(), $as3cf_item->bucket(), $objects_to_remove, $log_error, $return_on_error, $force_new_provider_client );
|
1285 |
}
|
1286 |
|
1287 |
/**
|
1288 |
-
*
|
|
|
|
|
|
|
1289 |
*
|
1290 |
-
* @
|
1291 |
-
* @param bool $force_new_provider_client if we are deleting in bulk, force new provider client
|
1292 |
-
* to cope with possible different regions
|
1293 |
*/
|
1294 |
-
function
|
1295 |
-
|
1296 |
-
return;
|
1297 |
-
}
|
1298 |
|
1299 |
-
$
|
|
|
1300 |
|
1301 |
-
if (
|
1302 |
-
|
1303 |
}
|
|
|
1304 |
|
1305 |
-
|
1306 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1307 |
}
|
1308 |
|
1309 |
-
|
|
|
|
|
|
|
1310 |
|
1311 |
-
|
1312 |
}
|
1313 |
|
1314 |
/**
|
1315 |
-
*
|
1316 |
-
* the 'wp_update_attachment_metadata' filter
|
1317 |
*
|
1318 |
-
* @param
|
1319 |
-
* @param
|
1320 |
*
|
1321 |
-
* @return
|
1322 |
* @throws Exception
|
1323 |
*/
|
1324 |
-
function
|
1325 |
-
|
1326 |
-
|
1327 |
-
}
|
1328 |
-
|
1329 |
-
// Protect against updates of partially formed metadata since WordPress 5.3.
|
1330 |
-
// Checks whether new upload currently has no subsizes recorded but is expected to have subsizes during upload,
|
1331 |
-
// and if so, are any of its currently missing sizes part of the set.
|
1332 |
-
if ( ! empty( $data ) && function_exists( 'wp_get_registered_image_subsizes' ) && function_exists( 'wp_get_missing_image_subsizes' ) ) {
|
1333 |
-
|
1334 |
-
// Plugin compat may require that we wait for wp_generate_attachment_metadata
|
1335 |
-
// to be run before proceeding. I.e Regenrerate Thumbnails requires this
|
1336 |
-
if ( apply_filters( 'as3cf_wait_for_generate_attachment_metadata', false ) ) {
|
1337 |
-
return $data;
|
1338 |
-
}
|
1339 |
-
|
1340 |
-
if ( empty( $data['sizes'] ) && wp_attachment_is_image( $post_id ) ) {
|
1341 |
-
|
1342 |
-
// There is no unified way of checking whether subsizes are expected, so we have to duplicate WordPress code here.
|
1343 |
-
$new_sizes = wp_get_registered_image_subsizes();
|
1344 |
-
$new_sizes = apply_filters( 'intermediate_image_sizes_advanced', $new_sizes, $data, $post_id );
|
1345 |
-
$missing_sizes = wp_get_missing_image_subsizes( $post_id );
|
1346 |
-
|
1347 |
-
if ( ! empty( $new_sizes ) && ! empty( $missing_sizes ) && array_intersect_key( $missing_sizes, $new_sizes ) ) {
|
1348 |
-
return $data;
|
1349 |
-
}
|
1350 |
-
}
|
1351 |
-
}
|
1352 |
-
|
1353 |
-
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
1354 |
-
|
1355 |
-
if ( ! $as3cf_item && ! $this->get_setting( 'copy-to-s3' ) ) {
|
1356 |
-
// abort if not already uploaded to provider and the copy setting is off
|
1357 |
-
return $data;
|
1358 |
-
}
|
1359 |
-
|
1360 |
-
if ( empty( $as3cf_item ) ) {
|
1361 |
-
$as3cf_item = null;
|
1362 |
-
}
|
1363 |
|
1364 |
-
|
1365 |
-
|
1366 |
-
if ( false !== $pre ) {
|
1367 |
-
return $data;
|
1368 |
}
|
1369 |
|
1370 |
-
|
1371 |
-
$
|
1372 |
-
|
1373 |
-
if ( is_wp_error( $attachment_metadata ) || empty( $attachment_metadata ) || ! is_array( $attachment_metadata ) ) {
|
1374 |
-
return $data;
|
1375 |
-
}
|
1376 |
|
1377 |
-
return $
|
1378 |
}
|
1379 |
|
1380 |
/**
|
1381 |
-
*
|
1382 |
*
|
1383 |
-
* @param
|
1384 |
-
* @param
|
1385 |
-
* @param string
|
1386 |
-
* @param bool $force_new_provider_client if we are uploading in bulk, force new provider client
|
1387 |
-
* to cope with possible different regions
|
1388 |
-
* @param bool $remove_local_files
|
1389 |
*
|
1390 |
-
* @return
|
1391 |
-
* @throws Exception
|
1392 |
*/
|
1393 |
-
|
1394 |
-
|
1395 |
-
|
1396 |
-
|
1397 |
-
$return_metadata = null;
|
1398 |
-
if ( is_null( $data ) ) {
|
1399 |
-
$data = wp_get_attachment_metadata( $post_id, true );
|
1400 |
-
} else {
|
1401 |
-
// As we have passed in the meta, return it later
|
1402 |
-
$return_metadata = $data;
|
1403 |
-
}
|
1404 |
-
|
1405 |
-
if ( is_wp_error( $data ) ) {
|
1406 |
-
return $data;
|
1407 |
-
}
|
1408 |
-
|
1409 |
-
// Allow provider upload to be hijacked / cancelled for any reason
|
1410 |
-
try {
|
1411 |
-
$pre = apply_filters( 'as3cf_pre_upload_attachment', false, $post_id, $data );
|
1412 |
-
} catch ( Exception $e ) {
|
1413 |
-
return $this->return_upload_error( $e->getMessage() );
|
1414 |
-
}
|
1415 |
|
1416 |
-
|
1417 |
-
|
|
|
1418 |
}
|
1419 |
|
1420 |
-
|
1421 |
-
|
1422 |
-
$error_msg = sprintf( __( 'Media Library item ID %d. Provided path is not a string', 'amazon-s3-and-cloudfront' ), $post_id );
|
1423 |
|
1424 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1425 |
}
|
1426 |
|
1427 |
-
|
1428 |
-
|
1429 |
-
|
1430 |
-
$error_msg = sprintf( __( 'Media Library item with ID %d has damaged meta data', 'amazon-s3-and-cloudfront' ), $post_id );
|
1431 |
-
|
1432 |
-
return $this->return_upload_error( $error_msg );
|
1433 |
}
|
1434 |
|
1435 |
-
if (
|
1436 |
-
|
|
|
1437 |
}
|
1438 |
|
1439 |
-
//
|
1440 |
-
|
1441 |
-
|
1442 |
|
1443 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1444 |
}
|
1445 |
|
1446 |
-
$
|
1447 |
-
|
1448 |
-
|
1449 |
-
// If item not already offloaded, is it a duplicate?
|
1450 |
-
$duplicate = false;
|
1451 |
-
if ( empty( $old_item ) ) {
|
1452 |
-
$old_items = Media_Library_Item::get_by_source_path( $file_path, $post_id, true, true );
|
1453 |
-
|
1454 |
-
if ( ! empty( $old_items[0] ) ) {
|
1455 |
-
$duplicate = true;
|
1456 |
-
|
1457 |
-
/** @var Media_Library_Item $duplicate_item */
|
1458 |
-
$duplicate_item = $old_items[0];
|
1459 |
-
|
1460 |
-
$old_item = new Media_Library_Item(
|
1461 |
-
$duplicate_item->provider(),
|
1462 |
-
$duplicate_item->region(),
|
1463 |
-
$duplicate_item->bucket(),
|
1464 |
-
$duplicate_item->path(),
|
1465 |
-
$duplicate_item->is_private(),
|
1466 |
-
$post_id,
|
1467 |
-
$duplicate_item->source_path(),
|
1468 |
-
wp_basename( $duplicate_item->original_source_path() ),
|
1469 |
-
$duplicate_item->extra_info()
|
1470 |
-
);
|
1471 |
-
|
1472 |
-
$old_item->save();
|
1473 |
-
|
1474 |
-
// If original offloaded in same process, skip offloading anything it's already processed.
|
1475 |
-
// Otherwise, do not need to offload full file if duplicate and file missing.
|
1476 |
-
if ( ! empty( $offloaded_path_filesizes[ $duplicate_item->id() ] ) ) {
|
1477 |
-
$offloaded_path_filesizes[ $old_item->id() ] = $offloaded_path_filesizes[ $duplicate_item->id() ];
|
1478 |
-
$offloaded_size_paths[ $old_item->id() ] = $offloaded_size_paths[ $duplicate_item->id() ];
|
1479 |
-
} elseif ( ! file_exists( $file_path ) ) {
|
1480 |
-
$offload_full = false;
|
1481 |
-
}
|
1482 |
|
1483 |
-
|
1484 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1485 |
}
|
1486 |
|
1487 |
-
|
1488 |
-
|
1489 |
-
if ( $old_item && ! empty( $offloaded_path_filesizes[ $old_item->id() ][ $file_path ] ) ) {
|
1490 |
-
$offload_full = false;
|
1491 |
-
} elseif ( ! file_exists( $file_path ) ) {
|
1492 |
-
$error_msg = sprintf( __( 'File %s does not exist', 'amazon-s3-and-cloudfront' ), $file_path );
|
1493 |
-
|
1494 |
-
return $this->return_upload_error( $error_msg, $return_metadata );
|
1495 |
-
}
|
1496 |
}
|
1497 |
|
1498 |
-
|
1499 |
-
|
1500 |
-
|
1501 |
-
// Are there any files not already offloaded if full already offloaded in this request?
|
1502 |
-
if ( false === $offload_full ) {
|
1503 |
-
if ( empty( $file_paths ) ) {
|
1504 |
-
// Item does not have any additional files, we're done.
|
1505 |
-
return $return_metadata;
|
1506 |
-
}
|
1507 |
-
|
1508 |
-
if ( ! empty( $offloaded_size_paths[ $old_item->id() ] ) && empty( array_diff_key( $file_paths, $offloaded_size_paths[ $old_item->id() ] ) ) ) {
|
1509 |
-
// Item's additional files all offloaded, we're done.
|
1510 |
-
return $return_metadata;
|
1511 |
-
}
|
1512 |
}
|
1513 |
|
1514 |
-
|
1515 |
-
|
1516 |
-
$type = get_post_mime_type( $post_id );
|
1517 |
-
$allowed_types = $this->get_allowed_mime_types();
|
1518 |
-
|
1519 |
-
// Check mime type of file is in allowed provider mime types.
|
1520 |
-
// Note: This check is based on the item's original upload format.
|
1521 |
-
if ( ! in_array( $type, $allowed_types ) ) {
|
1522 |
-
$error_msg = sprintf( __( 'Mime type %s is not allowed', 'amazon-s3-and-cloudfront' ), $type );
|
1523 |
|
1524 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1525 |
}
|
1526 |
|
1527 |
-
|
1528 |
-
|
1529 |
-
// check the attachment already exists in provider, eg. edit or restore image
|
1530 |
-
if ( $old_item ) {
|
1531 |
-
// Must be offloaded to same provider as currently configured.
|
1532 |
-
if ( ! $this->is_attachment_served_by_provider( $post_id, true ) ) {
|
1533 |
-
return $this->return_upload_error( __( 'Already offloaded to a different provider', 'amazon-s3-and-cloudfront' ), $return_metadata );
|
1534 |
-
}
|
1535 |
-
|
1536 |
-
// Use private ACL if existing offload is already private.
|
1537 |
-
if ( $old_item->is_private() ) {
|
1538 |
-
$acl = $this->get_storage_provider()->get_private_acl();
|
1539 |
-
}
|
1540 |
-
|
1541 |
-
// use existing prefix
|
1542 |
-
$prefix = $old_item->normalized_path_dir();
|
1543 |
-
// use existing private prefix
|
1544 |
-
$private_prefix = $old_item->private_prefix();
|
1545 |
-
// use existing bucket
|
1546 |
-
$bucket = $old_item->bucket();
|
1547 |
-
// get existing region
|
1548 |
-
$region = $old_item->region();
|
1549 |
-
// Get existing original filename.
|
1550 |
-
$original_filename = wp_basename( $old_item->original_source_path() );
|
1551 |
-
} else {
|
1552 |
-
// derive prefix from various settings
|
1553 |
-
$prefix = $this->get_new_attachment_prefix( $post_id, $data );
|
1554 |
-
|
1555 |
-
// maybe set a private prefix.
|
1556 |
-
if ( $this->private_prefix_enabled() ) {
|
1557 |
-
$private_prefix = AS3CF_Utils::trailingslash_prefix( $this->get_setting( 'signed-urls-object-prefix', '' ) );
|
1558 |
-
} else {
|
1559 |
-
$private_prefix = '';
|
1560 |
-
}
|
1561 |
-
|
1562 |
-
// use bucket from settings
|
1563 |
-
$bucket = $this->get_setting( 'bucket' );
|
1564 |
-
$region = $this->get_setting( 'region' );
|
1565 |
-
if ( is_wp_error( $region ) ) {
|
1566 |
-
$region = '';
|
1567 |
-
}
|
1568 |
-
|
1569 |
-
// There may be an original image that can override the default original filename.
|
1570 |
-
$original_filename = empty( $data['original_image'] ) ? null : $data['original_image'];
|
1571 |
-
}
|
1572 |
-
|
1573 |
-
$acl = apply_filters( 'wps3_upload_acl', $acl, $type, $data, $post_id, $this ); // Old naming convention, will be deprecated soon
|
1574 |
-
$acl = apply_filters( 'as3cf_upload_acl', $acl, $data, $post_id );
|
1575 |
-
$is_private = ! empty( $acl ) && $this->get_storage_provider()->get_private_acl() === $acl;
|
1576 |
-
|
1577 |
-
$args = array(
|
1578 |
-
'Bucket' => $bucket,
|
1579 |
-
'Key' => $prefix . $file_name,
|
1580 |
-
'SourceFile' => $file_path,
|
1581 |
-
'ContentType' => $this->get_mime_type( $file_path ),
|
1582 |
-
'CacheControl' => 'max-age=31536000',
|
1583 |
-
'Expires' => date( 'D, d M Y H:i:s O', time() + 31536000 ),
|
1584 |
-
);
|
1585 |
-
|
1586 |
-
$image_size = wp_attachment_is_image( $post_id ) ? 'full' : '';
|
1587 |
-
|
1588 |
-
// Only set ACL if actually required, some storage provider and bucket settings disable changing ACL.
|
1589 |
-
if ( ! empty( $acl ) && $this->use_acl_for_intermediate_size( $post_id, $image_size, $bucket ) ) {
|
1590 |
-
$args['ACL'] = $acl;
|
1591 |
-
}
|
1592 |
-
|
1593 |
-
// TODO: Remove GZIP functionality.
|
1594 |
-
// Handle gzip on supported items
|
1595 |
-
if ( $this->should_gzip_file( $file_path, $type ) && false !== ( $gzip_body = gzencode( file_get_contents( $file_path ) ) ) ) {
|
1596 |
-
unset( $args['SourceFile'] );
|
1597 |
-
|
1598 |
-
$args['Body'] = $gzip_body;
|
1599 |
-
$args['ContentEncoding'] = 'gzip';
|
1600 |
-
}
|
1601 |
-
|
1602 |
-
$args = apply_filters( 'as3cf_object_meta', $args, $post_id, $image_size, false );
|
1603 |
-
|
1604 |
-
$provider = $this->get_storage_provider()->get_provider_key_name();
|
1605 |
-
$region = $bucket !== $args['Bucket'] ? $this->get_bucket_region( $args['Bucket'], true ) : $region;
|
1606 |
-
$is_private = ( ! empty( $args['ACL'] ) && $this->get_storage_provider()->get_private_acl() === $args['ACL'] ) ? true : $is_private;
|
1607 |
-
$extra_info = empty( $old_item ) ? array( 'private_prefix' => $private_prefix ) : $old_item->extra_info();
|
1608 |
-
$item_id = empty( $old_item ) ? null : $old_item->id();
|
1609 |
-
|
1610 |
-
// Protect against filter use and only set ACL if actually required, some storage provider and bucket settings disable changing ACL.
|
1611 |
-
if ( isset( $args['ACL'] ) && ! $this->use_acl_for_intermediate_size( $post_id, $image_size, $bucket ) ) {
|
1612 |
-
unset( $args['ACL'] );
|
1613 |
-
}
|
1614 |
-
|
1615 |
-
$as3cf_item = new Media_Library_Item( $provider, $region, $args['Bucket'], $args['Key'], $is_private, $post_id, $file_path, $original_filename, $extra_info, $item_id );
|
1616 |
-
|
1617 |
-
// With public path and private prefix now in place, we can set the final path for the full sized file.
|
1618 |
-
$size_private_prefix = $as3cf_item->is_private() ? $as3cf_item->private_prefix() : '';
|
1619 |
-
$args['Key'] = $size_private_prefix . $args['Key'];
|
1620 |
-
|
1621 |
-
do_action( 'as3cf_upload_attachment_pre_remove', $post_id, $as3cf_item, $as3cf_item->normalized_path_dir(), $args );
|
1622 |
-
|
1623 |
-
$new_offload_path_filesizes = array();
|
1624 |
-
$new_offload_size_paths = array();
|
1625 |
-
$files_to_remove = array();
|
1626 |
-
|
1627 |
-
$provider_client = $this->get_provider_client( $as3cf_item->region(), $force_new_provider_client );
|
1628 |
-
|
1629 |
-
if ( $offload_full ) {
|
1630 |
-
try {
|
1631 |
-
// May raise exception, so don't offload anything else if there's an error.
|
1632 |
-
$filesize = (int) filesize( $file_path );
|
1633 |
-
|
1634 |
-
// May raise exception, so don't offload anything else if there's an error.
|
1635 |
-
$provider_client->upload_object( $args );
|
1636 |
-
|
1637 |
-
$new_offload_path_filesizes[ $file_path ] = $filesize; // Note: pre `as3cf_object_meta` filter value.
|
1638 |
-
$new_offload_size_paths['original'] = $file_path;
|
1639 |
-
$files_to_remove[] = $file_path; // Note: pre `as3cf_object_meta` filter value.
|
1640 |
-
} catch ( Exception $e ) {
|
1641 |
-
$error_msg = sprintf( __( 'Error offloading %s to provider: %s', 'amazon-s3-and-cloudfront' ), $file_path, $e->getMessage() );
|
1642 |
-
|
1643 |
-
return $this->return_upload_error( $error_msg, $return_metadata );
|
1644 |
-
}
|
1645 |
-
}
|
1646 |
-
|
1647 |
-
$additional_images = array();
|
1648 |
-
$private_sizes = array(); // Reset private sizes to be as expected at time of (re)upload.
|
1649 |
-
|
1650 |
-
foreach ( $file_paths as $size => $file_path ) {
|
1651 |
-
if ( ! in_array( $file_path, $files_to_remove ) ) {
|
1652 |
-
$acl = apply_filters( 'as3cf_upload_acl_sizes', $this->get_storage_provider()->get_default_acl(), $size, $post_id, $data );
|
1653 |
-
|
1654 |
-
if ( ! empty( $acl ) && $this->get_storage_provider()->get_private_acl() === $acl ) {
|
1655 |
-
$private_sizes[] = $size;
|
1656 |
-
}
|
1657 |
-
|
1658 |
-
// Public path, modified to private in next block as needed.
|
1659 |
-
$additional_images[ $size ] = array(
|
1660 |
-
'Key' => $as3cf_item->normalized_path_dir() . wp_basename( $file_path ),
|
1661 |
-
'SourceFile' => $file_path,
|
1662 |
-
'ContentType' => $this->get_mime_type( $file_path ),
|
1663 |
-
);
|
1664 |
-
|
1665 |
-
// Only set ACL if actually required, some storage provider and bucket settings disable changing ACL.
|
1666 |
-
if ( ! empty( $acl ) && $this->use_acl_for_intermediate_size( $post_id, $size, $bucket, $as3cf_item ) ) {
|
1667 |
-
$additional_images[ $size ]['ACL'] = $acl;
|
1668 |
-
}
|
1669 |
-
} else {
|
1670 |
-
// If the previous offload of file path was private, this size also needs to be private.
|
1671 |
-
// This is a case of first (in process) offload wins, duplicate file paths should have same access.
|
1672 |
-
if ( ! empty( $private_sizes ) ) {
|
1673 |
-
$duplicate_private = array_intersect( $private_sizes, array_keys( array_intersect( $file_paths, array( $file_path ) ) ) );
|
1674 |
-
|
1675 |
-
if ( ! empty( $duplicate_private ) ) {
|
1676 |
-
$private_sizes[] = $size;
|
1677 |
-
}
|
1678 |
-
}
|
1679 |
-
}
|
1680 |
-
}
|
1681 |
-
|
1682 |
-
$upload_errors = array();
|
1683 |
-
|
1684 |
-
foreach ( $additional_images as $size => $image ) {
|
1685 |
-
// If this file has already been offloaded during this request, skip actual offload.
|
1686 |
-
if ( $old_item && ! empty( $offloaded_path_filesizes[ $old_item->id() ][ $image['SourceFile'] ] ) ) {
|
1687 |
-
// We still have to record whether this size is private based on previous offload of the source file.
|
1688 |
-
// We also need to ensure this file is marked as possibly needing removal from server, and size has been processed.
|
1689 |
-
if ( ! empty( $private_sizes ) ) {
|
1690 |
-
$duplicate_private = array_intersect( $private_sizes, array_keys( array_intersect( $file_paths, array( $image['SourceFile'] ) ) ) );
|
1691 |
-
|
1692 |
-
if ( ! empty( $duplicate_private ) ) {
|
1693 |
-
$private_sizes[] = $size;
|
1694 |
-
}
|
1695 |
-
}
|
1696 |
-
|
1697 |
-
// Processed file, but not this duplicate size, so file may have been re-created by WordPress.
|
1698 |
-
if ( file_exists( $image['SourceFile'] ) ) {
|
1699 |
-
$files_to_remove[] = $image['SourceFile'];
|
1700 |
-
}
|
1701 |
-
$new_offload_size_paths[ $size ] = $image['SourceFile'];
|
1702 |
-
continue;
|
1703 |
-
}
|
1704 |
-
|
1705 |
-
$args = apply_filters( 'as3cf_object_meta', array_merge( $args, $image ), $post_id, $size, false );
|
1706 |
-
|
1707 |
-
// Is size private and therefore needs to be in private prefix?
|
1708 |
-
$size_private_prefix = in_array( $size, $private_sizes ) ? $as3cf_item->private_prefix() : '';
|
1709 |
-
$args['Key'] = $size_private_prefix . $args['Key'];
|
1710 |
-
|
1711 |
-
// Protect against filter use and only set ACL if actually required, some storage provider and bucket settings disable changing ACL.
|
1712 |
-
if ( isset( $args['ACL'] ) && ! $this->use_acl_for_intermediate_size( $post_id, $size, $bucket, $as3cf_item ) ) {
|
1713 |
-
unset( $args['ACL'] );
|
1714 |
-
}
|
1715 |
-
|
1716 |
-
if ( ! file_exists( $args['SourceFile'] ) ) {
|
1717 |
-
if ( ! $duplicate ) {
|
1718 |
-
$upload_errors[] = $this->return_upload_error( sprintf( __( 'File %s does not exist', 'amazon-s3-and-cloudfront' ), $args['SourceFile'] ) );
|
1719 |
-
}
|
1720 |
-
continue;
|
1721 |
-
}
|
1722 |
-
|
1723 |
-
try {
|
1724 |
-
// May raise exception, but for sizes we'll just log it and maybe try again later if called.
|
1725 |
-
$provider_client->upload_object( $args );
|
1726 |
-
$files_to_remove[] = $image['SourceFile']; // Note: pre `as3cf_object_meta` filter value.
|
1727 |
-
$new_offload_size_paths[ $size ] = $image['SourceFile'];
|
1728 |
-
|
1729 |
-
// May raise exception, we'll log that, and carry on anyway.
|
1730 |
-
$new_offload_path_filesizes[ $image['SourceFile'] ] = (int) filesize( $image['SourceFile'] ); // Note: pre `as3cf_object_meta` filter value.
|
1731 |
-
} catch ( Exception $e ) {
|
1732 |
-
$upload_errors[] = $this->return_upload_error( sprintf( __( 'Error offloading %s to provider: %s', 'amazon-s3-and-cloudfront' ), $args['SourceFile'], $e->getMessage() ) );
|
1733 |
-
}
|
1734 |
-
|
1735 |
-
// Edge Case: If previously uploaded and a different original_image wasn't picked up but is now, record it.
|
1736 |
-
// This is most likely to happen if older version of plugin was used with WP5.3 and large or rotated image auto-created.
|
1737 |
-
if ( 'original_image' === $size && wp_basename( $as3cf_item->original_source_path() ) !== wp_basename( $image['SourceFile'] ) ) {
|
1738 |
-
$as3cf_item = new Media_Library_Item(
|
1739 |
-
$as3cf_item->provider(),
|
1740 |
-
$as3cf_item->region(),
|
1741 |
-
$as3cf_item->bucket(),
|
1742 |
-
$as3cf_item->path(),
|
1743 |
-
$as3cf_item->is_private(),
|
1744 |
-
$as3cf_item->source_id(),
|
1745 |
-
$as3cf_item->source_path(),
|
1746 |
-
wp_basename( $image['SourceFile'] ),
|
1747 |
-
$as3cf_item->extra_info(),
|
1748 |
-
$as3cf_item->id()
|
1749 |
-
);
|
1750 |
-
}
|
1751 |
-
}
|
1752 |
-
|
1753 |
-
$remove_local_files_setting = $this->get_setting( 'remove-local-file' );
|
1754 |
-
|
1755 |
-
if ( $remove_local_files && $remove_local_files_setting ) {
|
1756 |
-
// Allow other functions to remove files after they have processed
|
1757 |
-
$files_to_remove = apply_filters( 'as3cf_upload_attachment_local_files_to_remove', $files_to_remove, $post_id, $file_path );
|
1758 |
-
|
1759 |
-
// Remove duplicates
|
1760 |
-
$files_to_remove = array_unique( $files_to_remove );
|
1761 |
-
|
1762 |
-
$filesize_total = 0;
|
1763 |
-
if ( ! empty( $old_item ) && ! empty( $offloaded_path_filesizes[ $old_item->id() ] ) ) {
|
1764 |
-
$filesize_total = array_sum( $offloaded_path_filesizes[ $old_item->id() ] );
|
1765 |
-
}
|
1766 |
-
// Delete the files and record original file's size before removal.
|
1767 |
-
$this->remove_local_files( $files_to_remove, $post_id, $filesize_total );
|
1768 |
-
|
1769 |
-
// Store filesize in the attachment meta data for use by WP if we've just offloaded the full size file.
|
1770 |
-
if ( ! empty( $filesize ) ) {
|
1771 |
-
$data['filesize'] = $filesize;
|
1772 |
-
|
1773 |
-
if ( is_null( $return_metadata ) ) {
|
1774 |
-
// Update metadata with filesize
|
1775 |
-
update_post_meta( $post_id, '_wp_attachment_metadata', $data );
|
1776 |
-
}
|
1777 |
-
}
|
1778 |
-
}
|
1779 |
-
|
1780 |
-
// Make sure we don't have cached file sizes in the meta if we previously added it.
|
1781 |
-
if ( ! $remove_local_files_setting && isset( $data['filesize'] ) && ! empty( get_post_meta( $post_id, 'as3cf_filesize_total', true ) ) ) {
|
1782 |
-
$data = $this->maybe_cleanup_filesize_metadata( $post_id, $data, empty( $return_metadata ) );
|
1783 |
-
}
|
1784 |
-
|
1785 |
-
// Additional image sizes have custom ACLs, record them.
|
1786 |
-
if ( ! empty( $private_sizes ) ) {
|
1787 |
-
$extra_info = $as3cf_item->extra_info();
|
1788 |
-
$extra_info['private_sizes'] = $private_sizes;
|
1789 |
-
|
1790 |
-
$as3cf_item = new Media_Library_Item(
|
1791 |
-
$as3cf_item->provider(),
|
1792 |
-
$as3cf_item->region(),
|
1793 |
-
$as3cf_item->bucket(),
|
1794 |
-
$as3cf_item->path(),
|
1795 |
-
$as3cf_item->is_private(),
|
1796 |
-
$as3cf_item->source_id(),
|
1797 |
-
$as3cf_item->source_path(),
|
1798 |
-
wp_basename( $as3cf_item->original_source_path() ),
|
1799 |
-
$extra_info,
|
1800 |
-
$as3cf_item->id()
|
1801 |
-
);
|
1802 |
-
}
|
1803 |
-
|
1804 |
-
// All done, save record of offloaded item.
|
1805 |
-
$as3cf_item->save();
|
1806 |
-
|
1807 |
-
// Keep track of individual files offloaded during this request.
|
1808 |
-
if ( empty( $offloaded_path_filesizes[ $as3cf_item->id() ] ) ) {
|
1809 |
-
$offloaded_path_filesizes[ $as3cf_item->id() ] = $new_offload_path_filesizes;
|
1810 |
-
$offloaded_size_paths[ $as3cf_item->id() ] = $new_offload_size_paths;
|
1811 |
-
} else {
|
1812 |
-
$offloaded_path_filesizes[ $as3cf_item->id() ] += $new_offload_path_filesizes;
|
1813 |
-
$offloaded_size_paths[ $as3cf_item->id() ] += $new_offload_size_paths;
|
1814 |
-
}
|
1815 |
-
|
1816 |
-
// Keep track of attachments uploaded by this instance.
|
1817 |
-
$this->uploaded_post_ids[] = $post_id;
|
1818 |
-
|
1819 |
-
do_action( 'as3cf_post_upload_attachment', $post_id, $as3cf_item );
|
1820 |
-
|
1821 |
-
if ( $upload_errors ) {
|
1822 |
-
return $this->consolidate_upload_errors( $upload_errors );
|
1823 |
-
}
|
1824 |
-
|
1825 |
-
if ( ! is_null( $return_metadata ) ) {
|
1826 |
-
// If the attachment metadata is supplied, return it
|
1827 |
-
return $data;
|
1828 |
-
}
|
1829 |
-
|
1830 |
-
return $as3cf_item;
|
1831 |
-
}
|
1832 |
-
|
1833 |
-
/**
|
1834 |
-
* Get a file's real mime type
|
1835 |
-
*
|
1836 |
-
* @param string $file_path
|
1837 |
-
*
|
1838 |
-
* @return string
|
1839 |
-
*/
|
1840 |
-
protected function get_mime_type( $file_path ) {
|
1841 |
-
$file_type = wp_check_filetype_and_ext( $file_path, wp_basename( $file_path ) );
|
1842 |
-
|
1843 |
-
return $file_type['type'];
|
1844 |
-
}
|
1845 |
-
|
1846 |
-
/**
|
1847 |
-
* Should gzip file
|
1848 |
-
*
|
1849 |
-
* @param string $file_path
|
1850 |
-
* @param string $type
|
1851 |
-
*
|
1852 |
-
* @return bool
|
1853 |
-
*/
|
1854 |
-
protected function should_gzip_file( $file_path, $type ) {
|
1855 |
-
$mimes = $this->get_mime_types_to_gzip( true );
|
1856 |
-
|
1857 |
-
if ( in_array( $type, $mimes ) && is_readable( $file_path ) ) {
|
1858 |
-
return true;
|
1859 |
-
}
|
1860 |
-
|
1861 |
-
return false;
|
1862 |
-
}
|
1863 |
-
|
1864 |
-
/**
|
1865 |
-
* Get mime types to gzip
|
1866 |
-
*
|
1867 |
-
* @param bool $media_library
|
1868 |
-
*
|
1869 |
-
* @return array
|
1870 |
-
*/
|
1871 |
-
protected function get_mime_types_to_gzip( $media_library = false ) {
|
1872 |
-
$mimes = apply_filters( 'as3cf_gzip_mime_types', array(
|
1873 |
-
'css' => 'text/css',
|
1874 |
-
'eot' => 'application/vnd.ms-fontobject',
|
1875 |
-
'html' => 'text/html',
|
1876 |
-
'ico' => 'image/x-icon',
|
1877 |
-
'js' => 'application/javascript',
|
1878 |
-
'json' => 'application/json',
|
1879 |
-
'otf' => 'application/x-font-opentype',
|
1880 |
-
'rss' => 'application/rss+xml',
|
1881 |
-
'svg' => 'image/svg+xml',
|
1882 |
-
'ttf' => 'application/x-font-ttf',
|
1883 |
-
'woff' => 'application/font-woff',
|
1884 |
-
'woff2' => 'application/font-woff2',
|
1885 |
-
'xml' => 'application/xml',
|
1886 |
-
), $media_library );
|
1887 |
-
|
1888 |
-
return $mimes;
|
1889 |
-
}
|
1890 |
-
|
1891 |
-
/**
|
1892 |
-
* Helper to record errors and return meta data on upload error.
|
1893 |
-
*
|
1894 |
-
* @param string $error_msg
|
1895 |
-
* @param array|null $return
|
1896 |
-
*
|
1897 |
-
* @return array|WP_Error
|
1898 |
-
*/
|
1899 |
-
protected function return_upload_error( $error_msg, $return = null ) {
|
1900 |
-
|
1901 |
-
AS3CF_Error::log( $error_msg );
|
1902 |
-
|
1903 |
-
if ( is_null( $return ) ) {
|
1904 |
-
return new WP_Error( 'exception', $error_msg );
|
1905 |
-
}
|
1906 |
-
|
1907 |
-
return $return;
|
1908 |
-
}
|
1909 |
-
|
1910 |
-
/**
|
1911 |
-
* Remove files from the local site, recording total filesize in meta if attachment ID given.
|
1912 |
-
*
|
1913 |
-
* @param array $file_paths Files to remove.
|
1914 |
-
* @param int $attachment_id Optional, if supplied filesize metadata recorded.
|
1915 |
-
* @param int $filesize_total Optional, if removing partial set of an attachment's files, pass in previously removed total.
|
1916 |
-
*/
|
1917 |
-
function remove_local_files( $file_paths, $attachment_id = 0, $filesize_total = 0 ) {
|
1918 |
-
if ( empty( $filesize_total ) ) {
|
1919 |
-
$filesize_total = 0;
|
1920 |
-
}
|
1921 |
-
|
1922 |
-
foreach ( $file_paths as $index => $path ) {
|
1923 |
-
if ( ! empty( $attachment_id ) && is_int( $attachment_id ) ) {
|
1924 |
-
$bytes = filesize( $path );
|
1925 |
-
|
1926 |
-
$filesize_total += ( false !== $bytes ) ? $bytes : 0;
|
1927 |
-
}
|
1928 |
-
|
1929 |
-
// Individual files might still be kept local, but we're still going to count them towards total above.
|
1930 |
-
if ( false !== ( $pre = apply_filters( 'as3cf_preserve_file_from_local_removal', false, $path ) ) ) {
|
1931 |
-
continue;
|
1932 |
-
}
|
1933 |
-
|
1934 |
-
if ( ! @unlink( $path ) ) {
|
1935 |
-
$message = 'Error removing local file ';
|
1936 |
-
|
1937 |
-
if ( ! file_exists( $path ) ) {
|
1938 |
-
$message = "Error removing local file. Couldn't find the file at ";
|
1939 |
-
} else if ( ! is_writable( $path ) ) {
|
1940 |
-
$message = 'Error removing local file. Ownership or permissions are mis-configured for ';
|
1941 |
-
}
|
1942 |
-
|
1943 |
-
AS3CF_Error::log( $message . $path );
|
1944 |
-
}
|
1945 |
-
}
|
1946 |
-
|
1947 |
-
// If we were able to sum up file sizes for an attachment, record it.
|
1948 |
-
if ( ! empty( $attachment_id ) && is_int( $attachment_id ) && $filesize_total > 0 ) {
|
1949 |
-
update_post_meta( $attachment_id, 'as3cf_filesize_total', $filesize_total );
|
1950 |
-
}
|
1951 |
-
}
|
1952 |
-
|
1953 |
-
/**
|
1954 |
-
* Get the object versioning string prefix
|
1955 |
-
*
|
1956 |
-
* @return string
|
1957 |
-
*/
|
1958 |
-
function get_object_version_string() {
|
1959 |
-
if ( $this->get_setting( 'use-yearmonth-folders' ) ) {
|
1960 |
-
$date_format = 'dHis';
|
1961 |
-
} else {
|
1962 |
-
$date_format = 'YmdHis';
|
1963 |
-
}
|
1964 |
-
|
1965 |
-
// Use current time so that object version is unique
|
1966 |
-
$time = current_time( 'timestamp' );
|
1967 |
-
|
1968 |
-
$object_version = date( $date_format, $time ) . '/';
|
1969 |
-
$object_version = apply_filters( 'as3cf_get_object_version_string', $object_version );
|
1970 |
-
|
1971 |
-
return $object_version;
|
1972 |
-
}
|
1973 |
-
|
1974 |
-
/**
|
1975 |
-
* Get the upload folder time from given URL
|
1976 |
-
*
|
1977 |
-
* @param string $url
|
1978 |
-
*
|
1979 |
-
* @return null|string YYYY/MM format.
|
1980 |
-
*/
|
1981 |
-
function get_folder_time_from_url( $url ) {
|
1982 |
-
if ( ! is_string( $url ) ) {
|
1983 |
-
return null;
|
1984 |
-
}
|
1985 |
-
|
1986 |
-
preg_match( '@[0-9]{4}/[0-9]{2}/@', $url, $matches );
|
1987 |
-
|
1988 |
-
if ( isset( $matches[0] ) ) {
|
1989 |
-
return untrailingslashit( $matches[0] );
|
1990 |
-
}
|
1991 |
-
|
1992 |
-
return null;
|
1993 |
-
}
|
1994 |
-
|
1995 |
-
/**
|
1996 |
-
* Get the year/month string for attachment's upload.
|
1997 |
-
*
|
1998 |
-
* Fall back to post date if attached, otherwise current date.
|
1999 |
-
*
|
2000 |
-
* @param int $post_id Attachment's ID
|
2001 |
-
* @param array $data Attachment's metadata
|
2002 |
-
*
|
2003 |
-
* @return string
|
2004 |
-
*/
|
2005 |
-
function get_attachment_folder_year_month( $post_id, $data = null ) {
|
2006 |
-
if ( isset( $data['file'] ) ) {
|
2007 |
-
$time = $this->get_folder_time_from_url( $data['file'] );
|
2008 |
-
}
|
2009 |
-
|
2010 |
-
if ( empty( $time ) && ( $local_url = wp_get_attachment_url( $post_id ) ) ) {
|
2011 |
-
$time = $this->get_folder_time_from_url( $local_url );
|
2012 |
-
}
|
2013 |
-
|
2014 |
-
if ( empty( $time ) ) {
|
2015 |
-
$time = date( 'Y/m' );
|
2016 |
-
|
2017 |
-
if ( ! ( $attach = get_post( $post_id ) ) ) {
|
2018 |
-
return $time;
|
2019 |
-
}
|
2020 |
-
|
2021 |
-
if ( ! $attach->post_parent ) {
|
2022 |
-
return $time;
|
2023 |
-
}
|
2024 |
-
|
2025 |
-
if ( ! ( $post = get_post( $attach->post_parent ) ) ) {
|
2026 |
-
return $time;
|
2027 |
-
}
|
2028 |
-
|
2029 |
-
if ( substr( $post->post_date_gmt, 0, 4 ) > 0 ) {
|
2030 |
-
return date( 'Y/m', strtotime( $post->post_date_gmt . ' +0000' ) );
|
2031 |
-
}
|
2032 |
-
}
|
2033 |
-
|
2034 |
-
return $time;
|
2035 |
-
}
|
2036 |
-
|
2037 |
-
/**
|
2038 |
-
* Filters the result when generating a unique file name.
|
2039 |
-
*
|
2040 |
-
* @param string $filename Unique file name.
|
2041 |
-
* @param string $ext File extension, eg. ".png".
|
2042 |
-
* @param string $dir Directory path.
|
2043 |
-
*
|
2044 |
-
* @return string
|
2045 |
-
* @since 4.5.0
|
2046 |
-
*
|
2047 |
-
*/
|
2048 |
-
public function wp_unique_filename( $filename, $ext, $dir ) {
|
2049 |
-
// Get Post ID if uploaded in post screen.
|
2050 |
-
$post_id = filter_input( INPUT_POST, 'post_id', FILTER_VALIDATE_INT );
|
2051 |
-
|
2052 |
-
$filename = $this->filter_unique_filename( $filename, $ext, $dir, $post_id );
|
2053 |
-
|
2054 |
-
return $filename;
|
2055 |
-
}
|
2056 |
-
|
2057 |
-
/**
|
2058 |
-
* Create unique names for file to be uploaded to AWS.
|
2059 |
-
* This only applies when the remove local file option is enabled.
|
2060 |
-
*
|
2061 |
-
* @param string $filename Unique file name.
|
2062 |
-
* @param string $ext File extension, eg. ".png".
|
2063 |
-
* @param string $dir Directory path.
|
2064 |
-
* @param int $post_id Attachment's parent Post ID.
|
2065 |
-
*
|
2066 |
-
* @return string
|
2067 |
-
*/
|
2068 |
-
public function filter_unique_filename( $filename, $ext, $dir, $post_id = null ) {
|
2069 |
-
if ( ! $this->is_plugin_setup( true ) ) {
|
2070 |
-
return $filename;
|
2071 |
-
}
|
2072 |
-
|
2073 |
-
// sanitize the file name before we begin processing
|
2074 |
-
$filename = sanitize_file_name( $filename );
|
2075 |
-
$ext = strtolower( $ext );
|
2076 |
-
$name = wp_basename( $filename, $ext );
|
2077 |
-
|
2078 |
-
// Edge case: if file is named '.ext', treat as an empty name.
|
2079 |
-
if ( $name === $ext ) {
|
2080 |
-
$name = '';
|
2081 |
-
}
|
2082 |
-
|
2083 |
-
// Rebuild filename with lowercase extension as provider will have converted extension on upload.
|
2084 |
-
$filename = $name . $ext;
|
2085 |
-
$time = current_time( 'mysql' );
|
2086 |
-
|
2087 |
-
// Get time if uploaded in post screen.
|
2088 |
-
if ( ! empty( $post_id ) ) {
|
2089 |
-
$time = $this->get_post_time( $post_id );
|
2090 |
-
}
|
2091 |
-
|
2092 |
-
if ( ! $this->does_file_exist( $filename, $time ) ) {
|
2093 |
-
// File doesn't exist locally or on provider, return it.
|
2094 |
-
return $filename;
|
2095 |
-
}
|
2096 |
-
|
2097 |
-
$filename = $this->generate_unique_filename( $name, $ext, $time );
|
2098 |
-
|
2099 |
-
return $filename;
|
2100 |
-
}
|
2101 |
-
|
2102 |
-
/**
|
2103 |
-
* Get post time
|
2104 |
-
*
|
2105 |
-
* @param int $post_id
|
2106 |
-
*
|
2107 |
-
* @return string
|
2108 |
-
*/
|
2109 |
-
function get_post_time( $post_id ) {
|
2110 |
-
$time = current_time( 'mysql' );
|
2111 |
-
|
2112 |
-
if ( ! $post = get_post( $post_id ) ) {
|
2113 |
-
return $time;
|
2114 |
-
}
|
2115 |
-
|
2116 |
-
if ( substr( $post->post_date, 0, 4 ) > 0 ) {
|
2117 |
-
$time = $post->post_date;
|
2118 |
-
}
|
2119 |
-
|
2120 |
-
return $time;
|
2121 |
-
}
|
2122 |
-
|
2123 |
-
/**
|
2124 |
-
* Does file exist
|
2125 |
-
*
|
2126 |
-
* @param string $filename
|
2127 |
-
* @param string $time
|
2128 |
-
*
|
2129 |
-
* @return bool
|
2130 |
-
*/
|
2131 |
-
function does_file_exist( $filename, $time ) {
|
2132 |
-
if ( $this->does_file_exist_local( $filename, $time ) ) {
|
2133 |
-
return true;
|
2134 |
-
}
|
2135 |
-
|
2136 |
-
if ( ! $this->get_setting( 'object-versioning' ) && $this->does_file_exist_provider( $filename, $time ) ) {
|
2137 |
-
return true;
|
2138 |
-
}
|
2139 |
-
|
2140 |
-
return false;
|
2141 |
-
}
|
2142 |
-
|
2143 |
-
/**
|
2144 |
-
* Does file exist local
|
2145 |
-
*
|
2146 |
-
* @param string $filename
|
2147 |
-
* @param string $time
|
2148 |
-
*
|
2149 |
-
* @return bool
|
2150 |
-
*/
|
2151 |
-
function does_file_exist_local( $filename, $time ) {
|
2152 |
-
global $wpdb;
|
2153 |
-
|
2154 |
-
$path = wp_upload_dir( $time );
|
2155 |
-
$path = ltrim( $path['subdir'], '/' );
|
2156 |
-
|
2157 |
-
if ( '' !== $path ) {
|
2158 |
-
$path = trailingslashit( $path );
|
2159 |
-
}
|
2160 |
-
$file = $path . $filename;
|
2161 |
-
|
2162 |
-
// WordPress doesn't check its own basic record, so we will.
|
2163 |
-
$sql = $wpdb->prepare( "
|
2164 |
-
SELECT COUNT(*)
|
2165 |
-
FROM $wpdb->postmeta
|
2166 |
-
WHERE meta_key = %s
|
2167 |
-
AND meta_value = %s
|
2168 |
-
", '_wp_attached_file', $file );
|
2169 |
-
|
2170 |
-
if ( (bool) $wpdb->get_var( $sql ) ) {
|
2171 |
-
return true;
|
2172 |
-
}
|
2173 |
-
|
2174 |
-
// Check our records of local source path as it also covers original_image.
|
2175 |
-
if ( ! empty( Media_Library_Item::get_by_source_path( array( $file ), array(), true, true ) ) ) {
|
2176 |
-
return true;
|
2177 |
-
}
|
2178 |
-
|
2179 |
-
return false;
|
2180 |
-
}
|
2181 |
-
|
2182 |
-
/**
|
2183 |
-
* Does file exist provider
|
2184 |
-
*
|
2185 |
-
* @param string $filename
|
2186 |
-
* @param string $time
|
2187 |
-
*
|
2188 |
-
* @return bool
|
2189 |
-
* @throws Exception
|
2190 |
-
*/
|
2191 |
-
function does_file_exist_provider( $filename, $time ) {
|
2192 |
-
$bucket = $this->get_setting( 'bucket' );
|
2193 |
-
$region = $this->get_setting( 'region' );
|
2194 |
-
|
2195 |
-
if ( is_wp_error( $region ) ) {
|
2196 |
-
return false;
|
2197 |
-
}
|
2198 |
-
|
2199 |
-
$provider_client = $this->get_provider_client( $region );
|
2200 |
-
$prefix = AS3CF_Utils::trailingslash_prefix( $this->get_object_prefix() );
|
2201 |
-
$prefix .= AS3CF_Utils::trailingslash_prefix( $this->get_dynamic_prefix( $time ) );
|
2202 |
-
|
2203 |
-
return $provider_client->does_object_exist( $bucket, $prefix . $filename );
|
2204 |
-
}
|
2205 |
-
|
2206 |
-
/**
|
2207 |
-
* Generate unique filename
|
2208 |
-
*
|
2209 |
-
* @param string $name
|
2210 |
-
* @param string $ext
|
2211 |
-
* @param string $time
|
2212 |
-
*
|
2213 |
-
* @return string
|
2214 |
-
*/
|
2215 |
-
function generate_unique_filename( $name, $ext, $time ) {
|
2216 |
-
$count = 1;
|
2217 |
-
$filename = $name . '-' . $count . $ext;
|
2218 |
-
|
2219 |
-
while ( $this->does_file_exist( $filename, $time ) ) {
|
2220 |
-
$count++;
|
2221 |
-
$filename = $name . '-' . $count . $ext;
|
2222 |
-
}
|
2223 |
-
|
2224 |
-
return $filename;
|
2225 |
-
}
|
2226 |
-
|
2227 |
-
/**
|
2228 |
-
* Check the plugin is correctly setup
|
2229 |
-
*
|
2230 |
-
* @param bool $with_credentials Do provider credentials need to be set up too? Defaults to false.
|
2231 |
-
*
|
2232 |
-
* @return bool
|
2233 |
-
*
|
2234 |
-
* TODO: Performance - cache / static var by param.
|
2235 |
-
*/
|
2236 |
-
function is_plugin_setup( $with_credentials = false ) {
|
2237 |
-
if ( $with_credentials && $this->get_storage_provider()->needs_access_keys() ) {
|
2238 |
-
// AWS not configured
|
2239 |
-
return false;
|
2240 |
-
}
|
2241 |
-
|
2242 |
-
if ( false === (bool) $this->get_setting( 'bucket' ) ) {
|
2243 |
-
// No bucket selected
|
2244 |
-
return false;
|
2245 |
-
}
|
2246 |
-
|
2247 |
-
if ( is_wp_error( $this->get_setting( 'region' ) ) ) {
|
2248 |
-
// Region error when retrieving bucket location
|
2249 |
-
return false;
|
2250 |
-
}
|
2251 |
-
|
2252 |
-
// All good, let's do this
|
2253 |
-
return true;
|
2254 |
-
}
|
2255 |
-
|
2256 |
-
/**
|
2257 |
-
* Generate a link to download a file from Amazon provider using query string
|
2258 |
-
* authentication. This link is only valid for a limited amount of time.
|
2259 |
-
*
|
2260 |
-
* @param int $post_id Post ID of the attachment
|
2261 |
-
* @param int|null $expires Seconds for the link to live
|
2262 |
-
* @param string|null $size Size of the image to get
|
2263 |
-
* @param array $headers Header overrides for request
|
2264 |
-
* @param bool $skip_rewrite_check
|
2265 |
-
*
|
2266 |
-
* @return string|bool|WP_Error
|
2267 |
-
*/
|
2268 |
-
public function get_secure_attachment_url( $post_id, $expires = null, $size = null, $headers = array(), $skip_rewrite_check = false ) {
|
2269 |
-
if ( is_null( $expires ) ) {
|
2270 |
-
$expires = self::DEFAULT_EXPIRES;
|
2271 |
-
}
|
2272 |
-
|
2273 |
-
return $this->get_attachment_url( $post_id, $expires, $size, null, $headers, $skip_rewrite_check );
|
2274 |
-
}
|
2275 |
-
|
2276 |
-
/**
|
2277 |
-
* Return the scheme to be used in URLs
|
2278 |
-
*
|
2279 |
-
* @param bool|null $use_ssl
|
2280 |
-
*
|
2281 |
-
* @return string
|
2282 |
-
*/
|
2283 |
-
function get_url_scheme( $use_ssl = null ) {
|
2284 |
-
if ( $this->use_ssl( $use_ssl ) ) {
|
2285 |
-
$scheme = 'https';
|
2286 |
-
} else {
|
2287 |
-
$scheme = 'http';
|
2288 |
-
}
|
2289 |
-
|
2290 |
-
return $scheme;
|
2291 |
-
}
|
2292 |
-
|
2293 |
-
/**
|
2294 |
-
* Determine when to use https in URLS
|
2295 |
-
*
|
2296 |
-
* @param bool|null $use_ssl
|
2297 |
-
*
|
2298 |
-
* @return bool
|
2299 |
-
*/
|
2300 |
-
public function use_ssl( $use_ssl = null ) {
|
2301 |
-
if ( is_ssl() ) {
|
2302 |
-
$use_ssl = true;
|
2303 |
-
}
|
2304 |
-
|
2305 |
-
if ( ! is_bool( $use_ssl ) ) {
|
2306 |
-
$use_ssl = $this->get_setting( 'force-https' );
|
2307 |
-
}
|
2308 |
-
|
2309 |
-
if ( empty( $use_ssl ) ) {
|
2310 |
-
$use_ssl = false;
|
2311 |
-
}
|
2312 |
-
|
2313 |
-
return apply_filters( 'as3cf_use_ssl', $use_ssl );
|
2314 |
-
}
|
2315 |
-
|
2316 |
-
/**
|
2317 |
-
* Get the custom object prefix if enabled
|
2318 |
-
*
|
2319 |
-
* @param string $toggle_setting
|
2320 |
-
*
|
2321 |
-
* @return string
|
2322 |
-
*/
|
2323 |
-
function get_object_prefix( $toggle_setting = 'enable-object-prefix' ) {
|
2324 |
-
if ( $this->get_setting( $toggle_setting ) ) {
|
2325 |
-
return trailingslashit( trim( $this->get_setting( 'object-prefix' ) ) );
|
2326 |
-
}
|
2327 |
-
|
2328 |
-
return '';
|
2329 |
-
}
|
2330 |
-
|
2331 |
-
/**
|
2332 |
-
* Get the file prefix
|
2333 |
-
*
|
2334 |
-
* @param null|string $time
|
2335 |
-
* @param bool $object_versioning_allowed Can an Object Versioning string be appended if setting turned on? Default true.
|
2336 |
-
*
|
2337 |
-
* @return string
|
2338 |
-
*/
|
2339 |
-
public function get_file_prefix( $time = null, $object_versioning_allowed = true ) {
|
2340 |
-
$prefix = AS3CF_Utils::trailingslash_prefix( $this->get_object_prefix() );
|
2341 |
-
$prefix .= AS3CF_Utils::trailingslash_prefix( $this->get_dynamic_prefix( $time ) );
|
2342 |
-
|
2343 |
-
if ( ! empty( $object_versioning_allowed ) && $this->get_setting( 'object-versioning' ) ) {
|
2344 |
-
$prefix .= AS3CF_Utils::trailingslash_prefix( $this->get_object_version_string() );
|
2345 |
-
}
|
2346 |
-
|
2347 |
-
return $prefix;
|
2348 |
-
}
|
2349 |
-
|
2350 |
-
/**
|
2351 |
-
* Get attachment's new public prefix path for current settings.
|
2352 |
-
*
|
2353 |
-
* @param int $post_id Attachment ID
|
2354 |
-
* @param array $metadata Optional attachment metadata
|
2355 |
-
* @param bool $object_versioning_allowed Can an Object Versioning string be appended if setting turned on? Default true.
|
2356 |
-
*
|
2357 |
-
* @return string
|
2358 |
-
*/
|
2359 |
-
public function get_new_attachment_prefix( $post_id, $metadata = null, $object_versioning_allowed = true ) {
|
2360 |
-
if ( empty( $metadata ) ) {
|
2361 |
-
$metadata = wp_get_attachment_metadata( $post_id, true );
|
2362 |
-
}
|
2363 |
-
|
2364 |
-
$time = $this->get_attachment_folder_year_month( $post_id, $metadata );
|
2365 |
-
|
2366 |
-
return $this->get_file_prefix( $time, $object_versioning_allowed );
|
2367 |
-
}
|
2368 |
-
|
2369 |
-
/**
|
2370 |
-
* Get the url of the file from provider
|
2371 |
-
*
|
2372 |
-
* @param int $post_id Post ID of the attachment, required.
|
2373 |
-
* @param int|null $expires Seconds for the link to live, optional.
|
2374 |
-
* @param string|null $size Size of the image to get, optional.
|
2375 |
-
* @param array|null $meta Pre retrieved _wp_attachment_metadata for the attachment, optional.
|
2376 |
-
* @param array $headers Header overrides for request, optional.
|
2377 |
-
* @param bool $skip_rewrite_check Always return the URL regardless of the 'Rewrite File URLs' setting, optional, default: false.
|
2378 |
-
* Useful for the EDD and Woo addons to not break download URLs when the option is disabled.
|
2379 |
-
*
|
2380 |
-
* @return string|bool|WP_Error
|
2381 |
-
*/
|
2382 |
-
public function get_attachment_url( $post_id, $expires = null, $size = null, $meta = null, $headers = array(), $skip_rewrite_check = false ) {
|
2383 |
-
if ( ! ( $as3cf_item = $this->is_attachment_served_by_provider( $post_id, $skip_rewrite_check ) ) ) {
|
2384 |
-
return false;
|
2385 |
-
}
|
2386 |
-
|
2387 |
-
$url = $this->get_attachment_provider_url( $post_id, $as3cf_item, $expires, $size, $meta, $headers );
|
2388 |
-
|
2389 |
-
return apply_filters( 'as3cf_wp_get_attachment_url', $url, $post_id );
|
2390 |
-
}
|
2391 |
-
|
2392 |
-
/**
|
2393 |
-
* Get attachment local URL.
|
2394 |
-
*
|
2395 |
-
* This is a direct copy of wp_get_attachment_url() from /wp-includes/post.php
|
2396 |
-
* as we filter the URL in AS3CF and can't remove this filter using the current implementation
|
2397 |
-
* of globals for class instances.
|
2398 |
-
*
|
2399 |
-
* @param int $post_id
|
2400 |
-
*
|
2401 |
-
* @return string|false Attachment URL, otherwise false.
|
2402 |
-
*/
|
2403 |
-
public function get_attachment_local_url( $post_id ) {
|
2404 |
-
$url = '';
|
2405 |
-
|
2406 |
-
// Get attached file.
|
2407 |
-
if ( $file = get_post_meta( $post_id, '_wp_attached_file', true ) ) {
|
2408 |
-
// Get upload directory.
|
2409 |
-
if ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) {
|
2410 |
-
// Check that the upload base exists in the file location.
|
2411 |
-
if ( 0 === strpos( $file, $uploads['basedir'] ) ) {
|
2412 |
-
// Replace file location with url location.
|
2413 |
-
$url = str_replace( $uploads['basedir'], $uploads['baseurl'], $file );
|
2414 |
-
} elseif ( false !== strpos( $file, 'wp-content/uploads' ) ) {
|
2415 |
-
$url = $uploads['baseurl'] . substr( $file, strpos( $file, 'wp-content/uploads' ) + 18 );
|
2416 |
-
} else {
|
2417 |
-
// It's a newly-uploaded file, therefore $file is relative to the basedir.
|
2418 |
-
$url = $uploads['baseurl'] . "/$file";
|
2419 |
-
}
|
2420 |
-
}
|
2421 |
-
}
|
2422 |
-
|
2423 |
-
if ( empty( $url ) ) {
|
2424 |
-
return false;
|
2425 |
-
}
|
2426 |
-
|
2427 |
-
$url = $this->maybe_fix_local_subsite_url( $url );
|
2428 |
-
|
2429 |
-
return $url;
|
2430 |
-
}
|
2431 |
-
|
2432 |
-
/**
|
2433 |
-
* Get attachment local URL size.
|
2434 |
-
*
|
2435 |
-
* @param int $post_id
|
2436 |
-
* @param string|null $size
|
2437 |
-
*
|
2438 |
-
* @return false|string
|
2439 |
-
*/
|
2440 |
-
public function get_attachment_local_url_size( $post_id, $size = null ) {
|
2441 |
-
$url = $this->get_attachment_local_url( $post_id );
|
2442 |
-
|
2443 |
-
if ( empty( $size ) ) {
|
2444 |
-
return $url;
|
2445 |
-
}
|
2446 |
-
|
2447 |
-
$meta = get_post_meta( $post_id, '_wp_attachment_metadata', true );
|
2448 |
-
|
2449 |
-
if ( empty( $meta['sizes'][ $size ]['file'] ) ) {
|
2450 |
-
// No alternative sizes available, return
|
2451 |
-
return $url;
|
2452 |
-
}
|
2453 |
-
|
2454 |
-
return str_replace( wp_basename( $url ), $meta['sizes'][ $size ]['file'], $url );
|
2455 |
-
}
|
2456 |
-
|
2457 |
-
/**
|
2458 |
-
* Get the provider URL for an attachment
|
2459 |
-
*
|
2460 |
-
* @param int $post_id
|
2461 |
-
* @param Media_Library_Item $as3cf_item
|
2462 |
-
* @param null|int $expires
|
2463 |
-
* @param null|string|array $size
|
2464 |
-
* @param null|array $meta
|
2465 |
-
* @param array $headers
|
2466 |
-
*
|
2467 |
-
* @return string|WP_Error
|
2468 |
-
*/
|
2469 |
-
public function get_attachment_provider_url( $post_id, Media_Library_Item $as3cf_item, $expires = null, $size = null, $meta = null, $headers = array() ) {
|
2470 |
-
$size = AS3CF_Utils::maybe_convert_size_to_string( $post_id, $size );
|
2471 |
-
|
2472 |
-
// Is a signed expiring URL required for the requested object?
|
2473 |
-
if ( is_null( $expires ) ) {
|
2474 |
-
$expires = $as3cf_item->is_private_size( $size ) ? self::DEFAULT_EXPIRES : null;
|
2475 |
-
} else {
|
2476 |
-
$expires = $as3cf_item->is_private_size( $size ) ? $expires : null;
|
2477 |
-
}
|
2478 |
-
|
2479 |
-
$item_path = $as3cf_item->path();
|
2480 |
-
|
2481 |
-
if ( ! is_null( $size ) ) {
|
2482 |
-
if ( is_null( $meta ) ) {
|
2483 |
-
$meta = get_post_meta( $post_id, '_wp_attachment_metadata', true );
|
2484 |
-
}
|
2485 |
-
|
2486 |
-
if ( is_wp_error( $meta ) ) {
|
2487 |
-
return $meta;
|
2488 |
-
}
|
2489 |
-
|
2490 |
-
if ( ! empty( $meta ) && isset( $meta['sizes'][ $size ]['file'] ) ) {
|
2491 |
-
$size_prefix = dirname( $item_path );
|
2492 |
-
$size_file_prefix = ( '.' === $size_prefix ) ? '' : $size_prefix . '/';
|
2493 |
-
|
2494 |
-
$item_path = $size_file_prefix . $meta['sizes'][ $size ]['file'];
|
2495 |
-
}
|
2496 |
-
}
|
2497 |
-
|
2498 |
-
$scheme = $this->get_url_scheme();
|
2499 |
-
$enable_delivery_domain = $this->get_delivery_provider()->delivery_domain_allowed() ? $this->get_setting( 'enable-delivery-domain' ) : false;
|
2500 |
-
$delivery_domain = $this->get_setting( 'delivery-domain' );
|
2501 |
-
|
2502 |
-
if ( ! $enable_delivery_domain || empty( $delivery_domain ) ) {
|
2503 |
-
$region = $as3cf_item->region();
|
2504 |
-
|
2505 |
-
if ( is_wp_error( $region ) ) {
|
2506 |
-
return $region;
|
2507 |
-
}
|
2508 |
-
|
2509 |
-
$delivery_domain = $this->get_storage_provider()->get_url_domain( $as3cf_item->bucket(), $region, $expires );
|
2510 |
-
} else {
|
2511 |
-
$delivery_domain = AS3CF_Utils::sanitize_custom_domain( $delivery_domain );
|
2512 |
-
}
|
2513 |
-
|
2514 |
-
if ( ! is_null( $expires ) && $this->is_plugin_setup( true ) ) {
|
2515 |
-
try {
|
2516 |
-
$timestamp = time() + apply_filters( 'as3cf_expires', $expires );
|
2517 |
-
$url = $this->get_delivery_provider()->get_signed_url( $as3cf_item, $item_path, $delivery_domain, $scheme, $timestamp, $headers );
|
2518 |
-
|
2519 |
-
return apply_filters( 'as3cf_get_attachment_secure_url', $url, $as3cf_item, $post_id, $timestamp, $headers );
|
2520 |
-
} catch ( Exception $e ) {
|
2521 |
-
return new WP_Error( 'exception', $e->getMessage() );
|
2522 |
-
}
|
2523 |
-
} else {
|
2524 |
-
try {
|
2525 |
-
$url = $this->get_delivery_provider()->get_url( $as3cf_item, $item_path, $delivery_domain, $scheme, $headers );
|
2526 |
-
|
2527 |
-
return apply_filters( 'as3cf_get_attachment_url', $url, $as3cf_item, $post_id, $expires, $headers );
|
2528 |
-
} catch ( Exception $e ) {
|
2529 |
-
return new WP_Error( 'exception', $e->getMessage() );
|
2530 |
-
}
|
2531 |
-
}
|
2532 |
-
}
|
2533 |
-
|
2534 |
-
/**
|
2535 |
-
* Get attachment url
|
2536 |
-
*
|
2537 |
-
* @param string $url
|
2538 |
-
* @param int $post_id
|
2539 |
-
*
|
2540 |
-
* @return bool|mixed|WP_Error
|
2541 |
-
*/
|
2542 |
-
public function wp_get_attachment_url( $url, $post_id ) {
|
2543 |
-
if ( $this->plugin_compat->is_customizer_crop_action() ) {
|
2544 |
-
return $url;
|
2545 |
-
}
|
2546 |
-
|
2547 |
-
$new_url = $this->get_attachment_url( $post_id );
|
2548 |
-
|
2549 |
-
if ( false === $new_url ) {
|
2550 |
-
return $url;
|
2551 |
-
}
|
2552 |
-
|
2553 |
-
$new_url = apply_filters( 'wps3_get_attachment_url', $new_url, $post_id, $this ); // Old naming convention, will be deprecated soon
|
2554 |
-
$new_url = apply_filters( 'as3cf_wp_get_attachment_url', $new_url, $post_id );
|
2555 |
-
|
2556 |
-
return $new_url;
|
2557 |
-
}
|
2558 |
-
|
2559 |
-
/**
|
2560 |
-
* Filters the list of attachment image attributes.
|
2561 |
-
*
|
2562 |
-
* @param array $attr Attributes for the image markup.
|
2563 |
-
* @param WP_Post $attachment Image attachment post.
|
2564 |
-
* @param string|array $size Requested size. Image size or array of width and height values (in that order).
|
2565 |
-
*
|
2566 |
-
* @return array
|
2567 |
-
*/
|
2568 |
-
public function wp_get_attachment_image_attributes( $attr, $attachment, $size ) {
|
2569 |
-
if ( ! ( $as3cf_item = $this->is_attachment_served_by_provider( $attachment->ID ) ) ) {
|
2570 |
-
return $attr;
|
2571 |
-
}
|
2572 |
-
|
2573 |
-
$size = AS3CF_Utils::maybe_convert_size_to_string( $attachment->ID, $size );
|
2574 |
-
|
2575 |
-
// image_downsize incorrectly substitutes size filename into full URL for src attribute instead of clobbering.
|
2576 |
-
// So we need to fix up the src attribute if a size is being used.
|
2577 |
-
if ( ! empty( $size ) && ! empty( $attr['src'] ) ) {
|
2578 |
-
$attr['src'] = $this->get_attachment_provider_url( $attachment->ID, $as3cf_item, null, $size );
|
2579 |
-
}
|
2580 |
-
|
2581 |
-
/**
|
2582 |
-
* Filtered list of attachment image attributes.
|
2583 |
-
*
|
2584 |
-
* @param array $attr Attributes for the image markup.
|
2585 |
-
* @param WP_Post $attachment Image attachment post.
|
2586 |
-
* @param string $size Requested size.
|
2587 |
-
* @param Media_Library_Item $as3cf_item
|
2588 |
-
*/
|
2589 |
-
return apply_filters( 'as3cf_wp_get_attachment_image_attributes', $attr, $attachment, $size, $as3cf_item );
|
2590 |
-
}
|
2591 |
-
|
2592 |
-
/**
|
2593 |
-
* Maybe encode attachment URLs when retrieving the image tag
|
2594 |
-
*
|
2595 |
-
* @param string $html
|
2596 |
-
* @param int $id
|
2597 |
-
* @param string $alt
|
2598 |
-
* @param string $title
|
2599 |
-
* @param string $align
|
2600 |
-
* @param string $size
|
2601 |
-
*
|
2602 |
-
* @return string
|
2603 |
-
*/
|
2604 |
-
public function maybe_encode_get_image_tag( $html, $id, $alt, $title, $align, $size ) {
|
2605 |
-
if ( ! ( $as3cf_item = $this->is_attachment_served_by_provider( $id ) ) ) {
|
2606 |
-
// Not served by provider, return
|
2607 |
-
return $html;
|
2608 |
-
}
|
2609 |
-
|
2610 |
-
if ( ! is_string( $html ) ) {
|
2611 |
-
return $html;
|
2612 |
-
}
|
2613 |
-
|
2614 |
-
preg_match( '@\ssrc=[\'\"]([^\'\"]*)[\'\"]@', $html, $matches );
|
2615 |
-
|
2616 |
-
if ( ! isset( $matches[1] ) ) {
|
2617 |
-
// Can't establish img src
|
2618 |
-
return $html;
|
2619 |
-
}
|
2620 |
-
|
2621 |
-
$img_src = $matches[1];
|
2622 |
-
$new_img_src = $this->maybe_sign_intermediate_size( $img_src, $id, $size, $as3cf_item );
|
2623 |
-
$new_img_src = AS3CF_Utils::encode_filename_in_path( $new_img_src );
|
2624 |
-
|
2625 |
-
return str_replace( $img_src, $new_img_src, $html );
|
2626 |
-
}
|
2627 |
-
|
2628 |
-
/**
|
2629 |
-
* Maybe encode URLs for images that represent an attachment
|
2630 |
-
*
|
2631 |
-
* @param array|bool $image
|
2632 |
-
* @param int $attachment_id
|
2633 |
-
* @param string|array $size
|
2634 |
-
* @param bool $icon
|
2635 |
-
*
|
2636 |
-
* @return array
|
2637 |
-
*/
|
2638 |
-
public function maybe_encode_wp_get_attachment_image_src( $image, $attachment_id, $size, $icon ) {
|
2639 |
-
if ( ! ( $as3cf_item = $this->is_attachment_served_by_provider( $attachment_id ) ) ) {
|
2640 |
-
// Not served by provider, return
|
2641 |
-
return $image;
|
2642 |
-
}
|
2643 |
-
|
2644 |
-
if ( isset( $image[0] ) ) {
|
2645 |
-
$url = $this->maybe_sign_intermediate_size( $image[0], $attachment_id, $size, $as3cf_item );
|
2646 |
-
$url = AS3CF_Utils::encode_filename_in_path( $url );
|
2647 |
-
|
2648 |
-
$image[0] = $url;
|
2649 |
-
}
|
2650 |
-
|
2651 |
-
return $image;
|
2652 |
-
}
|
2653 |
-
|
2654 |
-
/**
|
2655 |
-
* Maybe encode URLs when outputting attachments in the media grid
|
2656 |
-
*
|
2657 |
-
* @param array $response
|
2658 |
-
* @param int|object $attachment
|
2659 |
-
* @param array $meta
|
2660 |
-
*
|
2661 |
-
* @return array
|
2662 |
-
*/
|
2663 |
-
public function maybe_encode_wp_prepare_attachment_for_js( $response, $attachment, $meta ) {
|
2664 |
-
if ( ! ( $as3cf_item = $this->is_attachment_served_by_provider( $attachment->ID ) ) ) {
|
2665 |
-
// Not served by provider, return
|
2666 |
-
return $response;
|
2667 |
-
}
|
2668 |
-
|
2669 |
-
if ( isset( $response['url'] ) ) {
|
2670 |
-
$response['url'] = AS3CF_Utils::encode_filename_in_path( $response['url'] );
|
2671 |
-
}
|
2672 |
-
|
2673 |
-
if ( isset( $response['sizes'] ) && is_array( $response['sizes'] ) ) {
|
2674 |
-
foreach ( $response['sizes'] as $size => $value ) {
|
2675 |
-
$url = $this->maybe_sign_intermediate_size( $value['url'], $attachment->ID, $size, $as3cf_item, true );
|
2676 |
-
$url = AS3CF_Utils::encode_filename_in_path( $url );
|
2677 |
-
|
2678 |
-
$response['sizes'][ $size ]['url'] = $url;
|
2679 |
-
}
|
2680 |
-
}
|
2681 |
-
|
2682 |
-
return $response;
|
2683 |
-
}
|
2684 |
-
|
2685 |
-
/**
|
2686 |
-
* Maybe encode URLs when retrieving intermediate sizes.
|
2687 |
-
*
|
2688 |
-
* @param array $data
|
2689 |
-
* @param int $post_id
|
2690 |
-
* @param string|array $size
|
2691 |
-
*
|
2692 |
-
* @return array
|
2693 |
-
*/
|
2694 |
-
public function maybe_encode_image_get_intermediate_size( $data, $post_id, $size ) {
|
2695 |
-
if ( ! ( $as3cf_item = $this->is_attachment_served_by_provider( $post_id ) ) ) {
|
2696 |
-
// Not served by provider, return
|
2697 |
-
return $data;
|
2698 |
-
}
|
2699 |
-
|
2700 |
-
if ( isset( $data['url'] ) ) {
|
2701 |
-
$url = $this->maybe_sign_intermediate_size( $data['url'], $post_id, $size, $as3cf_item );
|
2702 |
-
$url = AS3CF_Utils::encode_filename_in_path( $url );
|
2703 |
-
|
2704 |
-
$data['url'] = $url;
|
2705 |
-
}
|
2706 |
-
|
2707 |
-
return $data;
|
2708 |
-
}
|
2709 |
-
|
2710 |
-
/**
|
2711 |
-
* Sign intermediate size.
|
2712 |
-
*
|
2713 |
-
* @param string $url
|
2714 |
-
* @param int $attachment_id
|
2715 |
-
* @param string|array $size
|
2716 |
-
* @param bool|Media_Library_Item $as3cf_item
|
2717 |
-
* @param bool $force_rewrite If size not signed, make sure correct URL is being used anyway.
|
2718 |
-
*
|
2719 |
-
* @return string|WP_Error
|
2720 |
-
*/
|
2721 |
-
protected function maybe_sign_intermediate_size( $url, $attachment_id, $size, $as3cf_item = false, $force_rewrite = false ) {
|
2722 |
-
if ( ! $as3cf_item ) {
|
2723 |
-
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
2724 |
-
}
|
2725 |
-
|
2726 |
-
$size = AS3CF_Utils::maybe_convert_size_to_string( $attachment_id, $size );
|
2727 |
-
|
2728 |
-
if ( $force_rewrite || $as3cf_item->is_private_size( $size ) ) {
|
2729 |
-
// Private file, add AWS signature if required
|
2730 |
-
return $this->get_attachment_provider_url( $attachment_id, $as3cf_item, null, $size );
|
2731 |
-
}
|
2732 |
-
|
2733 |
-
return $url;
|
2734 |
-
}
|
2735 |
|
2736 |
/**
|
2737 |
* Is attachment served by provider.
|
@@ -2744,91 +1467,34 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
2744 |
*
|
2745 |
* @return bool|Media_Library_Item
|
2746 |
*/
|
2747 |
-
public function is_attachment_served_by_provider( $attachment_id, $skip_rewrite_check = false, $skip_current_provider_check = false, Storage_Provider $provider = null, $check_is_verified = false ) {
|
2748 |
-
if ( ! $skip_rewrite_check && ! $this->get_setting( 'serve-from-s3' ) ) {
|
2749 |
-
// Not serving provider URLs
|
2750 |
-
return false;
|
2751 |
-
}
|
2752 |
-
|
2753 |
-
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
2754 |
-
|
2755 |
-
if ( ! $as3cf_item ) {
|
2756 |
-
// File not uploaded to a provider
|
2757 |
-
return false;
|
2758 |
-
}
|
2759 |
-
|
2760 |
-
if ( ! $skip_rewrite_check && ! empty( $check_is_verified ) && ! $as3cf_item->is_verified() ) {
|
2761 |
-
// Offload not verified, treat as not offloaded.
|
2762 |
-
return false;
|
2763 |
-
}
|
2764 |
-
|
2765 |
-
if ( ! $skip_current_provider_check && empty( $provider ) ) {
|
2766 |
-
$provider = $this->get_storage_provider();
|
2767 |
-
}
|
2768 |
-
|
2769 |
-
if ( ! empty( $provider ) && $provider::get_provider_key_name() !== $as3cf_item->provider() ) {
|
2770 |
-
// File not uploaded to required provider
|
2771 |
-
return false;
|
2772 |
-
}
|
2773 |
-
|
2774 |
-
return $as3cf_item;
|
2775 |
-
}
|
2776 |
-
|
2777 |
-
/**
|
2778 |
-
* Allow processes to update the file on provider via update_attached_file()
|
2779 |
-
*
|
2780 |
-
* @param string $file
|
2781 |
-
* @param int $attachment_id
|
2782 |
-
*
|
2783 |
-
* @return string
|
2784 |
-
*/
|
2785 |
-
function update_attached_file( $file, $attachment_id ) {
|
2786 |
-
if ( ! $this->is_plugin_setup( true ) ) {
|
2787 |
-
return $file;
|
2788 |
}
|
2789 |
|
2790 |
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
2791 |
|
2792 |
if ( ! $as3cf_item ) {
|
2793 |
-
|
|
|
2794 |
}
|
2795 |
|
2796 |
-
|
2797 |
-
|
2798 |
-
|
2799 |
-
}
|
2800 |
-
|
2801 |
-
/**
|
2802 |
-
* Return the provider URL when the local file is missing
|
2803 |
-
* unless we know who the calling process is and we are happy
|
2804 |
-
* to copy the file back to the server to be used.
|
2805 |
-
*
|
2806 |
-
* @handles get_attached_file
|
2807 |
-
* @handles wp_get_original_image_path
|
2808 |
-
*
|
2809 |
-
* @param string $file
|
2810 |
-
* @param int $attachment_id
|
2811 |
-
*
|
2812 |
-
* @return string
|
2813 |
-
*/
|
2814 |
-
function get_attached_file( $file, $attachment_id ) {
|
2815 |
-
$as3cf_item = $this->is_attachment_served_by_provider( $attachment_id );
|
2816 |
-
|
2817 |
-
if ( file_exists( $file ) || ! $as3cf_item ) {
|
2818 |
-
if ( $as3cf_item ) {
|
2819 |
-
// Although we have a local file, give filter implementors a chance to override or copy back siblings.
|
2820 |
-
return apply_filters( 'as3cf_get_attached_file_noop', $file, $file, $attachment_id, $as3cf_item );
|
2821 |
-
} else {
|
2822 |
-
return $file;
|
2823 |
-
}
|
2824 |
}
|
2825 |
|
2826 |
-
$
|
|
|
|
|
2827 |
|
2828 |
-
|
2829 |
-
|
|
|
|
|
2830 |
|
2831 |
-
return $
|
2832 |
}
|
2833 |
|
2834 |
/**
|
@@ -3068,7 +1734,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
3068 |
/**
|
3069 |
* Add the settings page to the top-level AWS menu item for backwards compatibility.
|
3070 |
*
|
3071 |
-
* @param
|
3072 |
*/
|
3073 |
public function aws_admin_menu( $aws ) {
|
3074 |
$aws->add_page(
|
@@ -3283,7 +1949,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
3283 |
return self::$buckets_check[ $bucket ];
|
3284 |
}
|
3285 |
|
3286 |
-
$key = $this->
|
3287 |
$file_contents = __( 'This is a test file to check if the user has write permission to the bucket. Delete me if found.', 'amazon-s3-and-cloudfront' );
|
3288 |
|
3289 |
$can_write = $this->get_provider_client( $region, true )->can_write( $bucket, $key, $file_contents );
|
@@ -3301,6 +1967,28 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
3301 |
return $can_write;
|
3302 |
}
|
3303 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3304 |
/**
|
3305 |
* Render error messages in a view for bucket permission and access issues
|
3306 |
*
|
@@ -4010,10 +2698,11 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
4010 |
* year month subdirectory setting and just uses S3 setting
|
4011 |
*
|
4012 |
* @param string $time
|
|
|
4013 |
*
|
4014 |
* @return string
|
4015 |
*/
|
4016 |
-
function get_dynamic_prefix( $time = null ) {
|
4017 |
$prefix = '';
|
4018 |
$subdir = '';
|
4019 |
|
@@ -4056,7 +2745,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
4056 |
}
|
4057 |
}
|
4058 |
|
4059 |
-
if ( $this->get_setting( 'use-yearmonth-folders' ) ) {
|
4060 |
$subdir = $this->get_year_month_directory_name( $time );
|
4061 |
$prefix .= $subdir;
|
4062 |
}
|
@@ -4153,9 +2842,9 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
4153 |
* @param Media_Library_Item $as3cf_item
|
4154 |
* @param string|null $size
|
4155 |
*/
|
4156 |
-
function make_acl_admin_notice( Media_Library_Item $as3cf_item, $size = null ) {
|
4157 |
$filename = wp_basename( $as3cf_item->path( $size ) );
|
4158 |
-
$acl = $as3cf_item->
|
4159 |
$acl_name = $this->get_acl_display_name( $acl );
|
4160 |
$text = sprintf( __( '<strong>WP Offload Media</strong> — The file %s has been given %s permissions in the bucket.', 'amazon-s3-and-cloudfront' ), "<strong>{$filename}</strong>", "<strong>{$acl_name}</strong>" );
|
4161 |
|
@@ -5043,7 +3732,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
5043 |
* Used to give a realistic total of storage space used on a Multisite subsite,
|
5044 |
* when there have been attachments uploaded to S3 but removed from server
|
5045 |
*
|
5046 |
-
* @param $space_used
|
5047 |
*
|
5048 |
* @return float|int
|
5049 |
*/
|
@@ -5133,10 +3822,12 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
5133 |
foreach ( $table_prefixes as $blog_id => $table_prefix ) {
|
5134 |
$this->switch_to_blog( $blog_id );
|
5135 |
|
5136 |
-
|
5137 |
-
|
5138 |
-
|
5139 |
-
|
|
|
|
|
5140 |
|
5141 |
$this->restore_current_blog();
|
5142 |
}
|
@@ -5295,17 +3986,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
5295 |
return filter_input( $type, $variable, $filter, $options );
|
5296 |
}
|
5297 |
|
5298 |
-
/**
|
5299 |
-
* Helper function for terminating script execution. Easily testable.
|
5300 |
-
*
|
5301 |
-
* @param int|string $exit_code
|
5302 |
-
*
|
5303 |
-
* @return void
|
5304 |
-
*/
|
5305 |
-
public function _exit( $exit_code = 0 ) {
|
5306 |
-
exit( $exit_code );
|
5307 |
-
}
|
5308 |
-
|
5309 |
/**
|
5310 |
* Upgrade the 'virtual host' / 'bucket as domain' setting to the
|
5311 |
* new CloudFront / Domain setting
|
@@ -5371,210 +4051,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
5371 |
return $path;
|
5372 |
}
|
5373 |
|
5374 |
-
/**
|
5375 |
-
* Add the S3 meta box to the attachment screen
|
5376 |
-
*/
|
5377 |
-
public function attachment_provider_meta_box() {
|
5378 |
-
add_meta_box(
|
5379 |
-
's3-actions',
|
5380 |
-
__( 'Offload', 'amazon-s3-and-cloudfront' ),
|
5381 |
-
array( $this, 'attachment_provider_actions_meta_box' ),
|
5382 |
-
'attachment',
|
5383 |
-
'side',
|
5384 |
-
'core'
|
5385 |
-
);
|
5386 |
-
}
|
5387 |
-
|
5388 |
-
/**
|
5389 |
-
* Check we can do the media actions
|
5390 |
-
*
|
5391 |
-
* @return bool
|
5392 |
-
*/
|
5393 |
-
public function verify_media_actions() {
|
5394 |
-
return false;
|
5395 |
-
}
|
5396 |
-
|
5397 |
-
/**
|
5398 |
-
* Get a list of available media actions which can be performed according to plugin and user capability requirements.
|
5399 |
-
*
|
5400 |
-
* @param string|null $scope
|
5401 |
-
*
|
5402 |
-
* @return array
|
5403 |
-
*/
|
5404 |
-
public function get_available_media_actions( $scope = '' ) {
|
5405 |
-
return array();
|
5406 |
-
}
|
5407 |
-
|
5408 |
-
/**
|
5409 |
-
* Render the S3 attachment meta box
|
5410 |
-
*/
|
5411 |
-
public function attachment_provider_actions_meta_box() {
|
5412 |
-
global $post;
|
5413 |
-
$file = get_attached_file( $post->ID, true );
|
5414 |
-
|
5415 |
-
$args = array(
|
5416 |
-
'provider_object' => $this->get_formatted_provider_info( $post->ID ),
|
5417 |
-
'post' => $post,
|
5418 |
-
'local_file_exists' => file_exists( $file ),
|
5419 |
-
'available_actions' => $this->get_available_media_actions( 'singular' ),
|
5420 |
-
'sendback' => 'post.php?post=' . $post->ID . '&action=edit',
|
5421 |
-
);
|
5422 |
-
|
5423 |
-
$this->render_view( 'attachment-metabox', $args );
|
5424 |
-
}
|
5425 |
-
|
5426 |
-
/**
|
5427 |
-
* Get ACL value string.
|
5428 |
-
*
|
5429 |
-
* @param array $acl
|
5430 |
-
* @param int $post_id
|
5431 |
-
*
|
5432 |
-
* @return string
|
5433 |
-
*/
|
5434 |
-
protected function get_acl_value_string( $acl, $post_id ) {
|
5435 |
-
return $acl['name'];
|
5436 |
-
}
|
5437 |
-
|
5438 |
-
/**
|
5439 |
-
* Return a formatted provider info array with display friendly defaults
|
5440 |
-
*
|
5441 |
-
* @param int $id
|
5442 |
-
*
|
5443 |
-
* @return bool|array
|
5444 |
-
*/
|
5445 |
-
public function get_formatted_provider_info( $id ) {
|
5446 |
-
$as3cf_item = Media_Library_Item::get_by_source_id( $id );
|
5447 |
-
|
5448 |
-
if ( ! $as3cf_item ) {
|
5449 |
-
return false;
|
5450 |
-
}
|
5451 |
-
|
5452 |
-
$provider_object = $as3cf_item->key_values();
|
5453 |
-
|
5454 |
-
// Backwards compatibility.
|
5455 |
-
$provider_object['key'] = $provider_object['path'];
|
5456 |
-
$provider_object['url'] = $this->get_attachment_provider_url( $id, $as3cf_item );
|
5457 |
-
|
5458 |
-
$acl = $as3cf_item->is_private() ? $this->get_storage_provider()->get_private_acl() : $this->get_storage_provider()->get_default_acl();
|
5459 |
-
$acl_info = array(
|
5460 |
-
'acl' => $acl,
|
5461 |
-
'name' => $this->get_acl_display_name( $acl ),
|
5462 |
-
'title' => $this->get_media_action_strings( 'change_to_private' ),
|
5463 |
-
);
|
5464 |
-
|
5465 |
-
if ( $as3cf_item->is_private() ) {
|
5466 |
-
$acl_info['title'] = $this->get_media_action_strings( 'change_to_public' );
|
5467 |
-
}
|
5468 |
-
|
5469 |
-
$provider_object['acl'] = $acl_info;
|
5470 |
-
$provider_object['region'] = $this->get_storage_provider()->get_region_name( $provider_object['region'] );
|
5471 |
-
$provider_object['provider_name'] = $this->get_provider_service_name( $provider_object['provider'] );
|
5472 |
-
|
5473 |
-
return $provider_object;
|
5474 |
-
}
|
5475 |
-
|
5476 |
-
/**
|
5477 |
-
* Get all strings or a specific string used for the media actions
|
5478 |
-
*
|
5479 |
-
* @param null|string $string
|
5480 |
-
*
|
5481 |
-
* @return array|string
|
5482 |
-
*/
|
5483 |
-
public function get_media_action_strings( $string = null ) {
|
5484 |
-
$not_verified_value = __( 'No', 'amazon-s3-and-cloudfront' );
|
5485 |
-
$not_verified_value .= ' ';
|
5486 |
-
$not_verified_value .= $this->more_info_link( '/wp-offload-media/doc/add-metadata-tool/', 'os3+attachment+metabox', 'analyze-and-repair', 'More Info', '(', ')' );
|
5487 |
-
|
5488 |
-
$strings = apply_filters( 'as3cf_media_action_strings', array(
|
5489 |
-
'provider' => _x( 'Storage Provider', 'Storage provider key name', 'amazon-s3-and-cloudfront' ),
|
5490 |
-
'provider_name' => _x( 'Storage Provider', 'Storage provider name', 'amazon-s3-and-cloudfront' ),
|
5491 |
-
'bucket' => _x( 'Bucket', 'Bucket name', 'amazon-s3-and-cloudfront' ),
|
5492 |
-
'key' => _x( 'Path', 'Path to file in bucket', 'amazon-s3-and-cloudfront' ),
|
5493 |
-
'region' => _x( 'Region', 'Location of bucket', 'amazon-s3-and-cloudfront' ),
|
5494 |
-
'acl' => _x( 'Access', 'Access control list of the file in bucket', 'amazon-s3-and-cloudfront' ),
|
5495 |
-
'url' => __( 'URL', 'amazon-s3-and-cloudfront' ),
|
5496 |
-
'is_verified' => _x( 'Verified', 'Whether or not metadata has been verified', 'amazon-s3-and-cloudfront' ),
|
5497 |
-
'not_verified' => $not_verified_value,
|
5498 |
-
) );
|
5499 |
-
|
5500 |
-
if ( ! is_null( $string ) ) {
|
5501 |
-
return isset( $strings[ $string ] ) ? $strings[ $string ] : '';
|
5502 |
-
}
|
5503 |
-
|
5504 |
-
return $strings;
|
5505 |
-
}
|
5506 |
-
|
5507 |
-
/**
|
5508 |
-
* Load media assets.
|
5509 |
-
*/
|
5510 |
-
public function load_media_assets() {
|
5511 |
-
$this->enqueue_style( 'as3cf-media-styles', 'assets/css/media', array( 'as3cf-modal' ) );
|
5512 |
-
$this->enqueue_script( 'as3cf-media-script', 'assets/js/media', array(
|
5513 |
-
'jquery',
|
5514 |
-
'media-views',
|
5515 |
-
'media-grid',
|
5516 |
-
'wp-util',
|
5517 |
-
) );
|
5518 |
-
|
5519 |
-
wp_localize_script( 'as3cf-media-script', 'as3cf_media', array(
|
5520 |
-
'strings' => $this->get_media_action_strings(),
|
5521 |
-
'nonces' => array(
|
5522 |
-
'get_attachment_provider_details' => wp_create_nonce( 'get-attachment-s3-details' ),
|
5523 |
-
),
|
5524 |
-
) );
|
5525 |
-
}
|
5526 |
-
|
5527 |
-
/**
|
5528 |
-
* Handle retrieving the provider details for attachment modals.
|
5529 |
-
*/
|
5530 |
-
public function ajax_get_attachment_provider_details() {
|
5531 |
-
if ( ! isset( $_POST['id'] ) ) {
|
5532 |
-
return;
|
5533 |
-
}
|
5534 |
-
|
5535 |
-
check_ajax_referer( 'get-attachment-s3-details', '_nonce' );
|
5536 |
-
|
5537 |
-
$id = intval( $_POST['id'] );
|
5538 |
-
|
5539 |
-
// get the actions available for the attachment
|
5540 |
-
$data = array(
|
5541 |
-
'links' => $this->add_media_row_actions( array(), $id ),
|
5542 |
-
'provider_object' => $this->get_formatted_provider_info( $id ),
|
5543 |
-
'acl_toggle' => $this->verify_media_actions() && $this->is_attachment_served_by_provider( $id, true ),
|
5544 |
-
);
|
5545 |
-
|
5546 |
-
wp_send_json_success( $data );
|
5547 |
-
}
|
5548 |
-
|
5549 |
-
/**
|
5550 |
-
* Conditionally adds copy, remove and download S3 action links for an
|
5551 |
-
* attachment on the Media library list view
|
5552 |
-
*
|
5553 |
-
* @param array $actions
|
5554 |
-
* @param WP_Post|int $post
|
5555 |
-
*
|
5556 |
-
* @return array
|
5557 |
-
*/
|
5558 |
-
function add_media_row_actions( array $actions, $post ) {
|
5559 |
-
return $actions;
|
5560 |
-
}
|
5561 |
-
|
5562 |
-
/**
|
5563 |
-
* Load the attachment assets only when editing an attachment
|
5564 |
-
*
|
5565 |
-
* @param $hook_suffix
|
5566 |
-
*/
|
5567 |
-
public function load_attachment_assets( $hook_suffix ) {
|
5568 |
-
global $post;
|
5569 |
-
if ( 'post.php' !== $hook_suffix || 'attachment' !== $post->post_type ) {
|
5570 |
-
return;
|
5571 |
-
}
|
5572 |
-
|
5573 |
-
$this->enqueue_style( 'as3cf-pro-attachment-styles', 'assets/css/attachment', array( 'as3cf-modal' ) );
|
5574 |
-
|
5575 |
-
do_action( 'as3cf_load_attachment_assets' );
|
5576 |
-
}
|
5577 |
-
|
5578 |
/**
|
5579 |
* Maybe remove query string from URL.
|
5580 |
*
|
@@ -5588,40 +4064,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
5588 |
return reset( $parts );
|
5589 |
}
|
5590 |
|
5591 |
-
/**
|
5592 |
-
* Has the given attachment been uploaded by this instance?
|
5593 |
-
*
|
5594 |
-
* @param int $attachment_id
|
5595 |
-
*
|
5596 |
-
* @return bool
|
5597 |
-
*/
|
5598 |
-
public function attachment_just_uploaded( $attachment_id ) {
|
5599 |
-
if ( is_int( $attachment_id ) && in_array( $attachment_id, $this->uploaded_post_ids ) ) {
|
5600 |
-
return true;
|
5601 |
-
}
|
5602 |
-
|
5603 |
-
return false;
|
5604 |
-
}
|
5605 |
-
|
5606 |
-
/**
|
5607 |
-
* Filters the audio & video shortcodes output to remove "&_=NN" params from source.src as it breaks signed URLs.
|
5608 |
-
*
|
5609 |
-
* @param string $html Shortcode HTML output.
|
5610 |
-
* @param array $atts Array of shortcode attributes.
|
5611 |
-
* @param string $media Media file.
|
5612 |
-
* @param int $post_id Post ID.
|
5613 |
-
* @param string $library Media library used for the shortcode.
|
5614 |
-
*
|
5615 |
-
* @return string
|
5616 |
-
*
|
5617 |
-
* Note: Depends on 30377.4.diff from https://core.trac.wordpress.org/ticket/30377
|
5618 |
-
*/
|
5619 |
-
public function wp_media_shortcode( $html, $atts, $media, $post_id, $library ) {
|
5620 |
-
$html = preg_replace( '/&_=[0-9]+/', '', $html );
|
5621 |
-
|
5622 |
-
return $html;
|
5623 |
-
}
|
5624 |
-
|
5625 |
/**
|
5626 |
* Ensure local URL is correct for multisite's non-primary subsites.
|
5627 |
*
|
@@ -5662,7 +4104,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
5662 |
$acl = $this->get_storage_provider()->get_default_acl();
|
5663 |
|
5664 |
if ( ! empty( $as3cf_item ) ) {
|
5665 |
-
$acl = $as3cf_item->
|
5666 |
}
|
5667 |
}
|
5668 |
|
@@ -5672,14 +4114,15 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
5672 |
/**
|
5673 |
* Are ACLs in use for intermediate size on bucket?
|
5674 |
*
|
5675 |
-
* @param int
|
5676 |
-
* @param string
|
5677 |
-
* @param string
|
5678 |
-
* @param
|
5679 |
*
|
5680 |
* @return bool
|
5681 |
*/
|
5682 |
-
public function use_acl_for_intermediate_size( $attachment_id, $size, $bucket = null,
|
|
|
5683 |
if ( empty( $as3cf_item ) ) {
|
5684 |
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
5685 |
}
|
@@ -5696,7 +4139,7 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
5696 |
$use_private_prefix = apply_filters( 'as3cf_enable_signed_urls_for_intermediate_size', $this->private_prefix_enabled(), $attachment_id, $size, $bucket, $as3cf_item );
|
5697 |
|
5698 |
// If signed custom URLs are in play, and we have a private object, usually you can not use ACLs.
|
5699 |
-
if ( $use_acl && $use_private_prefix && ! empty( $as3cf_item ) && $as3cf_item->
|
5700 |
$use_acl = false;
|
5701 |
}
|
5702 |
|
@@ -5704,25 +4147,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
5704 |
return apply_filters( 'as3cf_use_acl_for_intermediate_size', $use_acl, $attachment_id, $size, $bucket, $as3cf_item );
|
5705 |
}
|
5706 |
|
5707 |
-
/**
|
5708 |
-
* Consolidate an array of WP_Errors into a single WP_Error object.
|
5709 |
-
*
|
5710 |
-
* @param array $upload_errors
|
5711 |
-
*
|
5712 |
-
* @return WP_Error
|
5713 |
-
*/
|
5714 |
-
protected function consolidate_upload_errors( $upload_errors ) {
|
5715 |
-
$errors = new WP_Error;
|
5716 |
-
|
5717 |
-
foreach ( $upload_errors as $error ) {
|
5718 |
-
|
5719 |
-
/* @var WP_Error $error */
|
5720 |
-
$errors->add( $error->get_error_code(), $error->get_error_message() );
|
5721 |
-
}
|
5722 |
-
|
5723 |
-
return $errors;
|
5724 |
-
}
|
5725 |
-
|
5726 |
/**
|
5727 |
* Get all defined addons that use this plugin
|
5728 |
*
|
@@ -5838,46 +4262,6 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
5838 |
$this->render_view( 'notice', $notice );
|
5839 |
}
|
5840 |
|
5841 |
-
/**
|
5842 |
-
* Remove 'filesize' from attachment's metatdata if appropriate, also our total filesize record.
|
5843 |
-
*
|
5844 |
-
* @param integer $post_id Attachment's post_id.
|
5845 |
-
* @param array $data Attachment's metadata.
|
5846 |
-
* @param bool $update_metadata Update the metadata record now? Defaults to true.
|
5847 |
-
*
|
5848 |
-
* @return array Attachment's cleaned up metadata.
|
5849 |
-
*/
|
5850 |
-
public function maybe_cleanup_filesize_metadata( $post_id, $data, $update_metadata = true ) {
|
5851 |
-
if ( ! is_int( $post_id ) || empty( $post_id ) || empty( $data ) || ! is_array( $data ) ) {
|
5852 |
-
return $data;
|
5853 |
-
}
|
5854 |
-
|
5855 |
-
/*
|
5856 |
-
* Audio and video have a filesize added to metadata by default, but images and anything else don't.
|
5857 |
-
* Note: Could have used `wp_generate_attachment_metadata` here to test whether default metadata has 'filesize',
|
5858 |
-
* 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.
|
5859 |
-
*/
|
5860 |
-
if (
|
5861 |
-
empty( $data['mime_type'] ) ||
|
5862 |
-
0 === strpos( $data['mime_type'], 'image/' ) ||
|
5863 |
-
! ( 0 === strpos( $data['mime_type'], 'audio/' ) || 0 === strpos( $data['mime_type'], 'video/' ) )
|
5864 |
-
) {
|
5865 |
-
unset( $data['filesize'] );
|
5866 |
-
}
|
5867 |
-
|
5868 |
-
if ( $update_metadata ) {
|
5869 |
-
if ( empty( $data ) ) {
|
5870 |
-
delete_post_meta( $post_id, '_wp_attachment_metadata' );
|
5871 |
-
} else {
|
5872 |
-
update_post_meta( $post_id, '_wp_attachment_metadata', $data );
|
5873 |
-
}
|
5874 |
-
}
|
5875 |
-
|
5876 |
-
delete_post_meta( $post_id, 'as3cf_filesize_total' );
|
5877 |
-
|
5878 |
-
return $data;
|
5879 |
-
}
|
5880 |
-
|
5881 |
/**
|
5882 |
* Is there an upgrade in progress?
|
5883 |
*
|
@@ -5903,4 +4287,87 @@ class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
|
5903 |
|
5904 |
return false;
|
5905 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5906 |
}
|
1 |
<?php
|
2 |
|
3 |
+
use DeliciousBrains\WP_Offload_Media\Integrations\Core as Core_Integration;
|
4 |
+
use DeliciousBrains\WP_Offload_Media\Integrations\Integration_Manager;
|
5 |
+
use DeliciousBrains\WP_Offload_Media\Integrations\Media_Library as Media_Library_Integration;
|
6 |
+
use DeliciousBrains\WP_Offload_Media\Items\Download_Handler;
|
7 |
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
8 |
+
use DeliciousBrains\WP_Offload_Media\Items\Item_Handler;
|
9 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
10 |
+
use DeliciousBrains\WP_Offload_Media\Items\Remove_Local_Handler;
|
11 |
+
use DeliciousBrains\WP_Offload_Media\Items\Remove_Provider_Handler;
|
12 |
+
use DeliciousBrains\WP_Offload_Media\Items\Upload_Handler;
|
13 |
use DeliciousBrains\WP_Offload_Media\Providers\Delivery\Another_CDN;
|
14 |
use DeliciousBrains\WP_Offload_Media\Providers\Delivery\AWS_CloudFront;
|
15 |
use DeliciousBrains\WP_Offload_Media\Providers\Delivery\Cloudflare;
|
31 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_EDD_Replace_URLs;
|
32 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_File_Sizes;
|
33 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Filter_Post_Excerpt;
|
34 |
+
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Item_Extra_Data;
|
35 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Items_Table;
|
36 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Meta_WP_Error;
|
37 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Region_Meta;
|
38 |
+
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_Tools_Errors;
|
39 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Upgrade_WPOS3_To_AS3CF;
|
40 |
|
41 |
class Amazon_S3_And_CloudFront extends AS3CF_Plugin_Base {
|
130 |
*/
|
131 |
protected static $delivery_provider_classes = array();
|
132 |
|
133 |
+
/**
|
134 |
+
* @var Item_Handler[]
|
135 |
+
*/
|
136 |
+
protected $item_handlers = array();
|
137 |
+
|
138 |
/**
|
139 |
* @var AS3CF_Plugin_Compatibility
|
140 |
*/
|
152 |
'WPOS3_SETTINGS',
|
153 |
);
|
154 |
|
155 |
+
/**
|
156 |
+
* Class map to determine Item subclass per item source type
|
157 |
+
*
|
158 |
+
* @var string[]
|
159 |
+
*/
|
160 |
+
private $source_type_classes = array(
|
161 |
+
'media-library' => 'DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item',
|
162 |
+
);
|
163 |
+
|
164 |
+
/**
|
165 |
+
* @var Integration_Manager
|
166 |
+
*/
|
167 |
+
protected $integration_manager;
|
168 |
+
|
169 |
+
const LATEST_UPGRADE_ROUTINE = 10;
|
170 |
|
171 |
/**
|
172 |
* @param string $plugin_file_path
|
174 |
*
|
175 |
* @throws Exception
|
176 |
*/
|
177 |
+
public function __construct( $plugin_file_path, $slug = null ) {
|
178 |
$this->plugin_slug = ( is_null( $slug ) ) ? 'amazon-s3-and-cloudfront' : $slug;
|
179 |
|
180 |
parent::__construct( $plugin_file_path );
|
191 |
*
|
192 |
* @throws Exception
|
193 |
*/
|
194 |
+
public function init( $plugin_file_path ) {
|
195 |
$this->plugin_title = __( 'Offload Media Lite', 'amazon-s3-and-cloudfront' );
|
196 |
$this->plugin_menu_title = __( 'Offload Media Lite', 'amazon-s3-and-cloudfront' );
|
197 |
|
215 |
Storage::get_provider_key_name() => 'DeliciousBrains\WP_Offload_Media\Providers\Delivery\Storage',
|
216 |
) );
|
217 |
|
|
|
|
|
218 |
$this->set_storage_provider();
|
219 |
$this->set_delivery_provider();
|
220 |
|
229 |
new Upgrade_Filter_Post_Excerpt( $this );
|
230 |
new Upgrade_WPOS3_To_AS3CF( $this );
|
231 |
new Upgrade_Items_Table( $this );
|
232 |
+
new Upgrade_Tools_Errors( $this );
|
233 |
+
new Upgrade_Item_Extra_Data( $this );
|
234 |
|
235 |
// Plugin setup
|
236 |
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
|
239 |
add_filter( 'plugin_action_links', array( $this, 'plugin_actions_settings_link' ), 10, 2 );
|
240 |
add_filter( 'network_admin_plugin_action_links', array( $this, 'plugin_actions_settings_link' ), 10, 2 );
|
241 |
add_filter( 'pre_get_space_used', array( $this, 'multisite_get_space_used' ) );
|
242 |
+
|
243 |
// display a notice when either lite or pro is automatically deactivated
|
244 |
add_action( 'pre_current_active_plugins', array( $this, 'plugin_deactivated_notice' ) );
|
245 |
add_action( 'as3cf_plugin_load', array( $this, 'remove_access_keys_if_constants_set' ) );
|
246 |
|
|
|
|
|
|
|
|
|
|
|
247 |
// UI AJAX
|
248 |
add_action( 'wp_ajax_as3cf-get-buckets', array( $this, 'ajax_get_buckets' ) );
|
249 |
add_action( 'wp_ajax_as3cf-get-url-preview', array( $this, 'ajax_get_url_preview' ) );
|
|
|
250 |
add_action( 'wp_ajax_as3cf-get-diagnostic-info', array( $this, 'ajax_get_diagnostic_info' ) );
|
251 |
|
252 |
+
// Enable integrations once everything has been initialized.
|
253 |
+
add_action( 'as3cf_init', array( $this, 'enable_integrations' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
254 |
|
255 |
// Listen for settings changes
|
256 |
if ( false !== static::settings_constant() ) {
|
276 |
$this->register_delivery_provider_assets();
|
277 |
}
|
278 |
|
279 |
+
/**
|
280 |
+
* Enable integrations.
|
281 |
+
*
|
282 |
+
* @param Amazon_S3_And_CloudFront $as3cf
|
283 |
+
*/
|
284 |
+
public function enable_integrations( $as3cf ) {
|
285 |
+
/**
|
286 |
+
* Filters which integrations to enable. To disable an integration
|
287 |
+
* implement this filter and unset all unwanted integrations from
|
288 |
+
* the array.
|
289 |
+
*
|
290 |
+
* @param array $integrations Associative array of integrations
|
291 |
+
*/
|
292 |
+
$integrations = apply_filters( 'as3cf_integrations', array(
|
293 |
+
'core' => new Core_Integration( $as3cf ),
|
294 |
+
'mlib' => new Media_Library_Integration( $as3cf ),
|
295 |
+
) );
|
296 |
+
|
297 |
+
$this->integration_manager = Integration_Manager::get_instance();
|
298 |
+
|
299 |
+
foreach ( $integrations as $integration_key => $integration ) {
|
300 |
+
$this->integration_manager->register_integration( $integration_key, $integration );
|
301 |
+
}
|
302 |
+
}
|
303 |
+
|
304 |
/**
|
305 |
* @return Storage_Provider
|
306 |
*/
|
453 |
return empty( $class ) ? __( 'Unknown', 'amazon-s3-and-cloudfront' ) : $class::get_provider_service_name();
|
454 |
}
|
455 |
|
456 |
+
/**
|
457 |
+
* Getter for the Integrations Manager instance
|
458 |
+
*
|
459 |
+
* @return Integration_Manager
|
460 |
+
*/
|
461 |
+
public function get_integration_manager() {
|
462 |
+
return $this->integration_manager;
|
463 |
+
}
|
464 |
+
|
465 |
/**
|
466 |
* Get the plugin title to be used in page headings
|
467 |
*
|
1090 |
*
|
1091 |
* @return array
|
1092 |
*/
|
1093 |
+
public function get_allowed_mime_types() {
|
1094 |
+
/**
|
1095 |
+
* Filters list of allowed mime types and file extensions for uploading
|
1096 |
+
*
|
1097 |
+
* @param array $types Mime types keyed by the file extension regex corresponding to those types.
|
1098 |
+
*/
|
1099 |
return apply_filters( 'as3cf_allowed_mime_types', get_allowed_mime_types() );
|
1100 |
}
|
1101 |
|
1173 |
*
|
1174 |
* @return string
|
1175 |
*/
|
1176 |
+
public function get_url_preview( $escape = true, $suffix = 'photo.jpg' ) {
|
1177 |
$as3cf_item = new Media_Library_Item(
|
1178 |
$this->get_storage_provider()->get_provider_key_name(),
|
1179 |
$this->get_setting( 'region' ),
|
1180 |
$this->get_setting( 'bucket' ),
|
1181 |
+
AS3CF_Utils::trailingslash_prefix( $this->get_simple_file_prefix() ) . $suffix,
|
1182 |
false,
|
1183 |
null,
|
1184 |
+
AS3CF_Utils::trailingslash_prefix( $this->get_simple_file_prefix() ) . $suffix
|
1185 |
);
|
1186 |
|
1187 |
+
$url = $as3cf_item->get_provider_url();
|
1188 |
|
1189 |
if ( is_wp_error( $url ) ) {
|
1190 |
return '';
|
1248 |
}
|
1249 |
|
1250 |
/**
|
1251 |
+
* Get the object versioning string prefix
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1252 |
*
|
1253 |
+
* @return string
|
1254 |
*/
|
1255 |
+
function get_object_version_string() {
|
1256 |
+
if ( $this->get_setting( 'use-yearmonth-folders' ) ) {
|
1257 |
+
$date_format = 'dHis';
|
1258 |
+
} else {
|
1259 |
+
$date_format = 'YmdHis';
|
1260 |
+
}
|
1261 |
|
1262 |
+
// Use current time so that object version is unique
|
1263 |
+
$time = current_time( 'timestamp' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1264 |
|
1265 |
+
$object_version = date( $date_format, $time ) . '/';
|
1266 |
+
$object_version = apply_filters( 'as3cf_get_object_version_string', $object_version );
|
1267 |
|
1268 |
+
return $object_version;
|
1269 |
}
|
1270 |
|
1271 |
/**
|
1272 |
+
* Does file exist
|
1273 |
*
|
1274 |
+
* @param string $filename
|
1275 |
+
* @param string $time
|
1276 |
+
*
|
1277 |
+
* @return bool
|
|
|
|
|
|
|
1278 |
*/
|
1279 |
+
function does_file_exist( $filename, $time ) {
|
1280 |
+
if ( $this->does_file_exist_local( $filename, $time ) ) {
|
1281 |
+
return true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1282 |
}
|
1283 |
|
1284 |
+
if ( ! $this->get_setting( 'object-versioning' ) && $this->does_file_exist_provider( $filename, $time ) ) {
|
1285 |
+
return true;
|
|
|
|
|
|
|
|
|
|
|
1286 |
}
|
1287 |
|
1288 |
+
return false;
|
|
|
1289 |
}
|
1290 |
|
1291 |
/**
|
1292 |
+
* Does file exist local
|
1293 |
+
*
|
1294 |
+
* @param string $filename
|
1295 |
+
* @param string $time
|
1296 |
*
|
1297 |
+
* @return bool
|
|
|
|
|
1298 |
*/
|
1299 |
+
function does_file_exist_local( $filename, $time ) {
|
1300 |
+
global $wpdb;
|
|
|
|
|
1301 |
|
1302 |
+
$path = wp_upload_dir( $time );
|
1303 |
+
$path = ltrim( $path['subdir'], '/' );
|
1304 |
|
1305 |
+
if ( '' !== $path ) {
|
1306 |
+
$path = trailingslashit( $path );
|
1307 |
}
|
1308 |
+
$file = $path . $filename;
|
1309 |
|
1310 |
+
// WordPress doesn't check its own basic record, so we will.
|
1311 |
+
$sql = $wpdb->prepare( "
|
1312 |
+
SELECT COUNT(*)
|
1313 |
+
FROM $wpdb->postmeta
|
1314 |
+
WHERE meta_key = %s
|
1315 |
+
AND meta_value = %s
|
1316 |
+
", '_wp_attached_file', $file );
|
1317 |
+
|
1318 |
+
if ( (bool) $wpdb->get_var( $sql ) ) {
|
1319 |
+
return true;
|
1320 |
}
|
1321 |
|
1322 |
+
// Check our records of local source path as it also covers original_image.
|
1323 |
+
if ( ! empty( Media_Library_Item::get_by_source_path( array( $file ), array(), true, true ) ) ) {
|
1324 |
+
return true;
|
1325 |
+
}
|
1326 |
|
1327 |
+
return false;
|
1328 |
}
|
1329 |
|
1330 |
/**
|
1331 |
+
* Does file exist provider
|
|
|
1332 |
*
|
1333 |
+
* @param string $filename
|
1334 |
+
* @param string $time
|
1335 |
*
|
1336 |
+
* @return bool
|
1337 |
* @throws Exception
|
1338 |
*/
|
1339 |
+
function does_file_exist_provider( $filename, $time ) {
|
1340 |
+
$bucket = $this->get_setting( 'bucket' );
|
1341 |
+
$region = $this->get_setting( 'region' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1342 |
|
1343 |
+
if ( is_wp_error( $region ) ) {
|
1344 |
+
return false;
|
|
|
|
|
1345 |
}
|
1346 |
|
1347 |
+
$provider_client = $this->get_provider_client( $region );
|
1348 |
+
$prefix = AS3CF_Utils::trailingslash_prefix( $this->get_object_prefix() );
|
1349 |
+
$prefix .= AS3CF_Utils::trailingslash_prefix( $this->get_dynamic_prefix( $time ) );
|
|
|
|
|
|
|
1350 |
|
1351 |
+
return $provider_client->does_object_exist( $bucket, $prefix . $filename );
|
1352 |
}
|
1353 |
|
1354 |
/**
|
1355 |
+
* Generate unique filename
|
1356 |
*
|
1357 |
+
* @param string $name
|
1358 |
+
* @param string $ext
|
1359 |
+
* @param string $time
|
|
|
|
|
|
|
1360 |
*
|
1361 |
+
* @return string
|
|
|
1362 |
*/
|
1363 |
+
function generate_unique_filename( $name, $ext, $time ) {
|
1364 |
+
$count = 1;
|
1365 |
+
$filename = $name . '-' . $count . $ext;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1366 |
|
1367 |
+
while ( $this->does_file_exist( $filename, $time ) ) {
|
1368 |
+
$count++;
|
1369 |
+
$filename = $name . '-' . $count . $ext;
|
1370 |
}
|
1371 |
|
1372 |
+
return $filename;
|
1373 |
+
}
|
|
|
1374 |
|
1375 |
+
/**
|
1376 |
+
* Check the plugin is correctly setup
|
1377 |
+
*
|
1378 |
+
* @param bool $with_credentials Do provider credentials need to be set up too? Defaults to false.
|
1379 |
+
*
|
1380 |
+
* @return bool
|
1381 |
+
*
|
1382 |
+
* TODO: Performance - cache / static var by param.
|
1383 |
+
*/
|
1384 |
+
function is_plugin_setup( $with_credentials = false ) {
|
1385 |
+
if ( $with_credentials && $this->get_storage_provider()->needs_access_keys() ) {
|
1386 |
+
// AWS not configured
|
1387 |
+
return false;
|
1388 |
}
|
1389 |
|
1390 |
+
if ( false === (bool) $this->get_setting( 'bucket' ) ) {
|
1391 |
+
// No bucket selected
|
1392 |
+
return false;
|
|
|
|
|
|
|
1393 |
}
|
1394 |
|
1395 |
+
if ( is_wp_error( $this->get_setting( 'region' ) ) ) {
|
1396 |
+
// Region error when retrieving bucket location
|
1397 |
+
return false;
|
1398 |
}
|
1399 |
|
1400 |
+
// All good, let's do this
|
1401 |
+
return true;
|
1402 |
+
}
|
1403 |
|
1404 |
+
/**
|
1405 |
+
* Return the scheme to be used in URLs
|
1406 |
+
*
|
1407 |
+
* @param bool|null $use_ssl
|
1408 |
+
*
|
1409 |
+
* @return string
|
1410 |
+
*/
|
1411 |
+
function get_url_scheme( $use_ssl = null ) {
|
1412 |
+
if ( $this->use_ssl( $use_ssl ) ) {
|
1413 |
+
$scheme = 'https';
|
1414 |
+
} else {
|
1415 |
+
$scheme = 'http';
|
1416 |
}
|
1417 |
|
1418 |
+
return $scheme;
|
1419 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1420 |
|
1421 |
+
/**
|
1422 |
+
* Determine when to use https in URLS
|
1423 |
+
*
|
1424 |
+
* @param bool|null $use_ssl
|
1425 |
+
*
|
1426 |
+
* @return bool
|
1427 |
+
*/
|
1428 |
+
public function use_ssl( $use_ssl = null ) {
|
1429 |
+
if ( is_ssl() ) {
|
1430 |
+
$use_ssl = true;
|
1431 |
}
|
1432 |
|
1433 |
+
if ( ! is_bool( $use_ssl ) ) {
|
1434 |
+
$use_ssl = $this->get_setting( 'force-https' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1435 |
}
|
1436 |
|
1437 |
+
if ( empty( $use_ssl ) ) {
|
1438 |
+
$use_ssl = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1439 |
}
|
1440 |
|
1441 |
+
return apply_filters( 'as3cf_use_ssl', $use_ssl );
|
1442 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1443 |
|
1444 |
+
/**
|
1445 |
+
* Get the custom object prefix if enabled
|
1446 |
+
*
|
1447 |
+
* @param string $toggle_setting
|
1448 |
+
*
|
1449 |
+
* @return string
|
1450 |
+
*/
|
1451 |
+
function get_object_prefix( $toggle_setting = 'enable-object-prefix' ) {
|
1452 |
+
if ( $this->get_setting( $toggle_setting ) ) {
|
1453 |
+
return trailingslashit( trim( $this->get_setting( 'object-prefix' ) ) );
|
1454 |
}
|
1455 |
|
1456 |
+
return '';
|
1457 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1458 |
|
1459 |
/**
|
1460 |
* Is attachment served by provider.
|
1467 |
*
|
1468 |
* @return bool|Media_Library_Item
|
1469 |
*/
|
1470 |
+
public function is_attachment_served_by_provider( $attachment_id, $skip_rewrite_check = false, $skip_current_provider_check = false, Storage_Provider $provider = null, $check_is_verified = false ) {
|
1471 |
+
if ( ! $skip_rewrite_check && ! $this->get_setting( 'serve-from-s3' ) ) {
|
1472 |
+
// Not serving provider URLs
|
1473 |
+
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1474 |
}
|
1475 |
|
1476 |
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
1477 |
|
1478 |
if ( ! $as3cf_item ) {
|
1479 |
+
// File not uploaded to a provider
|
1480 |
+
return false;
|
1481 |
}
|
1482 |
|
1483 |
+
if ( ! $skip_rewrite_check && ! empty( $check_is_verified ) && ! $as3cf_item->is_verified() ) {
|
1484 |
+
// Offload not verified, treat as not offloaded.
|
1485 |
+
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1486 |
}
|
1487 |
|
1488 |
+
if ( ! $skip_current_provider_check && empty( $provider ) ) {
|
1489 |
+
$provider = $this->get_storage_provider();
|
1490 |
+
}
|
1491 |
|
1492 |
+
if ( ! empty( $provider ) && $provider::get_provider_key_name() !== $as3cf_item->provider() ) {
|
1493 |
+
// File not uploaded to required provider
|
1494 |
+
return false;
|
1495 |
+
}
|
1496 |
|
1497 |
+
return $as3cf_item;
|
1498 |
}
|
1499 |
|
1500 |
/**
|
1734 |
/**
|
1735 |
* Add the settings page to the top-level AWS menu item for backwards compatibility.
|
1736 |
*
|
1737 |
+
* @param Amazon_Web_Services $aws Plugin class instance from the amazon-web-services plugin.
|
1738 |
*/
|
1739 |
public function aws_admin_menu( $aws ) {
|
1740 |
$aws->add_page(
|
1949 |
return self::$buckets_check[ $bucket ];
|
1950 |
}
|
1951 |
|
1952 |
+
$key = $this->get_simple_file_prefix() . 'as3cf-permission-check.txt';
|
1953 |
$file_contents = __( 'This is a test file to check if the user has write permission to the bucket. Delete me if found.', 'amazon-s3-and-cloudfront' );
|
1954 |
|
1955 |
$can_write = $this->get_provider_client( $region, true )->can_write( $bucket, $key, $file_contents );
|
1967 |
return $can_write;
|
1968 |
}
|
1969 |
|
1970 |
+
/**
|
1971 |
+
* Get the file prefix for test and display purposes.
|
1972 |
+
*
|
1973 |
+
* Note: This should only be used for "naive" prefix calculations for
|
1974 |
+
* display and write permission test purposes
|
1975 |
+
*
|
1976 |
+
* @param null|string $time
|
1977 |
+
* @param bool $object_versioning_allowed Can an Object Versioning string be appended if setting turned on? Default true.
|
1978 |
+
*
|
1979 |
+
* @return string
|
1980 |
+
*/
|
1981 |
+
private function get_simple_file_prefix( $time = null, $object_versioning_allowed = true ) {
|
1982 |
+
$prefix = AS3CF_Utils::trailingslash_prefix( $this->get_object_prefix() );
|
1983 |
+
$prefix .= AS3CF_Utils::trailingslash_prefix( $this->get_dynamic_prefix( $time ) );
|
1984 |
+
|
1985 |
+
if ( ! empty( $object_versioning_allowed ) && $this->get_setting( 'object-versioning' ) ) {
|
1986 |
+
$prefix .= AS3CF_Utils::trailingslash_prefix( $this->get_object_version_string() );
|
1987 |
+
}
|
1988 |
+
|
1989 |
+
return $prefix;
|
1990 |
+
}
|
1991 |
+
|
1992 |
/**
|
1993 |
* Render error messages in a view for bucket permission and access issues
|
1994 |
*
|
2698 |
* year month subdirectory setting and just uses S3 setting
|
2699 |
*
|
2700 |
* @param string $time
|
2701 |
+
* @param bool $can_use_yearmonth
|
2702 |
*
|
2703 |
* @return string
|
2704 |
*/
|
2705 |
+
public function get_dynamic_prefix( $time = null, $can_use_yearmonth = true ) {
|
2706 |
$prefix = '';
|
2707 |
$subdir = '';
|
2708 |
|
2745 |
}
|
2746 |
}
|
2747 |
|
2748 |
+
if ( $this->get_setting( 'use-yearmonth-folders' ) && $can_use_yearmonth ) {
|
2749 |
$subdir = $this->get_year_month_directory_name( $time );
|
2750 |
$prefix .= $subdir;
|
2751 |
}
|
2842 |
* @param Media_Library_Item $as3cf_item
|
2843 |
* @param string|null $size
|
2844 |
*/
|
2845 |
+
public function make_acl_admin_notice( Media_Library_Item $as3cf_item, $size = null ) {
|
2846 |
$filename = wp_basename( $as3cf_item->path( $size ) );
|
2847 |
+
$acl = $as3cf_item->is_private( $size ) ? $this->get_storage_provider()->get_private_acl() : $this->get_storage_provider()->get_default_acl();
|
2848 |
$acl_name = $this->get_acl_display_name( $acl );
|
2849 |
$text = sprintf( __( '<strong>WP Offload Media</strong> — The file %s has been given %s permissions in the bucket.', 'amazon-s3-and-cloudfront' ), "<strong>{$filename}</strong>", "<strong>{$acl_name}</strong>" );
|
2850 |
|
3732 |
* Used to give a realistic total of storage space used on a Multisite subsite,
|
3733 |
* when there have been attachments uploaded to S3 but removed from server
|
3734 |
*
|
3735 |
+
* @param bool $space_used
|
3736 |
*
|
3737 |
* @return float|int
|
3738 |
*/
|
3822 |
foreach ( $table_prefixes as $blog_id => $table_prefix ) {
|
3823 |
$this->switch_to_blog( $blog_id );
|
3824 |
|
3825 |
+
foreach ( $this->get_source_type_classes() as $class ) {
|
3826 |
+
$counts = $class::count_items( $skip_transient, $force );
|
3827 |
+
$total += $counts['total'];
|
3828 |
+
$offloaded += $counts['offloaded'];
|
3829 |
+
$not_offloaded += $counts['not_offloaded'];
|
3830 |
+
}
|
3831 |
|
3832 |
$this->restore_current_blog();
|
3833 |
}
|
3986 |
return filter_input( $type, $variable, $filter, $options );
|
3987 |
}
|
3988 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3989 |
/**
|
3990 |
* Upgrade the 'virtual host' / 'bucket as domain' setting to the
|
3991 |
* new CloudFront / Domain setting
|
4051 |
return $path;
|
4052 |
}
|
4053 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4054 |
/**
|
4055 |
* Maybe remove query string from URL.
|
4056 |
*
|
4064 |
return reset( $parts );
|
4065 |
}
|
4066 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4067 |
/**
|
4068 |
* Ensure local URL is correct for multisite's non-primary subsites.
|
4069 |
*
|
4104 |
$acl = $this->get_storage_provider()->get_default_acl();
|
4105 |
|
4106 |
if ( ! empty( $as3cf_item ) ) {
|
4107 |
+
$acl = $as3cf_item->is_private( $size ) ? $this->get_storage_provider()->get_private_acl() : $this->get_storage_provider()->get_default_acl();
|
4108 |
}
|
4109 |
}
|
4110 |
|
4114 |
/**
|
4115 |
* Are ACLs in use for intermediate size on bucket?
|
4116 |
*
|
4117 |
+
* @param int $attachment_id
|
4118 |
+
* @param string $size
|
4119 |
+
* @param string $bucket Optional bucket that ACL is potentially to be used with.
|
4120 |
+
* @param Item|null $as3cf_item Optional item.
|
4121 |
*
|
4122 |
* @return bool
|
4123 |
*/
|
4124 |
+
public function use_acl_for_intermediate_size( $attachment_id, $size, $bucket = null, Item $as3cf_item = null ) {
|
4125 |
+
// If this function is used without passing in an Item object, we're assuming $attachment
|
4126 |
if ( empty( $as3cf_item ) ) {
|
4127 |
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
4128 |
}
|
4139 |
$use_private_prefix = apply_filters( 'as3cf_enable_signed_urls_for_intermediate_size', $this->private_prefix_enabled(), $attachment_id, $size, $bucket, $as3cf_item );
|
4140 |
|
4141 |
// If signed custom URLs are in play, and we have a private object, usually you can not use ACLs.
|
4142 |
+
if ( $use_acl && $use_private_prefix && ! empty( $as3cf_item ) && $as3cf_item->is_private( $size ) ) {
|
4143 |
$use_acl = false;
|
4144 |
}
|
4145 |
|
4147 |
return apply_filters( 'as3cf_use_acl_for_intermediate_size', $use_acl, $attachment_id, $size, $bucket, $as3cf_item );
|
4148 |
}
|
4149 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4150 |
/**
|
4151 |
* Get all defined addons that use this plugin
|
4152 |
*
|
4262 |
$this->render_view( 'notice', $notice );
|
4263 |
}
|
4264 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4265 |
/**
|
4266 |
* Is there an upgrade in progress?
|
4267 |
*
|
4287 |
|
4288 |
return false;
|
4289 |
}
|
4290 |
+
|
4291 |
+
/**
|
4292 |
+
* Register an item type name and class
|
4293 |
+
*
|
4294 |
+
* @param string $source_type
|
4295 |
+
* @param string $class
|
4296 |
+
*/
|
4297 |
+
public function register_source_type( $source_type, $class ) {
|
4298 |
+
$this->source_type_classes[ $source_type ] = $class;
|
4299 |
+
}
|
4300 |
+
|
4301 |
+
/**
|
4302 |
+
* Get Item type class from item type identifier
|
4303 |
+
*
|
4304 |
+
* @param string $source_type
|
4305 |
+
*
|
4306 |
+
* @return string|false
|
4307 |
+
*/
|
4308 |
+
public function get_source_type_class( $source_type ) {
|
4309 |
+
if ( isset( $this->source_type_classes[ $source_type ] ) ) {
|
4310 |
+
return $this->source_type_classes[ $source_type ];
|
4311 |
+
}
|
4312 |
+
|
4313 |
+
return false;
|
4314 |
+
}
|
4315 |
+
|
4316 |
+
/**
|
4317 |
+
* Get Item type human friendly name item type identifier
|
4318 |
+
*
|
4319 |
+
* @param string $source_type
|
4320 |
+
*
|
4321 |
+
* @return string|false
|
4322 |
+
*/
|
4323 |
+
public function get_source_type_name( $source_type ) {
|
4324 |
+
/** @var Item $class */
|
4325 |
+
$class = $this->get_source_type_class( $source_type );
|
4326 |
+
if ( ! empty( $class ) ) {
|
4327 |
+
return $class::source_type_name();
|
4328 |
+
}
|
4329 |
+
|
4330 |
+
return false;
|
4331 |
+
}
|
4332 |
+
|
4333 |
+
/**
|
4334 |
+
* Get all registered Item classes
|
4335 |
+
*
|
4336 |
+
* @return array
|
4337 |
+
*/
|
4338 |
+
public function get_source_type_classes() {
|
4339 |
+
return $this->source_type_classes;
|
4340 |
+
}
|
4341 |
+
|
4342 |
+
/**
|
4343 |
+
* Returns the Item_Handler instance for the given handler type.
|
4344 |
+
*
|
4345 |
+
* @param string $handler_type
|
4346 |
+
*
|
4347 |
+
* @return Item_Handler
|
4348 |
+
*/
|
4349 |
+
public function get_item_handler( $handler_type ) {
|
4350 |
+
if ( isset( $this->item_handlers[ $handler_type ] ) ) {
|
4351 |
+
return $this->item_handlers[ $handler_type ];
|
4352 |
+
}
|
4353 |
+
|
4354 |
+
switch ( $handler_type ) {
|
4355 |
+
case Upload_Handler::get_item_handler_key_name():
|
4356 |
+
$this->item_handlers[ $handler_type ] = new Upload_Handler( $this );
|
4357 |
+
break;
|
4358 |
+
case Download_Handler::get_item_handler_key_name():
|
4359 |
+
$this->item_handlers[ $handler_type ] = new Download_Handler( $this );
|
4360 |
+
break;
|
4361 |
+
case Remove_Local_Handler::get_item_handler_key_name():
|
4362 |
+
$this->item_handlers[ $handler_type ] = new Remove_Local_Handler( $this );
|
4363 |
+
break;
|
4364 |
+
case Remove_Provider_Handler::get_item_handler_key_name():
|
4365 |
+
$this->item_handlers[ $handler_type ] = new Remove_Provider_Handler( $this );
|
4366 |
+
break;
|
4367 |
+
default:
|
4368 |
+
return null;
|
4369 |
+
}
|
4370 |
+
|
4371 |
+
return $this->item_handlers[ $handler_type ];
|
4372 |
+
}
|
4373 |
}
|
@@ -1,5 +1,8 @@
|
|
1 |
<?php
|
2 |
|
|
|
|
|
|
|
3 |
abstract class AS3CF_Filter {
|
4 |
|
5 |
/**
|
@@ -17,21 +20,20 @@ abstract class AS3CF_Filter {
|
|
17 |
*/
|
18 |
const OPTION_CACHE_GROUP = 'option_amazonS3_cache';
|
19 |
|
|
|
|
|
|
|
|
|
|
|
20 |
/**
|
21 |
* @var Amazon_S3_And_CloudFront
|
22 |
*/
|
23 |
protected $as3cf;
|
24 |
-
|
25 |
/**
|
26 |
* @var array
|
27 |
*/
|
28 |
protected $query_cache = array();
|
29 |
|
30 |
-
/**
|
31 |
-
* @var array IDs which have already been purged this request.
|
32 |
-
*/
|
33 |
-
protected static $purged_ids = array();
|
34 |
-
|
35 |
/**
|
36 |
* Constructor
|
37 |
*
|
@@ -72,7 +74,11 @@ abstract class AS3CF_Filter {
|
|
72 |
}
|
73 |
|
74 |
foreach ( $value as $key => $attachment ) {
|
75 |
-
$
|
|
|
|
|
|
|
|
|
76 |
|
77 |
if ( $url ) {
|
78 |
$value[ $key ]['file'] = $url;
|
@@ -113,7 +119,11 @@ abstract class AS3CF_Filter {
|
|
113 |
* @return stdClass
|
114 |
*/
|
115 |
public function filter_header_image_data( $value, $old_value = false ) {
|
116 |
-
$
|
|
|
|
|
|
|
|
|
117 |
|
118 |
if ( $url ) {
|
119 |
$value->url = $url;
|
@@ -148,16 +158,17 @@ abstract class AS3CF_Filter {
|
|
148 |
/**
|
149 |
* Handle widget instances.
|
150 |
*
|
151 |
-
* @param array
|
152 |
-
* @param WP_Widget $class
|
153 |
*
|
154 |
* @return array
|
155 |
*/
|
156 |
-
protected function handle_widget( $instance
|
157 |
-
if ( empty( $instance ) ) {
|
158 |
return $instance;
|
159 |
}
|
160 |
|
|
|
|
|
161 |
$update_cache = true;
|
162 |
|
163 |
// Editing widgets in Customizer throws an error if more than one option record is updated.
|
@@ -166,39 +177,12 @@ abstract class AS3CF_Filter {
|
|
166 |
$update_cache = false;
|
167 |
}
|
168 |
|
169 |
-
if ( $class instanceof WP_Widget_Media ) {
|
170 |
-
return $this->filter_media_widget( $instance, $update_cache );
|
171 |
-
}
|
172 |
-
|
173 |
-
if ( $class instanceof WP_Widget_Text ) {
|
174 |
-
return $this->filter_text_widget( $instance, $update_cache );
|
175 |
-
}
|
176 |
-
|
177 |
-
if ( $class instanceof WP_Widget_Custom_HTML ) {
|
178 |
-
return $this->filter_custom_html_widget( $instance, $update_cache );
|
179 |
-
}
|
180 |
-
|
181 |
-
return $instance;
|
182 |
-
}
|
183 |
-
|
184 |
-
/**
|
185 |
-
* Filter media widget.
|
186 |
-
*
|
187 |
-
* @param array $instance
|
188 |
-
* @param bool $update_cache
|
189 |
-
*
|
190 |
-
* @return array
|
191 |
-
*/
|
192 |
-
protected function filter_media_widget( $instance, $update_cache ) {
|
193 |
-
$cache = $this->get_option_cache();
|
194 |
-
$to_cache = array();
|
195 |
-
|
196 |
foreach ( $instance as $key => $value ) {
|
197 |
if ( empty( $value ) ) {
|
198 |
continue;
|
199 |
}
|
200 |
|
201 |
-
if ( AS3CF_Utils::is_url( $value ) ) {
|
202 |
$instance[ $key ] = $this->process_content( $value, $cache, $to_cache );
|
203 |
}
|
204 |
}
|
@@ -210,46 +194,6 @@ abstract class AS3CF_Filter {
|
|
210 |
return $instance;
|
211 |
}
|
212 |
|
213 |
-
/**
|
214 |
-
* Filter text widget.
|
215 |
-
*
|
216 |
-
* @param array $instance
|
217 |
-
* @param bool $update_cache
|
218 |
-
*
|
219 |
-
* @return array
|
220 |
-
*/
|
221 |
-
protected function filter_text_widget( $instance, $update_cache ) {
|
222 |
-
$cache = $this->get_option_cache();
|
223 |
-
$to_cache = array();
|
224 |
-
$instance['text'] = $this->process_content( $instance['text'], $cache, $to_cache );
|
225 |
-
|
226 |
-
if ( $update_cache ) {
|
227 |
-
$this->maybe_update_option_cache( $to_cache );
|
228 |
-
}
|
229 |
-
|
230 |
-
return $instance;
|
231 |
-
}
|
232 |
-
|
233 |
-
/**
|
234 |
-
* Filter custom html widget.
|
235 |
-
*
|
236 |
-
* @param array $instance
|
237 |
-
* @param bool $update_cache
|
238 |
-
*
|
239 |
-
* @return array
|
240 |
-
*/
|
241 |
-
protected function filter_custom_html_widget( $instance, $update_cache ) {
|
242 |
-
$cache = $this->get_option_cache();
|
243 |
-
$to_cache = array();
|
244 |
-
$instance['content'] = $this->process_content( $instance['content'], $cache, $to_cache );
|
245 |
-
|
246 |
-
if ( $update_cache ) {
|
247 |
-
$this->maybe_update_option_cache( $to_cache );
|
248 |
-
}
|
249 |
-
|
250 |
-
return $instance;
|
251 |
-
}
|
252 |
-
|
253 |
/**
|
254 |
* Process content.
|
255 |
*
|
@@ -326,8 +270,8 @@ abstract class AS3CF_Filter {
|
|
326 |
return $url_pairs;
|
327 |
}
|
328 |
|
329 |
-
$matches
|
330 |
-
$
|
331 |
|
332 |
foreach ( $matches as $image ) {
|
333 |
if ( ! preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) || ! isset( $class_id[1] ) ) {
|
@@ -349,26 +293,29 @@ abstract class AS3CF_Filter {
|
|
349 |
|
350 |
$url = AS3CF_Utils::reduce_url( $url );
|
351 |
|
352 |
-
$
|
|
|
|
|
|
|
353 |
}
|
354 |
|
355 |
-
if ( count( $
|
356 |
/*
|
357 |
* Warm object cache for use with 'get_post_meta()'.
|
358 |
*
|
359 |
* To avoid making a database call for each image, a single query
|
360 |
* warms the object cache with the meta information for all images.
|
361 |
*/
|
362 |
-
update_meta_cache( 'post', array_unique(
|
363 |
}
|
364 |
|
365 |
-
foreach ( $
|
366 |
-
if ( ! $this->
|
367 |
// Path doesn't match attachment, skip
|
368 |
continue;
|
369 |
}
|
370 |
|
371 |
-
$this->push_to_url_pairs( $url_pairs, $
|
372 |
}
|
373 |
|
374 |
return $url_pairs;
|
@@ -418,46 +365,46 @@ abstract class AS3CF_Filter {
|
|
418 |
continue;
|
419 |
}
|
420 |
|
421 |
-
$
|
422 |
-
$bare_url
|
423 |
|
424 |
// If attachment ID recently or previously cached, skip full search.
|
425 |
if ( isset( $to_cache[ $bare_url ] ) ) {
|
426 |
-
$
|
427 |
|
428 |
-
if ( $this->is_failure( $
|
429 |
// Attachment ID failure, continue
|
430 |
continue;
|
431 |
}
|
432 |
} elseif ( isset( $cache[ $bare_url ] ) ) {
|
433 |
-
$
|
434 |
|
435 |
-
if ( $this->is_failure( $
|
436 |
// Attachment ID failure, continue
|
437 |
continue;
|
438 |
}
|
439 |
}
|
440 |
|
441 |
-
if ( is_null( $
|
442 |
// Attachment ID not cached, need to search by URL.
|
443 |
$urls[] = $bare_url;
|
444 |
} else {
|
445 |
-
$this->push_to_url_pairs( $url_pairs, $
|
446 |
}
|
447 |
}
|
448 |
|
449 |
if ( ! empty( $urls ) ) {
|
450 |
-
$
|
451 |
|
452 |
-
foreach ( $
|
453 |
-
if ( ! $
|
454 |
-
// Can't determine
|
455 |
$this->url_cache_failure( $url, $to_cache );
|
456 |
|
457 |
continue;
|
458 |
}
|
459 |
|
460 |
-
$this->push_to_url_pairs( $url_pairs, $
|
461 |
}
|
462 |
}
|
463 |
|
@@ -467,7 +414,7 @@ abstract class AS3CF_Filter {
|
|
467 |
/**
|
468 |
* Is failure?
|
469 |
*
|
470 |
-
* @param
|
471 |
*
|
472 |
* @return bool
|
473 |
*/
|
@@ -488,20 +435,23 @@ abstract class AS3CF_Filter {
|
|
488 |
/**
|
489 |
* Does attachment ID match src?
|
490 |
*
|
491 |
-
* @param
|
492 |
* @param string $url
|
493 |
*
|
494 |
* @return bool
|
495 |
*/
|
496 |
-
|
497 |
-
$
|
|
|
|
|
|
|
498 |
|
499 |
if ( ! isset( $meta['sizes'] ) ) {
|
500 |
// No sizes found, return
|
501 |
return false;
|
502 |
}
|
503 |
|
504 |
-
$base_url = AS3CF_Utils::encode_filename_in_path( AS3CF_Utils::reduce_url( $this->get_base_url( $
|
505 |
$basename = wp_basename( $base_url );
|
506 |
|
507 |
// Add full size URL
|
@@ -526,31 +476,31 @@ abstract class AS3CF_Filter {
|
|
526 |
* Push to URL pairs.
|
527 |
*
|
528 |
* @param array $url_pairs
|
529 |
-
* @param
|
530 |
* @param string $find
|
531 |
* @param array $to_cache
|
532 |
*/
|
533 |
-
protected function push_to_url_pairs( &$url_pairs, $
|
534 |
$find_full = AS3CF_Utils::remove_size_from_filename( $find );
|
535 |
$find_full = $this->normalize_find_value( $this->as3cf->maybe_remove_query_string( $find_full ) );
|
536 |
$find_size = $this->normalize_find_value( $this->as3cf->maybe_remove_query_string( $find ) );
|
537 |
|
538 |
// Cache find URLs even if no replacement.
|
539 |
-
$to_cache[ $find_full ] = $
|
540 |
|
541 |
if ( wp_basename( $find_full ) !== wp_basename( $find_size ) ) {
|
542 |
-
$to_cache[ $find_size ] = $
|
543 |
}
|
544 |
|
545 |
-
$replace_full = $this->get_url( $
|
546 |
|
547 |
// Replacement URL can't be found.
|
548 |
if ( ! $replace_full ) {
|
549 |
return;
|
550 |
}
|
551 |
|
552 |
-
$size = $this->get_size_string_from_url( $
|
553 |
-
$replace_size = $this->get_url( $
|
554 |
$parts = parse_url( $find );
|
555 |
|
556 |
if ( ! isset( $parts['scheme'] ) ) {
|
@@ -570,35 +520,24 @@ abstract class AS3CF_Filter {
|
|
570 |
$replace_full = $this->as3cf->maybe_remove_query_string( $replace_full );
|
571 |
$replace_size = $this->as3cf->maybe_remove_query_string( $replace_size );
|
572 |
|
573 |
-
$to_cache[ $this->normalize_find_value( $replace_full ) ] = $
|
574 |
-
$to_cache[ $this->normalize_find_value( $replace_size ) ] = $
|
575 |
}
|
576 |
|
577 |
/**
|
578 |
* Get size string from URL.
|
579 |
*
|
580 |
-
* @param
|
581 |
* @param string $url
|
582 |
*
|
583 |
* @return null|string
|
584 |
*/
|
585 |
-
public function get_size_string_from_url( $
|
586 |
-
$
|
587 |
-
|
588 |
-
if ( empty( $meta['sizes'] ) ) {
|
589 |
-
// No alternative sizes available, return
|
590 |
-
return null;
|
591 |
-
}
|
592 |
-
|
593 |
-
$basename = AS3CF_Utils::encode_filename_in_path( wp_basename( $this->as3cf->maybe_remove_query_string( $url ) ) );
|
594 |
-
|
595 |
-
foreach ( $meta['sizes'] as $size => $file ) {
|
596 |
-
if ( $basename === AS3CF_Utils::encode_filename_in_path( $file['file'] ) ) {
|
597 |
-
return $size;
|
598 |
-
}
|
599 |
}
|
600 |
|
601 |
-
return
|
602 |
}
|
603 |
|
604 |
/**
|
@@ -659,11 +598,14 @@ abstract class AS3CF_Filter {
|
|
659 |
/**
|
660 |
* Get post cache
|
661 |
*
|
662 |
-
* @param null|int|WP_Post $post
|
|
|
|
|
663 |
*
|
664 |
-
*
|
|
|
665 |
*/
|
666 |
-
public function get_post_cache( $post = null ) {
|
667 |
$post_id = AS3CF_Utils::get_post_id( $post );
|
668 |
|
669 |
if ( ! $post_id ) {
|
@@ -680,6 +622,21 @@ abstract class AS3CF_Filter {
|
|
680 |
$cache = array();
|
681 |
}
|
682 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
683 |
return $cache;
|
684 |
}
|
685 |
|
@@ -731,7 +688,7 @@ abstract class AS3CF_Filter {
|
|
731 |
return;
|
732 |
}
|
733 |
|
734 |
-
$cached = $this->get_post_cache( $post_id );
|
735 |
$urls = static::merge_cache( $cached, $to_cache );
|
736 |
|
737 |
if ( $urls !== $cached ) {
|
@@ -777,13 +734,17 @@ abstract class AS3CF_Filter {
|
|
777 |
}
|
778 |
|
779 |
/**
|
780 |
-
* Purge
|
781 |
*
|
782 |
* @param int $post_id
|
783 |
*/
|
784 |
public function purge_cache_on_attachment_delete( $post_id ) {
|
785 |
if ( ! in_array( $post_id, self::$purged_ids ) ) {
|
786 |
-
$
|
|
|
|
|
|
|
|
|
787 |
self::$purged_ids[] = $post_id;
|
788 |
}
|
789 |
}
|
@@ -1044,30 +1005,30 @@ abstract class AS3CF_Filter {
|
|
1044 |
/**
|
1045 |
* Get URL.
|
1046 |
*
|
1047 |
-
* @param int
|
1048 |
-
* @param null|string $
|
1049 |
*
|
1050 |
* @return bool|string
|
1051 |
*/
|
1052 |
-
abstract protected function get_url( $
|
1053 |
|
1054 |
/**
|
1055 |
* Get base URL.
|
1056 |
*
|
1057 |
-
* @param int $
|
1058 |
*
|
1059 |
* @return string|false
|
1060 |
*/
|
1061 |
-
abstract protected function get_base_url( $
|
1062 |
|
1063 |
/**
|
1064 |
* Get attachment ID from URL.
|
1065 |
*
|
1066 |
* @param string $url
|
1067 |
*
|
1068 |
-
* @return
|
1069 |
*/
|
1070 |
-
abstract
|
1071 |
|
1072 |
/**
|
1073 |
* Get attachment IDs from URLs.
|
@@ -1076,7 +1037,7 @@ abstract class AS3CF_Filter {
|
|
1076 |
*
|
1077 |
* @return array url => attachment ID (or false)
|
1078 |
*/
|
1079 |
-
abstract protected function
|
1080 |
|
1081 |
/**
|
1082 |
* Normalize find value.
|
1 |
<?php
|
2 |
|
3 |
+
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
4 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
5 |
+
|
6 |
abstract class AS3CF_Filter {
|
7 |
|
8 |
/**
|
20 |
*/
|
21 |
const OPTION_CACHE_GROUP = 'option_amazonS3_cache';
|
22 |
|
23 |
+
/**
|
24 |
+
* @var array IDs which have already been purged this request.
|
25 |
+
*/
|
26 |
+
protected static $purged_ids = array();
|
27 |
+
|
28 |
/**
|
29 |
* @var Amazon_S3_And_CloudFront
|
30 |
*/
|
31 |
protected $as3cf;
|
|
|
32 |
/**
|
33 |
* @var array
|
34 |
*/
|
35 |
protected $query_cache = array();
|
36 |
|
|
|
|
|
|
|
|
|
|
|
37 |
/**
|
38 |
* Constructor
|
39 |
*
|
74 |
}
|
75 |
|
76 |
foreach ( $value as $key => $attachment ) {
|
77 |
+
$item_source = array(
|
78 |
+
'id' => $attachment['attachment_id'],
|
79 |
+
'source_type' => Media_Library_Item::source_type(),
|
80 |
+
);
|
81 |
+
$url = $this->get_url( $item_source );
|
82 |
|
83 |
if ( $url ) {
|
84 |
$value[ $key ]['file'] = $url;
|
119 |
* @return stdClass
|
120 |
*/
|
121 |
public function filter_header_image_data( $value, $old_value = false ) {
|
122 |
+
$item_source = array(
|
123 |
+
'id' => $value->attachment_id,
|
124 |
+
'source_type' => Media_Library_Item::source_type(),
|
125 |
+
);
|
126 |
+
$url = $this->get_url( $item_source );
|
127 |
|
128 |
if ( $url ) {
|
129 |
$value->url = $url;
|
158 |
/**
|
159 |
* Handle widget instances.
|
160 |
*
|
161 |
+
* @param array $instance
|
|
|
162 |
*
|
163 |
* @return array
|
164 |
*/
|
165 |
+
protected function handle_widget( $instance ) {
|
166 |
+
if ( empty( $instance ) || ! is_array( $instance ) ) {
|
167 |
return $instance;
|
168 |
}
|
169 |
|
170 |
+
$cache = $this->get_option_cache();
|
171 |
+
$to_cache = array();
|
172 |
$update_cache = true;
|
173 |
|
174 |
// Editing widgets in Customizer throws an error if more than one option record is updated.
|
177 |
$update_cache = false;
|
178 |
}
|
179 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
180 |
foreach ( $instance as $key => $value ) {
|
181 |
if ( empty( $value ) ) {
|
182 |
continue;
|
183 |
}
|
184 |
|
185 |
+
if ( in_array( $key, array( 'text', 'content' ) ) || AS3CF_Utils::is_url( $value ) ) {
|
186 |
$instance[ $key ] = $this->process_content( $value, $cache, $to_cache );
|
187 |
}
|
188 |
}
|
194 |
return $instance;
|
195 |
}
|
196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
/**
|
198 |
* Process content.
|
199 |
*
|
270 |
return $url_pairs;
|
271 |
}
|
272 |
|
273 |
+
$matches = array_unique( $matches[0] );
|
274 |
+
$item_sources = array();
|
275 |
|
276 |
foreach ( $matches as $image ) {
|
277 |
if ( ! preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) || ! isset( $class_id[1] ) ) {
|
293 |
|
294 |
$url = AS3CF_Utils::reduce_url( $url );
|
295 |
|
296 |
+
$item_sources[ $url ] = array(
|
297 |
+
'id' => absint( $class_id[1] ),
|
298 |
+
'source_type' => Media_Library_Item::source_type(),
|
299 |
+
);
|
300 |
}
|
301 |
|
302 |
+
if ( count( $item_sources ) > 1 ) {
|
303 |
/*
|
304 |
* Warm object cache for use with 'get_post_meta()'.
|
305 |
*
|
306 |
* To avoid making a database call for each image, a single query
|
307 |
* warms the object cache with the meta information for all images.
|
308 |
*/
|
309 |
+
update_meta_cache( 'post', array_unique( array_column( $item_sources, 'id' ) ) );
|
310 |
}
|
311 |
|
312 |
+
foreach ( $item_sources as $url => $item_source ) {
|
313 |
+
if ( ! $this->item_matches_src( $item_source, $url ) ) {
|
314 |
// Path doesn't match attachment, skip
|
315 |
continue;
|
316 |
}
|
317 |
|
318 |
+
$this->push_to_url_pairs( $url_pairs, $item_source, $url, $to_cache );
|
319 |
}
|
320 |
|
321 |
return $url_pairs;
|
365 |
continue;
|
366 |
}
|
367 |
|
368 |
+
$item_source = null;
|
369 |
+
$bare_url = AS3CF_Utils::reduce_url( $url );
|
370 |
|
371 |
// If attachment ID recently or previously cached, skip full search.
|
372 |
if ( isset( $to_cache[ $bare_url ] ) ) {
|
373 |
+
$item_source = $to_cache[ $bare_url ];
|
374 |
|
375 |
+
if ( $this->is_failure( $item_source ) ) {
|
376 |
// Attachment ID failure, continue
|
377 |
continue;
|
378 |
}
|
379 |
} elseif ( isset( $cache[ $bare_url ] ) ) {
|
380 |
+
$item_source = $cache[ $bare_url ];
|
381 |
|
382 |
+
if ( $this->is_failure( $item_source ) ) {
|
383 |
// Attachment ID failure, continue
|
384 |
continue;
|
385 |
}
|
386 |
}
|
387 |
|
388 |
+
if ( is_null( $item_source ) || ( is_array( $item_source ) && ! empty( $item_source['timestamp'] ) ) ) {
|
389 |
// Attachment ID not cached, need to search by URL.
|
390 |
$urls[] = $bare_url;
|
391 |
} else {
|
392 |
+
$this->push_to_url_pairs( $url_pairs, $item_source, $bare_url, $to_cache );
|
393 |
}
|
394 |
}
|
395 |
|
396 |
if ( ! empty( $urls ) ) {
|
397 |
+
$item_sources = $this->get_item_sources_from_urls( $urls );
|
398 |
|
399 |
+
foreach ( $item_sources as $url => $item_source ) {
|
400 |
+
if ( ! $item_source ) {
|
401 |
+
// Can't determine item ID, continue
|
402 |
$this->url_cache_failure( $url, $to_cache );
|
403 |
|
404 |
continue;
|
405 |
}
|
406 |
|
407 |
+
$this->push_to_url_pairs( $url_pairs, $item_source, $url, $to_cache );
|
408 |
}
|
409 |
}
|
410 |
|
414 |
/**
|
415 |
* Is failure?
|
416 |
*
|
417 |
+
* @param array $value
|
418 |
*
|
419 |
* @return bool
|
420 |
*/
|
435 |
/**
|
436 |
* Does attachment ID match src?
|
437 |
*
|
438 |
+
* @param array $item_source
|
439 |
* @param string $url
|
440 |
*
|
441 |
* @return bool
|
442 |
*/
|
443 |
+
public function item_matches_src( $item_source, $url ) {
|
444 |
+
if ( empty( $item_source['id'] ) || empty( $item_source['source_type'] ) || Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
445 |
+
return false;
|
446 |
+
}
|
447 |
+
$meta = get_post_meta( $item_source['id'], '_wp_attachment_metadata', true );
|
448 |
|
449 |
if ( ! isset( $meta['sizes'] ) ) {
|
450 |
// No sizes found, return
|
451 |
return false;
|
452 |
}
|
453 |
|
454 |
+
$base_url = AS3CF_Utils::encode_filename_in_path( AS3CF_Utils::reduce_url( $this->get_base_url( $item_source ) ) );
|
455 |
$basename = wp_basename( $base_url );
|
456 |
|
457 |
// Add full size URL
|
476 |
* Push to URL pairs.
|
477 |
*
|
478 |
* @param array $url_pairs
|
479 |
+
* @param array $item_source
|
480 |
* @param string $find
|
481 |
* @param array $to_cache
|
482 |
*/
|
483 |
+
protected function push_to_url_pairs( &$url_pairs, $item_source, $find, &$to_cache ) {
|
484 |
$find_full = AS3CF_Utils::remove_size_from_filename( $find );
|
485 |
$find_full = $this->normalize_find_value( $this->as3cf->maybe_remove_query_string( $find_full ) );
|
486 |
$find_size = $this->normalize_find_value( $this->as3cf->maybe_remove_query_string( $find ) );
|
487 |
|
488 |
// Cache find URLs even if no replacement.
|
489 |
+
$to_cache[ $find_full ] = $item_source;
|
490 |
|
491 |
if ( wp_basename( $find_full ) !== wp_basename( $find_size ) ) {
|
492 |
+
$to_cache[ $find_size ] = $item_source;
|
493 |
}
|
494 |
|
495 |
+
$replace_full = $this->get_url( $item_source );
|
496 |
|
497 |
// Replacement URL can't be found.
|
498 |
if ( ! $replace_full ) {
|
499 |
return;
|
500 |
}
|
501 |
|
502 |
+
$size = $this->get_size_string_from_url( $item_source, $find );
|
503 |
+
$replace_size = $this->get_url( $item_source, $size );
|
504 |
$parts = parse_url( $find );
|
505 |
|
506 |
if ( ! isset( $parts['scheme'] ) ) {
|
520 |
$replace_full = $this->as3cf->maybe_remove_query_string( $replace_full );
|
521 |
$replace_size = $this->as3cf->maybe_remove_query_string( $replace_size );
|
522 |
|
523 |
+
$to_cache[ $this->normalize_find_value( $replace_full ) ] = $item_source;
|
524 |
+
$to_cache[ $this->normalize_find_value( $replace_size ) ] = $item_source;
|
525 |
}
|
526 |
|
527 |
/**
|
528 |
* Get size string from URL.
|
529 |
*
|
530 |
+
* @param array $item_source
|
531 |
* @param string $url
|
532 |
*
|
533 |
* @return null|string
|
534 |
*/
|
535 |
+
public function get_size_string_from_url( $item_source, $url ) {
|
536 |
+
if ( empty( $item_source['id'] ) || empty( $item_source['source_type'] ) ) {
|
537 |
+
return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
538 |
}
|
539 |
|
540 |
+
return apply_filters( 'as3cf_get_size_string_from_url_for_item_source', Item::primary_object_key(), $url, $item_source );
|
541 |
}
|
542 |
|
543 |
/**
|
598 |
/**
|
599 |
* Get post cache
|
600 |
*
|
601 |
+
* @param null|int|WP_Post $post Optional. Post ID or post object. Defaults to current post.
|
602 |
+
* @param bool $transform_ints Optional. If true (default), convert integer hits to array with id and source_type keys.
|
603 |
+
* If false, return integer hits as integers
|
604 |
*
|
605 |
+
*
|
606 |
+
* @return array|int
|
607 |
*/
|
608 |
+
public function get_post_cache( $post = null, $transform_ints = true ) {
|
609 |
$post_id = AS3CF_Utils::get_post_id( $post );
|
610 |
|
611 |
if ( ! $post_id ) {
|
622 |
$cache = array();
|
623 |
}
|
624 |
|
625 |
+
if ( ! $transform_ints ) {
|
626 |
+
return $cache;
|
627 |
+
}
|
628 |
+
|
629 |
+
// Handle old cache items that are stored as plain integers
|
630 |
+
foreach ( $cache as &$cache_item ) {
|
631 |
+
if ( ! is_array( $cache_item ) && is_numeric( $cache_item ) ) {
|
632 |
+
$id = $cache_item;
|
633 |
+
$cache_item = array(
|
634 |
+
'id' => $id,
|
635 |
+
'source_type' => Media_Library_Item::source_type(),
|
636 |
+
);
|
637 |
+
}
|
638 |
+
}
|
639 |
+
|
640 |
return $cache;
|
641 |
}
|
642 |
|
688 |
return;
|
689 |
}
|
690 |
|
691 |
+
$cached = $this->get_post_cache( $post_id, false );
|
692 |
$urls = static::merge_cache( $cached, $to_cache );
|
693 |
|
694 |
if ( $urls !== $cached ) {
|
734 |
}
|
735 |
|
736 |
/**
|
737 |
+
* Purge items from cache on delete.
|
738 |
*
|
739 |
* @param int $post_id
|
740 |
*/
|
741 |
public function purge_cache_on_attachment_delete( $post_id ) {
|
742 |
if ( ! in_array( $post_id, self::$purged_ids ) ) {
|
743 |
+
$item_source = array(
|
744 |
+
'id' => $post_id,
|
745 |
+
'source_type' => Media_Library_Item::source_type(),
|
746 |
+
);
|
747 |
+
$this->purge_from_cache( $this->get_url( $item_source ) );
|
748 |
self::$purged_ids[] = $post_id;
|
749 |
}
|
750 |
}
|
1005 |
/**
|
1006 |
* Get URL.
|
1007 |
*
|
1008 |
+
* @param int|array $item_source
|
1009 |
+
* @param null|string $object_key
|
1010 |
*
|
1011 |
* @return bool|string
|
1012 |
*/
|
1013 |
+
abstract protected function get_url( $item_source, $object_key = null );
|
1014 |
|
1015 |
/**
|
1016 |
* Get base URL.
|
1017 |
*
|
1018 |
+
* @param int|array $item_source
|
1019 |
*
|
1020 |
* @return string|false
|
1021 |
*/
|
1022 |
+
abstract protected function get_base_url( $item_source );
|
1023 |
|
1024 |
/**
|
1025 |
* Get attachment ID from URL.
|
1026 |
*
|
1027 |
* @param string $url
|
1028 |
*
|
1029 |
+
* @return array
|
1030 |
*/
|
1031 |
+
abstract public function get_item_source_from_url( $url );
|
1032 |
|
1033 |
/**
|
1034 |
* Get attachment IDs from URLs.
|
1037 |
*
|
1038 |
* @return array url => attachment ID (or false)
|
1039 |
*/
|
1040 |
+
abstract protected function get_item_sources_from_urls( $urls );
|
1041 |
|
1042 |
/**
|
1043 |
* Normalize find value.
|
@@ -9,7 +9,11 @@
|
|
9 |
* @since 0.8.3
|
10 |
*/
|
11 |
|
|
|
|
|
|
|
12 |
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
|
|
13 |
use DeliciousBrains\WP_Offload_Media\Providers\Storage\Storage_Provider;
|
14 |
|
15 |
// Exit if accessed directly
|
@@ -26,35 +30,25 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|
26 |
*/
|
27 |
class AS3CF_Plugin_Compatibility {
|
28 |
|
29 |
-
/**
|
30 |
-
* @var Amazon_S3_And_CloudFront
|
31 |
-
*/
|
32 |
-
protected $as3cf;
|
33 |
-
|
34 |
/**
|
35 |
* @var array
|
36 |
*/
|
37 |
protected static $stream_wrappers = array();
|
38 |
|
39 |
/**
|
40 |
-
* @var
|
41 |
-
*/
|
42 |
-
protected $compatibility_addons;
|
43 |
-
|
44 |
-
/**
|
45 |
-
* @var array
|
46 |
*/
|
47 |
-
|
48 |
|
49 |
/**
|
50 |
* @var bool
|
51 |
*/
|
52 |
-
protected $
|
53 |
|
54 |
/**
|
55 |
-
* @var
|
56 |
*/
|
57 |
-
|
58 |
|
59 |
/**
|
60 |
* @param Amazon_S3_And_CloudFront $as3cf
|
@@ -110,12 +104,12 @@ class AS3CF_Plugin_Compatibility {
|
|
110 |
* WP_Image_Editor
|
111 |
* /wp-includes/class-wp-image-editor.php
|
112 |
*/
|
113 |
-
|
114 |
add_filter( 'as3cf_get_attached_file_noop', array( $this, 'image_editor_download_file' ), 10, 4 );
|
115 |
add_filter( 'as3cf_get_attached_file', array( $this, 'image_editor_download_file' ), 10, 4 );
|
116 |
-
add_filter( '
|
117 |
add_filter( 'as3cf_get_attached_file', array( $this, 'customizer_crop_download_file' ), 10, 4 );
|
118 |
-
add_filter( '
|
119 |
add_filter( 'wp_unique_filename', array( $this, 'customizer_crop_unique_filename' ), 10, 3 );
|
120 |
|
121 |
/*
|
@@ -134,7 +128,7 @@ class AS3CF_Plugin_Compatibility {
|
|
134 |
* WP-CLI Compatibility
|
135 |
*/
|
136 |
if ( defined( 'WP_CLI' ) && class_exists( 'WP_CLI' ) ) {
|
137 |
-
WP_CLI::add_hook( 'before_invoke:media regenerate', array( $this, '
|
138 |
}
|
139 |
}
|
140 |
|
@@ -159,12 +153,24 @@ class AS3CF_Plugin_Compatibility {
|
|
159 |
if ( ( $file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) ) {
|
160 |
// Return the file if successfully downloaded from S3
|
161 |
return $file;
|
162 |
-
}
|
163 |
|
164 |
// Return S3 URL as a fallback
|
165 |
return $url;
|
166 |
}
|
167 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
168 |
/**
|
169 |
* Enables copying missing local files back to the server when `get_attached_file` filter is called.
|
170 |
*/
|
@@ -238,12 +244,13 @@ class AS3CF_Plugin_Compatibility {
|
|
238 |
*
|
239 |
* @handles wp_generate_attachment_metadata
|
240 |
*
|
241 |
-
* @param $metadata
|
242 |
*
|
243 |
* @return mixed
|
244 |
*/
|
245 |
public function wp_generate_attachment_metadata( $metadata ) {
|
246 |
-
$this->
|
|
|
247 |
return $metadata;
|
248 |
}
|
249 |
|
@@ -253,14 +260,16 @@ class AS3CF_Plugin_Compatibility {
|
|
253 |
*
|
254 |
* @handles as3cf_wait_for_generate_attachment_metadata
|
255 |
*
|
|
|
|
|
256 |
* @return bool
|
257 |
*/
|
258 |
-
public function wait_for_generate_attachment_metadata() {
|
259 |
-
if (
|
260 |
-
return
|
261 |
}
|
262 |
|
263 |
-
return
|
264 |
}
|
265 |
|
266 |
/**
|
@@ -323,23 +332,30 @@ class AS3CF_Plugin_Compatibility {
|
|
323 |
if ( ( $file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) ) {
|
324 |
// Return the file if successfully downloaded from S3
|
325 |
return $file;
|
326 |
-
}
|
327 |
|
328 |
return $url;
|
329 |
}
|
330 |
|
331 |
/**
|
332 |
-
* Get the file path of the
|
|
|
|
|
|
|
|
|
333 |
*
|
334 |
-
* @param
|
335 |
-
* @param string $file_path
|
336 |
*
|
337 |
* @return bool|string
|
338 |
*/
|
339 |
-
function get_original_image_file(
|
340 |
-
|
341 |
-
|
342 |
-
|
|
|
|
|
|
|
|
|
343 |
if ( file_exists( $original_file ) ) {
|
344 |
return $original_file;
|
345 |
}
|
@@ -351,66 +367,43 @@ class AS3CF_Plugin_Compatibility {
|
|
351 |
* Allow the WordPress Image Editor to remove edited version of images
|
352 |
* if the original image is being restored and 'IMAGE_EDIT_OVERWRITE' is set
|
353 |
*
|
354 |
-
* @param bool
|
355 |
-
* @param
|
356 |
-
* @param
|
|
|
357 |
*
|
358 |
* @return bool
|
359 |
*/
|
360 |
-
public function image_editor_remove_files( $
|
361 |
if ( ! isset( $_POST['do'] ) || 'restore' !== $_POST['do'] ) {
|
362 |
-
return $
|
363 |
}
|
364 |
|
365 |
if ( ! defined( 'IMAGE_EDIT_OVERWRITE' ) || ! IMAGE_EDIT_OVERWRITE ) {
|
366 |
-
return $
|
367 |
}
|
368 |
|
369 |
-
|
370 |
-
|
371 |
-
if ( ! $as3cf_item ) {
|
372 |
-
return $pre;
|
373 |
}
|
374 |
|
375 |
-
$
|
376 |
-
|
377 |
-
|
378 |
-
$
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
$as3cf_item->region(),
|
385 |
-
$as3cf_item->bucket(),
|
386 |
-
$item_path,
|
387 |
-
$as3cf_item->is_private(),
|
388 |
-
$as3cf_item->source_id(),
|
389 |
-
$as3cf_item->source_path(),
|
390 |
-
wp_basename( $as3cf_item->original_source_path() ),
|
391 |
-
$as3cf_item->extra_info(),
|
392 |
-
$as3cf_item->id()
|
393 |
-
);
|
394 |
|
|
|
|
|
|
|
|
|
395 |
$as3cf_item->save();
|
396 |
|
397 |
-
return
|
398 |
-
}
|
399 |
-
|
400 |
-
/**
|
401 |
-
* Remove edited image files from S3.
|
402 |
-
*
|
403 |
-
* @param int $attachment_id
|
404 |
-
* @param Media_Library_Item $as3cf_item
|
405 |
-
*/
|
406 |
-
protected function remove_edited_image_files( $attachment_id, Media_Library_Item $as3cf_item ) {
|
407 |
-
$keys = AS3CF_Utils::get_attachment_edited_keys( $attachment_id, $as3cf_item );
|
408 |
-
|
409 |
-
if ( empty( $keys ) ) {
|
410 |
-
return;
|
411 |
-
}
|
412 |
-
|
413 |
-
$this->as3cf->delete_objects( $as3cf_item->region(), $as3cf_item->bucket(), $keys );
|
414 |
}
|
415 |
|
416 |
/**
|
@@ -434,25 +427,11 @@ class AS3CF_Plugin_Compatibility {
|
|
434 |
// for the restore to be successful and edited images to be deleted from the bucket
|
435 |
// via image_editor_remove_files()
|
436 |
if ( isset( $_POST['do'] ) && 'restore' == $_POST['do'] ) {
|
437 |
-
$
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
$as3cf_item->region(),
|
443 |
-
$as3cf_item->bucket(),
|
444 |
-
$as3cf_item->normalized_path_dir() . $original_filename,
|
445 |
-
$as3cf_item->is_private(),
|
446 |
-
$as3cf_item->source_id(),
|
447 |
-
$as3cf_item->source_path(),
|
448 |
-
wp_basename( $as3cf_item->original_source_path() ),
|
449 |
-
$as3cf_item->extra_info(),
|
450 |
-
$as3cf_item->id()
|
451 |
-
);
|
452 |
-
$orig_file = dirname( $file ) . '/' . $original_filename;
|
453 |
-
|
454 |
-
// Copy the original file back to the server for the restore process
|
455 |
-
$this->copy_provider_file_to_server( $as3cf_item_orig, $orig_file );
|
456 |
|
457 |
// Copy the edited file back to the server as well, it will be cleaned up later
|
458 |
if ( $provider_file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) {
|
@@ -480,27 +459,26 @@ class AS3CF_Plugin_Compatibility {
|
|
480 |
|
481 |
/**
|
482 |
* Allow the WordPress Image Editor to remove the main image file after it has been copied
|
483 |
-
* back from
|
484 |
*
|
485 |
-
* @param array
|
486 |
-
* @param
|
487 |
-
* @param
|
488 |
*
|
489 |
* @return array
|
490 |
*/
|
491 |
-
function image_editor_remove_original_image( $
|
492 |
if ( ! $this->is_ajax() ) {
|
493 |
-
return $
|
494 |
}
|
495 |
|
496 |
if ( isset( $_POST['action'] ) && 'image-editor' === sanitize_key( $_POST['action'] ) ) { // input var okay
|
497 |
-
|
498 |
-
|
499 |
-
$files[] = $original_file;
|
500 |
}
|
501 |
}
|
502 |
|
503 |
-
return $
|
504 |
}
|
505 |
|
506 |
/**
|
@@ -538,39 +516,40 @@ class AS3CF_Plugin_Compatibility {
|
|
538 |
return $url;
|
539 |
}
|
540 |
|
541 |
-
|
|
|
|
|
542 |
return $url;
|
543 |
}
|
544 |
|
545 |
if ( ( $file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) ) {
|
546 |
// Return the file if successfully downloaded from bucket.
|
547 |
return $file;
|
548 |
-
}
|
549 |
|
550 |
return $url;
|
551 |
}
|
552 |
|
553 |
/**
|
554 |
* Allow the WordPress Image Editor to remove the main image file after it has been copied
|
555 |
-
* back from
|
556 |
*
|
557 |
-
* @param array
|
558 |
-
* @param
|
559 |
-
* @param
|
560 |
*
|
561 |
* @return array
|
562 |
*/
|
563 |
-
function customizer_crop_remove_original_image( $
|
564 |
if ( false === $this->is_customizer_crop_action() ) {
|
565 |
-
return $
|
566 |
}
|
567 |
|
568 |
-
|
569 |
-
|
570 |
-
$files[] = $original_file;
|
571 |
}
|
572 |
|
573 |
-
return $
|
574 |
}
|
575 |
|
576 |
/**
|
@@ -595,7 +574,9 @@ class AS3CF_Plugin_Compatibility {
|
|
595 |
$post_id = $url;
|
596 |
}
|
597 |
} else {
|
598 |
-
|
|
|
|
|
599 |
}
|
600 |
|
601 |
// Must return null if not found.
|
@@ -631,26 +612,11 @@ class AS3CF_Plugin_Compatibility {
|
|
631 |
* @return string|bool File if downloaded, false on failure
|
632 |
*/
|
633 |
public function copy_provider_file_to_server( Media_Library_Item $as3cf_item, $file ) {
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
$dir = dirname( $file );
|
638 |
-
if ( ! wp_mkdir_p( $dir ) ) {
|
639 |
-
$error_message = sprintf( __( 'The local directory %s does not exist and could not be created.', 'amazon-s3-and-cloudfront' ), $dir );
|
640 |
-
AS3CF_Error::log( sprintf( __( 'There was an error attempting to download the file %s from the bucket: %s', 'amazon-s3-and-cloudfront' ), $as3cf_item->key( $filename ), $error_message ) );
|
641 |
-
|
642 |
-
return false;
|
643 |
-
}
|
644 |
-
|
645 |
-
try {
|
646 |
-
$this->as3cf->get_provider_client( $as3cf_item->region(), true )->get_object( array(
|
647 |
-
'Bucket' => $as3cf_item->bucket(),
|
648 |
-
'Key' => $as3cf_item->key( $filename ),
|
649 |
-
'SaveAs' => $file,
|
650 |
-
) );
|
651 |
-
} catch ( Exception $e ) {
|
652 |
-
AS3CF_Error::log( sprintf( __( 'There was an error attempting to download the file %s from the bucket: %s', 'amazon-s3-and-cloudfront' ), $as3cf_item->key( $filename ), $e->getMessage() ) );
|
653 |
|
|
|
654 |
return false;
|
655 |
}
|
656 |
|
@@ -722,11 +688,13 @@ class AS3CF_Plugin_Compatibility {
|
|
722 |
public function wp_get_attachment_metadata( $data, $attachment_id ) {
|
723 |
global $wp_current_filter;
|
724 |
|
|
|
725 |
if (
|
726 |
is_array( $wp_current_filter ) &&
|
727 |
! empty( $wp_current_filter[0] ) &&
|
728 |
'the_content' === $wp_current_filter[0] &&
|
729 |
-
|
|
|
730 |
) {
|
731 |
// Ensure each filename is encoded the same way as URL, slightly fixed up for wp_basename() manipulation compatibility.
|
732 |
if ( ! empty( $data['file'] ) ) {
|
@@ -855,7 +823,8 @@ class AS3CF_Plugin_Compatibility {
|
|
855 |
return $image_meta;
|
856 |
}
|
857 |
|
858 |
-
|
|
|
859 |
// Attachment not uploaded to S3, abort
|
860 |
return $image_meta;
|
861 |
}
|
@@ -901,7 +870,8 @@ class AS3CF_Plugin_Compatibility {
|
|
901 |
return $sources;
|
902 |
}
|
903 |
|
904 |
-
|
|
|
905 |
// Attachment not uploaded to S3, abort
|
906 |
return $sources;
|
907 |
}
|
@@ -909,7 +879,7 @@ class AS3CF_Plugin_Compatibility {
|
|
909 |
foreach ( $sources as $width => $source ) {
|
910 |
$filename = wp_basename( $source['url'] );
|
911 |
$size = $this->find_image_size_from_width( $image_meta['sizes'], $width, $filename );
|
912 |
-
$provider_url = $
|
913 |
|
914 |
if ( false === $provider_url || is_wp_error( $provider_url ) ) {
|
915 |
// Skip URLs not offloaded to S3
|
@@ -958,7 +928,9 @@ class AS3CF_Plugin_Compatibility {
|
|
958 |
// Get parent Post ID for cropped image.
|
959 |
$post_id = filter_input( INPUT_POST, 'id', FILTER_VALIDATE_INT );
|
960 |
|
961 |
-
|
|
|
|
|
962 |
|
963 |
return $filename;
|
964 |
}
|
@@ -1026,9 +998,7 @@ class AS3CF_Plugin_Compatibility {
|
|
1026 |
if ( ! empty( $routes ) ) {
|
1027 |
foreach ( $routes as $match_route ) {
|
1028 |
if ( preg_match( '@' . $match_route . '@i', $route ) ) {
|
1029 |
-
$this->
|
1030 |
-
$this->wait_for_generate_attachment_metadata = true;
|
1031 |
-
$this->generate_attachment_metadata_done = false;
|
1032 |
break;
|
1033 |
}
|
1034 |
}
|
9 |
* @since 0.8.3
|
10 |
*/
|
11 |
|
12 |
+
use DeliciousBrains\WP_Offload_Media\Integrations\Media_Library;
|
13 |
+
use DeliciousBrains\WP_Offload_Media\Items\Download_Handler;
|
14 |
+
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
15 |
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
16 |
+
use DeliciousBrains\WP_Offload_Media\Items\Remove_Provider_Handler;
|
17 |
use DeliciousBrains\WP_Offload_Media\Providers\Storage\Storage_Provider;
|
18 |
|
19 |
// Exit if accessed directly
|
30 |
*/
|
31 |
class AS3CF_Plugin_Compatibility {
|
32 |
|
|
|
|
|
|
|
|
|
|
|
33 |
/**
|
34 |
* @var array
|
35 |
*/
|
36 |
protected static $stream_wrappers = array();
|
37 |
|
38 |
/**
|
39 |
+
* @var Amazon_S3_And_CloudFront
|
|
|
|
|
|
|
|
|
|
|
40 |
*/
|
41 |
+
protected $as3cf;
|
42 |
|
43 |
/**
|
44 |
* @var bool
|
45 |
*/
|
46 |
+
protected $wait_for_generate_attachment_metadata = false;
|
47 |
|
48 |
/**
|
49 |
+
* @var array
|
50 |
*/
|
51 |
+
private $removed_files = array();
|
52 |
|
53 |
/**
|
54 |
* @param Amazon_S3_And_CloudFront $as3cf
|
104 |
* WP_Image_Editor
|
105 |
* /wp-includes/class-wp-image-editor.php
|
106 |
*/
|
107 |
+
add_filter( 'as3cf_pre_update_attachment_metadata', array( $this, 'image_editor_remove_files' ), 10, 4 );
|
108 |
add_filter( 'as3cf_get_attached_file_noop', array( $this, 'image_editor_download_file' ), 10, 4 );
|
109 |
add_filter( 'as3cf_get_attached_file', array( $this, 'image_editor_download_file' ), 10, 4 );
|
110 |
+
add_filter( 'as3cf_remove_local_files', array( $this, 'image_editor_remove_original_image' ), 10, 3 );
|
111 |
add_filter( 'as3cf_get_attached_file', array( $this, 'customizer_crop_download_file' ), 10, 4 );
|
112 |
+
add_filter( 'as3cf_remove_local_files', array( $this, 'customizer_crop_remove_original_image' ), 10, 3 );
|
113 |
add_filter( 'wp_unique_filename', array( $this, 'customizer_crop_unique_filename' ), 10, 3 );
|
114 |
|
115 |
/*
|
128 |
* WP-CLI Compatibility
|
129 |
*/
|
130 |
if ( defined( 'WP_CLI' ) && class_exists( 'WP_CLI' ) ) {
|
131 |
+
WP_CLI::add_hook( 'before_invoke:media regenerate', array( $this, 'enable_copy_back_and_wait_for_generate_metadata' ) );
|
132 |
}
|
133 |
}
|
134 |
|
153 |
if ( ( $file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) ) {
|
154 |
// Return the file if successfully downloaded from S3
|
155 |
return $file;
|
156 |
+
}
|
157 |
|
158 |
// Return S3 URL as a fallback
|
159 |
return $url;
|
160 |
}
|
161 |
|
162 |
+
/**
|
163 |
+
* Enable copying back attachments from provider
|
164 |
+
* and waiting for their metadata to be regenerated
|
165 |
+
* before re-offloading.
|
166 |
+
*
|
167 |
+
* @handles WP_CLI:before_invoke:media regenerate
|
168 |
+
*/
|
169 |
+
public function enable_copy_back_and_wait_for_generate_metadata() {
|
170 |
+
$this->enable_get_attached_file_copy_back_to_local();
|
171 |
+
$this->wait_for_generate_attachment_metadata = true;
|
172 |
+
}
|
173 |
+
|
174 |
/**
|
175 |
* Enables copying missing local files back to the server when `get_attached_file` filter is called.
|
176 |
*/
|
244 |
*
|
245 |
* @handles wp_generate_attachment_metadata
|
246 |
*
|
247 |
+
* @param mixed $metadata
|
248 |
*
|
249 |
* @return mixed
|
250 |
*/
|
251 |
public function wp_generate_attachment_metadata( $metadata ) {
|
252 |
+
$this->wait_for_generate_attachment_metadata = false;
|
253 |
+
|
254 |
return $metadata;
|
255 |
}
|
256 |
|
260 |
*
|
261 |
* @handles as3cf_wait_for_generate_attachment_metadata
|
262 |
*
|
263 |
+
* @param bool $wait
|
264 |
+
*
|
265 |
* @return bool
|
266 |
*/
|
267 |
+
public function wait_for_generate_attachment_metadata( $wait ) {
|
268 |
+
if ( $this->wait_for_generate_attachment_metadata ) {
|
269 |
+
return true;
|
270 |
}
|
271 |
|
272 |
+
return $wait;
|
273 |
}
|
274 |
|
275 |
/**
|
332 |
if ( ( $file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) ) {
|
333 |
// Return the file if successfully downloaded from S3
|
334 |
return $file;
|
335 |
+
}
|
336 |
|
337 |
return $url;
|
338 |
}
|
339 |
|
340 |
/**
|
341 |
+
* Get the file path of the primary image file if it exists.
|
342 |
+
*
|
343 |
+
* This helper function looks at the current metadata for the Media Library item.
|
344 |
+
* In various scenarios this is useful when an item's offloaded objects
|
345 |
+
* and the attachment's metadata are not yet in sync.
|
346 |
*
|
347 |
+
* @param Item $as3cf_item
|
|
|
348 |
*
|
349 |
* @return bool|string
|
350 |
*/
|
351 |
+
private function get_original_image_file( Item $as3cf_item ) {
|
352 |
+
if ( Media_Library_Item::source_type() !== $as3cf_item->source_type() ) {
|
353 |
+
return false;
|
354 |
+
}
|
355 |
+
|
356 |
+
$meta = get_post_meta( $as3cf_item->source_id(), '_wp_attachment_metadata', true );
|
357 |
+
$original_file = trailingslashit( dirname( $as3cf_item->full_source_path() ) ) . wp_basename( $meta['file'] );
|
358 |
+
|
359 |
if ( file_exists( $original_file ) ) {
|
360 |
return $original_file;
|
361 |
}
|
367 |
* Allow the WordPress Image Editor to remove edited version of images
|
368 |
* if the original image is being restored and 'IMAGE_EDIT_OVERWRITE' is set
|
369 |
*
|
370 |
+
* @param bool $cancel True if the upload should be cancelled
|
371 |
+
* @param array $data Array describing the object being uploaded
|
372 |
+
* @param int $post_id Attachment's ID
|
373 |
+
* @param Media_Library_Item $as3cf_item The Media Library Item object if previously offloaded
|
374 |
*
|
375 |
* @return bool
|
376 |
*/
|
377 |
+
public function image_editor_remove_files( $cancel, $data, $post_id, $as3cf_item ) {
|
378 |
if ( ! isset( $_POST['do'] ) || 'restore' !== $_POST['do'] ) {
|
379 |
+
return $cancel;
|
380 |
}
|
381 |
|
382 |
if ( ! defined( 'IMAGE_EDIT_OVERWRITE' ) || ! IMAGE_EDIT_OVERWRITE ) {
|
383 |
+
return $cancel;
|
384 |
}
|
385 |
|
386 |
+
if ( empty( $as3cf_item ) ) {
|
387 |
+
return $cancel;
|
|
|
|
|
388 |
}
|
389 |
|
390 |
+
$keys_to_remove = array();
|
391 |
+
$pattern = '/-e[0-9]{13}(?:-[0-9]{1,4}x[0-9]{1,4})?\./';
|
392 |
+
$objects = $as3cf_item->objects();
|
393 |
+
foreach ( $objects as $object_key => $object ) {
|
394 |
+
if ( preg_match( $pattern, $object['source_file'] ) ) {
|
395 |
+
$keys_to_remove[] = $object_key;
|
396 |
+
unset( $objects[ $object_key ] );
|
397 |
+
}
|
398 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
399 |
|
400 |
+
$remove_provider_handler = $this->as3cf->get_item_handler( Remove_Provider_Handler::get_item_handler_key_name() );
|
401 |
+
$remove_provider_handler->handle( $as3cf_item, array( 'object_keys' => $keys_to_remove ) );
|
402 |
+
// TODO: Check these following statements are required.
|
403 |
+
$as3cf_item->set_objects( $objects );
|
404 |
$as3cf_item->save();
|
405 |
|
406 |
+
return $cancel;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
407 |
}
|
408 |
|
409 |
/**
|
427 |
// for the restore to be successful and edited images to be deleted from the bucket
|
428 |
// via image_editor_remove_files()
|
429 |
if ( isset( $_POST['do'] ) && 'restore' == $_POST['do'] ) {
|
430 |
+
$objects = $as3cf_item->objects();
|
431 |
+
if ( isset( $objects['full-orig'] ) ) {
|
432 |
+
// Copy the original file back to the server for the restore process
|
433 |
+
$this->copy_provider_file_to_server( $as3cf_item, $objects['full-orig']['source_file'] );
|
434 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
435 |
|
436 |
// Copy the edited file back to the server as well, it will be cleaned up later
|
437 |
if ( $provider_file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) {
|
459 |
|
460 |
/**
|
461 |
* Allow the WordPress Image Editor to remove the main image file after it has been copied
|
462 |
+
* back from the bucket after it has done the edit.
|
463 |
*
|
464 |
+
* @param array $files_to_remove
|
465 |
+
* @param Item $as3cf_item
|
466 |
+
* @param array $item_source
|
467 |
*
|
468 |
* @return array
|
469 |
*/
|
470 |
+
public function image_editor_remove_original_image( $files_to_remove, $as3cf_item, $item_source ) {
|
471 |
if ( ! $this->is_ajax() ) {
|
472 |
+
return $files_to_remove;
|
473 |
}
|
474 |
|
475 |
if ( isset( $_POST['action'] ) && 'image-editor' === sanitize_key( $_POST['action'] ) ) { // input var okay
|
476 |
+
if ( ( $original_file = $this->get_original_image_file( $as3cf_item ) ) ) {
|
477 |
+
$files_to_remove[] = $original_file;
|
|
|
478 |
}
|
479 |
}
|
480 |
|
481 |
+
return $files_to_remove;
|
482 |
}
|
483 |
|
484 |
/**
|
516 |
return $url;
|
517 |
}
|
518 |
|
519 |
+
/** @var Media_Library $media_library */
|
520 |
+
$media_library = $this->as3cf->get_integration_manager()->get_integration( 'mlib' );
|
521 |
+
if ( $media_library->item_just_uploaded( $attachment_id ) ) {
|
522 |
return $url;
|
523 |
}
|
524 |
|
525 |
if ( ( $file = $this->copy_provider_file_to_server( $as3cf_item, $file ) ) ) {
|
526 |
// Return the file if successfully downloaded from bucket.
|
527 |
return $file;
|
528 |
+
}
|
529 |
|
530 |
return $url;
|
531 |
}
|
532 |
|
533 |
/**
|
534 |
* Allow the WordPress Image Editor to remove the main image file after it has been copied
|
535 |
+
* back from the bucket after it has done the edit.
|
536 |
*
|
537 |
+
* @param array $files_to_remove
|
538 |
+
* @param Item $as3cf_item
|
539 |
+
* @param array $item_source
|
540 |
*
|
541 |
* @return array
|
542 |
*/
|
543 |
+
function customizer_crop_remove_original_image( $files_to_remove, $as3cf_item, $item_source ) {
|
544 |
if ( false === $this->is_customizer_crop_action() ) {
|
545 |
+
return $files_to_remove;
|
546 |
}
|
547 |
|
548 |
+
if ( ( $original_file = $this->get_original_image_file( $as3cf_item ) ) ) {
|
549 |
+
$files_to_remove[] = $original_file;
|
|
|
550 |
}
|
551 |
|
552 |
+
return $files_to_remove;
|
553 |
}
|
554 |
|
555 |
/**
|
574 |
$post_id = $url;
|
575 |
}
|
576 |
} else {
|
577 |
+
/** @var Media_Library $media_library */
|
578 |
+
$media_library = $this->as3cf->get_integration_manager()->get_integration( 'mlib' );
|
579 |
+
$post_id = $media_library->get_attachment_id_from_provider_url( $url );
|
580 |
}
|
581 |
|
582 |
// Must return null if not found.
|
612 |
* @return string|bool File if downloaded, false on failure
|
613 |
*/
|
614 |
public function copy_provider_file_to_server( Media_Library_Item $as3cf_item, $file ) {
|
615 |
+
/** @var Download_Handler $download_handler */
|
616 |
+
$download_handler = $this->as3cf->get_item_handler( Download_Handler::get_item_handler_key_name() );
|
617 |
+
$result = $download_handler->handle( $as3cf_item, array( 'full_source_paths' => array( $file ) ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
618 |
|
619 |
+
if ( empty( $result ) || is_wp_error( $result ) ) {
|
620 |
return false;
|
621 |
}
|
622 |
|
688 |
public function wp_get_attachment_metadata( $data, $attachment_id ) {
|
689 |
global $wp_current_filter;
|
690 |
|
691 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
692 |
if (
|
693 |
is_array( $wp_current_filter ) &&
|
694 |
! empty( $wp_current_filter[0] ) &&
|
695 |
'the_content' === $wp_current_filter[0] &&
|
696 |
+
! empty( $as3cf_item ) &&
|
697 |
+
$as3cf_item->served_by_provider( $attachment_id )
|
698 |
) {
|
699 |
// Ensure each filename is encoded the same way as URL, slightly fixed up for wp_basename() manipulation compatibility.
|
700 |
if ( ! empty( $data['file'] ) ) {
|
823 |
return $image_meta;
|
824 |
}
|
825 |
|
826 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
827 |
+
if ( ! $as3cf_item || ! $as3cf_item->served_by_provider() ) {
|
828 |
// Attachment not uploaded to S3, abort
|
829 |
return $image_meta;
|
830 |
}
|
870 |
return $sources;
|
871 |
}
|
872 |
|
873 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
874 |
+
if ( ! $as3cf_item || ! $as3cf_item->served_by_provider() ) {
|
875 |
// Attachment not uploaded to S3, abort
|
876 |
return $sources;
|
877 |
}
|
879 |
foreach ( $sources as $width => $source ) {
|
880 |
$filename = wp_basename( $source['url'] );
|
881 |
$size = $this->find_image_size_from_width( $image_meta['sizes'], $width, $filename );
|
882 |
+
$provider_url = $as3cf_item->get_provider_url( $size );
|
883 |
|
884 |
if ( false === $provider_url || is_wp_error( $provider_url ) ) {
|
885 |
// Skip URLs not offloaded to S3
|
928 |
// Get parent Post ID for cropped image.
|
929 |
$post_id = filter_input( INPUT_POST, 'id', FILTER_VALIDATE_INT );
|
930 |
|
931 |
+
/** @var Media_Library $media_library */
|
932 |
+
$media_library = $this->as3cf->get_integration_manager()->get_integration( 'mlib' );
|
933 |
+
$filename = $media_library->filter_unique_filename( $filename, $ext, $dir, $post_id );
|
934 |
|
935 |
return $filename;
|
936 |
}
|
998 |
if ( ! empty( $routes ) ) {
|
999 |
foreach ( $routes as $match_route ) {
|
1000 |
if ( preg_match( '@' . $match_route . '@i', $route ) ) {
|
1001 |
+
$this->enable_copy_back_and_wait_for_generate_metadata();
|
|
|
|
|
1002 |
break;
|
1003 |
}
|
1004 |
}
|
@@ -8,6 +8,7 @@
|
|
8 |
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
9 |
*/
|
10 |
|
|
|
11 |
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
12 |
|
13 |
// Exit if accessed directly
|
@@ -103,6 +104,8 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
103 |
public static function remove_size_from_filename( $url, $remove_extension = false ) {
|
104 |
$url = preg_replace( '/^(\S+)-[0-9]{1,4}x[0-9]{1,4}(\.[a-zA-Z0-9\.]{2,})?/', '$1$2', $url );
|
105 |
|
|
|
|
|
106 |
if ( $remove_extension ) {
|
107 |
$ext = pathinfo( $url, PATHINFO_EXTENSION );
|
108 |
$url = str_replace( ".$ext", '', $url );
|
@@ -119,7 +122,7 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
119 |
* @return bool
|
120 |
*/
|
121 |
public static function is_full_size( $size ) {
|
122 |
-
if ( empty( $size ) || in_array( $size, array( 'full',
|
123 |
return true;
|
124 |
}
|
125 |
|
@@ -224,7 +227,7 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
224 |
public static function get_attachment_file_paths( $attachment_id, $exists_locally = true, $meta = false, $include_backups = true ) {
|
225 |
$file_path = get_attached_file( $attachment_id, true );
|
226 |
$paths = array(
|
227 |
-
|
228 |
);
|
229 |
|
230 |
if ( ! $meta ) {
|
@@ -240,6 +243,11 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
240 |
// If file edited, current file name might be different.
|
241 |
if ( isset( $meta['file'] ) ) {
|
242 |
$paths['file'] = str_replace( $file_name, wp_basename( $meta['file'] ), $file_path );
|
|
|
|
|
|
|
|
|
|
|
243 |
}
|
244 |
|
245 |
// Thumb
|
@@ -287,39 +295,6 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
287 |
return $paths;
|
288 |
}
|
289 |
|
290 |
-
/**
|
291 |
-
* Get an attachment's edited file paths.
|
292 |
-
*
|
293 |
-
* @param int $attachment_id
|
294 |
-
*
|
295 |
-
* @return array
|
296 |
-
*/
|
297 |
-
public static function get_attachment_edited_file_paths( $attachment_id ) {
|
298 |
-
$paths = self::get_attachment_file_paths( $attachment_id, false );
|
299 |
-
$paths = array_filter( $paths, function ( $path ) {
|
300 |
-
return preg_match( '/-e[0-9]{13}(?:-[0-9]{1,4}x[0-9]{1,4})?\./', wp_basename( $path ) );
|
301 |
-
} );
|
302 |
-
|
303 |
-
return $paths;
|
304 |
-
}
|
305 |
-
|
306 |
-
/**
|
307 |
-
* Get an attachment's edited S3 keys.
|
308 |
-
*
|
309 |
-
* @param int $attachment_id
|
310 |
-
* @param Media_Library_Item $as3cf_item
|
311 |
-
*
|
312 |
-
* @return array
|
313 |
-
*/
|
314 |
-
public static function get_attachment_edited_keys( $attachment_id, Media_Library_Item $as3cf_item ) {
|
315 |
-
$paths = self::get_attachment_edited_file_paths( $attachment_id );
|
316 |
-
$paths = array_map( function ( $path ) use ( $as3cf_item ) {
|
317 |
-
return array( 'Key' => $as3cf_item->key( wp_basename( $path ) ) );
|
318 |
-
}, $paths );
|
319 |
-
|
320 |
-
return $paths;
|
321 |
-
}
|
322 |
-
|
323 |
/**
|
324 |
* Get intermediate size from attachment filename.
|
325 |
* If multiple sizes exist with same filename, only the first size found will be returned.
|
@@ -345,14 +320,24 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
345 |
* Strip edited image suffix and extension from path.
|
346 |
*
|
347 |
* @param string $path
|
|
|
348 |
*
|
349 |
* @return string
|
350 |
*/
|
351 |
-
public static function strip_image_edit_suffix_and_extension( $path ) {
|
352 |
$parts = pathinfo( $path );
|
353 |
$filename = preg_replace( '/-e[0-9]{13}/', '', $parts['filename'] );
|
|
|
354 |
|
355 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
356 |
}
|
357 |
|
358 |
/**
|
@@ -513,19 +498,23 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
513 |
/**
|
514 |
* Ensure returned keys are for correct attachment.
|
515 |
*
|
516 |
-
* @param
|
|
|
|
|
517 |
*
|
518 |
* @return array
|
519 |
*/
|
520 |
-
public static function validate_attachment_keys( $
|
521 |
-
|
522 |
-
|
|
|
523 |
|
524 |
-
|
525 |
-
|
526 |
|
527 |
-
|
528 |
-
|
|
|
529 |
}
|
530 |
}
|
531 |
|
@@ -584,7 +573,7 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
584 |
*/
|
585 |
public static function fullsize_paths( $paths ) {
|
586 |
if ( is_array( $paths ) && ! empty( $paths ) ) {
|
587 |
-
return array_values( array_unique( array_intersect_key( $paths, array_flip( array(
|
588 |
} else {
|
589 |
return array();
|
590 |
}
|
@@ -620,70 +609,6 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
620 |
return $paths;
|
621 |
}
|
622 |
|
623 |
-
/**
|
624 |
-
* Convert dimensions to size
|
625 |
-
*
|
626 |
-
* @param int $attachment_id
|
627 |
-
* @param array $dimensions
|
628 |
-
*
|
629 |
-
* @return null|string
|
630 |
-
*/
|
631 |
-
public static function convert_dimensions_to_size_name( $attachment_id, $dimensions ) {
|
632 |
-
$w = ( isset( $dimensions[0] ) && $dimensions[0] > 0 ) ? $dimensions[0] : 1;
|
633 |
-
$h = ( isset( $dimensions[1] ) && $dimensions[1] > 0 ) ? $dimensions[1] : 1;
|
634 |
-
$original_aspect_ratio = $w / $h;
|
635 |
-
$meta = wp_get_attachment_metadata( $attachment_id );
|
636 |
-
|
637 |
-
if ( ! isset( $meta['sizes'] ) || empty( $meta['sizes'] ) ) {
|
638 |
-
return null;
|
639 |
-
}
|
640 |
-
|
641 |
-
$sizes = $meta['sizes'];
|
642 |
-
uasort( $sizes, function ( $a, $b ) {
|
643 |
-
// Order by image area
|
644 |
-
return ( $a['width'] * $a['height'] ) - ( $b['width'] * $b['height'] );
|
645 |
-
} );
|
646 |
-
|
647 |
-
$nearest_matches = array();
|
648 |
-
|
649 |
-
foreach ( $sizes as $size => $value ) {
|
650 |
-
if ( $w > $value['width'] || $h > $value['height'] ) {
|
651 |
-
continue;
|
652 |
-
}
|
653 |
-
|
654 |
-
$aspect_ratio = $value['width'] / $value['height'];
|
655 |
-
|
656 |
-
if ( $aspect_ratio === $original_aspect_ratio ) {
|
657 |
-
return $size;
|
658 |
-
}
|
659 |
-
|
660 |
-
$nearest_matches[] = $size;
|
661 |
-
}
|
662 |
-
|
663 |
-
// Return nearest match
|
664 |
-
if ( ! empty( $nearest_matches ) ) {
|
665 |
-
return $nearest_matches[0];
|
666 |
-
}
|
667 |
-
|
668 |
-
return null;
|
669 |
-
}
|
670 |
-
|
671 |
-
/**
|
672 |
-
* Maybe convert size to string
|
673 |
-
*
|
674 |
-
* @param int $attachment_id
|
675 |
-
* @param mixed $size
|
676 |
-
*
|
677 |
-
* @return null|string
|
678 |
-
*/
|
679 |
-
public static function maybe_convert_size_to_string( $attachment_id, $size ) {
|
680 |
-
if ( is_array( $size ) ) {
|
681 |
-
return static::convert_dimensions_to_size_name( $attachment_id, $size );
|
682 |
-
}
|
683 |
-
|
684 |
-
return $size;
|
685 |
-
}
|
686 |
-
|
687 |
/**
|
688 |
* Encode file names according to RFC 3986 when generating urls
|
689 |
* As per Amazon https://forums.aws.amazon.com/thread.jspa?threadID=55746#jive-message-244233
|
@@ -721,5 +646,18 @@ if ( ! class_exists( 'AS3CF_Utils' ) ) {
|
|
721 |
|
722 |
return str_replace( $file_name, $encoded_file_name, $file );
|
723 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
724 |
}
|
725 |
}
|
8 |
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
9 |
*/
|
10 |
|
11 |
+
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
12 |
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
13 |
|
14 |
// Exit if accessed directly
|
104 |
public static function remove_size_from_filename( $url, $remove_extension = false ) {
|
105 |
$url = preg_replace( '/^(\S+)-[0-9]{1,4}x[0-9]{1,4}(\.[a-zA-Z0-9\.]{2,})?/', '$1$2', $url );
|
106 |
|
107 |
+
$url = apply_filters( 'as3cf_remove_size_from_filename', $url );
|
108 |
+
|
109 |
if ( $remove_extension ) {
|
110 |
$ext = pathinfo( $url, PATHINFO_EXTENSION );
|
111 |
$url = str_replace( ".$ext", '', $url );
|
122 |
* @return bool
|
123 |
*/
|
124 |
public static function is_full_size( $size ) {
|
125 |
+
if ( empty( $size ) || in_array( $size, array( 'full', Item::primary_object_key() ) ) ) {
|
126 |
return true;
|
127 |
}
|
128 |
|
227 |
public static function get_attachment_file_paths( $attachment_id, $exists_locally = true, $meta = false, $include_backups = true ) {
|
228 |
$file_path = get_attached_file( $attachment_id, true );
|
229 |
$paths = array(
|
230 |
+
Item::primary_object_key() => $file_path,
|
231 |
);
|
232 |
|
233 |
if ( ! $meta ) {
|
243 |
// If file edited, current file name might be different.
|
244 |
if ( isset( $meta['file'] ) ) {
|
245 |
$paths['file'] = str_replace( $file_name, wp_basename( $meta['file'] ), $file_path );
|
246 |
+
|
247 |
+
// However, if this file path turns out to be exactly the same as the primary objet key, we don't need it.
|
248 |
+
if ( $paths[ Item::primary_object_key() ] === $paths['file'] ) {
|
249 |
+
unset( $paths['file'] );
|
250 |
+
}
|
251 |
}
|
252 |
|
253 |
// Thumb
|
295 |
return $paths;
|
296 |
}
|
297 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
298 |
/**
|
299 |
* Get intermediate size from attachment filename.
|
300 |
* If multiple sizes exist with same filename, only the first size found will be returned.
|
320 |
* Strip edited image suffix and extension from path.
|
321 |
*
|
322 |
* @param string $path
|
323 |
+
* @param string $source_type
|
324 |
*
|
325 |
* @return string
|
326 |
*/
|
327 |
+
public static function strip_image_edit_suffix_and_extension( $path, $source_type = 'media-library' ) {
|
328 |
$parts = pathinfo( $path );
|
329 |
$filename = preg_replace( '/-e[0-9]{13}/', '', $parts['filename'] );
|
330 |
+
$result = str_replace( $parts['basename'], $filename, $path );
|
331 |
|
332 |
+
/**
|
333 |
+
* Allow source type specific cleanup
|
334 |
+
*
|
335 |
+
* @param string $path
|
336 |
+
* @param string $source_type
|
337 |
+
*
|
338 |
+
* @return string
|
339 |
+
*/
|
340 |
+
return apply_filters( 'as3cf_strip_image_edit_suffix_and_extension', $result, $source_type );
|
341 |
}
|
342 |
|
343 |
/**
|
498 |
/**
|
499 |
* Ensure returned keys are for correct attachment.
|
500 |
*
|
501 |
+
* @param int $source_id
|
502 |
+
* @param array $keys
|
503 |
+
* @param string $source_type
|
504 |
*
|
505 |
* @return array
|
506 |
*/
|
507 |
+
public static function validate_attachment_keys( $source_id, $keys, $source_type ) {
|
508 |
+
if ( Media_Library_Item::source_type() === $source_type ) {
|
509 |
+
$paths = self::get_attachment_file_paths( $source_id, false );
|
510 |
+
$filenames = array_map( 'wp_basename', $paths );
|
511 |
|
512 |
+
foreach ( $keys as $key => $value ) {
|
513 |
+
$filename = wp_basename( $value );
|
514 |
|
515 |
+
if ( ! in_array( $filename, $filenames ) ) {
|
516 |
+
unset( $keys[ $key ] );
|
517 |
+
}
|
518 |
}
|
519 |
}
|
520 |
|
573 |
*/
|
574 |
public static function fullsize_paths( $paths ) {
|
575 |
if ( is_array( $paths ) && ! empty( $paths ) ) {
|
576 |
+
return array_values( array_unique( array_intersect_key( $paths, array_flip( array( Item::primary_object_key(), 'file', 'full-orig', 'original_image' ) ) ) ) );
|
577 |
} else {
|
578 |
return array();
|
579 |
}
|
609 |
return $paths;
|
610 |
}
|
611 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
612 |
/**
|
613 |
* Encode file names according to RFC 3986 when generating urls
|
614 |
* As per Amazon https://forums.aws.amazon.com/thread.jspa?threadID=55746#jive-message-244233
|
646 |
|
647 |
return str_replace( $file_name, $encoded_file_name, $file );
|
648 |
}
|
649 |
+
|
650 |
+
/**
|
651 |
+
* Get a file's real mime type
|
652 |
+
*
|
653 |
+
* @param string $file_path
|
654 |
+
*
|
655 |
+
* @return string
|
656 |
+
*/
|
657 |
+
public static function get_mime_type( $file_path ) {
|
658 |
+
$file_type = wp_check_filetype_and_ext( $file_path, wp_basename( $file_path ) );
|
659 |
+
|
660 |
+
return $file_type['type'];
|
661 |
+
}
|
662 |
}
|
663 |
}
|
@@ -1,6 +1,6 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
use DeliciousBrains\WP_Offload_Media\Items\
|
4 |
|
5 |
class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
6 |
|
@@ -26,10 +26,20 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
26 |
add_filter( 'as3cf_filter_post_local_to_s3', array( $this, 'filter_post' ) ); // Backwards compatibility
|
27 |
add_filter( 'as3cf_filter_post_local_to_provider', array( $this, 'filter_post' ) );
|
28 |
// Widgets
|
29 |
-
add_filter( 'widget_form_callback', array( $this, 'filter_widget_display' )
|
30 |
-
add_filter( 'widget_display_callback', array( $this, 'filter_widget_display' )
|
|
|
|
|
|
|
|
|
31 |
// Edit Media page
|
32 |
add_filter( 'set_url_scheme', array( $this, 'set_url_scheme' ), 10, 3 );
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
}
|
34 |
|
35 |
/**
|
@@ -38,7 +48,7 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
38 |
* @param mixed $value
|
39 |
* @param WP_Customize_Custom_CSS_Setting $setting
|
40 |
*
|
41 |
-
* @return
|
42 |
*/
|
43 |
public function filter_customize_value_custom_css( $value, $setting ) {
|
44 |
return $this->filter_custom_css( $value, $setting->stylesheet );
|
@@ -102,13 +112,49 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
102 |
/**
|
103 |
* Filter widget display.
|
104 |
*
|
105 |
-
* @param array
|
106 |
-
* @param WP_Widget $class
|
107 |
*
|
108 |
* @return array
|
109 |
*/
|
110 |
-
public function filter_widget_display( $instance
|
111 |
-
return $this->handle_widget( $instance
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
}
|
113 |
|
114 |
/**
|
@@ -131,35 +177,61 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
131 |
/**
|
132 |
* Get URL
|
133 |
*
|
134 |
-
* @param
|
135 |
-
* @param null|string $
|
136 |
*
|
137 |
* @return bool|string
|
138 |
*/
|
139 |
-
protected function get_url( $
|
140 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
}
|
142 |
|
143 |
/**
|
144 |
* Get base URL.
|
145 |
*
|
146 |
-
* @param
|
147 |
*
|
148 |
* @return string|false
|
149 |
*/
|
150 |
-
protected function get_base_url( $
|
151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
}
|
153 |
|
154 |
/**
|
155 |
-
* Get
|
156 |
*
|
157 |
* @param string $url
|
158 |
*
|
159 |
-
* @return bool|
|
160 |
*/
|
161 |
-
public function
|
162 |
-
$results = $this->
|
163 |
|
164 |
if ( empty( $results ) ) {
|
165 |
return false;
|
@@ -175,13 +247,13 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
175 |
}
|
176 |
|
177 |
/**
|
178 |
-
* Get
|
179 |
*
|
180 |
* @param array $urls
|
181 |
*
|
182 |
-
* @return array url =>
|
183 |
*/
|
184 |
-
protected function
|
185 |
$results = array();
|
186 |
|
187 |
if ( empty( $urls ) ) {
|
@@ -226,24 +298,28 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
226 |
}
|
227 |
|
228 |
if ( ! empty( $paths ) ) {
|
229 |
-
$as3cf_items =
|
230 |
|
231 |
if ( ! empty( $as3cf_items ) ) {
|
232 |
-
/* @var
|
233 |
foreach ( $as3cf_items as $as3cf_item ) {
|
234 |
// Each returned item may have matched on either the source_path or original_source_path.
|
235 |
-
// Because the base image file name of a thumbnail might match the
|
236 |
// it's possible that both source paths are used by separate URLs.
|
237 |
foreach ( array( $as3cf_item->source_path(), $as3cf_item->original_source_path() ) as $source_path ) {
|
238 |
if ( ! empty( $paths[ $source_path ] ) ) {
|
239 |
$matched_full_url = $paths[ $source_path ];
|
240 |
|
241 |
if ( ! empty( $full_urls[ $matched_full_url ] ) ) {
|
242 |
-
$
|
243 |
-
|
|
|
|
|
|
|
|
|
244 |
|
245 |
foreach ( $full_urls[ $matched_full_url ] as $url ) {
|
246 |
-
$results[ $url ] = $
|
247 |
}
|
248 |
unset( $full_urls[ $matched_full_url ] );
|
249 |
}
|
@@ -252,7 +328,7 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
252 |
}
|
253 |
}
|
254 |
|
255 |
-
// No more
|
256 |
if ( count( $query_set ) !== count( $results ) ) {
|
257 |
foreach ( $full_urls as $full_url => $schema_urls ) {
|
258 |
foreach ( $schema_urls as $url ) {
|
@@ -369,4 +445,54 @@ class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
|
369 |
|
370 |
return $url;
|
371 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
372 |
}
|
1 |
<?php
|
2 |
|
3 |
+
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
4 |
|
5 |
class AS3CF_Local_To_S3 extends AS3CF_Filter {
|
6 |
|
26 |
add_filter( 'as3cf_filter_post_local_to_s3', array( $this, 'filter_post' ) ); // Backwards compatibility
|
27 |
add_filter( 'as3cf_filter_post_local_to_provider', array( $this, 'filter_post' ) );
|
28 |
// Widgets
|
29 |
+
add_filter( 'widget_form_callback', array( $this, 'filter_widget_display' ) );
|
30 |
+
add_filter( 'widget_display_callback', array( $this, 'filter_widget_display' ) );
|
31 |
+
if ( function_exists( 'is_wp_version_compatible' ) && is_wp_version_compatible( '5.8' ) ) {
|
32 |
+
add_filter( 'customize_value_widget_block', array( $this, 'filter_customize_value_widget_block' ) );
|
33 |
+
add_filter( 'widget_block_content', array( $this, 'filter_widget_block_content' ) );
|
34 |
+
}
|
35 |
// Edit Media page
|
36 |
add_filter( 'set_url_scheme', array( $this, 'set_url_scheme' ), 10, 3 );
|
37 |
+
// Blocks
|
38 |
+
if ( function_exists( 'is_wp_version_compatible' ) && is_wp_version_compatible( '5.9' ) ) {
|
39 |
+
add_filter( 'render_block', array( $this, 'filter_post' ), 100 );
|
40 |
+
add_filter( 'get_block_templates', array( $this, 'filter_get_block_templates' ), 100, 3 );
|
41 |
+
add_filter( 'get_block_template', array( $this, 'filter_get_block_template' ), 100, 3 );
|
42 |
+
}
|
43 |
}
|
44 |
|
45 |
/**
|
48 |
* @param mixed $value
|
49 |
* @param WP_Customize_Custom_CSS_Setting $setting
|
50 |
*
|
51 |
+
* @return string
|
52 |
*/
|
53 |
public function filter_customize_value_custom_css( $value, $setting ) {
|
54 |
return $this->filter_custom_css( $value, $setting->stylesheet );
|
112 |
/**
|
113 |
* Filter widget display.
|
114 |
*
|
115 |
+
* @param array $instance
|
|
|
116 |
*
|
117 |
* @return array
|
118 |
*/
|
119 |
+
public function filter_widget_display( $instance ) {
|
120 |
+
return $this->handle_widget( $instance );
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* Filters the content of the block widget during initial load of the customizer.
|
125 |
+
*
|
126 |
+
* @param array $value The widget block.
|
127 |
+
*
|
128 |
+
* @return array
|
129 |
+
*/
|
130 |
+
public function filter_customize_value_widget_block( $value ) {
|
131 |
+
return $this->handle_widget( $value );
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Filters the content of the block widget before output.
|
136 |
+
*
|
137 |
+
* @param string $content The widget content.
|
138 |
+
*
|
139 |
+
* @return string
|
140 |
+
*/
|
141 |
+
public function filter_widget_block_content( $content ) {
|
142 |
+
if ( empty( $content ) ) {
|
143 |
+
return $content;
|
144 |
+
}
|
145 |
+
|
146 |
+
$cache = $this->get_option_cache();
|
147 |
+
$to_cache = array();
|
148 |
+
|
149 |
+
$changed_content = $this->process_content( $content, $cache, $to_cache );
|
150 |
+
|
151 |
+
if ( ! empty( $changed_content ) && $changed_content !== $content ) {
|
152 |
+
$content = $changed_content;
|
153 |
+
}
|
154 |
+
|
155 |
+
$this->maybe_update_option_cache( $to_cache );
|
156 |
+
|
157 |
+
return $content;
|
158 |
}
|
159 |
|
160 |
/**
|
177 |
/**
|
178 |
* Get URL
|
179 |
*
|
180 |
+
* @param array $item_source
|
181 |
+
* @param null|string $object_key
|
182 |
*
|
183 |
* @return bool|string
|
184 |
*/
|
185 |
+
protected function get_url( $item_source, $object_key = null ) {
|
186 |
+
if ( empty( $item_source['id'] ) || empty( $item_source['source_type'] ) ) {
|
187 |
+
return false;
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Return the provider URL for an item
|
192 |
+
*
|
193 |
+
* @param string|false $url Url for the item, false if no URL can be determined
|
194 |
+
* @param array $item_source Associative array describing the item, guaranteed keys:-
|
195 |
+
* id: source item's unique integer id
|
196 |
+
* source_type: source item's string type identifier
|
197 |
+
* @param string|null $object_key Object key (size) describing what sub file of an item to return url for
|
198 |
+
*/
|
199 |
+
return apply_filters( 'as3cf_get_provider_url_for_item_source', false, $item_source, $object_key );
|
200 |
}
|
201 |
|
202 |
/**
|
203 |
* Get base URL.
|
204 |
*
|
205 |
+
* @param array $item_source
|
206 |
*
|
207 |
* @return string|false
|
208 |
*/
|
209 |
+
protected function get_base_url( $item_source ) {
|
210 |
+
if ( empty( $item_source['id'] ) || empty( $item_source['source_type'] ) ) {
|
211 |
+
return false;
|
212 |
+
}
|
213 |
+
|
214 |
+
/**
|
215 |
+
* Return the local URL for an item
|
216 |
+
*
|
217 |
+
* @param string|false $url Url for the item, false if no URL can be determined
|
218 |
+
* @param array $item_source Associative array describing the item, guaranteed keys:-
|
219 |
+
* id: source item's unique integer id
|
220 |
+
* source_type: source item's string type identifier
|
221 |
+
* @param string|null $object_key Object key (size) describing what sub file of an item to return url for
|
222 |
+
*/
|
223 |
+
return apply_filters( 'as3cf_get_local_url_for_item_source', false, $item_source, null );
|
224 |
}
|
225 |
|
226 |
/**
|
227 |
+
* Get item source descriptor from URL.
|
228 |
*
|
229 |
* @param string $url
|
230 |
*
|
231 |
+
* @return bool|array
|
232 |
*/
|
233 |
+
public function get_item_source_from_url( $url ) {
|
234 |
+
$results = $this->get_item_sources_from_urls( array( $url ) );
|
235 |
|
236 |
if ( empty( $results ) ) {
|
237 |
return false;
|
247 |
}
|
248 |
|
249 |
/**
|
250 |
+
* Get item source descriptors from URLs.
|
251 |
*
|
252 |
* @param array $urls
|
253 |
*
|
254 |
+
* @return array url => item source descriptor array (or false)
|
255 |
*/
|
256 |
+
protected function get_item_sources_from_urls( $urls ) {
|
257 |
$results = array();
|
258 |
|
259 |
if ( empty( $urls ) ) {
|
298 |
}
|
299 |
|
300 |
if ( ! empty( $paths ) ) {
|
301 |
+
$as3cf_items = Item::get_by_source_path( array_keys( $paths ) );
|
302 |
|
303 |
if ( ! empty( $as3cf_items ) ) {
|
304 |
+
/* @var Item $as3cf_item */
|
305 |
foreach ( $as3cf_items as $as3cf_item ) {
|
306 |
// Each returned item may have matched on either the source_path or original_source_path.
|
307 |
+
// Because the base image file name of a thumbnail might match the primary rather scaled or rotated full image
|
308 |
// it's possible that both source paths are used by separate URLs.
|
309 |
foreach ( array( $as3cf_item->source_path(), $as3cf_item->original_source_path() ) as $source_path ) {
|
310 |
if ( ! empty( $paths[ $source_path ] ) ) {
|
311 |
$matched_full_url = $paths[ $source_path ];
|
312 |
|
313 |
if ( ! empty( $full_urls[ $matched_full_url ] ) ) {
|
314 |
+
$item_source = array(
|
315 |
+
'id' => $as3cf_item->source_id(),
|
316 |
+
'source_type' => $as3cf_item->source_type(),
|
317 |
+
);
|
318 |
+
|
319 |
+
$this->query_cache[ $matched_full_url ] = $item_source;
|
320 |
|
321 |
foreach ( $full_urls[ $matched_full_url ] as $url ) {
|
322 |
+
$results[ $url ] = $item_source;
|
323 |
}
|
324 |
unset( $full_urls[ $matched_full_url ] );
|
325 |
}
|
328 |
}
|
329 |
}
|
330 |
|
331 |
+
// No more item IDs found, set remaining results as false.
|
332 |
if ( count( $query_set ) !== count( $results ) ) {
|
333 |
foreach ( $full_urls as $full_url => $schema_urls ) {
|
334 |
foreach ( $schema_urls as $url ) {
|
445 |
|
446 |
return $url;
|
447 |
}
|
448 |
+
|
449 |
+
/**
|
450 |
+
* Filters the array of queried block templates array after they've been fetched.
|
451 |
+
*
|
452 |
+
* @param WP_Block_Template[] $query_result Array of found block templates.
|
453 |
+
* @param array $query Arguments to retrieve templates.
|
454 |
+
* @param string $template_type wp_template or wp_template_part.
|
455 |
+
*
|
456 |
+
* @return WP_Block_Template[]
|
457 |
+
*/
|
458 |
+
public function filter_get_block_templates( $query_result, $query, $template_type ) {
|
459 |
+
if ( empty( $query_result ) ) {
|
460 |
+
return $query_result;
|
461 |
+
}
|
462 |
+
|
463 |
+
foreach ( $query_result as $block_template ) {
|
464 |
+
$block_template = $this->filter_get_block_template( $block_template, $block_template->id, $template_type );
|
465 |
+
}
|
466 |
+
|
467 |
+
return $query_result;
|
468 |
+
}
|
469 |
+
|
470 |
+
/**
|
471 |
+
* Filters the queried block template object after it's been fetched.
|
472 |
+
*
|
473 |
+
* @param WP_Block_Template|null $block_template The found block template, or null if there isn't one.
|
474 |
+
* @param string $id Template unique identifier (example: theme_slug//template_slug).
|
475 |
+
* @param string $template_type Template type: `'wp_template'` or '`wp_template_part'`.
|
476 |
+
*
|
477 |
+
* @return WP_Block_Template|null
|
478 |
+
*/
|
479 |
+
public function filter_get_block_template( $block_template, $id, $template_type ) {
|
480 |
+
if ( empty( $block_template ) ) {
|
481 |
+
return $block_template;
|
482 |
+
}
|
483 |
+
|
484 |
+
$content = $block_template->content;
|
485 |
+
|
486 |
+
if ( empty( $content ) ) {
|
487 |
+
return $block_template;
|
488 |
+
}
|
489 |
+
|
490 |
+
$content = $this->filter_post( $content );
|
491 |
+
|
492 |
+
if ( ! empty( $content ) && $content !== $block_template->content ) {
|
493 |
+
$block_template->content = $content;
|
494 |
+
}
|
495 |
+
|
496 |
+
return $block_template;
|
497 |
+
}
|
498 |
}
|
@@ -1,6 +1,6 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
use DeliciousBrains\WP_Offload_Media\Items\
|
4 |
|
5 |
class AS3CF_S3_To_Local extends AS3CF_Filter {
|
6 |
|
@@ -21,9 +21,8 @@ class AS3CF_S3_To_Local extends AS3CF_Filter {
|
|
21 |
add_filter( 'as3cf_filter_post_s3_to_local', array( $this, 'filter_post' ) ); // Backwards compatibility
|
22 |
add_filter( 'as3cf_filter_post_provider_to_local', array( $this, 'filter_post' ) );
|
23 |
// Widgets
|
24 |
-
add_filter( 'widget_update_callback', array( $this, 'filter_widget_save' )
|
25 |
-
|
26 |
-
add_filter( 'wp_image_file_matches_image_meta', array( $this, 'image_file_matches_image_meta' ), 10, 4 );
|
27 |
}
|
28 |
|
29 |
/**
|
@@ -43,16 +42,32 @@ class AS3CF_S3_To_Local extends AS3CF_Filter {
|
|
43 |
/**
|
44 |
* Filter widget on save.
|
45 |
*
|
46 |
-
* @param array
|
47 |
-
* @param array $new_instance
|
48 |
-
* @param array $old_instance
|
49 |
-
* @param WP_Widget $class
|
50 |
*
|
51 |
* @return array
|
52 |
*
|
53 |
*/
|
54 |
-
public function filter_widget_save( $instance
|
55 |
-
return $this->handle_widget( $instance
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
}
|
57 |
|
58 |
/**
|
@@ -89,54 +104,80 @@ class AS3CF_S3_To_Local extends AS3CF_Filter {
|
|
89 |
/**
|
90 |
* Get URL
|
91 |
*
|
92 |
-
* @param
|
93 |
-
* @param null|string $
|
94 |
*
|
95 |
* @return bool|string
|
96 |
*/
|
97 |
-
protected function get_url( $
|
98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
}
|
100 |
|
101 |
/**
|
102 |
* Get base URL.
|
103 |
*
|
104 |
-
* @param
|
105 |
*
|
106 |
* @return string|false
|
107 |
*/
|
108 |
-
protected function get_base_url( $
|
109 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
}
|
111 |
|
112 |
/**
|
113 |
-
* Get
|
114 |
*
|
115 |
* @param string $url
|
116 |
*
|
117 |
* @return bool|int
|
118 |
*/
|
119 |
-
public function
|
120 |
// Result for sized URL already cached in request, return it.
|
121 |
if ( isset( $this->query_cache[ $url ] ) ) {
|
122 |
return $this->query_cache[ $url ];
|
123 |
}
|
124 |
|
125 |
-
$
|
126 |
|
127 |
-
if ( $
|
128 |
-
$this->query_cache[ $url ] = $
|
129 |
|
130 |
-
return $
|
131 |
}
|
132 |
|
133 |
$full_url = AS3CF_Utils::remove_size_from_filename( $url );
|
134 |
|
135 |
// If we've already tried to find this URL above because it didn't have a size suffix, cache and return.
|
136 |
if ( $url === $full_url ) {
|
137 |
-
$this->query_cache[ $url ] = $
|
138 |
|
139 |
-
return $
|
140 |
}
|
141 |
|
142 |
// Result for URL already cached in request whether found or not, return it.
|
@@ -144,21 +185,21 @@ class AS3CF_S3_To_Local extends AS3CF_Filter {
|
|
144 |
return $this->query_cache[ $full_url ];
|
145 |
}
|
146 |
|
147 |
-
$
|
148 |
|
149 |
-
$this->query_cache[ $full_url ] = $
|
150 |
|
151 |
-
return $
|
152 |
}
|
153 |
|
154 |
/**
|
155 |
-
* Get
|
156 |
*
|
157 |
* @param array $urls
|
158 |
*
|
159 |
-
* @return array url =>
|
160 |
*/
|
161 |
-
protected function
|
162 |
$results = array();
|
163 |
|
164 |
if ( empty( $urls ) ) {
|
@@ -170,7 +211,7 @@ class AS3CF_S3_To_Local extends AS3CF_Filter {
|
|
170 |
}
|
171 |
|
172 |
foreach ( $urls as $url ) {
|
173 |
-
$results[ $url ] = $this->
|
174 |
}
|
175 |
|
176 |
return $results;
|
@@ -219,25 +260,4 @@ class AS3CF_S3_To_Local extends AS3CF_Filter {
|
|
219 |
protected function pre_replace_content( $content ) {
|
220 |
return $content;
|
221 |
}
|
222 |
-
|
223 |
-
/**
|
224 |
-
* Determines if the image meta data is for the image source file.
|
225 |
-
*
|
226 |
-
* @handles wp_image_file_matches_image_meta
|
227 |
-
*
|
228 |
-
* @param bool $match
|
229 |
-
* @param string $image_location
|
230 |
-
* @param array $image_meta
|
231 |
-
* @param int $attachment_id
|
232 |
-
*
|
233 |
-
* @return bool
|
234 |
-
*/
|
235 |
-
public function image_file_matches_image_meta( $match, $image_location, $image_meta, $attachment_id ) {
|
236 |
-
// If already matched or the URL is local, there's nothing for us to do.
|
237 |
-
if ( $match || ! $this->url_needs_replacing( $image_location ) ) {
|
238 |
-
return $match;
|
239 |
-
}
|
240 |
-
|
241 |
-
return $this->attachment_id_matches_src( $attachment_id, $image_location );
|
242 |
-
}
|
243 |
}
|
1 |
<?php
|
2 |
|
3 |
+
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
4 |
|
5 |
class AS3CF_S3_To_Local extends AS3CF_Filter {
|
6 |
|
21 |
add_filter( 'as3cf_filter_post_s3_to_local', array( $this, 'filter_post' ) ); // Backwards compatibility
|
22 |
add_filter( 'as3cf_filter_post_provider_to_local', array( $this, 'filter_post' ) );
|
23 |
// Widgets
|
24 |
+
add_filter( 'widget_update_callback', array( $this, 'filter_widget_save' ) );
|
25 |
+
add_filter( 'pre_update_option_widget_block', array( $this, 'filter_widget_block_save' ) );
|
|
|
26 |
}
|
27 |
|
28 |
/**
|
42 |
/**
|
43 |
* Filter widget on save.
|
44 |
*
|
45 |
+
* @param array $instance
|
|
|
|
|
|
|
46 |
*
|
47 |
* @return array
|
48 |
*
|
49 |
*/
|
50 |
+
public function filter_widget_save( $instance ) {
|
51 |
+
return $this->handle_widget( $instance );
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Filter widget block on save.
|
56 |
+
*
|
57 |
+
* @param array $value The new, unserialized option value.
|
58 |
+
*
|
59 |
+
* @return array
|
60 |
+
*/
|
61 |
+
public function filter_widget_block_save( $value ) {
|
62 |
+
if ( empty( $value ) || ! is_array( $value ) ) {
|
63 |
+
return $value;
|
64 |
+
}
|
65 |
+
|
66 |
+
foreach ( $value as $idx => $section ) {
|
67 |
+
$value[ $idx ] = $this->handle_widget( $section );
|
68 |
+
}
|
69 |
+
|
70 |
+
return $value;
|
71 |
}
|
72 |
|
73 |
/**
|
104 |
/**
|
105 |
* Get URL
|
106 |
*
|
107 |
+
* @param array $item_source
|
108 |
+
* @param null|string $object_key
|
109 |
*
|
110 |
* @return bool|string
|
111 |
*/
|
112 |
+
protected function get_url( $item_source, $object_key = null ) {
|
113 |
+
if ( empty( $item_source['id'] ) || empty( $item_source['source_type'] ) ) {
|
114 |
+
return false;
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Return the local URL for an item
|
119 |
+
*
|
120 |
+
* @param string|false $url Url for the item, false if no URL can be determined
|
121 |
+
* @param array $item_source Associative array describing the item, guaranteed keys:-
|
122 |
+
* id: source item's unique integer id
|
123 |
+
* source_type: source item's string type identifier
|
124 |
+
* @param string|null $object_key Object key (size) describing what sub file of an item to return url for
|
125 |
+
*/
|
126 |
+
return apply_filters( 'as3cf_get_local_url_for_item_source', false, $item_source, $object_key );
|
127 |
}
|
128 |
|
129 |
/**
|
130 |
* Get base URL.
|
131 |
*
|
132 |
+
* @param array $item_source
|
133 |
*
|
134 |
* @return string|false
|
135 |
*/
|
136 |
+
protected function get_base_url( $item_source ) {
|
137 |
+
if ( empty( $item_source['id'] ) || empty( $item_source['source_type'] ) ) {
|
138 |
+
return false;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Return the provider URL for an item
|
143 |
+
*
|
144 |
+
* @param string|false $url Url for the item, false if no URL can be determined
|
145 |
+
* @param array $item_source Associative array describing the item, guaranteed keys:-
|
146 |
+
* id: source item's unique integer id
|
147 |
+
* source_type: source item's string type identifier
|
148 |
+
* @param string|null $object_key Object key (size) describing what sub file of an item to return url for
|
149 |
+
*/
|
150 |
+
return apply_filters( 'as3cf_get_provider_url_for_item_source', false, $item_source, null );
|
151 |
}
|
152 |
|
153 |
/**
|
154 |
+
* Get item source descriptor from URL.
|
155 |
*
|
156 |
* @param string $url
|
157 |
*
|
158 |
* @return bool|int
|
159 |
*/
|
160 |
+
public function get_item_source_from_url( $url ) {
|
161 |
// Result for sized URL already cached in request, return it.
|
162 |
if ( isset( $this->query_cache[ $url ] ) ) {
|
163 |
return $this->query_cache[ $url ];
|
164 |
}
|
165 |
|
166 |
+
$item_source = Item::get_item_source_by_remote_url( $url );
|
167 |
|
168 |
+
if ( ! empty( $item_source['id'] ) ) {
|
169 |
+
$this->query_cache[ $url ] = $item_source;
|
170 |
|
171 |
+
return $item_source;
|
172 |
}
|
173 |
|
174 |
$full_url = AS3CF_Utils::remove_size_from_filename( $url );
|
175 |
|
176 |
// If we've already tried to find this URL above because it didn't have a size suffix, cache and return.
|
177 |
if ( $url === $full_url ) {
|
178 |
+
$this->query_cache[ $url ] = $item_source;
|
179 |
|
180 |
+
return $item_source;
|
181 |
}
|
182 |
|
183 |
// Result for URL already cached in request whether found or not, return it.
|
185 |
return $this->query_cache[ $full_url ];
|
186 |
}
|
187 |
|
188 |
+
$item_source = Item::get_item_source_by_remote_url( $full_url );
|
189 |
|
190 |
+
$this->query_cache[ $full_url ] = ! empty( $item_source['id'] ) ? $item_source : false;
|
191 |
|
192 |
+
return $this->query_cache[ $full_url ];
|
193 |
}
|
194 |
|
195 |
/**
|
196 |
+
* Get item source descriptors from URLs.
|
197 |
*
|
198 |
* @param array $urls
|
199 |
*
|
200 |
+
* @return array url => item source descriptor (or false)
|
201 |
*/
|
202 |
+
protected function get_item_sources_from_urls( $urls ) {
|
203 |
$results = array();
|
204 |
|
205 |
if ( empty( $urls ) ) {
|
211 |
}
|
212 |
|
213 |
foreach ( $urls as $url ) {
|
214 |
+
$results[ $url ] = $this->get_item_source_from_url( $url );
|
215 |
}
|
216 |
|
217 |
return $results;
|
260 |
protected function pre_replace_content( $content ) {
|
261 |
return $content;
|
262 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
}
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Integrations;
|
4 |
+
|
5 |
+
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
6 |
+
use DeliciousBrains\WP_Offload_Media\Items\Remove_Local_Handler;
|
7 |
+
use DeliciousBrains\WP_Offload_Media\Items\Upload_Handler;
|
8 |
+
use WP_Error;
|
9 |
+
|
10 |
+
class Core extends Integration {
|
11 |
+
/**
|
12 |
+
* Is installed?
|
13 |
+
*
|
14 |
+
* @return bool
|
15 |
+
*/
|
16 |
+
public static function is_installed() {
|
17 |
+
return true;
|
18 |
+
}
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Init integration.
|
22 |
+
*/
|
23 |
+
public function init() {
|
24 |
+
add_action( 'as3cf_post_handle_item_' . Upload_Handler::get_item_handler_key_name(), array( $this, 'maybe_remove_local_files' ), 10, 3 );
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* After an upload completes, maybe remove local files.
|
29 |
+
*
|
30 |
+
* @handles as3cf_post_handle_item_upload
|
31 |
+
*
|
32 |
+
* @param bool|WP_Error $result Result for the action, either handled (true/false), or an error.
|
33 |
+
* @param Item $as3cf_item The item that the action was being handled for.
|
34 |
+
* @param array $options Handler dependent options that may have been set for the action.
|
35 |
+
*/
|
36 |
+
public function maybe_remove_local_files( $result, Item $as3cf_item, array $options ) {
|
37 |
+
if ( ! is_wp_error( $result ) && $this->as3cf->get_setting( 'remove-local-file', false ) && $as3cf_item->exists_locally() ) {
|
38 |
+
$remove_local_handler = $this->as3cf->get_item_handler( Remove_Local_Handler::get_item_handler_key_name() );
|
39 |
+
|
40 |
+
$remove_local_handler->handle( $as3cf_item );
|
41 |
+
}
|
42 |
+
}
|
43 |
+
}
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Integrations;
|
4 |
+
|
5 |
+
class Integration_Manager {
|
6 |
+
|
7 |
+
/**
|
8 |
+
* @var Integration_Manager
|
9 |
+
*/
|
10 |
+
protected static $instance;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var array
|
14 |
+
*/
|
15 |
+
private $integrations;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Protected constructor to prevent creating a new instance of the
|
19 |
+
* class via the `new` operator from outside this class.
|
20 |
+
*/
|
21 |
+
protected function __construct() {
|
22 |
+
$this->integrations = array();
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Make this class a singleton.
|
27 |
+
*
|
28 |
+
* Use this instead of __construct().
|
29 |
+
*
|
30 |
+
* @return Integration_Manager
|
31 |
+
*/
|
32 |
+
public static function get_instance() {
|
33 |
+
if ( ! isset( static::$instance ) && ! ( self::$instance instanceof Integration_Manager ) ) {
|
34 |
+
static::$instance = new Integration_Manager();
|
35 |
+
}
|
36 |
+
|
37 |
+
return static::$instance;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Getter for integration class instance
|
42 |
+
*
|
43 |
+
* @param string $integration_key
|
44 |
+
*
|
45 |
+
* @return Integration|null
|
46 |
+
*/
|
47 |
+
public function get_integration( $integration_key ) {
|
48 |
+
if ( ! empty( $this->integrations[ $integration_key ] ) ) {
|
49 |
+
return $this->integrations[ $integration_key ];
|
50 |
+
}
|
51 |
+
|
52 |
+
return null;
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Register integration.
|
57 |
+
*
|
58 |
+
* @param string $integration_key
|
59 |
+
* @param Integration $integration
|
60 |
+
*/
|
61 |
+
public function register_integration( $integration_key, Integration $integration ) {
|
62 |
+
if ( $integration::is_installed() ) {
|
63 |
+
$integration->init();
|
64 |
+
}
|
65 |
+
|
66 |
+
$this->integrations[ $integration_key ] = $integration;
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* As this class is a singleton it should not be clone-able.
|
71 |
+
*/
|
72 |
+
protected function __clone() {
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* As this class is a singleton it should not be able to be unserialized.
|
77 |
+
*/
|
78 |
+
public function __wakeup() {
|
79 |
+
}
|
80 |
+
|
81 |
+
}
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Integrations;
|
4 |
+
|
5 |
+
use Amazon_S3_And_CloudFront;
|
6 |
+
|
7 |
+
abstract class Integration {
|
8 |
+
|
9 |
+
/**
|
10 |
+
* @var Amazon_S3_And_CloudFront
|
11 |
+
*/
|
12 |
+
protected $as3cf;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Integration constructor.
|
16 |
+
*
|
17 |
+
* @param Amazon_S3_And_CloudFront $as3cf
|
18 |
+
*/
|
19 |
+
public function __construct( $as3cf ) {
|
20 |
+
$this->as3cf = $as3cf;
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Is installed?
|
25 |
+
*
|
26 |
+
* @return bool
|
27 |
+
*/
|
28 |
+
public static function is_installed() {
|
29 |
+
return false;
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Init integration.
|
34 |
+
*/
|
35 |
+
abstract public function init();
|
36 |
+
|
37 |
+
}
|
@@ -0,0 +1,1551 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Integrations;
|
4 |
+
|
5 |
+
use AS3CF_Error;
|
6 |
+
use AS3CF_Utils;
|
7 |
+
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
8 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
9 |
+
use DeliciousBrains\WP_Offload_Media\Items\Remove_Provider_Handler;
|
10 |
+
use DeliciousBrains\WP_Offload_Media\Items\Upload_Handler;
|
11 |
+
use Exception;
|
12 |
+
use WP_Error;
|
13 |
+
use WP_Post;
|
14 |
+
|
15 |
+
class Media_Library extends Integration {
|
16 |
+
/**
|
17 |
+
* Is the current process deleting an attachment?
|
18 |
+
*
|
19 |
+
* @var bool
|
20 |
+
*/
|
21 |
+
private $deleting_attachment = false;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Keep track of items that are being updated multiple times in one request. I.e. when WP
|
25 |
+
* calls wp_update_attachment_metadata repeatedly during thumbnail generation
|
26 |
+
*
|
27 |
+
* @var array
|
28 |
+
*/
|
29 |
+
protected $items_in_progress = array();
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Keep track of items that has been replaced by an edit image operation
|
33 |
+
*
|
34 |
+
* @var array
|
35 |
+
*/
|
36 |
+
protected $replaced_object_keys = array();
|
37 |
+
|
38 |
+
/**
|
39 |
+
* Init Media Library integration.
|
40 |
+
*/
|
41 |
+
public function init() {
|
42 |
+
// Filter from WordPress media library handling, plugin needs to be set up
|
43 |
+
add_filter( 'wp_unique_filename', array( $this, 'wp_unique_filename' ), 10, 3 );
|
44 |
+
add_filter( 'wp_update_attachment_metadata', array( $this, 'wp_update_attachment_metadata' ), 110, 2 );
|
45 |
+
add_filter( 'pre_delete_attachment', array( $this, 'pre_delete_attachment' ), 20 );
|
46 |
+
add_filter( 'delete_attachment', array( $this, 'delete_attachment' ), 20 );
|
47 |
+
add_action( 'delete_post', array( $this, 'delete_post' ) );
|
48 |
+
add_filter( 'update_attached_file', array( $this, 'update_attached_file' ), 100, 2 );
|
49 |
+
add_filter( 'update_post_metadata', array( $this, 'update_post_metadata' ), 100, 5 );
|
50 |
+
|
51 |
+
// Attachment screens/modals
|
52 |
+
add_action( 'load-upload.php', array( $this, 'load_media_assets' ), 11 );
|
53 |
+
add_action( 'admin_enqueue_scripts', array( $this, 'load_attachment_assets' ), 11 );
|
54 |
+
add_action( 'add_meta_boxes', array( $this, 'attachment_provider_meta_box' ) );
|
55 |
+
|
56 |
+
// AJAX
|
57 |
+
add_action( 'wp_ajax_as3cf_get_attachment_provider_details', array( $this, 'ajax_get_attachment_provider_details' ) );
|
58 |
+
|
59 |
+
// Rewriting URLs, doesn't depend on plugin being set up
|
60 |
+
add_filter( 'wp_get_attachment_url', array( $this, 'wp_get_attachment_url' ), 99, 2 );
|
61 |
+
add_filter( 'wp_get_attachment_image_attributes', array( $this, 'wp_get_attachment_image_attributes' ), 99, 3 );
|
62 |
+
add_filter( 'get_image_tag', array( $this, 'maybe_encode_get_image_tag' ), 99, 6 );
|
63 |
+
add_filter( 'wp_get_attachment_image_src', array( $this, 'maybe_encode_wp_get_attachment_image_src' ), 99, 4 );
|
64 |
+
add_filter( 'wp_prepare_attachment_for_js', array( $this, 'maybe_encode_wp_prepare_attachment_for_js', ), 99, 3 );
|
65 |
+
add_filter( 'image_get_intermediate_size', array( $this, 'maybe_encode_image_get_intermediate_size' ), 99, 3 );
|
66 |
+
add_filter( 'get_attached_file', array( $this, 'get_attached_file' ), 10, 2 );
|
67 |
+
add_filter( 'wp_get_original_image_path', array( $this, 'get_attached_file' ), 10, 2 );
|
68 |
+
add_filter( 'wp_audio_shortcode', array( $this, 'wp_media_shortcode' ), 100, 5 );
|
69 |
+
add_filter( 'wp_video_shortcode', array( $this, 'wp_media_shortcode' ), 100, 5 );
|
70 |
+
|
71 |
+
// Srcset handling
|
72 |
+
add_filter( 'wp_image_file_matches_image_meta', array( $this, 'image_file_matches_image_meta' ), 10, 4 );
|
73 |
+
|
74 |
+
// Internal filters and actions
|
75 |
+
add_filter( 'as3cf_get_provider_url_for_item_source', array( $this, 'filter_get_provider_url_for_item_source' ), 10, 3 );
|
76 |
+
add_filter( 'as3cf_get_local_url_for_item_source', array( $this, 'filter_get_local_url_for_item_source' ), 10, 3 );
|
77 |
+
add_filter( 'as3cf_get_size_string_from_url_for_item_source', array( $this, 'get_size_string_from_url_for_item_source' ), 10, 3 );
|
78 |
+
add_filter( 'as3cf_get_item_secure_url', array( $this, 'get_item_secure_url' ), 10, 5 );
|
79 |
+
add_filter( 'as3cf_get_item_url', array( $this, 'get_item_url' ), 10, 5 );
|
80 |
+
add_filter( 'as3cf_remove_local_files', array( $this, 'filter_remove_local_files' ), 10, 3 );
|
81 |
+
add_filter( 'as3cf_remove_source_files_from_provider', array( $this, 'filter_remove_source_files_from_provider' ), 10, 3 );
|
82 |
+
add_action( 'as3cf_post_upload_item', array( $this, 'post_upload_item' ), 10, 1 );
|
83 |
+
add_filter( 'as3cf_pre_handle_item_' . Upload_Handler::get_item_handler_key_name(), array( $this, 'pre_handle_item_upload' ), 10, 3 );
|
84 |
+
add_filter( 'as3cf_upload_object_key_as_private', array( $this, 'filter_upload_object_key_as_private' ), 10, 3 );
|
85 |
+
add_action( 'as3cf_pre_upload_object', array( $this, 'action_pre_upload_object' ), 10, 2 );
|
86 |
+
|
87 |
+
Media_Library_Item::init_cache();
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Is installed?
|
92 |
+
*
|
93 |
+
* @return bool
|
94 |
+
*/
|
95 |
+
public static function is_installed() {
|
96 |
+
return true;
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Handles the upload of the attachment to provider when an attachment is updated.
|
101 |
+
*
|
102 |
+
* @handles wp_update_attachment_metadata
|
103 |
+
*
|
104 |
+
* @param array $data meta data for attachment
|
105 |
+
* @param int $post_id
|
106 |
+
*
|
107 |
+
* @return array|WP_Error
|
108 |
+
* @throws Exception
|
109 |
+
*/
|
110 |
+
public function wp_update_attachment_metadata( $data, $post_id ) {
|
111 |
+
if ( ! $this->as3cf->is_plugin_setup( true ) ) {
|
112 |
+
return $data;
|
113 |
+
}
|
114 |
+
|
115 |
+
// Some other filter may already have corrupted $data
|
116 |
+
if ( is_wp_error( $data ) ) {
|
117 |
+
return $data;
|
118 |
+
}
|
119 |
+
|
120 |
+
// Protect against updates of partially formed metadata since WordPress 5.3.
|
121 |
+
// Checks whether new upload currently has no subsizes recorded but is expected to have subsizes during upload,
|
122 |
+
// and if so, are any of its currently missing sizes part of the set.
|
123 |
+
if ( ! empty( $data ) && function_exists( 'wp_get_registered_image_subsizes' ) && function_exists( 'wp_get_missing_image_subsizes' ) ) {
|
124 |
+
|
125 |
+
/**
|
126 |
+
* Plugin compat may require that we wait for wp_generate_attachment_metadata
|
127 |
+
* to be run before proceeding with uploading. I.e. Regenerate Thumbnails requires this.
|
128 |
+
*
|
129 |
+
* @param bool True if we should wait AND generate_attachment_metadata hasn't run yet
|
130 |
+
*
|
131 |
+
*/
|
132 |
+
if ( apply_filters( 'as3cf_wait_for_generate_attachment_metadata', false ) ) {
|
133 |
+
return $data;
|
134 |
+
}
|
135 |
+
|
136 |
+
if ( empty( $data['sizes'] ) && wp_attachment_is_image( $post_id ) ) {
|
137 |
+
|
138 |
+
// There is no unified way of checking whether subsizes are expected, so we have to duplicate WordPress code here.
|
139 |
+
$new_sizes = wp_get_registered_image_subsizes();
|
140 |
+
$new_sizes = apply_filters( 'intermediate_image_sizes_advanced', $new_sizes, $data, $post_id );
|
141 |
+
$missing_sizes = wp_get_missing_image_subsizes( $post_id );
|
142 |
+
|
143 |
+
if ( ! empty( $new_sizes ) && ! empty( $missing_sizes ) && array_intersect_key( $missing_sizes, $new_sizes ) ) {
|
144 |
+
return $data;
|
145 |
+
}
|
146 |
+
}
|
147 |
+
}
|
148 |
+
|
149 |
+
// Is this a new item that we're already started working on in this request?
|
150 |
+
if ( ! empty( $this->items_in_progress[ $post_id ] ) ) {
|
151 |
+
$as3cf_item = $this->items_in_progress[ $post_id ];
|
152 |
+
}
|
153 |
+
|
154 |
+
// Is this an update for an existing item.
|
155 |
+
if ( empty( $as3cf_item ) || is_wp_error( $as3cf_item ) ) {
|
156 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
157 |
+
}
|
158 |
+
|
159 |
+
// Abort if not already uploaded to provider and the copy setting is off.
|
160 |
+
if ( ! $as3cf_item && ! $this->as3cf->get_setting( 'copy-to-s3' ) ) {
|
161 |
+
return $data;
|
162 |
+
}
|
163 |
+
|
164 |
+
if ( empty( $as3cf_item ) ) {
|
165 |
+
$as3cf_item = null;
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Allows implementors to cancel uploading a Media Library item for any reason.
|
170 |
+
*
|
171 |
+
* This filter is triggered by updates to an attachment's metadata.
|
172 |
+
* To potentially cancel an upload started by any method,
|
173 |
+
* please use the 'as3cf_pre_upload_item' filter.
|
174 |
+
*
|
175 |
+
* @param bool $cancel True if the upload should be cancelled
|
176 |
+
* @param array $data Array describing the object being uploaded
|
177 |
+
* @param int $post_id Attachment's ID
|
178 |
+
* @param Media_Library_Item $as3cf_item The Media Library Item object if previously offloaded
|
179 |
+
*
|
180 |
+
* @see as3cf_pre_upload_item
|
181 |
+
*/
|
182 |
+
$cancel = apply_filters( 'as3cf_pre_update_attachment_metadata', false, $data, $post_id, $as3cf_item );
|
183 |
+
if ( false !== $cancel ) {
|
184 |
+
return $data;
|
185 |
+
}
|
186 |
+
|
187 |
+
$offloaded_files = array();
|
188 |
+
|
189 |
+
// If we still don't have a valid item, create one from scratch.
|
190 |
+
if ( empty( $as3cf_item ) || is_wp_error( $as3cf_item ) ) {
|
191 |
+
$as3cf_item = Media_Library_Item::create_from_source_id( $post_id );
|
192 |
+
} else {
|
193 |
+
$offloaded_files = $as3cf_item->offloaded_files();
|
194 |
+
}
|
195 |
+
|
196 |
+
// Did we get a WP_Error?
|
197 |
+
if ( is_wp_error( $as3cf_item ) ) {
|
198 |
+
AS3CF_Error::Log( $as3cf_item->get_error_message() );
|
199 |
+
|
200 |
+
return $data;
|
201 |
+
}
|
202 |
+
|
203 |
+
// Or didn't we get anything at all?
|
204 |
+
if ( empty( $as3cf_item ) ) {
|
205 |
+
$message = sprintf( __( "Can't create item from media library item %d", 'amazon-s3-and-cloudfront' ), $post_id );
|
206 |
+
AS3CF_Error::Log( $message );
|
207 |
+
|
208 |
+
return $data;
|
209 |
+
}
|
210 |
+
|
211 |
+
// Update item's expected objects from attachment's new metadata.
|
212 |
+
$this->update_item_from_new_metadata( $as3cf_item, $data );
|
213 |
+
|
214 |
+
$this->upload_item( $as3cf_item, $offloaded_files );
|
215 |
+
$this->items_in_progress[ $post_id ] = $as3cf_item;
|
216 |
+
|
217 |
+
return $data;
|
218 |
+
}
|
219 |
+
|
220 |
+
/**
|
221 |
+
* Upload item.
|
222 |
+
*
|
223 |
+
* @param Media_Library_Item $as3cf_item
|
224 |
+
* @param array $offloaded_files An array of files previously offloaded for the item.
|
225 |
+
*/
|
226 |
+
protected function upload_item( Media_Library_Item $as3cf_item, array $offloaded_files ) {
|
227 |
+
$upload_handler = $this->as3cf->get_item_handler( Upload_Handler::get_item_handler_key_name() );
|
228 |
+
$upload_result = $upload_handler->handle( $as3cf_item, array( 'offloaded_files' => $offloaded_files ) );
|
229 |
+
|
230 |
+
if ( is_wp_error( $upload_result ) ) {
|
231 |
+
foreach ( $upload_result->get_error_messages() as $error_message ) {
|
232 |
+
AS3CF_Error::Log( $error_message );
|
233 |
+
}
|
234 |
+
}
|
235 |
+
}
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Handle update_post_metadata for some media library related keys
|
239 |
+
*
|
240 |
+
* @handles update_post_metadata
|
241 |
+
*
|
242 |
+
* @param bool $check
|
243 |
+
* @param int $object_id
|
244 |
+
* @param string $meta_key
|
245 |
+
* @param mixed $meta_value
|
246 |
+
* @param mixed $prev_value
|
247 |
+
*/
|
248 |
+
public function update_post_metadata( $check, $object_id, $meta_key, $meta_value, $prev_value ) {
|
249 |
+
if ( '_wp_attachment_backup_sizes' === $meta_key ) {
|
250 |
+
if ( $this->as3cf->is_plugin_setup( true ) ) {
|
251 |
+
$this->update_attachment_backup_sizes( $object_id, $meta_value );
|
252 |
+
}
|
253 |
+
}
|
254 |
+
|
255 |
+
return $check;
|
256 |
+
}
|
257 |
+
|
258 |
+
/**
|
259 |
+
* Handle updated attachment_backup_sizes.
|
260 |
+
*
|
261 |
+
* @param int $post_id
|
262 |
+
* @param array $sizes
|
263 |
+
*/
|
264 |
+
protected function update_attachment_backup_sizes( $post_id, $sizes ) {
|
265 |
+
// This item should already be known in this request, if not bail out
|
266 |
+
if ( empty( $this->items_in_progress[ $post_id ] ) ) {
|
267 |
+
return;
|
268 |
+
}
|
269 |
+
|
270 |
+
// We should also have recorded some replaced keys in this request, if not bail
|
271 |
+
if ( empty( $this->replaced_object_keys[ $post_id ] ) ) {
|
272 |
+
return;
|
273 |
+
}
|
274 |
+
|
275 |
+
/** @var Media_Library_Item $as3cf_item */
|
276 |
+
$as3cf_item = $this->items_in_progress[ $post_id ];
|
277 |
+
$existing_objects = $as3cf_item->objects();
|
278 |
+
|
279 |
+
foreach ( array_keys( $sizes ) as $key ) {
|
280 |
+
if ( ! isset( $existing_objects[ $key ] ) ) {
|
281 |
+
$parts = explode( '-', $key );
|
282 |
+
$size = join( '-', array_slice( $parts, 0, -1 ) );
|
283 |
+
if ( 'full' === $size ) {
|
284 |
+
$size = Item::primary_object_key();
|
285 |
+
}
|
286 |
+
|
287 |
+
if ( isset( $this->replaced_object_keys[ $post_id ][ $size ] ) ) {
|
288 |
+
$existing_objects[ $key ] = $this->replaced_object_keys[ $post_id ][ $size ];
|
289 |
+
}
|
290 |
+
}
|
291 |
+
}
|
292 |
+
|
293 |
+
$as3cf_item->set_objects( $existing_objects );
|
294 |
+
$as3cf_item->save();
|
295 |
+
}
|
296 |
+
|
297 |
+
/**
|
298 |
+
* Filters the result when generating a unique file name.
|
299 |
+
*
|
300 |
+
* @param string $filename Unique file name.
|
301 |
+
* @param string $ext File extension, eg. ".png".
|
302 |
+
* @param string $dir Directory path.
|
303 |
+
*
|
304 |
+
* @return string
|
305 |
+
* @since 4.5.0
|
306 |
+
*
|
307 |
+
*/
|
308 |
+
public function wp_unique_filename( $filename, $ext, $dir ) {
|
309 |
+
// Get Post ID if uploaded in post screen.
|
310 |
+
$post_id = filter_input( INPUT_POST, 'post_id', FILTER_VALIDATE_INT );
|
311 |
+
|
312 |
+
return $this->filter_unique_filename( $filename, $ext, $dir, $post_id );
|
313 |
+
}
|
314 |
+
|
315 |
+
/**
|
316 |
+
* Create unique names for file to be uploaded to AWS.
|
317 |
+
* This only applies when the remove local file option is enabled.
|
318 |
+
*
|
319 |
+
* @param string $filename Unique file name.
|
320 |
+
* @param string $ext File extension, eg. ".png".
|
321 |
+
* @param string $dir Directory path.
|
322 |
+
* @param int $post_id Attachment's parent Post ID.
|
323 |
+
*
|
324 |
+
* @return string
|
325 |
+
*/
|
326 |
+
public function filter_unique_filename( $filename, $ext, $dir, $post_id = null ) {
|
327 |
+
if ( ! $this->as3cf->is_plugin_setup( true ) ) {
|
328 |
+
return $filename;
|
329 |
+
}
|
330 |
+
|
331 |
+
// sanitize the file name before we begin processing
|
332 |
+
$filename = sanitize_file_name( $filename );
|
333 |
+
$ext = strtolower( $ext );
|
334 |
+
$name = wp_basename( $filename, $ext );
|
335 |
+
|
336 |
+
// Edge case: if file is named '.ext', treat as an empty name.
|
337 |
+
if ( $name === $ext ) {
|
338 |
+
$name = '';
|
339 |
+
}
|
340 |
+
|
341 |
+
// Rebuild filename with lowercase extension as provider will have converted extension on upload.
|
342 |
+
$filename = $name . $ext;
|
343 |
+
$time = current_time( 'mysql' );
|
344 |
+
|
345 |
+
// Get time if uploaded in post screen.
|
346 |
+
if ( ! empty( $post_id ) ) {
|
347 |
+
$time = $this->get_post_time( $post_id );
|
348 |
+
}
|
349 |
+
|
350 |
+
if ( ! $this->as3cf->does_file_exist( $filename, $time ) ) {
|
351 |
+
// File doesn't exist locally or on provider, return it.
|
352 |
+
return $filename;
|
353 |
+
}
|
354 |
+
|
355 |
+
return $this->as3cf->generate_unique_filename( $name, $ext, $time );
|
356 |
+
}
|
357 |
+
|
358 |
+
/**
|
359 |
+
* Allow processes to update the file on provider via update_attached_file()
|
360 |
+
*
|
361 |
+
* @param string $file
|
362 |
+
* @param int $attachment_id
|
363 |
+
*
|
364 |
+
* @return string
|
365 |
+
*/
|
366 |
+
public function update_attached_file( $file, $attachment_id ) {
|
367 |
+
if ( ! $this->as3cf->is_plugin_setup( true ) ) {
|
368 |
+
return $file;
|
369 |
+
}
|
370 |
+
|
371 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
372 |
+
|
373 |
+
if ( ! $as3cf_item ) {
|
374 |
+
return $file;
|
375 |
+
}
|
376 |
+
|
377 |
+
/**
|
378 |
+
* Allow processes to update the file on provider via update_attached_file()
|
379 |
+
*
|
380 |
+
* @param string $file File name/path
|
381 |
+
* @param int $attachment_id Attachment id
|
382 |
+
* @param Media_Library_Item $as3cf_item The item object
|
383 |
+
*/
|
384 |
+
return apply_filters( 'as3cf_update_attached_file', $file, $attachment_id, $as3cf_item );
|
385 |
+
}
|
386 |
+
|
387 |
+
/**
|
388 |
+
* Removes an attachment and intermediate image size files from provider
|
389 |
+
*
|
390 |
+
* @param int $post_id
|
391 |
+
*/
|
392 |
+
public function delete_attachment( $post_id ) {
|
393 |
+
if ( ! $this->as3cf->is_plugin_setup( true ) ) {
|
394 |
+
return;
|
395 |
+
}
|
396 |
+
|
397 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
398 |
+
|
399 |
+
if ( ! $as3cf_item ) {
|
400 |
+
return;
|
401 |
+
}
|
402 |
+
|
403 |
+
if ( ! $as3cf_item->served_by_provider( true ) ) {
|
404 |
+
return;
|
405 |
+
}
|
406 |
+
|
407 |
+
// Remove the objects from the provider
|
408 |
+
$remove_provider_handler = $this->as3cf->get_item_handler( Remove_Provider_Handler::get_item_handler_key_name() );
|
409 |
+
$remove_provider_handler->handle( $as3cf_item, array( 'verify_exists_on_local' => false ) );
|
410 |
+
$as3cf_item->delete();
|
411 |
+
}
|
412 |
+
|
413 |
+
/**
|
414 |
+
* Update an existing item's expected objects from attachment's new metadata.
|
415 |
+
*
|
416 |
+
* @param Media_Library_Item $as3cf_item
|
417 |
+
* @param array $metadata
|
418 |
+
*/
|
419 |
+
protected function update_item_from_new_metadata( $as3cf_item, $metadata ) {
|
420 |
+
if ( empty( $metadata ) || ! is_array( $metadata ) ) {
|
421 |
+
return;
|
422 |
+
}
|
423 |
+
|
424 |
+
$files = AS3CF_Utils::get_attachment_file_paths( $as3cf_item->source_id(), false, $metadata );
|
425 |
+
$existing_basename = wp_basename( $as3cf_item->path() );
|
426 |
+
$existing_objects = $as3cf_item->objects();
|
427 |
+
|
428 |
+
if ( ! isset( $this->replaced_object_keys[ $as3cf_item->source_id() ] ) ) {
|
429 |
+
$this->replaced_object_keys[ $as3cf_item->source_id() ] = array();
|
430 |
+
}
|
431 |
+
|
432 |
+
foreach ( $files as $object_key => $file ) {
|
433 |
+
$new_filename = wp_basename( $file );
|
434 |
+
|
435 |
+
if ( ! empty( $existing_objects[ $object_key ]['source_file'] ) && $existing_objects[ $object_key ]['source_file'] !== $new_filename ) {
|
436 |
+
$this->replaced_object_keys[ $as3cf_item->source_id() ][ $object_key ] = $existing_objects[ $object_key ];
|
437 |
+
}
|
438 |
+
|
439 |
+
if ( Item::primary_object_key() === $object_key && $existing_basename !== $new_filename ) {
|
440 |
+
$as3cf_item->set_path( str_replace( $existing_basename, $new_filename, $as3cf_item->path() ) );
|
441 |
+
$as3cf_item->set_source_path( str_replace( $existing_basename, $new_filename, $as3cf_item->source_path() ) );
|
442 |
+
}
|
443 |
+
|
444 |
+
$existing_objects[ $object_key ] = array(
|
445 |
+
'source_file' => $new_filename,
|
446 |
+
'is_private' => isset( $existing_objects[ $object_key ]['is_private'] ) ? $existing_objects[ $object_key ]['is_private'] : false,
|
447 |
+
);
|
448 |
+
}
|
449 |
+
|
450 |
+
$extra_info = $as3cf_item->extra_info();
|
451 |
+
$extra_info['objects'] = $existing_objects;
|
452 |
+
$as3cf_item->set_extra_info( $extra_info );
|
453 |
+
}
|
454 |
+
|
455 |
+
/**
|
456 |
+
* Load media assets.
|
457 |
+
*/
|
458 |
+
public function load_media_assets() {
|
459 |
+
$this->as3cf->enqueue_style( 'as3cf-media-styles', 'assets/css/media', array( 'as3cf-modal' ) );
|
460 |
+
$this->as3cf->enqueue_script( 'as3cf-media-script', 'assets/js/media', array(
|
461 |
+
'jquery',
|
462 |
+
'media-views',
|
463 |
+
'media-grid',
|
464 |
+
'wp-util',
|
465 |
+
) );
|
466 |
+
|
467 |
+
wp_localize_script( 'as3cf-media-script', 'as3cf_media', array(
|
468 |
+
'strings' => $this->get_media_action_strings(),
|
469 |
+
'nonces' => array(
|
470 |
+
'get_attachment_provider_details' => wp_create_nonce( 'get-attachment-s3-details' ),
|
471 |
+
),
|
472 |
+
) );
|
473 |
+
}
|
474 |
+
|
475 |
+
/**
|
476 |
+
* Load the attachment assets only when editing an attachment
|
477 |
+
*
|
478 |
+
* @param $hook_suffix
|
479 |
+
*/
|
480 |
+
public function load_attachment_assets( $hook_suffix ) {
|
481 |
+
global $post;
|
482 |
+
if ( 'post.php' !== $hook_suffix || 'attachment' !== $post->post_type ) {
|
483 |
+
return;
|
484 |
+
}
|
485 |
+
|
486 |
+
$this->as3cf->enqueue_style( 'as3cf-pro-attachment-styles', 'assets/css/attachment', array( 'as3cf-modal' ) );
|
487 |
+
|
488 |
+
do_action( 'as3cf_load_attachment_assets' );
|
489 |
+
}
|
490 |
+
|
491 |
+
/**
|
492 |
+
* Add the S3 meta box to the attachment screen
|
493 |
+
*/
|
494 |
+
public function attachment_provider_meta_box() {
|
495 |
+
add_meta_box(
|
496 |
+
's3-actions',
|
497 |
+
__( 'Offload', 'amazon-s3-and-cloudfront' ),
|
498 |
+
array( $this, 'attachment_provider_actions_meta_box' ),
|
499 |
+
'attachment',
|
500 |
+
'side',
|
501 |
+
'core'
|
502 |
+
);
|
503 |
+
}
|
504 |
+
|
505 |
+
/**
|
506 |
+
* Handle retrieving the provider details for attachment modals.
|
507 |
+
*/
|
508 |
+
public function ajax_get_attachment_provider_details() {
|
509 |
+
if ( ! isset( $_POST['id'] ) ) {
|
510 |
+
return;
|
511 |
+
}
|
512 |
+
|
513 |
+
check_ajax_referer( 'get-attachment-s3-details', '_nonce' );
|
514 |
+
|
515 |
+
$id = intval( $_POST['id'] );
|
516 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $id );
|
517 |
+
$served_by_provider = false;
|
518 |
+
|
519 |
+
if ( ! empty( $as3cf_item ) ) {
|
520 |
+
$served_by_provider = $as3cf_item->served_by_provider( true );
|
521 |
+
}
|
522 |
+
|
523 |
+
// get the actions available for the attachment
|
524 |
+
$data = array(
|
525 |
+
'links' => $this->add_media_row_actions( array(), $id ),
|
526 |
+
'provider_object' => $this->get_formatted_provider_info( $id ),
|
527 |
+
'acl_toggle' => $this->verify_media_actions() && $served_by_provider,
|
528 |
+
);
|
529 |
+
|
530 |
+
wp_send_json_success( $data );
|
531 |
+
}
|
532 |
+
|
533 |
+
/**
|
534 |
+
* Conditionally adds copy, remove and download S3 action links for an
|
535 |
+
* attachment on the Media library list view
|
536 |
+
*
|
537 |
+
* @param array $actions
|
538 |
+
* @param WP_Post|int $post
|
539 |
+
*
|
540 |
+
* @return array
|
541 |
+
*/
|
542 |
+
public function add_media_row_actions( array $actions, $post ) {
|
543 |
+
return $actions;
|
544 |
+
}
|
545 |
+
|
546 |
+
/**
|
547 |
+
* Get a list of available media actions which can be performed according to plugin and user capability requirements.
|
548 |
+
*
|
549 |
+
* @param string|null $scope
|
550 |
+
*
|
551 |
+
* @return array
|
552 |
+
*/
|
553 |
+
public function get_available_media_actions( $scope = '' ) {
|
554 |
+
return array();
|
555 |
+
}
|
556 |
+
|
557 |
+
/**
|
558 |
+
* Render the S3 attachment meta box
|
559 |
+
*/
|
560 |
+
public function attachment_provider_actions_meta_box() {
|
561 |
+
global $post;
|
562 |
+
$file = get_attached_file( $post->ID, true );
|
563 |
+
|
564 |
+
$args = array(
|
565 |
+
'provider_object' => $this->get_formatted_provider_info( $post->ID ),
|
566 |
+
'post' => $post,
|
567 |
+
'local_file_exists' => file_exists( $file ),
|
568 |
+
'available_actions' => $this->get_available_media_actions( 'singular' ),
|
569 |
+
'sendback' => 'post.php?post=' . $post->ID . '&action=edit',
|
570 |
+
);
|
571 |
+
|
572 |
+
$this->as3cf->render_view( 'attachment-metabox', $args );
|
573 |
+
}
|
574 |
+
|
575 |
+
/**
|
576 |
+
* Get attachment url
|
577 |
+
*
|
578 |
+
* @param string $url
|
579 |
+
* @param int $post_id
|
580 |
+
*
|
581 |
+
* @return bool|mixed|WP_Error
|
582 |
+
*/
|
583 |
+
public function wp_get_attachment_url( $url, $post_id ) {
|
584 |
+
if ( $this->as3cf->plugin_compat->is_customizer_crop_action() ) {
|
585 |
+
return $url;
|
586 |
+
}
|
587 |
+
|
588 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
589 |
+
if ( empty( $as3cf_item ) || ! $as3cf_item->served_by_provider() ) {
|
590 |
+
return $url;
|
591 |
+
}
|
592 |
+
|
593 |
+
$size = $as3cf_item->get_object_key_from_filename( $url );
|
594 |
+
$new_url = $as3cf_item->get_provider_url( $size );
|
595 |
+
|
596 |
+
if ( is_wp_error( $new_url ) || false === $new_url ) {
|
597 |
+
return $url;
|
598 |
+
}
|
599 |
+
|
600 |
+
// Old naming convention, will be deprecated soon
|
601 |
+
$new_url = apply_filters( 'wps3_get_attachment_url', $new_url, $post_id, $this );
|
602 |
+
|
603 |
+
/**
|
604 |
+
* Filter the rewritten provider URL for a Media Library Item (attachment)
|
605 |
+
*
|
606 |
+
* @param string $url The URL
|
607 |
+
* @param int $post_id Attachment post id
|
608 |
+
*/
|
609 |
+
return apply_filters( 'as3cf_wp_get_attachment_url', $new_url, $post_id );
|
610 |
+
}
|
611 |
+
|
612 |
+
/**
|
613 |
+
* Return a formatted provider info array with display friendly defaults
|
614 |
+
*
|
615 |
+
* @param int $id
|
616 |
+
*
|
617 |
+
* @return bool|array
|
618 |
+
*/
|
619 |
+
public function get_formatted_provider_info( $id ) {
|
620 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $id );
|
621 |
+
|
622 |
+
if ( ! $as3cf_item ) {
|
623 |
+
return false;
|
624 |
+
}
|
625 |
+
|
626 |
+
$provider_object = $as3cf_item->key_values();
|
627 |
+
|
628 |
+
// Backwards compatibility.
|
629 |
+
$provider_object['key'] = $provider_object['path'];
|
630 |
+
$provider_object['url'] = $as3cf_item->get_provider_url();
|
631 |
+
|
632 |
+
$acl = $as3cf_item->is_private() ? $this->as3cf->get_storage_provider()->get_private_acl() : $this->as3cf->get_storage_provider()->get_default_acl();
|
633 |
+
$acl_info = array(
|
634 |
+
'acl' => $acl,
|
635 |
+
'name' => $this->as3cf->get_acl_display_name( $acl ),
|
636 |
+
'title' => $this->get_media_action_strings( 'change_to_private' ),
|
637 |
+
);
|
638 |
+
|
639 |
+
if ( $as3cf_item->is_private() ) {
|
640 |
+
$acl_info['title'] = $this->get_media_action_strings( 'change_to_public' );
|
641 |
+
}
|
642 |
+
|
643 |
+
$provider_object['acl'] = $acl_info;
|
644 |
+
$provider_object['region'] = $this->as3cf->get_storage_provider()->get_region_name( $provider_object['region'] );
|
645 |
+
$provider_object['provider_name'] = $this->as3cf->get_provider_service_name( $provider_object['provider'] );
|
646 |
+
|
647 |
+
return $provider_object;
|
648 |
+
}
|
649 |
+
|
650 |
+
/**
|
651 |
+
* Filters the list of attachment image attributes.
|
652 |
+
*
|
653 |
+
* @param array $attr Attributes for the image markup.
|
654 |
+
* @param WP_Post $attachment Image attachment post.
|
655 |
+
* @param string|array $size Requested size. Image size or array of width and height values (in that order).
|
656 |
+
*
|
657 |
+
* @return array
|
658 |
+
*/
|
659 |
+
public function wp_get_attachment_image_attributes( $attr, $attachment, $size ) {
|
660 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment->ID );
|
661 |
+
if ( ! $as3cf_item || ! $as3cf_item->served_by_provider() ) {
|
662 |
+
return $attr;
|
663 |
+
}
|
664 |
+
|
665 |
+
$size = $this->maybe_convert_size_to_string( $attachment->ID, $size );
|
666 |
+
|
667 |
+
// image_downsize incorrectly substitutes size filename into full URL for src attribute instead of clobbering.
|
668 |
+
// So we need to fix up the src attribute if a size is being used.
|
669 |
+
if ( ! empty( $size ) && ! empty( $attr['src'] ) ) {
|
670 |
+
$attr['src'] = $as3cf_item->get_provider_url( $size );
|
671 |
+
}
|
672 |
+
|
673 |
+
/**
|
674 |
+
* Filtered list of attachment image attributes.
|
675 |
+
*
|
676 |
+
* @param array $attr Attributes for the image markup.
|
677 |
+
* @param WP_Post $attachment Image attachment post.
|
678 |
+
* @param string $size Requested size.
|
679 |
+
* @param Media_Library_Item $as3cf_item
|
680 |
+
*/
|
681 |
+
return apply_filters( 'as3cf_wp_get_attachment_image_attributes', $attr, $attachment, $size, $as3cf_item );
|
682 |
+
}
|
683 |
+
|
684 |
+
/**
|
685 |
+
* Maybe encode attachment URLs when retrieving the image tag
|
686 |
+
*
|
687 |
+
* @param string $html
|
688 |
+
* @param int $id
|
689 |
+
* @param string $alt
|
690 |
+
* @param string $title
|
691 |
+
* @param string $align
|
692 |
+
* @param string $size
|
693 |
+
*
|
694 |
+
* @return string
|
695 |
+
*/
|
696 |
+
public function maybe_encode_get_image_tag( $html, $id, $alt, $title, $align, $size ) {
|
697 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $id );
|
698 |
+
if ( ! $as3cf_item || ! $as3cf_item->served_by_provider() ) {
|
699 |
+
return $html;
|
700 |
+
}
|
701 |
+
|
702 |
+
if ( ! is_string( $html ) ) {
|
703 |
+
return $html;
|
704 |
+
}
|
705 |
+
|
706 |
+
preg_match( '@\ssrc=[\'\"]([^\'\"]*)[\'\"]@', $html, $matches );
|
707 |
+
|
708 |
+
if ( ! isset( $matches[1] ) ) {
|
709 |
+
// Can't establish img src
|
710 |
+
return $html;
|
711 |
+
}
|
712 |
+
|
713 |
+
$img_src = $matches[1];
|
714 |
+
$new_img_src = $this->maybe_sign_intermediate_size( $img_src, $id, $size, $as3cf_item );
|
715 |
+
$new_img_src = AS3CF_Utils::encode_filename_in_path( $new_img_src );
|
716 |
+
|
717 |
+
return str_replace( $img_src, $new_img_src, $html );
|
718 |
+
}
|
719 |
+
|
720 |
+
/**
|
721 |
+
* Maybe encode URLs for images that represent an attachment
|
722 |
+
*
|
723 |
+
* @param array|bool $image
|
724 |
+
* @param int $attachment_id
|
725 |
+
* @param string|array $size
|
726 |
+
* @param bool $icon
|
727 |
+
*
|
728 |
+
* @return array
|
729 |
+
*/
|
730 |
+
public function maybe_encode_wp_get_attachment_image_src( $image, $attachment_id, $size, $icon ) {
|
731 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
732 |
+
if ( ! $as3cf_item || ! $as3cf_item->served_by_provider() ) {
|
733 |
+
return $image;
|
734 |
+
}
|
735 |
+
|
736 |
+
if ( isset( $image[0] ) ) {
|
737 |
+
$url = $this->maybe_sign_intermediate_size( $image[0], $attachment_id, $size, $as3cf_item );
|
738 |
+
$url = AS3CF_Utils::encode_filename_in_path( $url );
|
739 |
+
|
740 |
+
$image[0] = $url;
|
741 |
+
}
|
742 |
+
|
743 |
+
return $image;
|
744 |
+
}
|
745 |
+
|
746 |
+
/**
|
747 |
+
* Maybe encode URLs when outputting attachments in the media grid
|
748 |
+
*
|
749 |
+
* @param array $response
|
750 |
+
* @param int|object $attachment
|
751 |
+
* @param array $meta
|
752 |
+
*
|
753 |
+
* @return array
|
754 |
+
*/
|
755 |
+
public function maybe_encode_wp_prepare_attachment_for_js( $response, $attachment, $meta ) {
|
756 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment->ID );
|
757 |
+
if ( empty( $as3cf_item ) || ! $as3cf_item->served_by_provider() ) {
|
758 |
+
return $response;
|
759 |
+
}
|
760 |
+
|
761 |
+
if ( isset( $response['url'] ) ) {
|
762 |
+
$response['url'] = AS3CF_Utils::encode_filename_in_path( $response['url'] );
|
763 |
+
}
|
764 |
+
|
765 |
+
if ( isset( $response['sizes'] ) && is_array( $response['sizes'] ) ) {
|
766 |
+
foreach ( $response['sizes'] as $size => $value ) {
|
767 |
+
$url = $this->maybe_sign_intermediate_size( $value['url'], $attachment->ID, $size, $as3cf_item, true );
|
768 |
+
$url = AS3CF_Utils::encode_filename_in_path( $url );
|
769 |
+
|
770 |
+
$response['sizes'][ $size ]['url'] = $url;
|
771 |
+
}
|
772 |
+
}
|
773 |
+
|
774 |
+
return $response;
|
775 |
+
}
|
776 |
+
|
777 |
+
/**
|
778 |
+
* Maybe encode URLs when retrieving intermediate sizes.
|
779 |
+
*
|
780 |
+
* @param array $data
|
781 |
+
* @param int $post_id
|
782 |
+
* @param string|array $size
|
783 |
+
*
|
784 |
+
* @return array
|
785 |
+
*/
|
786 |
+
public function maybe_encode_image_get_intermediate_size( $data, $post_id, $size ) {
|
787 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
788 |
+
if ( ! $as3cf_item || ! $as3cf_item->served_by_provider() ) {
|
789 |
+
return $data;
|
790 |
+
}
|
791 |
+
|
792 |
+
if ( isset( $data['url'] ) ) {
|
793 |
+
$url = $this->maybe_sign_intermediate_size( $data['url'], $post_id, $size, $as3cf_item );
|
794 |
+
$url = AS3CF_Utils::encode_filename_in_path( $url );
|
795 |
+
|
796 |
+
$data['url'] = $url;
|
797 |
+
}
|
798 |
+
|
799 |
+
return $data;
|
800 |
+
}
|
801 |
+
|
802 |
+
/**
|
803 |
+
* Sign intermediate size.
|
804 |
+
*
|
805 |
+
* @param string $url
|
806 |
+
* @param int $attachment_id
|
807 |
+
* @param string|array $size
|
808 |
+
* @param bool|Media_Library_Item $as3cf_item
|
809 |
+
* @param bool $force_rewrite If size not signed, make sure correct URL is being used anyway.
|
810 |
+
*
|
811 |
+
* @return string|WP_Error
|
812 |
+
*/
|
813 |
+
protected function maybe_sign_intermediate_size( $url, $attachment_id, $size, $as3cf_item = false, $force_rewrite = false ) {
|
814 |
+
if ( ! $as3cf_item ) {
|
815 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
816 |
+
}
|
817 |
+
|
818 |
+
$size = $this->maybe_convert_size_to_string( $attachment_id, $size );
|
819 |
+
|
820 |
+
if ( $force_rewrite || $as3cf_item->is_private( $size ) ) {
|
821 |
+
// Private file, add AWS signature if required
|
822 |
+
return $as3cf_item->get_provider_url( $size );
|
823 |
+
}
|
824 |
+
|
825 |
+
return $url;
|
826 |
+
}
|
827 |
+
|
828 |
+
/**
|
829 |
+
* Return the provider URL when the local file is missing
|
830 |
+
* unless we know who the calling process is, and we are happy
|
831 |
+
* to copy the file back to the server to be used.
|
832 |
+
*
|
833 |
+
* @handles get_attached_file
|
834 |
+
* @handles wp_get_original_image_path
|
835 |
+
*
|
836 |
+
* @param string $file
|
837 |
+
* @param int $attachment_id
|
838 |
+
*
|
839 |
+
* @return string
|
840 |
+
*/
|
841 |
+
public function get_attached_file( $file, $attachment_id ) {
|
842 |
+
// During the deletion of an attachment, stream wrapper URLs should not be returned.
|
843 |
+
if ( $this->deleting_attachment ) {
|
844 |
+
return $file;
|
845 |
+
}
|
846 |
+
|
847 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment_id );
|
848 |
+
if ( ! empty( $as3cf_item ) && ! $as3cf_item->served_by_provider() ) {
|
849 |
+
$as3cf_item = false;
|
850 |
+
}
|
851 |
+
|
852 |
+
if ( file_exists( $file ) || ! $as3cf_item ) {
|
853 |
+
if ( $as3cf_item ) {
|
854 |
+
/**
|
855 |
+
* This filter gives filter implementors a chance to copy back siblings for
|
856 |
+
* a local file even if the main already exists locally.
|
857 |
+
*
|
858 |
+
* @param string $url Item URL
|
859 |
+
* @param string $file Local file path
|
860 |
+
* @param int $attachment_id Attachment post id
|
861 |
+
* @param Media_Library_Item $as3cf_item The Item object
|
862 |
+
*
|
863 |
+
*/
|
864 |
+
return apply_filters( 'as3cf_get_attached_file_noop', $file, $file, $attachment_id, $as3cf_item );
|
865 |
+
} else {
|
866 |
+
return $file;
|
867 |
+
}
|
868 |
+
}
|
869 |
+
|
870 |
+
$url = $as3cf_item->get_provider_url();
|
871 |
+
if ( false === $url || is_wp_error( $url ) ) {
|
872 |
+
return $file;
|
873 |
+
}
|
874 |
+
|
875 |
+
/**
|
876 |
+
* This filter gives filter implementors a chance to copy back missing item files
|
877 |
+
* from the provider before WordPress returns the file name/path for it. Defaults to
|
878 |
+
* returning the remote URL.
|
879 |
+
*
|
880 |
+
* @param string $url Item URL
|
881 |
+
* @param string $file Local file path
|
882 |
+
* @param int $attachment_id Attachment post id
|
883 |
+
* @param Media_Library_Item $as3cf_item The Item object
|
884 |
+
*
|
885 |
+
*/
|
886 |
+
return apply_filters( 'as3cf_get_attached_file', $url, $file, $attachment_id, $as3cf_item );
|
887 |
+
}
|
888 |
+
|
889 |
+
/**
|
890 |
+
* Filters the audio & video shortcodes output to remove "&_=NN" params from source.src as it breaks signed URLs.
|
891 |
+
*
|
892 |
+
* @param string $html Shortcode HTML output.
|
893 |
+
* @param array $atts Array of shortcode attributes.
|
894 |
+
* @param string $media Media file.
|
895 |
+
* @param int $post_id Post ID.
|
896 |
+
* @param string $library Media library used for the shortcode.
|
897 |
+
*
|
898 |
+
* @return string
|
899 |
+
*
|
900 |
+
* Note: Depends on 30377.4.diff from https://core.trac.wordpress.org/ticket/30377
|
901 |
+
*/
|
902 |
+
public function wp_media_shortcode( $html, $atts, $media, $post_id, $library ) {
|
903 |
+
return preg_replace( '/&_=[0-9]+/', '', $html );
|
904 |
+
}
|
905 |
+
|
906 |
+
/**
|
907 |
+
* Check we can do the media actions
|
908 |
+
*
|
909 |
+
* @return bool
|
910 |
+
*/
|
911 |
+
public function verify_media_actions() {
|
912 |
+
return false;
|
913 |
+
}
|
914 |
+
|
915 |
+
/**
|
916 |
+
* Get all strings or a specific string used for the media actions
|
917 |
+
*
|
918 |
+
* @param null|string $string
|
919 |
+
*
|
920 |
+
* @return array|string
|
921 |
+
*/
|
922 |
+
public function get_media_action_strings( $string = null ) {
|
923 |
+
$not_verified_value = __( 'No', 'amazon-s3-and-cloudfront' );
|
924 |
+
$not_verified_value .= ' ';
|
925 |
+
$not_verified_value .= $this->as3cf->more_info_link( '/wp-offload-media/doc/add-metadata-tool/', 'os3+attachment+metabox', 'analyze-and-repair', 'More Info', '(', ')' );
|
926 |
+
|
927 |
+
/**
|
928 |
+
* Returns all strings used to render meta boxes on the WordPress Media Library edit page
|
929 |
+
*
|
930 |
+
* @param array $strings Associative array of strings
|
931 |
+
*/
|
932 |
+
$strings = apply_filters( 'as3cf_media_action_strings', array(
|
933 |
+
'provider' => _x( 'Storage Provider', 'Storage provider key name', 'amazon-s3-and-cloudfront' ),
|
934 |
+
'provider_name' => _x( 'Storage Provider', 'Storage provider name', 'amazon-s3-and-cloudfront' ),
|
935 |
+
'bucket' => _x( 'Bucket', 'Bucket name', 'amazon-s3-and-cloudfront' ),
|
936 |
+
'key' => _x( 'Path', 'Path to file in bucket', 'amazon-s3-and-cloudfront' ),
|
937 |
+
'region' => _x( 'Region', 'Location of bucket', 'amazon-s3-and-cloudfront' ),
|
938 |
+
'acl' => _x( 'Access', 'Access control list of the file in bucket', 'amazon-s3-and-cloudfront' ),
|
939 |
+
'url' => __( 'URL', 'amazon-s3-and-cloudfront' ),
|
940 |
+
'is_verified' => _x( 'Verified', 'Whether or not metadata has been verified', 'amazon-s3-and-cloudfront' ),
|
941 |
+
'not_verified' => $not_verified_value,
|
942 |
+
) );
|
943 |
+
|
944 |
+
if ( ! is_null( $string ) ) {
|
945 |
+
return isset( $strings[ $string ] ) ? $strings[ $string ] : '';
|
946 |
+
}
|
947 |
+
|
948 |
+
return $strings;
|
949 |
+
}
|
950 |
+
|
951 |
+
/**
|
952 |
+
* Remove 'filesize' from attachment's metadata if appropriate, also our total filesize record.
|
953 |
+
*
|
954 |
+
* @param int $post_id Attachment's post_id.
|
955 |
+
* @param array $data Attachment's metadata.
|
956 |
+
* @param bool $update_metadata Update the metadata record now? Defaults to true.
|
957 |
+
*
|
958 |
+
* @return array Attachment's cleaned up metadata.
|
959 |
+
*/
|
960 |
+
public function maybe_cleanup_filesize_metadata( $post_id, $data, $update_metadata = true ) {
|
961 |
+
if ( ! is_int( $post_id ) || empty( $post_id ) || empty( $data ) || ! is_array( $data ) ) {
|
962 |
+
return $data;
|
963 |
+
}
|
964 |
+
|
965 |
+
/*
|
966 |
+
* Audio and video have a filesize added to metadata by default, but images and anything else don't.
|
967 |
+
* Note: Could have used `wp_generate_attachment_metadata` here to test whether default metadata has 'filesize',
|
968 |
+
* 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.
|
969 |
+
*/
|
970 |
+
if (
|
971 |
+
empty( $data['mime_type'] ) ||
|
972 |
+
0 === strpos( $data['mime_type'], 'image/' ) ||
|
973 |
+
! ( 0 === strpos( $data['mime_type'], 'audio/' ) || 0 === strpos( $data['mime_type'], 'video/' ) )
|
974 |
+
) {
|
975 |
+
unset( $data['filesize'] );
|
976 |
+
}
|
977 |
+
|
978 |
+
if ( $update_metadata ) {
|
979 |
+
if ( empty( $data ) ) {
|
980 |
+
delete_post_meta( $post_id, '_wp_attachment_metadata' );
|
981 |
+
} else {
|
982 |
+
update_post_meta( $post_id, '_wp_attachment_metadata', $data );
|
983 |
+
}
|
984 |
+
}
|
985 |
+
|
986 |
+
delete_post_meta( $post_id, 'as3cf_filesize_total' );
|
987 |
+
|
988 |
+
return $data;
|
989 |
+
}
|
990 |
+
|
991 |
+
/**
|
992 |
+
* Get ACL value string.
|
993 |
+
*
|
994 |
+
* @param array $acl
|
995 |
+
* @param int $post_id
|
996 |
+
*
|
997 |
+
* @return string
|
998 |
+
*/
|
999 |
+
public function get_acl_value_string( $acl, $post_id ) {
|
1000 |
+
return $acl['name'];
|
1001 |
+
}
|
1002 |
+
|
1003 |
+
/**
|
1004 |
+
* Determines if the image metadata is for the image source file.
|
1005 |
+
*
|
1006 |
+
* @handles wp_image_file_matches_image_meta
|
1007 |
+
*
|
1008 |
+
* @param bool $match
|
1009 |
+
* @param string $image_location
|
1010 |
+
* @param array $image_meta
|
1011 |
+
* @param int $source_id
|
1012 |
+
*
|
1013 |
+
* @return bool
|
1014 |
+
*/
|
1015 |
+
public function image_file_matches_image_meta( $match, $image_location, $image_meta, $source_id ) {
|
1016 |
+
// If already matched or the URL is local, there's nothing for us to do.
|
1017 |
+
if ( $match || ! $this->as3cf->filter_local->url_needs_replacing( $image_location ) ) {
|
1018 |
+
return $match;
|
1019 |
+
}
|
1020 |
+
|
1021 |
+
$item = array(
|
1022 |
+
'id' => $source_id,
|
1023 |
+
'source_type' => Media_Library_Item::source_type(),
|
1024 |
+
);
|
1025 |
+
|
1026 |
+
return $this->as3cf->filter_local->item_matches_src( $item, $image_location );
|
1027 |
+
}
|
1028 |
+
|
1029 |
+
/**
|
1030 |
+
* Get the local URL for a Media Library Item
|
1031 |
+
*
|
1032 |
+
* @handles as3cf_get_local_url_for_item_source
|
1033 |
+
*
|
1034 |
+
* @param string $url Url
|
1035 |
+
* @param array $item_source The item source descriptor array
|
1036 |
+
* @param string $size Name of requested size
|
1037 |
+
*
|
1038 |
+
* @return string|false
|
1039 |
+
*/
|
1040 |
+
public function filter_get_local_url_for_item_source( $url, $item_source, $size ) {
|
1041 |
+
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
1042 |
+
return $url;
|
1043 |
+
}
|
1044 |
+
|
1045 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $item_source['id'] );
|
1046 |
+
if ( ! empty( $as3cf_item ) ) {
|
1047 |
+
return $as3cf_item->get_local_url( $size );
|
1048 |
+
}
|
1049 |
+
|
1050 |
+
return $url;
|
1051 |
+
}
|
1052 |
+
|
1053 |
+
/**
|
1054 |
+
* Get the remote URL for a Media Library Item
|
1055 |
+
*
|
1056 |
+
* @handles as3cf_get_provider_url_for_item_source
|
1057 |
+
*
|
1058 |
+
* @param string $url Url
|
1059 |
+
* @param array $item_source The item source descriptor array
|
1060 |
+
* @param string $size Name of requested size
|
1061 |
+
*
|
1062 |
+
* @return string|false
|
1063 |
+
*/
|
1064 |
+
public function filter_get_provider_url_for_item_source( $url, $item_source, $size ) {
|
1065 |
+
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
1066 |
+
return $url;
|
1067 |
+
}
|
1068 |
+
|
1069 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $item_source['id'] );
|
1070 |
+
if ( empty( $as3cf_item ) ) {
|
1071 |
+
return $url;
|
1072 |
+
}
|
1073 |
+
|
1074 |
+
$url = $as3cf_item->get_provider_url( $size );
|
1075 |
+
|
1076 |
+
if ( is_wp_error( $url ) ) {
|
1077 |
+
return false;
|
1078 |
+
}
|
1079 |
+
|
1080 |
+
return $url;
|
1081 |
+
}
|
1082 |
+
|
1083 |
+
/**
|
1084 |
+
* Get the size from a URL for media library item types
|
1085 |
+
*
|
1086 |
+
* @handles as3cf_get_size_string_from_url_for_item_source
|
1087 |
+
*
|
1088 |
+
* @param string $size
|
1089 |
+
* @param string $url
|
1090 |
+
* @param array $item_source
|
1091 |
+
*
|
1092 |
+
* @return string
|
1093 |
+
*/
|
1094 |
+
public function get_size_string_from_url_for_item_source( $size, $url, $item_source ) {
|
1095 |
+
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
1096 |
+
return $size;
|
1097 |
+
}
|
1098 |
+
|
1099 |
+
$meta = get_post_meta( $item_source['id'], '_wp_attachment_metadata', true );
|
1100 |
+
|
1101 |
+
if ( empty( $meta['sizes'] ) ) {
|
1102 |
+
// No alternative sizes available, return
|
1103 |
+
return $size;
|
1104 |
+
}
|
1105 |
+
|
1106 |
+
$basename = AS3CF_Utils::encode_filename_in_path( wp_basename( $this->as3cf->maybe_remove_query_string( $url ) ) );
|
1107 |
+
|
1108 |
+
foreach ( $meta['sizes'] as $size_name => $file ) {
|
1109 |
+
if ( $basename === AS3CF_Utils::encode_filename_in_path( $file['file'] ) ) {
|
1110 |
+
return $size_name;
|
1111 |
+
}
|
1112 |
+
}
|
1113 |
+
|
1114 |
+
return $size;
|
1115 |
+
}
|
1116 |
+
|
1117 |
+
/**
|
1118 |
+
* Get attachment id from remote URL.
|
1119 |
+
*
|
1120 |
+
* @param string $url
|
1121 |
+
*
|
1122 |
+
* @return bool|int
|
1123 |
+
*/
|
1124 |
+
public function get_attachment_id_from_provider_url( $url ) {
|
1125 |
+
$item_source = $this->as3cf->filter_provider->get_item_source_from_url( $url );
|
1126 |
+
|
1127 |
+
if ( ! empty( $item_source['id'] ) && ! empty( $item_source['source_type'] ) && Media_Library_Item::source_type() === $item_source['source_type'] ) {
|
1128 |
+
return $item_source['id'];
|
1129 |
+
}
|
1130 |
+
|
1131 |
+
return false;
|
1132 |
+
}
|
1133 |
+
|
1134 |
+
/**
|
1135 |
+
* Get attachment id from local URL.
|
1136 |
+
*
|
1137 |
+
* @param string $url
|
1138 |
+
*
|
1139 |
+
* @return bool|int
|
1140 |
+
*/
|
1141 |
+
public function get_attachment_id_from_local_url( $url ) {
|
1142 |
+
$item_source = $this->as3cf->filter_local->get_item_source_from_url( $url );
|
1143 |
+
|
1144 |
+
if ( ! empty( $item_source['id'] ) && ! empty( $item_source['source_type'] ) && Media_Library_Item::source_type() === $item_source['source_type'] ) {
|
1145 |
+
return $item_source['id'];
|
1146 |
+
}
|
1147 |
+
|
1148 |
+
return false;
|
1149 |
+
}
|
1150 |
+
|
1151 |
+
/**
|
1152 |
+
* Get post time
|
1153 |
+
*
|
1154 |
+
* @param int $post_id
|
1155 |
+
*
|
1156 |
+
* @return string
|
1157 |
+
*/
|
1158 |
+
private function get_post_time( $post_id ) {
|
1159 |
+
$time = current_time( 'mysql' );
|
1160 |
+
|
1161 |
+
if ( ! $post = get_post( $post_id ) ) {
|
1162 |
+
return $time;
|
1163 |
+
}
|
1164 |
+
|
1165 |
+
if ( substr( $post->post_date, 0, 4 ) > 0 ) {
|
1166 |
+
$time = $post->post_date;
|
1167 |
+
}
|
1168 |
+
|
1169 |
+
return $time;
|
1170 |
+
}
|
1171 |
+
|
1172 |
+
/**
|
1173 |
+
* Maybe convert size to string
|
1174 |
+
*
|
1175 |
+
* @param int $attachment_id
|
1176 |
+
* @param mixed $size
|
1177 |
+
*
|
1178 |
+
* @return null|string
|
1179 |
+
*/
|
1180 |
+
private function maybe_convert_size_to_string( $attachment_id, $size ) {
|
1181 |
+
if ( is_array( $size ) ) {
|
1182 |
+
return $this->convert_dimensions_to_size_name( $attachment_id, $size );
|
1183 |
+
}
|
1184 |
+
|
1185 |
+
return $size;
|
1186 |
+
}
|
1187 |
+
|
1188 |
+
/**
|
1189 |
+
* Convert dimensions to size
|
1190 |
+
*
|
1191 |
+
* @param int $attachment_id
|
1192 |
+
* @param array $dimensions
|
1193 |
+
*
|
1194 |
+
* @return null|string
|
1195 |
+
*/
|
1196 |
+
private function convert_dimensions_to_size_name( $attachment_id, $dimensions ) {
|
1197 |
+
$w = ( isset( $dimensions[0] ) && $dimensions[0] > 0 ) ? $dimensions[0] : 1;
|
1198 |
+
$h = ( isset( $dimensions[1] ) && $dimensions[1] > 0 ) ? $dimensions[1] : 1;
|
1199 |
+
$original_aspect_ratio = $w / $h;
|
1200 |
+
$meta = wp_get_attachment_metadata( $attachment_id );
|
1201 |
+
|
1202 |
+
if ( ! isset( $meta['sizes'] ) || empty( $meta['sizes'] ) ) {
|
1203 |
+
return null;
|
1204 |
+
}
|
1205 |
+
|
1206 |
+
$sizes = $meta['sizes'];
|
1207 |
+
uasort( $sizes, function ( $a, $b ) {
|
1208 |
+
// Order by image area
|
1209 |
+
return ( $a['width'] * $a['height'] ) - ( $b['width'] * $b['height'] );
|
1210 |
+
} );
|
1211 |
+
|
1212 |
+
$nearest_matches = array();
|
1213 |
+
|
1214 |
+
foreach ( $sizes as $size => $value ) {
|
1215 |
+
if ( $w > $value['width'] || $h > $value['height'] ) {
|
1216 |
+
continue;
|
1217 |
+
}
|
1218 |
+
|
1219 |
+
$aspect_ratio = $value['width'] / $value['height'];
|
1220 |
+
|
1221 |
+
if ( $aspect_ratio === $original_aspect_ratio ) {
|
1222 |
+
return $size;
|
1223 |
+
}
|
1224 |
+
|
1225 |
+
$nearest_matches[] = $size;
|
1226 |
+
}
|
1227 |
+
|
1228 |
+
// Return nearest match
|
1229 |
+
if ( ! empty( $nearest_matches ) ) {
|
1230 |
+
return $nearest_matches[0];
|
1231 |
+
}
|
1232 |
+
|
1233 |
+
return null;
|
1234 |
+
}
|
1235 |
+
|
1236 |
+
/**
|
1237 |
+
* Has the given attachment been uploaded by this instance?
|
1238 |
+
*
|
1239 |
+
* @param int $source_id
|
1240 |
+
*
|
1241 |
+
* @return bool
|
1242 |
+
*/
|
1243 |
+
public function item_just_uploaded( $source_id ) {
|
1244 |
+
if ( is_int( $source_id ) && isset( $this->items_in_progress[ $source_id ] ) ) {
|
1245 |
+
return true;
|
1246 |
+
}
|
1247 |
+
|
1248 |
+
return false;
|
1249 |
+
}
|
1250 |
+
|
1251 |
+
/**
|
1252 |
+
* Call legacy attachment specific version of the as3cf_get_item_secure_url filter.
|
1253 |
+
*
|
1254 |
+
* @param string $url The URL
|
1255 |
+
* @param Item $as3cf_item The Item object
|
1256 |
+
* @param array $item_source The item source descriptor array
|
1257 |
+
* @param int $timestamp Expiry timestamp
|
1258 |
+
* @param array $headers Optional extra http headers
|
1259 |
+
*
|
1260 |
+
* @handles as3cf_get_item_secure_url
|
1261 |
+
*
|
1262 |
+
* @return string|mixed
|
1263 |
+
*/
|
1264 |
+
public function get_item_secure_url( $url, $as3cf_item, $item_source, $timestamp, $headers ) {
|
1265 |
+
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
1266 |
+
return $url;
|
1267 |
+
}
|
1268 |
+
|
1269 |
+
/**
|
1270 |
+
* Filters the secure url for an attachment
|
1271 |
+
*
|
1272 |
+
* @param string $url The URL
|
1273 |
+
* @param Item $as3cf_item The Item object
|
1274 |
+
* @param int $id The attachment id
|
1275 |
+
* @param int $timestamp Expiry timestamp
|
1276 |
+
* @param array $headers Optional extra http headers
|
1277 |
+
*
|
1278 |
+
* @deprecated 2.6.0 Please use filter "as3cf_get_item_secure_url" instead.
|
1279 |
+
*/
|
1280 |
+
return apply_filters( 'as3cf_get_attachment_secure_url', $url, $as3cf_item, $item_source['id'], $timestamp, $headers );
|
1281 |
+
}
|
1282 |
+
|
1283 |
+
/**
|
1284 |
+
* Call legacy attachment specific version of the as3cf_get_item_url filter.
|
1285 |
+
*
|
1286 |
+
* @param string $url The URL
|
1287 |
+
* @param Item $as3cf_item The Item object
|
1288 |
+
* @param array $item_source The item source descriptor array
|
1289 |
+
* @param int $timestamp Expiry timestamp
|
1290 |
+
* @param array $headers Optional extra http headers
|
1291 |
+
*
|
1292 |
+
* @handles as3cf_get_item_url
|
1293 |
+
*
|
1294 |
+
* @return string|mixed
|
1295 |
+
*/
|
1296 |
+
public function get_item_url( $url, $as3cf_item, $item_source, $timestamp, $headers ) {
|
1297 |
+
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
1298 |
+
return $url;
|
1299 |
+
}
|
1300 |
+
|
1301 |
+
/**
|
1302 |
+
* Filters the url for an attachment
|
1303 |
+
*
|
1304 |
+
* @param string $url The URL
|
1305 |
+
* @param Item $as3cf_item The Item object
|
1306 |
+
* @param int $id The attachment id
|
1307 |
+
* @param int $timestamp Expiry timestamp
|
1308 |
+
* @param array $headers Optional extra http headers
|
1309 |
+
*
|
1310 |
+
* @deprecated 2.6.0 Please use filter "as3cf_get_item_url" instead.
|
1311 |
+
*/
|
1312 |
+
return apply_filters( 'as3cf_get_attachment_url', $url, $as3cf_item, $item_source['id'], $timestamp, $headers );
|
1313 |
+
}
|
1314 |
+
|
1315 |
+
/**
|
1316 |
+
* Call legacy attachment specific version of the as3cf_remove_source_files_from_provider filter.
|
1317 |
+
*
|
1318 |
+
* @param array $paths Array of local paths to be removed from provider
|
1319 |
+
* @param Item $as3cf_item The Item object
|
1320 |
+
* @param array $item_source The item source descriptor array
|
1321 |
+
*
|
1322 |
+
* @handles as3cf_remove_source_files_from_provider
|
1323 |
+
*
|
1324 |
+
* @return array|mixed
|
1325 |
+
*/
|
1326 |
+
public function filter_remove_source_files_from_provider( $paths, Item $as3cf_item, $item_source ) {
|
1327 |
+
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
1328 |
+
return $paths;
|
1329 |
+
}
|
1330 |
+
|
1331 |
+
/**
|
1332 |
+
* Filters which provider files to remove
|
1333 |
+
*
|
1334 |
+
* @param array $paths Array of local paths to be removed from provider
|
1335 |
+
* @param int $id Item attachment id
|
1336 |
+
* @param Item $as3cf_item The Item
|
1337 |
+
* @param bool $include_backups Also include backup files?
|
1338 |
+
*
|
1339 |
+
* @deprecated 2.6.0 Please use filter "as3cf_remove_source_files_from_provider" instead.
|
1340 |
+
*/
|
1341 |
+
return apply_filters( 'as3cf_remove_attachment_paths', $paths, $item_source['id'], $as3cf_item, true );
|
1342 |
+
}
|
1343 |
+
|
1344 |
+
/**
|
1345 |
+
* Calls legacy attachment specific version of as3cf_remove_local_files filter.
|
1346 |
+
*
|
1347 |
+
* @param array $files_to_remove Array of paths to be removed
|
1348 |
+
* @param Item $as3cf_item The Item object
|
1349 |
+
* @param array $item_source The item source descriptor array
|
1350 |
+
*
|
1351 |
+
* @handles as3cf_remove_local_files
|
1352 |
+
*
|
1353 |
+
* @return array|mixed
|
1354 |
+
*/
|
1355 |
+
public function filter_remove_local_files( $files_to_remove, $as3cf_item, $item_source ) {
|
1356 |
+
if ( Media_Library_Item::source_type() !== $item_source['source_type'] ) {
|
1357 |
+
return $files_to_remove;
|
1358 |
+
}
|
1359 |
+
|
1360 |
+
/**
|
1361 |
+
* Filters which local files should be removed.
|
1362 |
+
*
|
1363 |
+
* @param array $paths Paths that will be removed
|
1364 |
+
* @param int $id Attachment id
|
1365 |
+
* @param string $source_path Path to primary file
|
1366 |
+
*
|
1367 |
+
* @deprecated 2.6.0 Please use filter "as3cf_remove_local_files" instead.
|
1368 |
+
*/
|
1369 |
+
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() ) );
|
1370 |
+
}
|
1371 |
+
|
1372 |
+
/**
|
1373 |
+
* Handle post upload duties if uploaded item is a media-library item.
|
1374 |
+
*
|
1375 |
+
* @handles as3cf_post_upload_item
|
1376 |
+
*
|
1377 |
+
* @param Media_Library_Item $as3cf_item
|
1378 |
+
*/
|
1379 |
+
public function post_upload_item( $as3cf_item ) {
|
1380 |
+
if ( Media_Library_Item::source_type() !== $as3cf_item->source_type() ) {
|
1381 |
+
return;
|
1382 |
+
}
|
1383 |
+
|
1384 |
+
// Make sure duplicates are marked as offloaded too.
|
1385 |
+
$as3cf_item->offload_duplicate_items();
|
1386 |
+
|
1387 |
+
/**
|
1388 |
+
* Fires after an attachment has been uploaded to the provider.
|
1389 |
+
*
|
1390 |
+
* @param int $id Attachment id
|
1391 |
+
* @param Item $as3cf_item The item that was just uploaded
|
1392 |
+
*
|
1393 |
+
* @deprecated 2.6.0 Please use action "as3cf_post_upload_item" instead.
|
1394 |
+
*/
|
1395 |
+
do_action( 'as3cf_post_upload_attachment', $as3cf_item->source_id(), $as3cf_item );
|
1396 |
+
}
|
1397 |
+
|
1398 |
+
/**
|
1399 |
+
* Call legacy media library specific filter for cancelling an upload.
|
1400 |
+
*
|
1401 |
+
* @param bool $cancel Should the action on the item be cancelled?
|
1402 |
+
* @param Item $as3cf_item The item that the action is being handled for.
|
1403 |
+
* @param array $options Handler dependent options that may have been set for the action.
|
1404 |
+
*
|
1405 |
+
* @handles as3cf_pre_handle_item_upload
|
1406 |
+
*
|
1407 |
+
* @return bool
|
1408 |
+
*/
|
1409 |
+
public function pre_handle_item_upload( $cancel, $as3cf_item, array $options ) {
|
1410 |
+
if ( Media_Library_Item::source_type() !== $as3cf_item->source_type() ) {
|
1411 |
+
return $cancel;
|
1412 |
+
}
|
1413 |
+
|
1414 |
+
// Get unfiltered attachment metadata to pass into legacy filter.
|
1415 |
+
$metadata = wp_get_attachment_metadata( $as3cf_item->source_id(), true );
|
1416 |
+
if ( is_wp_error( $metadata ) ) {
|
1417 |
+
return $metadata;
|
1418 |
+
}
|
1419 |
+
|
1420 |
+
/**
|
1421 |
+
* Allow provider upload to be cancelled for any reason.
|
1422 |
+
*
|
1423 |
+
* @param bool $cancel Should the upload for the attachment be cancelled?
|
1424 |
+
* @param int $id Attachment id
|
1425 |
+
* @param array $metadata Attachment metadata
|
1426 |
+
*
|
1427 |
+
* @deprecated 2.6.0 Please use filter "as3cf_pre_upload_item" instead.
|
1428 |
+
*/
|
1429 |
+
return apply_filters( 'as3cf_pre_upload_attachment', $cancel, $as3cf_item->source_id(), $metadata );
|
1430 |
+
}
|
1431 |
+
|
1432 |
+
/**
|
1433 |
+
* Call legacy filter for determining private status on an item's individual object_key.
|
1434 |
+
*
|
1435 |
+
* @param bool $is_private
|
1436 |
+
* @param string $object_key
|
1437 |
+
* @param Item $as3cf_item
|
1438 |
+
*
|
1439 |
+
* @handles as3cf_upload_object_key_as_private
|
1440 |
+
*
|
1441 |
+
* @return bool
|
1442 |
+
*/
|
1443 |
+
public function filter_upload_object_key_as_private( $is_private, $object_key, $as3cf_item ) {
|
1444 |
+
if ( Media_Library_Item::source_type() !== $as3cf_item->source_type() ) {
|
1445 |
+
return $is_private;
|
1446 |
+
}
|
1447 |
+
|
1448 |
+
$metadata = wp_get_attachment_metadata( $as3cf_item->source_id(), true );
|
1449 |
+
$default_acl = $this->as3cf->get_storage_provider()->get_default_acl();
|
1450 |
+
$private_acl = $this->as3cf->get_storage_provider()->get_private_acl();
|
1451 |
+
$acl = true === $is_private ? $private_acl : $default_acl;
|
1452 |
+
|
1453 |
+
if ( Item::primary_object_key() === $object_key ) {
|
1454 |
+
$file_name = wp_basename( $as3cf_item->source_path() );
|
1455 |
+
$file_type = wp_check_filetype_and_ext( $as3cf_item->source_path(), $file_name );
|
1456 |
+
|
1457 |
+
// Old naming convention, will be removed soon.
|
1458 |
+
$acl = apply_filters( 'wps3_upload_acl', $acl, $file_type['type'], $metadata, $as3cf_item->source_id(), $this->as3cf );
|
1459 |
+
|
1460 |
+
/**
|
1461 |
+
* Determine canned ACL for an item's original (full size) file about to be uploaded to provider.
|
1462 |
+
*
|
1463 |
+
* @param string $acl The canned ACL for the provider.
|
1464 |
+
* @param array $metadata The attachment's metadata.
|
1465 |
+
* @param int $id The attachment's ID.
|
1466 |
+
*
|
1467 |
+
* @deprecated 2.6.0 Please use filter "as3cf_upload_object_key_as_private" instead.
|
1468 |
+
*/
|
1469 |
+
$acl = apply_filters( 'as3cf_upload_acl', $acl, $metadata, $as3cf_item->source_id() );
|
1470 |
+
} else {
|
1471 |
+
/**
|
1472 |
+
* Determine ACL for an item's individual thumbnail size about to be uploaded to provider.
|
1473 |
+
*
|
1474 |
+
* @param string $acl The canned ACL for the provider.
|
1475 |
+
* @param string $size Size name for file (thumbnail, medium, large).
|
1476 |
+
* @param int $id The attachment's ID.
|
1477 |
+
* @param array $data The attachment's metadata.
|
1478 |
+
*
|
1479 |
+
* @deprecated 2.6.0 Please use filter "as3cf_upload_object_key_as_private" instead.
|
1480 |
+
*/
|
1481 |
+
$acl = apply_filters( 'as3cf_upload_acl_sizes', $acl, $object_key, $as3cf_item->source_id(), $metadata );
|
1482 |
+
}
|
1483 |
+
|
1484 |
+
if ( ! empty( $acl ) && $private_acl === $acl ) {
|
1485 |
+
return true;
|
1486 |
+
}
|
1487 |
+
|
1488 |
+
return $is_private;
|
1489 |
+
}
|
1490 |
+
|
1491 |
+
/**
|
1492 |
+
* Fire legacy action just before a Media Library Item is offloaded.
|
1493 |
+
*
|
1494 |
+
* @handles as3cf_pre_upload_object
|
1495 |
+
*
|
1496 |
+
* @param Item $as3cf_item
|
1497 |
+
* @param array $args
|
1498 |
+
*/
|
1499 |
+
public function action_pre_upload_object( $as3cf_item, $args ) {
|
1500 |
+
if ( Media_Library_Item::source_type() !== $as3cf_item->source_type() ) {
|
1501 |
+
return;
|
1502 |
+
}
|
1503 |
+
|
1504 |
+
/**
|
1505 |
+
* Actions fires when an Item's original file might be offloaded.
|
1506 |
+
*
|
1507 |
+
* This action gives notice that an Item is being processed for upload to a bucket,
|
1508 |
+
* and the given arguments represent the original file's potential offload location.
|
1509 |
+
* However, if the current process is for picking up extra files associated with the item,
|
1510 |
+
* the indicated original file may not actually be offloaded if it does not exist
|
1511 |
+
* on the server but has already been offloaded.
|
1512 |
+
*
|
1513 |
+
*
|
1514 |
+
* @param int $id The attachment id.
|
1515 |
+
* @param Media_Library_Item $as3cf_item The Item whose files are being offloaded.
|
1516 |
+
* @param string $path The path to the item.
|
1517 |
+
* @param array $args The arguments that could be used to offload the original file.
|
1518 |
+
*
|
1519 |
+
* @deprecated 2.6.0 Please use action "as3cf_pre_upload_object" instead.
|
1520 |
+
*/
|
1521 |
+
do_action( 'as3cf_upload_attachment_pre_remove', $as3cf_item->source_id(), $as3cf_item, $as3cf_item->normalized_path_dir(), $args );
|
1522 |
+
}
|
1523 |
+
|
1524 |
+
/**
|
1525 |
+
* Takes notice that an attachment is about to be deleted and prepares for it.
|
1526 |
+
*
|
1527 |
+
* @handles pre_delete_attachment
|
1528 |
+
*
|
1529 |
+
* @param bool|null $delete Whether to go forward with deletion.
|
1530 |
+
*
|
1531 |
+
* @return bool|null
|
1532 |
+
*/
|
1533 |
+
public function pre_delete_attachment( $delete ) {
|
1534 |
+
if ( is_null( $delete ) ) {
|
1535 |
+
$this->deleting_attachment = true;
|
1536 |
+
}
|
1537 |
+
|
1538 |
+
return $delete;
|
1539 |
+
}
|
1540 |
+
|
1541 |
+
/**
|
1542 |
+
* Takes notice that an attachment has been deleted and undoes previous preparations for the event.
|
1543 |
+
*
|
1544 |
+
* @handles delete_post
|
1545 |
+
*
|
1546 |
+
* Note: delete_post is used as there is a potential that deleted_post is not reached.
|
1547 |
+
*/
|
1548 |
+
public function delete_post() {
|
1549 |
+
$this->deleting_attachment = false;
|
1550 |
+
}
|
1551 |
+
}
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
+
|
5 |
+
use AS3CF_Error;
|
6 |
+
use DeliciousBrains\WP_Offload_Media\Providers\Storage\Storage_Provider;
|
7 |
+
use Exception;
|
8 |
+
use WP_Error;
|
9 |
+
|
10 |
+
class Download_Handler extends Item_Handler {
|
11 |
+
/**
|
12 |
+
* @var string
|
13 |
+
*/
|
14 |
+
protected static $item_handler_key = 'download';
|
15 |
+
|
16 |
+
/**
|
17 |
+
* The default options that should be used if none supplied.
|
18 |
+
*
|
19 |
+
* @return array
|
20 |
+
*/
|
21 |
+
public static function default_options() {
|
22 |
+
return array(
|
23 |
+
'full_source_paths' => array(),
|
24 |
+
);
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Prepare a manifest based on the item.
|
29 |
+
*
|
30 |
+
* @param Item $as3cf_item
|
31 |
+
* @param array $options
|
32 |
+
*
|
33 |
+
* @return Manifest
|
34 |
+
*/
|
35 |
+
protected function pre_handle( Item $as3cf_item, array $options ) {
|
36 |
+
$manifest = new Manifest();
|
37 |
+
$file_paths = array();
|
38 |
+
|
39 |
+
foreach ( $as3cf_item->objects() as $object_key => $object ) {
|
40 |
+
$file = $as3cf_item->full_source_path( $object_key );
|
41 |
+
|
42 |
+
if ( 0 < count( $options['full_source_paths'] ) && ! in_array( $file, $options['full_source_paths'] ) ) {
|
43 |
+
continue;
|
44 |
+
}
|
45 |
+
|
46 |
+
$file_paths[ $object_key ] = $file;
|
47 |
+
}
|
48 |
+
|
49 |
+
$file_paths = array_unique( $file_paths );
|
50 |
+
|
51 |
+
foreach ( $file_paths as $object_key => $file_path ) {
|
52 |
+
if ( ! file_exists( $file_path ) ) {
|
53 |
+
$manifest->objects[] = array(
|
54 |
+
'args' => array(
|
55 |
+
'Bucket' => $as3cf_item->bucket(),
|
56 |
+
'Key' => $as3cf_item->provider_key( $object_key ),
|
57 |
+
'SaveAs' => $file_path,
|
58 |
+
),
|
59 |
+
);
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
return $manifest;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Perform the downloads.
|
68 |
+
*
|
69 |
+
* @param Item $as3cf_item
|
70 |
+
* @param Manifest $manifest
|
71 |
+
* @param array $options
|
72 |
+
*
|
73 |
+
* @return boolean|WP_Error
|
74 |
+
* @throws Exception
|
75 |
+
*/
|
76 |
+
protected function handle_item( Item $as3cf_item, Manifest $manifest, array $options ) {
|
77 |
+
if ( ! empty( $manifest->objects ) ) {
|
78 |
+
// This test is "late" so that we don't raise the error if the local files exist anyway.
|
79 |
+
// If the provider of this item is different from what's currently configured,
|
80 |
+
// we'll return an error.
|
81 |
+
$current_provider = $this->as3cf->get_storage_provider();
|
82 |
+
if ( ! empty( $current_provider ) && $current_provider::get_provider_key_name() !== $as3cf_item->provider() ) {
|
83 |
+
$message = sprintf(
|
84 |
+
__( '%1$s with ID %d is offloaded to a different provider than currently configured', 'amazon-s3-and-cloudfront' ),
|
85 |
+
$this->as3cf->get_source_type_name( $as3cf_item->source_type() ),
|
86 |
+
$as3cf_item->source_id()
|
87 |
+
);
|
88 |
+
|
89 |
+
return new WP_Error( 'exception', $message );
|
90 |
+
} else {
|
91 |
+
$provider_client = $this->as3cf->get_provider_client( $as3cf_item->region() );
|
92 |
+
|
93 |
+
foreach ( $manifest->objects as &$manifest_object ) {
|
94 |
+
// Save object to a file.
|
95 |
+
$result = $this->download_object( $provider_client, $manifest_object['args'] );
|
96 |
+
|
97 |
+
$manifest_object['download_result']['status'] = self::STATUS_OK;
|
98 |
+
|
99 |
+
if ( is_wp_error( $result ) ) {
|
100 |
+
$manifest_object['download_result']['status'] = self::STATUS_FAILED;
|
101 |
+
$manifest_object['download_result']['message'] = $result->get_error_message();
|
102 |
+
}
|
103 |
+
}
|
104 |
+
}
|
105 |
+
}
|
106 |
+
|
107 |
+
return true;
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Perform post handle tasks. Log errors, update filesize totals etc.
|
112 |
+
*
|
113 |
+
* @param Item $as3cf_item
|
114 |
+
* @param Manifest $manifest
|
115 |
+
* @param array $options
|
116 |
+
*
|
117 |
+
* @return bool|WP_Error
|
118 |
+
*/
|
119 |
+
protected function post_handle( Item $as3cf_item, Manifest $manifest, array $options ) {
|
120 |
+
// Look for errors
|
121 |
+
$errors = new WP_Error;
|
122 |
+
$i = 1;
|
123 |
+
|
124 |
+
foreach ( $manifest->objects as $manifest_object ) {
|
125 |
+
if ( $manifest_object['download_result']['status'] !== self::STATUS_OK ) {
|
126 |
+
$errors->add( 'download-error-' . $i++, $manifest_object['download_result']['message'] );
|
127 |
+
}
|
128 |
+
}
|
129 |
+
|
130 |
+
if ( count( $errors->get_error_codes() ) ) {
|
131 |
+
return $errors;
|
132 |
+
}
|
133 |
+
|
134 |
+
$as3cf_item->update_filesize_after_download_local();
|
135 |
+
|
136 |
+
return true;
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Download an object from provider.
|
141 |
+
*
|
142 |
+
* @param Storage_Provider $provider_client
|
143 |
+
* @param array $object
|
144 |
+
*
|
145 |
+
* @return bool|WP_Error
|
146 |
+
*/
|
147 |
+
private function download_object( $provider_client, $object ) {
|
148 |
+
// Make sure the local directory exists.
|
149 |
+
$dir = dirname( $object['SaveAs'] );
|
150 |
+
if ( ! is_dir( $dir ) && ! wp_mkdir_p( $dir ) ) {
|
151 |
+
$error_message = sprintf( __( 'The local directory %s does not exist and could not be created.', 'amazon-s3-and-cloudfront' ), $dir );
|
152 |
+
AS3CF_Error::log( sprintf( __( 'There was an error attempting to download the file %s from the bucket: %s', 'amazon-s3-and-cloudfront' ), $object['Key'], $error_message ) );
|
153 |
+
}
|
154 |
+
|
155 |
+
try {
|
156 |
+
$provider_client->get_object( $object );
|
157 |
+
} catch ( Exception $e ) {
|
158 |
+
$error_msg = sprintf( __( 'Error downloading %1$s from bucket: %2$s', 'amazon-s3-and-cloudfront' ), $object['Key'], $e->getMessage() );
|
159 |
+
AS3CF_Error::log( $error_msg );
|
160 |
+
|
161 |
+
// If storage provider file doesn't exist, an empty local file will be created, clean it up.
|
162 |
+
@unlink( $object['SaveAs'] );
|
163 |
+
|
164 |
+
return new WP_Error( 'download_object', $error_msg );
|
165 |
+
}
|
166 |
+
|
167 |
+
return true;
|
168 |
+
}
|
169 |
+
}
|
@@ -0,0 +1,247 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
+
|
5 |
+
use Amazon_S3_And_CloudFront;
|
6 |
+
use AS3CF_Error;
|
7 |
+
use Exception;
|
8 |
+
use WP_Error;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Class Item_Handler
|
12 |
+
*
|
13 |
+
* Base class for item handler classes.
|
14 |
+
*
|
15 |
+
* @package DeliciousBrains\WP_Offload_Media\Items
|
16 |
+
*/
|
17 |
+
abstract class Item_Handler {
|
18 |
+
/**
|
19 |
+
* Status codes
|
20 |
+
*/
|
21 |
+
const STATUS_OK = 'ok';
|
22 |
+
const STATUS_FAILED = 'failed';
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @var string
|
26 |
+
*/
|
27 |
+
protected static $item_handler_key;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @var Amazon_S3_And_CloudFront
|
31 |
+
*/
|
32 |
+
protected $as3cf;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* AS3CF_Item_Handler constructor.
|
36 |
+
*
|
37 |
+
* @param Amazon_S3_And_CloudFront $as3cf
|
38 |
+
*/
|
39 |
+
public function __construct( Amazon_S3_And_CloudFront $as3cf ) {
|
40 |
+
$this->as3cf = $as3cf;
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Get the item handler key name.
|
45 |
+
*
|
46 |
+
* @return string
|
47 |
+
*/
|
48 |
+
public static function get_item_handler_key_name() {
|
49 |
+
return static::$item_handler_key;
|
50 |
+
}
|
51 |
+
|
52 |
+
/**
|
53 |
+
* The default options that should be used if none supplied.
|
54 |
+
*
|
55 |
+
* @return array
|
56 |
+
*/
|
57 |
+
public static function default_options() {
|
58 |
+
return array();
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Main entrypoint for handling an item.
|
63 |
+
*
|
64 |
+
* @param Item $as3cf_item
|
65 |
+
* @param array $options
|
66 |
+
*
|
67 |
+
* @return boolean|WP_Error
|
68 |
+
*/
|
69 |
+
public function handle( Item $as3cf_item, array $options = array() ) {
|
70 |
+
// Merge supplied option values into the defaults as long as supplied options are recognised.
|
71 |
+
if ( empty( $options ) || ! is_array( $options ) ) {
|
72 |
+
$options = array();
|
73 |
+
}
|
74 |
+
$options = array_merge( $this->default_options(), array_intersect_key( $options, $this->default_options() ) );
|
75 |
+
|
76 |
+
try {
|
77 |
+
/**
|
78 |
+
* Filter fires before handling an action on an item, allows action to be cancelled.
|
79 |
+
*
|
80 |
+
* This is a generic handler filter that includes the handler's key name as the last param.
|
81 |
+
*
|
82 |
+
* @param bool $cancel Should the action on the item be cancelled?
|
83 |
+
* @param Item $as3cf_item The item that the action is being handled for.
|
84 |
+
* @param array $options Handler dependent options that may have been set for the action.
|
85 |
+
* @param array $handler_key_name The handler's key name as per `Item_Handler::get_item_handler_key_name()`.
|
86 |
+
*
|
87 |
+
* @see Item_Handler::get_item_handler_key_name()
|
88 |
+
*/
|
89 |
+
$cancel = apply_filters(
|
90 |
+
'as3cf_pre_handle_item',
|
91 |
+
/**
|
92 |
+
* Filter fires before handling an action on an item, allows action to be cancelled.
|
93 |
+
*
|
94 |
+
* This is a handler specific filter whose name ends with the handler's key name.
|
95 |
+
* Format is `as3cf_pre_handle_item_{item-handler-key-name}`.
|
96 |
+
*
|
97 |
+
* Example filter names:
|
98 |
+
*
|
99 |
+
* as3cf_pre_handle_item_upload
|
100 |
+
* as3cf_pre_handle_item_download
|
101 |
+
* as3cf_pre_handle_item_remove-local
|
102 |
+
* as3cf_pre_handle_item_remove-provider
|
103 |
+
* as3cf_pre_handle_item_update-acl
|
104 |
+
*
|
105 |
+
* For a more generic filter, use `as3cf_pre_handle_item`.
|
106 |
+
*
|
107 |
+
* @param bool $cancel Should the action on the item be cancelled?
|
108 |
+
* @param Item $as3cf_item The item that the action is being handled for.
|
109 |
+
* @param array $options Handler dependent options that may have been set for the action.
|
110 |
+
*
|
111 |
+
* @see Item_Handler::get_item_handler_key_name()
|
112 |
+
*/
|
113 |
+
apply_filters( 'as3cf_pre_handle_item_' . static::get_item_handler_key_name(), false, $as3cf_item, $options ),
|
114 |
+
$as3cf_item,
|
115 |
+
$options,
|
116 |
+
static::get_item_handler_key_name()
|
117 |
+
);
|
118 |
+
} catch ( Exception $e ) {
|
119 |
+
return $this->return_result( new WP_Error( $e->getMessage() ), $as3cf_item, $options );
|
120 |
+
}
|
121 |
+
|
122 |
+
// Cancelled, let caller know that request was not handled.
|
123 |
+
if ( false !== $cancel ) {
|
124 |
+
return $this->return_result( false, $as3cf_item, $options );
|
125 |
+
}
|
126 |
+
|
127 |
+
$manifest = $this->pre_handle( $as3cf_item, $options );
|
128 |
+
if ( is_wp_error( $manifest ) ) {
|
129 |
+
return $this->return_result( $manifest, $as3cf_item, $options );
|
130 |
+
}
|
131 |
+
|
132 |
+
// Nothing to do, let caller know that request was not handled.
|
133 |
+
if ( empty( $manifest ) || empty( $manifest->objects ) ) {
|
134 |
+
return $this->return_result( false, $as3cf_item, $options );
|
135 |
+
}
|
136 |
+
|
137 |
+
$result = $this->handle_item( $as3cf_item, $manifest, $options );
|
138 |
+
if ( is_wp_error( $result ) ) {
|
139 |
+
return $this->return_result( $result, $as3cf_item, $options );
|
140 |
+
}
|
141 |
+
|
142 |
+
$result = $this->post_handle( $as3cf_item, $manifest, $options );
|
143 |
+
|
144 |
+
return $this->return_result( $result, $as3cf_item, $options );
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Process an Item and options to generate a Manifest for `handle_item`.
|
149 |
+
*
|
150 |
+
* @param Item $as3cf_item
|
151 |
+
* @param array $options
|
152 |
+
*
|
153 |
+
* @return Manifest|WP_Error
|
154 |
+
*/
|
155 |
+
abstract protected function pre_handle( Item $as3cf_item, array $options );
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Perform action for Item using given Manifest.
|
159 |
+
*
|
160 |
+
* @param Item $as3cf_item
|
161 |
+
* @param Manifest $manifest
|
162 |
+
* @param array $options
|
163 |
+
*
|
164 |
+
* @return bool|WP_Error
|
165 |
+
*/
|
166 |
+
abstract protected function handle_item( Item $as3cf_item, Manifest $manifest, array $options );
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Process results of `handle_item` as appropriate.
|
170 |
+
*
|
171 |
+
* @param Item $as3cf_item
|
172 |
+
* @param Manifest $manifest
|
173 |
+
* @param array $options
|
174 |
+
*
|
175 |
+
* @return bool|WP_Error
|
176 |
+
*/
|
177 |
+
abstract protected function post_handle( Item $as3cf_item, Manifest $manifest, array $options );
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Helper to record errors and return meta data on handler error.
|
181 |
+
*
|
182 |
+
* @param string $error_msg
|
183 |
+
* @param array|null $return
|
184 |
+
*
|
185 |
+
* @return array|WP_Error
|
186 |
+
*/
|
187 |
+
protected function return_handler_error( $error_msg, $return = null ) {
|
188 |
+
AS3CF_Error::log( $error_msg );
|
189 |
+
|
190 |
+
if ( is_null( $return ) ) {
|
191 |
+
return new WP_Error( 'exception', $error_msg );
|
192 |
+
}
|
193 |
+
|
194 |
+
return $return;
|
195 |
+
}
|
196 |
+
|
197 |
+
/**
|
198 |
+
* Fires a couple of actions to let interested parties know that a handler has returned a result.
|
199 |
+
*
|
200 |
+
* @param bool|WP_Error $result Result for the action, either handled (true/false), or an error.
|
201 |
+
* @param Item $as3cf_item The item that the action was being handled for.
|
202 |
+
* @param array $options Handler dependent options that may have been set for the action.
|
203 |
+
*
|
204 |
+
* @return bool|WP_Error
|
205 |
+
*/
|
206 |
+
private function return_result( $result, Item $as3cf_item, array $options ) {
|
207 |
+
/**
|
208 |
+
* Action fires after attempting to handle an action on an item.
|
209 |
+
*
|
210 |
+
* This is a handler specific action whose name ends with the handler's key name.
|
211 |
+
* Format is `as3cf_post_handle_item_{item-handler-key-name}`.
|
212 |
+
*
|
213 |
+
* Example filter names:
|
214 |
+
*
|
215 |
+
* as3cf_post_handle_item_upload
|
216 |
+
* as3cf_post_handle_item_download
|
217 |
+
* as3cf_post_handle_item_remove-local
|
218 |
+
* as3cf_post_handle_item_remove-provider
|
219 |
+
* as3cf_post_handle_item_update-acl
|
220 |
+
*
|
221 |
+
* For a more generic filter, use `as3cf_post_handle_item`.
|
222 |
+
*
|
223 |
+
* @param bool|WP_Error $result Result for the action, either handled (true/false), or an error.
|
224 |
+
* @param Item $as3cf_item The item that the action was being handled for.
|
225 |
+
* @param array $options Handler dependent options that may have been set for the action.
|
226 |
+
*
|
227 |
+
* @see Item_Handler::get_item_handler_key_name()
|
228 |
+
*/
|
229 |
+
do_action( 'as3cf_post_handle_item_' . static::get_item_handler_key_name(), $result, $as3cf_item, $options );
|
230 |
+
|
231 |
+
/**
|
232 |
+
* Action fires after attempting to handle an action on an item.
|
233 |
+
*
|
234 |
+
* This is a generic handler action that includes the handler's key name as the last param.
|
235 |
+
*
|
236 |
+
* @param bool|WP_Error $result Result for the action, either handled (true/false), or an error.
|
237 |
+
* @param Item $as3cf_item The item that the action was being handled for.
|
238 |
+
* @param array $options Handler dependent options that may have been set for the action.
|
239 |
+
* @param array $handler_key_name The handler's key name as per `Item_Handler::get_item_handler_key_name()`.
|
240 |
+
*
|
241 |
+
* @see Item_Handler::get_item_handler_key_name()
|
242 |
+
*/
|
243 |
+
do_action( 'as3cf_post_handle_item', $result, $as3cf_item, $options, static::get_item_handler_key_name() );
|
244 |
+
|
245 |
+
return $result;
|
246 |
+
}
|
247 |
+
}
|
@@ -3,21 +3,26 @@
|
|
3 |
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
|
5 |
use Amazon_S3_And_CloudFront;
|
|
|
6 |
use AS3CF_Utils;
|
|
|
|
|
7 |
use WP_Error;
|
8 |
|
9 |
abstract class Item {
|
10 |
-
const ITEMS_TABLE
|
11 |
-
const ORIGINATORS
|
12 |
'standard' => 0,
|
13 |
'metadata-tool' => 1,
|
14 |
);
|
|
|
15 |
|
16 |
-
protected static $
|
17 |
-
protected static $
|
18 |
-
protected static $
|
|
|
19 |
|
20 |
-
|
21 |
|
22 |
protected static $items_cache_by_id = array();
|
23 |
protected static $items_cache_by_source_id = array();
|
@@ -34,6 +39,8 @@ abstract class Item {
|
|
34 |
'source_path' => array( 'source_path', 'original_source_path' ),
|
35 |
);
|
36 |
|
|
|
|
|
37 |
private $id;
|
38 |
private $provider;
|
39 |
private $region;
|
@@ -51,18 +58,19 @@ abstract class Item {
|
|
51 |
/**
|
52 |
* Item constructor.
|
53 |
*
|
54 |
-
* @param string $provider
|
55 |
-
* @param string $region
|
56 |
-
* @param string $bucket
|
57 |
-
* @param string $path
|
58 |
-
* @param bool $is_private
|
59 |
-
* @param int $source_id
|
60 |
-
* @param string $source_path
|
61 |
-
* @param string $original_filename
|
62 |
-
* @param array $extra_info
|
63 |
-
* @param int $id
|
64 |
-
* @param int $originator
|
65 |
-
* @param bool $is_verified
|
|
|
66 |
*/
|
67 |
public function __construct(
|
68 |
$provider,
|
@@ -76,34 +84,101 @@ abstract class Item {
|
|
76 |
$extra_info = array(),
|
77 |
$id = null,
|
78 |
$originator = 0,
|
79 |
-
$is_verified = true
|
|
|
80 |
) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
81 |
$this->provider = $provider;
|
82 |
$this->region = $region;
|
83 |
$this->bucket = $bucket;
|
84 |
$this->path = $path;
|
85 |
-
$this->
|
86 |
-
$this->source_id = $source_id;
|
87 |
-
$this->source_path = $source_path;
|
88 |
-
$this->extra_info = serialize( $extra_info );
|
89 |
$this->originator = $originator;
|
90 |
$this->is_verified = $is_verified;
|
91 |
|
92 |
if ( empty( $original_filename ) ) {
|
93 |
-
$this->original_path
|
94 |
-
$this->original_source_path = $source_path;
|
95 |
} else {
|
96 |
-
$this->original_path
|
97 |
-
$this->original_source_path = str_replace( wp_basename( $source_path ), $original_filename, $source_path );
|
98 |
}
|
99 |
|
100 |
if ( ! empty( $id ) ) {
|
101 |
$this->id = $id;
|
102 |
}
|
103 |
|
|
|
|
|
104 |
static::add_to_items_cache( $this );
|
105 |
}
|
106 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
/**
|
108 |
* Returns the string used to group all keys in the object cache by.
|
109 |
*
|
@@ -115,6 +190,12 @@ abstract class Item {
|
|
115 |
if ( empty( $group ) ) {
|
116 |
/** @var Amazon_S3_And_CloudFront $as3cf */
|
117 |
global $as3cf;
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
$group = trim( '' . apply_filters( 'as3cf_object_cache_group', $as3cf->get_plugin_prefix() ) );
|
119 |
}
|
120 |
|
@@ -463,7 +544,7 @@ abstract class Item {
|
|
463 |
'source_id' => $this->source_id,
|
464 |
'source_path' => $this->source_path,
|
465 |
'original_source_path' => $this->original_source_path,
|
466 |
-
'extra_info' => $this->extra_info,
|
467 |
'originator' => $this->originator,
|
468 |
'is_verified' => $this->is_verified,
|
469 |
);
|
@@ -477,28 +558,6 @@ abstract class Item {
|
|
477 |
return $key_values;
|
478 |
}
|
479 |
|
480 |
-
/**
|
481 |
-
* All the item's property names in an array, optionally with id if available.
|
482 |
-
*
|
483 |
-
* @param bool $include_id Default false.
|
484 |
-
*
|
485 |
-
* @return array
|
486 |
-
*/
|
487 |
-
private function keys( $include_id = false ) {
|
488 |
-
return array_keys( $this->key_values( $include_id ) );
|
489 |
-
}
|
490 |
-
|
491 |
-
/**
|
492 |
-
* All the item's property values in an array, optionally with id if available.
|
493 |
-
*
|
494 |
-
* @param bool $include_id Default false.
|
495 |
-
*
|
496 |
-
* @return array
|
497 |
-
*/
|
498 |
-
private function values( $include_id = false ) {
|
499 |
-
return array_values( $this->key_values( $include_id ) );
|
500 |
-
}
|
501 |
-
|
502 |
/**
|
503 |
* Get item's column formats as an associative array, optionally with id if available.
|
504 |
*
|
@@ -546,11 +605,15 @@ abstract class Item {
|
|
546 |
/**
|
547 |
* Save the item's current data.
|
548 |
*
|
|
|
|
|
549 |
* @return int|WP_Error
|
550 |
*/
|
551 |
-
public function save() {
|
552 |
global $wpdb;
|
553 |
|
|
|
|
|
554 |
if ( empty( $this->id ) ) {
|
555 |
$result = $wpdb->insert( static::items_table(), $this->key_values(), $this->formats() );
|
556 |
|
@@ -561,6 +624,8 @@ abstract class Item {
|
|
561 |
static::add_to_items_cache( $this );
|
562 |
}
|
563 |
} else {
|
|
|
|
|
564 |
// Make sure object cache does not have stale items.
|
565 |
$old_item = static::get_from_object_cache( 'id', $this->id() );
|
566 |
static::remove_from_object_cache( $old_item );
|
@@ -578,6 +643,34 @@ abstract class Item {
|
|
578 |
return new WP_Error( 'item_save', 'Error saving item:- ' . $wpdb->last_error );
|
579 |
}
|
580 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
581 |
return $this->id;
|
582 |
}
|
583 |
|
@@ -614,13 +707,29 @@ abstract class Item {
|
|
614 |
* @return Item
|
615 |
*/
|
616 |
protected static function create( $object, $add_to_object_cache = false ) {
|
|
|
|
|
|
|
617 |
$extra_info = array();
|
618 |
|
619 |
if ( ! empty( $object->extra_info ) ) {
|
620 |
$extra_info = unserialize( $object->extra_info );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
621 |
}
|
622 |
|
623 |
-
$item = new
|
624 |
$object->provider,
|
625 |
$object->region,
|
626 |
$object->bucket,
|
@@ -636,7 +745,7 @@ abstract class Item {
|
|
636 |
);
|
637 |
|
638 |
if ( $add_to_object_cache ) {
|
639 |
-
|
640 |
}
|
641 |
|
642 |
return $item;
|
@@ -678,7 +787,7 @@ abstract class Item {
|
|
678 |
*
|
679 |
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
680 |
*
|
681 |
-
* @param
|
682 |
*
|
683 |
* @return bool|Item
|
684 |
*/
|
@@ -697,7 +806,7 @@ abstract class Item {
|
|
697 |
|
698 |
$item = static::get_from_items_cache_by_source_id( $source_id );
|
699 |
|
700 |
-
if ( ! empty( $item ) ) {
|
701 |
return $item;
|
702 |
}
|
703 |
|
@@ -712,6 +821,24 @@ abstract class Item {
|
|
712 |
return static::create( $object, true );
|
713 |
}
|
714 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
715 |
/**
|
716 |
* Getter for item's id value.
|
717 |
*
|
@@ -739,6 +866,15 @@ abstract class Item {
|
|
739 |
return $this->region;
|
740 |
}
|
741 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
742 |
/**
|
743 |
* Getter for item's bucket value.
|
744 |
*
|
@@ -748,13 +884,45 @@ abstract class Item {
|
|
748 |
return $this->bucket;
|
749 |
}
|
750 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
751 |
/**
|
752 |
* Getter for item's path value.
|
753 |
*
|
|
|
|
|
|
|
|
|
|
|
754 |
* @return string
|
755 |
*/
|
756 |
-
public function path() {
|
757 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
758 |
}
|
759 |
|
760 |
/**
|
@@ -766,22 +934,168 @@ abstract class Item {
|
|
766 |
return $this->original_path;
|
767 |
}
|
768 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
769 |
/**
|
770 |
* Getter for item's is_private value.
|
771 |
*
|
|
|
|
|
772 |
* @return bool
|
773 |
*/
|
774 |
-
public function is_private() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
775 |
return (bool) $this->is_private;
|
776 |
}
|
777 |
|
778 |
/**
|
779 |
* Setter for item's is_private value
|
780 |
*
|
781 |
-
* @param bool
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
782 |
*/
|
783 |
-
public function
|
784 |
-
$this->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
785 |
}
|
786 |
|
787 |
/**
|
@@ -796,12 +1110,32 @@ abstract class Item {
|
|
796 |
/**
|
797 |
* Getter for item's source_path value.
|
798 |
*
|
|
|
|
|
799 |
* @return string
|
800 |
*/
|
801 |
-
public function source_path() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
802 |
return $this->source_path;
|
803 |
}
|
804 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
805 |
/**
|
806 |
* Getter for item's original_source_path value.
|
807 |
*
|
@@ -811,22 +1145,80 @@ abstract class Item {
|
|
811 |
return $this->original_source_path;
|
812 |
}
|
813 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
814 |
/**
|
815 |
* Getter for item's extra_info value.
|
816 |
*
|
817 |
* @return array
|
818 |
*/
|
819 |
public function extra_info() {
|
820 |
-
return
|
821 |
}
|
822 |
|
823 |
/**
|
824 |
-
* Setter for extra_info value
|
825 |
*
|
826 |
* @param array $extra_info
|
827 |
*/
|
828 |
-
|
829 |
-
$this->extra_info =
|
830 |
}
|
831 |
|
832 |
/**
|
@@ -838,6 +1230,15 @@ abstract class Item {
|
|
838 |
return $this->originator;
|
839 |
}
|
840 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
841 |
/**
|
842 |
* Getter for item's is_verified value.
|
843 |
*
|
@@ -848,7 +1249,7 @@ abstract class Item {
|
|
848 |
}
|
849 |
|
850 |
/**
|
851 |
-
* Setter for item's is_verified value
|
852 |
*
|
853 |
* @param bool $is_verified
|
854 |
*/
|
@@ -856,6 +1257,15 @@ abstract class Item {
|
|
856 |
$this->is_verified = (bool) $is_verified;
|
857 |
}
|
858 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
859 |
/**
|
860 |
* Get normalized object path dir.
|
861 |
*
|
@@ -912,14 +1322,12 @@ abstract class Item {
|
|
912 |
*
|
913 |
* @param string $url
|
914 |
*
|
915 |
-
* @return
|
916 |
*/
|
917 |
-
public static function
|
918 |
global $wpdb;
|
919 |
|
920 |
-
/**
|
921 |
-
* @var Amazon_S3_And_CloudFront|\Amazon_S3_And_CloudFront_Pro $as3cf
|
922 |
-
*/
|
923 |
global $as3cf;
|
924 |
|
925 |
$parts = AS3CF_Utils::parse_url( $url );
|
@@ -952,8 +1360,7 @@ abstract class Item {
|
|
952 |
}
|
953 |
|
954 |
$sql = $wpdb->prepare(
|
955 |
-
"SELECT * FROM " . static::items_table() . " WHERE
|
956 |
-
, static::$source_type
|
957 |
, '%' . $path
|
958 |
, '%' . $path
|
959 |
);
|
@@ -970,7 +1377,9 @@ abstract class Item {
|
|
970 |
$path = AS3CF_Utils::decode_filename_in_path( ltrim( $parts['path'], '/' ) );
|
971 |
|
972 |
foreach ( $results as $result ) {
|
973 |
-
|
|
|
|
|
974 |
|
975 |
// If item's bucket matches first segment of URL path, remove it from URL path before checking match.
|
976 |
if ( 0 === strpos( $path, trailingslashit( $as3cf_item->bucket() ) ) ) {
|
@@ -986,7 +1395,10 @@ abstract class Item {
|
|
986 |
|
987 |
// Exact match, return ID.
|
988 |
if ( $as3cf_item->path() === $match_path || $as3cf_item->original_path() === $match_path ) {
|
989 |
-
return
|
|
|
|
|
|
|
990 |
}
|
991 |
}
|
992 |
|
@@ -998,11 +1410,11 @@ abstract class Item {
|
|
998 |
*
|
999 |
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
1000 |
*
|
1001 |
-
* @param
|
1002 |
-
* @param
|
1003 |
-
* @param bool
|
1004 |
-
* @param int
|
1005 |
-
* @param bool
|
1006 |
*
|
1007 |
* @return array|int
|
1008 |
*/
|
@@ -1030,7 +1442,7 @@ abstract class Item {
|
|
1030 |
$sql .= ' AND originator = %d';
|
1031 |
$args[] = $originator;
|
1032 |
} else {
|
1033 |
-
|
1034 |
|
1035 |
return $count ? 0 : array();
|
1036 |
}
|
@@ -1042,7 +1454,7 @@ abstract class Item {
|
|
1042 |
$sql .= ' AND is_verified = %d';
|
1043 |
$args[] = (int) $is_verified;
|
1044 |
} else {
|
1045 |
-
|
1046 |
|
1047 |
return $count ? 0 : array();
|
1048 |
}
|
@@ -1067,9 +1479,9 @@ abstract class Item {
|
|
1067 |
*
|
1068 |
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
1069 |
*
|
1070 |
-
* @param
|
1071 |
-
* @param
|
1072 |
-
* @param bool
|
1073 |
*
|
1074 |
* @return array|int
|
1075 |
*
|
@@ -1084,11 +1496,475 @@ abstract class Item {
|
|
1084 |
}
|
1085 |
|
1086 |
/**
|
1087 |
-
* Get
|
1088 |
*
|
1089 |
-
* @
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1090 |
*
|
1091 |
* @return array
|
1092 |
*/
|
1093 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1094 |
}
|
3 |
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
|
5 |
use Amazon_S3_And_CloudFront;
|
6 |
+
use AS3CF_Error;
|
7 |
use AS3CF_Utils;
|
8 |
+
use DeliciousBrains\WP_Offload_Media\Providers\Storage\Storage_Provider;
|
9 |
+
use Exception;
|
10 |
use WP_Error;
|
11 |
|
12 |
abstract class Item {
|
13 |
+
const ITEMS_TABLE = 'as3cf_items';
|
14 |
+
const ORIGINATORS = array(
|
15 |
'standard' => 0,
|
16 |
'metadata-tool' => 1,
|
17 |
);
|
18 |
+
const CAN_USE_OBJECT_VERSIONING = true;
|
19 |
|
20 |
+
protected static $source_type_name = 'Item';
|
21 |
+
protected static $source_type = '';
|
22 |
+
protected static $source_table = '';
|
23 |
+
protected static $source_fk = '';
|
24 |
|
25 |
+
protected static $can_use_yearmonth = true;
|
26 |
|
27 |
protected static $items_cache_by_id = array();
|
28 |
protected static $items_cache_by_source_id = array();
|
39 |
'source_path' => array( 'source_path', 'original_source_path' ),
|
40 |
);
|
41 |
|
42 |
+
private static $checked_table_exists = array();
|
43 |
+
|
44 |
private $id;
|
45 |
private $provider;
|
46 |
private $region;
|
58 |
/**
|
59 |
* Item constructor.
|
60 |
*
|
61 |
+
* @param string $provider Storage provider key name, e.g. "aws".
|
62 |
+
* @param string $region Region for item's bucket.
|
63 |
+
* @param string $bucket Bucket for item.
|
64 |
+
* @param string $path Key path for item (full sized if type has thumbnails etc).
|
65 |
+
* @param bool $is_private Is the object private in the bucket.
|
66 |
+
* @param int $source_id ID that source has.
|
67 |
+
* @param string $source_path Path that source uses, could be relative or absolute depending on source.
|
68 |
+
* @param string $original_filename An optional filename with no path that was previously used for the item.
|
69 |
+
* @param array $extra_info An optional array of extra data specific to the source type.
|
70 |
+
* @param int $id Optional Item record ID.
|
71 |
+
* @param int $originator Optional originator of record from ORIGINATORS const.
|
72 |
+
* @param bool $is_verified Optional flag as to whether Item's objects are known to exist.
|
73 |
+
* @param bool $use_object_versioning Optional flag as to whether path prefix should use Object Versioning if type allows it.
|
74 |
*/
|
75 |
public function __construct(
|
76 |
$provider,
|
84 |
$extra_info = array(),
|
85 |
$id = null,
|
86 |
$originator = 0,
|
87 |
+
$is_verified = true,
|
88 |
+
$use_object_versioning = self::CAN_USE_OBJECT_VERSIONING
|
89 |
) {
|
90 |
+
/** @var Amazon_S3_And_CloudFront $as3cf */
|
91 |
+
global $as3cf;
|
92 |
+
|
93 |
+
$this->source_id = $source_id;
|
94 |
+
$this->source_path = $source_path;
|
95 |
+
|
96 |
+
if ( empty( $original_filename ) ) {
|
97 |
+
$this->original_source_path = $source_path;
|
98 |
+
} else {
|
99 |
+
$this->original_source_path = str_replace( wp_basename( $source_path ), $original_filename, $source_path );
|
100 |
+
}
|
101 |
+
|
102 |
+
// Set offload data from previous duplicate if exact match by source path exists.
|
103 |
+
if ( empty( $path ) ) {
|
104 |
+
$prev_items = static::get_by_source_path( array( $this->source_path, $this->original_source_path ), $this->source_id, true, true );
|
105 |
+
|
106 |
+
if ( ! is_wp_error( $prev_items ) && ! empty( $prev_items[0] ) && is_a( $prev_items[0], get_class( $this ) ) ) {
|
107 |
+
/** @var Item $prev_item */
|
108 |
+
$prev_item = $prev_items[0];
|
109 |
+
$provider = $prev_item->provider();
|
110 |
+
$region = $prev_item->region();
|
111 |
+
$bucket = $prev_item->bucket();
|
112 |
+
$path = $prev_item->path();
|
113 |
+
$is_private = $prev_item->is_private();
|
114 |
+
$extra_info = $prev_item->extra_info();
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
// Not a duplicate, create a new path to offload to.
|
119 |
+
if ( empty( $path ) ) {
|
120 |
+
$prefix = $this->get_new_item_prefix( $use_object_versioning );
|
121 |
+
$path = $prefix . wp_basename( $source_path );
|
122 |
+
}
|
123 |
+
|
124 |
+
if ( ! is_array( $extra_info ) ) {
|
125 |
+
$extra_info = array();
|
126 |
+
}
|
127 |
+
|
128 |
+
if ( ! isset( $extra_info['private_prefix'] ) || is_null( $extra_info['private_prefix'] ) ) {
|
129 |
+
$extra_info['private_prefix'] = '';
|
130 |
+
if ( $as3cf->private_prefix_enabled() ) {
|
131 |
+
$extra_info['private_prefix'] = AS3CF_Utils::trailingslash_prefix( $as3cf->get_setting( 'signed-urls-object-prefix', '' ) );
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
if ( empty( $provider ) ) {
|
136 |
+
$provider = $as3cf->get_storage_provider()->get_provider_key_name();
|
137 |
+
}
|
138 |
+
|
139 |
+
if ( empty( $region ) ) {
|
140 |
+
$region = $as3cf->get_setting( 'region' );
|
141 |
+
if ( is_wp_error( $region ) ) {
|
142 |
+
$region = '';
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
if ( empty( $bucket ) ) {
|
147 |
+
$bucket = $as3cf->get_setting( 'bucket' );
|
148 |
+
}
|
149 |
+
|
150 |
$this->provider = $provider;
|
151 |
$this->region = $region;
|
152 |
$this->bucket = $bucket;
|
153 |
$this->path = $path;
|
154 |
+
$this->extra_info = $extra_info;
|
|
|
|
|
|
|
155 |
$this->originator = $originator;
|
156 |
$this->is_verified = $is_verified;
|
157 |
|
158 |
if ( empty( $original_filename ) ) {
|
159 |
+
$this->original_path = $path;
|
|
|
160 |
} else {
|
161 |
+
$this->original_path = str_replace( wp_basename( $path ), $original_filename, $path );
|
|
|
162 |
}
|
163 |
|
164 |
if ( ! empty( $id ) ) {
|
165 |
$this->id = $id;
|
166 |
}
|
167 |
|
168 |
+
$this->set_is_private( (bool) $is_private );
|
169 |
+
|
170 |
static::add_to_items_cache( $this );
|
171 |
}
|
172 |
|
173 |
+
/**
|
174 |
+
* Returns the standard object key for an items primary object
|
175 |
+
*
|
176 |
+
* @return string
|
177 |
+
*/
|
178 |
+
public static function primary_object_key() {
|
179 |
+
return '__as3cf_primary';
|
180 |
+
}
|
181 |
+
|
182 |
/**
|
183 |
* Returns the string used to group all keys in the object cache by.
|
184 |
*
|
190 |
if ( empty( $group ) ) {
|
191 |
/** @var Amazon_S3_And_CloudFront $as3cf */
|
192 |
global $as3cf;
|
193 |
+
|
194 |
+
/**
|
195 |
+
* Filters the object cache group name.
|
196 |
+
*
|
197 |
+
* @param string $group Defaults to 'as3cf'
|
198 |
+
*/
|
199 |
$group = trim( '' . apply_filters( 'as3cf_object_cache_group', $as3cf->get_plugin_prefix() ) );
|
200 |
}
|
201 |
|
544 |
'source_id' => $this->source_id,
|
545 |
'source_path' => $this->source_path,
|
546 |
'original_source_path' => $this->original_source_path,
|
547 |
+
'extra_info' => serialize( $this->extra_info ),
|
548 |
'originator' => $this->originator,
|
549 |
'is_verified' => $this->is_verified,
|
550 |
);
|
558 |
return $key_values;
|
559 |
}
|
560 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
561 |
/**
|
562 |
* Get item's column formats as an associative array, optionally with id if available.
|
563 |
*
|
605 |
/**
|
606 |
* Save the item's current data.
|
607 |
*
|
608 |
+
* @param bool $update_duplicates If updating, also update records for duplicated source, defaults to true.
|
609 |
+
*
|
610 |
* @return int|WP_Error
|
611 |
*/
|
612 |
+
public function save( $update_duplicates = true ) {
|
613 |
global $wpdb;
|
614 |
|
615 |
+
$update = false;
|
616 |
+
|
617 |
if ( empty( $this->id ) ) {
|
618 |
$result = $wpdb->insert( static::items_table(), $this->key_values(), $this->formats() );
|
619 |
|
624 |
static::add_to_items_cache( $this );
|
625 |
}
|
626 |
} else {
|
627 |
+
$update = true;
|
628 |
+
|
629 |
// Make sure object cache does not have stale items.
|
630 |
$old_item = static::get_from_object_cache( 'id', $this->id() );
|
631 |
static::remove_from_object_cache( $old_item );
|
643 |
return new WP_Error( 'item_save', 'Error saving item:- ' . $wpdb->last_error );
|
644 |
}
|
645 |
|
646 |
+
// If one or more duplicate exists that still has the same source paths, keep them in step.
|
647 |
+
if ( $update && $update_duplicates ) {
|
648 |
+
$duplicates = static::get_by_source_path( array( $this->source_path, $this->original_source_path ), $this->source_id );
|
649 |
+
|
650 |
+
if ( ! empty( $duplicates ) && ! is_wp_error( $duplicates ) ) {
|
651 |
+
/** @var Item $duplicate */
|
652 |
+
foreach ( $duplicates as $duplicate ) {
|
653 |
+
if (
|
654 |
+
! is_wp_error( $duplicate ) &&
|
655 |
+
$duplicate->source_type() === $this->source_type() &&
|
656 |
+
$duplicate->source_path() === $this->source_path() &&
|
657 |
+
$duplicate->original_source_path() === $this->original_source_path()
|
658 |
+
) {
|
659 |
+
$duplicate->provider = $this->provider;
|
660 |
+
$duplicate->region = $this->region;
|
661 |
+
$duplicate->bucket = $this->bucket;
|
662 |
+
$duplicate->path = $this->path;
|
663 |
+
$duplicate->original_path = $this->original_path;
|
664 |
+
$duplicate->is_private = $this->is_private;
|
665 |
+
$duplicate->extra_info = $this->extra_info;
|
666 |
+
$duplicate->originator = $this->originator;
|
667 |
+
$duplicate->is_verified = $this->is_verified;
|
668 |
+
$duplicate->save( false );
|
669 |
+
}
|
670 |
+
}
|
671 |
+
}
|
672 |
+
}
|
673 |
+
|
674 |
return $this->id;
|
675 |
}
|
676 |
|
707 |
* @return Item
|
708 |
*/
|
709 |
protected static function create( $object, $add_to_object_cache = false ) {
|
710 |
+
/** @var Amazon_S3_And_CloudFront $as3cf */
|
711 |
+
global $as3cf;
|
712 |
+
|
713 |
$extra_info = array();
|
714 |
|
715 |
if ( ! empty( $object->extra_info ) ) {
|
716 |
$extra_info = unserialize( $object->extra_info );
|
717 |
+
static::maybe_update_extra_info( $extra_info, $object->source_id, $object->is_private );
|
718 |
+
}
|
719 |
+
|
720 |
+
if ( ! empty( static::$source_type ) && static::$source_type !== $object->source_type ) {
|
721 |
+
AS3CF_Error::log( sprintf( 'Doing it wrong! Trying to create a %s class instance with data representing a %s', __CLASS__, $object->source_type ) );
|
722 |
+
}
|
723 |
+
|
724 |
+
if ( empty( static::$source_type ) ) {
|
725 |
+
/** @var Item $class */
|
726 |
+
$class = $as3cf->get_source_type_class( $object->source_type );
|
727 |
+
} else {
|
728 |
+
/** @var Item $class */
|
729 |
+
$class = $as3cf->get_source_type_class( static::$source_type );
|
730 |
}
|
731 |
|
732 |
+
$item = new $class(
|
733 |
$object->provider,
|
734 |
$object->region,
|
735 |
$object->bucket,
|
745 |
);
|
746 |
|
747 |
if ( $add_to_object_cache ) {
|
748 |
+
$class::add_to_object_cache( $item );
|
749 |
}
|
750 |
|
751 |
return $item;
|
787 |
*
|
788 |
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
789 |
*
|
790 |
+
* @param int $source_id
|
791 |
*
|
792 |
* @return bool|Item
|
793 |
*/
|
806 |
|
807 |
$item = static::get_from_items_cache_by_source_id( $source_id );
|
808 |
|
809 |
+
if ( ! empty( $item ) && ! empty( $item->id() ) ) {
|
810 |
return $item;
|
811 |
}
|
812 |
|
821 |
return static::create( $object, true );
|
822 |
}
|
823 |
|
824 |
+
/**
|
825 |
+
* Getter for item's source type.
|
826 |
+
*
|
827 |
+
* @return string
|
828 |
+
*/
|
829 |
+
public static function source_type() {
|
830 |
+
return static::$source_type;
|
831 |
+
}
|
832 |
+
|
833 |
+
/**
|
834 |
+
* Getter for item's source type name.
|
835 |
+
*
|
836 |
+
* @return string
|
837 |
+
*/
|
838 |
+
public static function source_type_name() {
|
839 |
+
return static::$source_type_name;
|
840 |
+
}
|
841 |
+
|
842 |
/**
|
843 |
* Getter for item's id value.
|
844 |
*
|
866 |
return $this->region;
|
867 |
}
|
868 |
|
869 |
+
/**
|
870 |
+
* Setter for item's region value.
|
871 |
+
*
|
872 |
+
* @param string $region
|
873 |
+
*/
|
874 |
+
public function set_region( $region ) {
|
875 |
+
$this->region = $region;
|
876 |
+
}
|
877 |
+
|
878 |
/**
|
879 |
* Getter for item's bucket value.
|
880 |
*
|
884 |
return $this->bucket;
|
885 |
}
|
886 |
|
887 |
+
/**
|
888 |
+
* Setter for item's bucket value.
|
889 |
+
*
|
890 |
+
* @param string $bucket
|
891 |
+
*/
|
892 |
+
public function set_bucket( $bucket ) {
|
893 |
+
$this->bucket = $bucket;
|
894 |
+
}
|
895 |
+
|
896 |
/**
|
897 |
* Getter for item's path value.
|
898 |
*
|
899 |
+
* The path is always the public representation,
|
900 |
+
* see provider_key() and provider_keys() for realised versions.
|
901 |
+
*
|
902 |
+
* @param string $object_key
|
903 |
+
*
|
904 |
* @return string
|
905 |
*/
|
906 |
+
public function path( $object_key = null ) {
|
907 |
+
$path = $this->path;
|
908 |
+
|
909 |
+
if ( ! empty( $object_key ) ) {
|
910 |
+
$objects = $this->objects();
|
911 |
+
if ( isset( $objects[ $object_key ]['source_file'] ) ) {
|
912 |
+
$path = $this->prefix() . $objects[ $object_key ]['source_file'];
|
913 |
+
}
|
914 |
+
}
|
915 |
+
|
916 |
+
return $path;
|
917 |
+
}
|
918 |
+
|
919 |
+
/**
|
920 |
+
* Setter for item's path value.
|
921 |
+
*
|
922 |
+
* @param $path
|
923 |
+
*/
|
924 |
+
public function set_path( $path ) {
|
925 |
+
$this->path = $path;
|
926 |
}
|
927 |
|
928 |
/**
|
934 |
return $this->original_path;
|
935 |
}
|
936 |
|
937 |
+
/**
|
938 |
+
* Setter for item's original path value.
|
939 |
+
*
|
940 |
+
* @param $path
|
941 |
+
*/
|
942 |
+
public function set_original_path( $path ) {
|
943 |
+
$this->original_path = $path;
|
944 |
+
}
|
945 |
+
|
946 |
/**
|
947 |
* Getter for item's is_private value.
|
948 |
*
|
949 |
+
* @param string|null $object_key
|
950 |
+
*
|
951 |
* @return bool
|
952 |
*/
|
953 |
+
public function is_private( $object_key = null ) {
|
954 |
+
if ( ! empty( $object_key ) ) {
|
955 |
+
$objects = $this->objects();
|
956 |
+
if ( isset( $objects[ $object_key ]['is_private'] ) ) {
|
957 |
+
return (bool) $objects[ $object_key ]['is_private'];
|
958 |
+
}
|
959 |
+
|
960 |
+
return false;
|
961 |
+
}
|
962 |
+
|
963 |
return (bool) $this->is_private;
|
964 |
}
|
965 |
|
966 |
/**
|
967 |
* Setter for item's is_private value
|
968 |
*
|
969 |
+
* @param bool $private
|
970 |
+
* @param string|null $object_key
|
971 |
+
*/
|
972 |
+
public function set_is_private( $private, $object_key = null ) {
|
973 |
+
if ( ! empty( $object_key ) ) {
|
974 |
+
$objects = $this->objects();
|
975 |
+
if ( isset( $objects[ $object_key ] ) ) {
|
976 |
+
$objects[ $object_key ]['is_private'] = $private;
|
977 |
+
$this->set_objects( $objects );
|
978 |
+
}
|
979 |
+
|
980 |
+
if ( $object_key === Item::primary_object_key() ) {
|
981 |
+
$this->is_private = $private;
|
982 |
+
}
|
983 |
+
|
984 |
+
return;
|
985 |
+
}
|
986 |
+
|
987 |
+
$this->set_is_private( $private, Item::primary_object_key() );
|
988 |
+
}
|
989 |
+
|
990 |
+
/**
|
991 |
+
* Any private objects in this item
|
992 |
+
*
|
993 |
+
* @return bool
|
994 |
*/
|
995 |
+
public function has_private_objects() {
|
996 |
+
foreach ( $this->objects() as $object ) {
|
997 |
+
if ( $object['is_private'] ) {
|
998 |
+
return true;
|
999 |
+
}
|
1000 |
+
}
|
1001 |
+
|
1002 |
+
return false;
|
1003 |
+
}
|
1004 |
+
|
1005 |
+
/**
|
1006 |
+
* Getter for the item prefix
|
1007 |
+
*
|
1008 |
+
* @return string
|
1009 |
+
*/
|
1010 |
+
public function prefix() {
|
1011 |
+
$dirname = dirname( $this->path );
|
1012 |
+
$dirname = $dirname === '.' ? '' : $dirname;
|
1013 |
+
|
1014 |
+
return AS3CF_Utils::trailingslash_prefix( $dirname );
|
1015 |
+
}
|
1016 |
+
|
1017 |
+
/**
|
1018 |
+
* Get the private prefix for item's private objects.
|
1019 |
+
*
|
1020 |
+
* @return string
|
1021 |
+
*/
|
1022 |
+
public function private_prefix() {
|
1023 |
+
$extra_info = $this->extra_info();
|
1024 |
+
|
1025 |
+
if ( ! empty( $extra_info['private_prefix'] ) ) {
|
1026 |
+
return AS3CF_Utils::trailingslash_prefix( $extra_info['private_prefix'] );
|
1027 |
+
}
|
1028 |
+
|
1029 |
+
return '';
|
1030 |
+
}
|
1031 |
+
|
1032 |
+
/**
|
1033 |
+
* Setter for the private prefix
|
1034 |
+
*
|
1035 |
+
* @param string $new_private_prefix
|
1036 |
+
*/
|
1037 |
+
public function set_private_prefix( $new_private_prefix ) {
|
1038 |
+
$extra_info = $this->extra_info();
|
1039 |
+
$extra_info['private_prefix'] = AS3CF_Utils::trailingslash_prefix( $new_private_prefix );
|
1040 |
+
$this->set_extra_info( $extra_info );
|
1041 |
+
}
|
1042 |
+
|
1043 |
+
/**
|
1044 |
+
* Get the full remote key for this item including private prefix when needed
|
1045 |
+
*
|
1046 |
+
* @param string|null $object_key
|
1047 |
+
*
|
1048 |
+
* @return string
|
1049 |
+
*/
|
1050 |
+
public function provider_key( $object_key = null ) {
|
1051 |
+
$path = $this->path( $object_key );
|
1052 |
+
if ( $this->is_private( $object_key ) ) {
|
1053 |
+
$path = $this->private_prefix() . $path;
|
1054 |
+
}
|
1055 |
+
|
1056 |
+
return $path;
|
1057 |
+
}
|
1058 |
+
|
1059 |
+
/**
|
1060 |
+
* Returns an associative array of provider keys by their object_key.
|
1061 |
+
*
|
1062 |
+
* NOTE: There may be duplicate keys if object_keys reference same source file/object.
|
1063 |
+
*
|
1064 |
+
* @return array
|
1065 |
+
*/
|
1066 |
+
public function provider_keys() {
|
1067 |
+
$keys = array();
|
1068 |
+
|
1069 |
+
foreach ( array_keys( $this->objects() ) as $object_key ) {
|
1070 |
+
$keys[ $object_key ] = $this->provider_key( $object_key );
|
1071 |
+
}
|
1072 |
+
|
1073 |
+
return $keys;
|
1074 |
+
}
|
1075 |
+
|
1076 |
+
/**
|
1077 |
+
* Creates a provider key for a given filename using the item's prefix settings.
|
1078 |
+
*
|
1079 |
+
* This function can be used to create ad-hoc custom provider keys.
|
1080 |
+
* There are no tests to see if the filename is known to be associated with the item.
|
1081 |
+
*
|
1082 |
+
* @param string $filename Just a filename without any path.
|
1083 |
+
* @param bool $is_private Should a private prefixed provider key be created if appropriate?
|
1084 |
+
*
|
1085 |
+
* @return string
|
1086 |
+
*/
|
1087 |
+
public function provider_key_for_filename( $filename, $is_private ) {
|
1088 |
+
$provider_key = '';
|
1089 |
+
|
1090 |
+
if ( ! empty( $filename ) ) {
|
1091 |
+
$provider_key = $this->prefix() . wp_basename( trim( $filename ) );
|
1092 |
+
|
1093 |
+
if ( $is_private ) {
|
1094 |
+
$provider_key = $this->private_prefix() . $provider_key;
|
1095 |
+
}
|
1096 |
+
}
|
1097 |
+
|
1098 |
+
return $provider_key;
|
1099 |
}
|
1100 |
|
1101 |
/**
|
1110 |
/**
|
1111 |
* Getter for item's source_path value.
|
1112 |
*
|
1113 |
+
* @param string|null $object_key
|
1114 |
+
*
|
1115 |
* @return string
|
1116 |
*/
|
1117 |
+
public function source_path( $object_key = null ) {
|
1118 |
+
if ( ! empty( $object_key ) ) {
|
1119 |
+
$objects = $this->objects();
|
1120 |
+
if ( isset( $objects[ $object_key ] ) ) {
|
1121 |
+
$object_file = $objects[ $object_key ]['source_file'];
|
1122 |
+
|
1123 |
+
return str_replace( wp_basename( $this->source_path ), $object_file, $this->source_path );
|
1124 |
+
}
|
1125 |
+
}
|
1126 |
+
|
1127 |
return $this->source_path;
|
1128 |
}
|
1129 |
|
1130 |
+
/**
|
1131 |
+
* Setter for item's source_path value
|
1132 |
+
*
|
1133 |
+
* @param string $new_path
|
1134 |
+
*/
|
1135 |
+
public function set_source_path( $new_path ) {
|
1136 |
+
$this->source_path = $new_path;
|
1137 |
+
}
|
1138 |
+
|
1139 |
/**
|
1140 |
* Getter for item's original_source_path value.
|
1141 |
*
|
1145 |
return $this->original_source_path;
|
1146 |
}
|
1147 |
|
1148 |
+
/**
|
1149 |
+
* Setter for item's original_source_path value
|
1150 |
+
*
|
1151 |
+
* @param string $new_path
|
1152 |
+
*/
|
1153 |
+
public function set_original_source_path( $new_path ) {
|
1154 |
+
$this->original_source_path = $new_path;
|
1155 |
+
}
|
1156 |
+
|
1157 |
+
/**
|
1158 |
+
* Get an absolute source path.
|
1159 |
+
*
|
1160 |
+
* Default it is based on the WordPress uploads folder.
|
1161 |
+
*
|
1162 |
+
* @param string|null $object_key Optional, by default the original file's source path is used.
|
1163 |
+
*
|
1164 |
+
* @return string
|
1165 |
+
*/
|
1166 |
+
public function full_source_path( $object_key = null ) {
|
1167 |
+
/**
|
1168 |
+
* Filter the absolute directory path prefix for an item's source files.
|
1169 |
+
*
|
1170 |
+
* @param string $basedir Default is WordPress uploads folder.
|
1171 |
+
* @param Item $as3cf_item The Item whose full source path is being accessed.
|
1172 |
+
*/
|
1173 |
+
$basedir = trailingslashit( apply_filters( 'as3cf_item_basedir', wp_upload_dir()['basedir'], $this ) );
|
1174 |
+
|
1175 |
+
return $basedir . $this->source_path( $object_key );
|
1176 |
+
}
|
1177 |
+
|
1178 |
+
/**
|
1179 |
+
* Creates an absolute source path for a given filename using the item's source path settings.
|
1180 |
+
*
|
1181 |
+
* This function can be used to create ad-hoc custom source file paths.
|
1182 |
+
* There are no tests to see if the filename is known to be associated with the item.
|
1183 |
+
*
|
1184 |
+
* Default it is based on the WordPress uploads folder.
|
1185 |
+
*
|
1186 |
+
* @param string $filename Just a filename without any path.
|
1187 |
+
*
|
1188 |
+
* @return string
|
1189 |
+
*/
|
1190 |
+
public function full_source_path_for_filename( $filename ) {
|
1191 |
+
if ( empty( $filename ) ) {
|
1192 |
+
return '';
|
1193 |
+
}
|
1194 |
+
|
1195 |
+
/**
|
1196 |
+
* Filter the absolute directory path prefix for an item's source files.
|
1197 |
+
*
|
1198 |
+
* @param string $basedir Default is WordPress uploads folder.
|
1199 |
+
* @param Item $as3cf_item The Item whose full source path is being accessed.
|
1200 |
+
*/
|
1201 |
+
$basedir = trailingslashit( apply_filters( 'as3cf_item_basedir', wp_upload_dir()['basedir'], $this ) );
|
1202 |
+
|
1203 |
+
return $basedir . str_replace( wp_basename( $this->source_path ), wp_basename( trim( $filename ) ), $this->source_path );
|
1204 |
+
}
|
1205 |
+
|
1206 |
/**
|
1207 |
* Getter for item's extra_info value.
|
1208 |
*
|
1209 |
* @return array
|
1210 |
*/
|
1211 |
public function extra_info() {
|
1212 |
+
return $this->extra_info;
|
1213 |
}
|
1214 |
|
1215 |
/**
|
1216 |
+
* Setter for extra_info value.
|
1217 |
*
|
1218 |
* @param array $extra_info
|
1219 |
*/
|
1220 |
+
public function set_extra_info( $extra_info ) {
|
1221 |
+
$this->extra_info = $extra_info;
|
1222 |
}
|
1223 |
|
1224 |
/**
|
1230 |
return $this->originator;
|
1231 |
}
|
1232 |
|
1233 |
+
/**
|
1234 |
+
* Setter for item's originator value.
|
1235 |
+
*
|
1236 |
+
* @param int $originator
|
1237 |
+
*/
|
1238 |
+
public function set_originator( $originator ) {
|
1239 |
+
$this->originator = $originator;
|
1240 |
+
}
|
1241 |
+
|
1242 |
/**
|
1243 |
* Getter for item's is_verified value.
|
1244 |
*
|
1249 |
}
|
1250 |
|
1251 |
/**
|
1252 |
+
* Setter for item's is_verified value.
|
1253 |
*
|
1254 |
* @param bool $is_verified
|
1255 |
*/
|
1257 |
$this->is_verified = (bool) $is_verified;
|
1258 |
}
|
1259 |
|
1260 |
+
/**
|
1261 |
+
* Does this item type use object versioning?
|
1262 |
+
*
|
1263 |
+
* @return bool
|
1264 |
+
*/
|
1265 |
+
public static function can_use_object_versioning() {
|
1266 |
+
return static::CAN_USE_OBJECT_VERSIONING;
|
1267 |
+
}
|
1268 |
+
|
1269 |
/**
|
1270 |
* Get normalized object path dir.
|
1271 |
*
|
1322 |
*
|
1323 |
* @param string $url
|
1324 |
*
|
1325 |
+
* @return array|bool
|
1326 |
*/
|
1327 |
+
public static function get_item_source_by_remote_url( $url ) {
|
1328 |
global $wpdb;
|
1329 |
|
1330 |
+
/** @var Amazon_S3_And_CloudFront $as3cf */
|
|
|
|
|
1331 |
global $as3cf;
|
1332 |
|
1333 |
$parts = AS3CF_Utils::parse_url( $url );
|
1360 |
}
|
1361 |
|
1362 |
$sql = $wpdb->prepare(
|
1363 |
+
"SELECT * FROM " . static::items_table() . " WHERE (path LIKE %s OR original_path LIKE %s);"
|
|
|
1364 |
, '%' . $path
|
1365 |
, '%' . $path
|
1366 |
);
|
1377 |
$path = AS3CF_Utils::decode_filename_in_path( ltrim( $parts['path'], '/' ) );
|
1378 |
|
1379 |
foreach ( $results as $result ) {
|
1380 |
+
/** @var Item $class */
|
1381 |
+
$class = $as3cf->get_source_type_class( $result->source_type );
|
1382 |
+
$as3cf_item = $class::create( $result );
|
1383 |
|
1384 |
// If item's bucket matches first segment of URL path, remove it from URL path before checking match.
|
1385 |
if ( 0 === strpos( $path, trailingslashit( $as3cf_item->bucket() ) ) ) {
|
1395 |
|
1396 |
// Exact match, return ID.
|
1397 |
if ( $as3cf_item->path() === $match_path || $as3cf_item->original_path() === $match_path ) {
|
1398 |
+
return array(
|
1399 |
+
'id' => $as3cf_item->source_id(),
|
1400 |
+
'source_type' => $as3cf_item->source_type(),
|
1401 |
+
);
|
1402 |
}
|
1403 |
}
|
1404 |
|
1410 |
*
|
1411 |
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
1412 |
*
|
1413 |
+
* @param int $upper_bound Returned source_ids should be lower than this, use null/0 for no upper bound.
|
1414 |
+
* @param int $limit Maximum number of source_ids to return. Required if not counting.
|
1415 |
+
* @param bool $count Just return a count of matching source_ids? Negates $limit, default false.
|
1416 |
+
* @param int $originator Optionally restrict to only records with given originator type from ORIGINATORS const.
|
1417 |
+
* @param bool $is_verified Optionally restrict to only records that either are or are not verified.
|
1418 |
*
|
1419 |
* @return array|int
|
1420 |
*/
|
1442 |
$sql .= ' AND originator = %d';
|
1443 |
$args[] = $originator;
|
1444 |
} else {
|
1445 |
+
AS3CF_Error::log( __METHOD__ . ' called with invalid originator: ' . $originator );
|
1446 |
|
1447 |
return $count ? 0 : array();
|
1448 |
}
|
1454 |
$sql .= ' AND is_verified = %d';
|
1455 |
$args[] = (int) $is_verified;
|
1456 |
} else {
|
1457 |
+
AS3CF_Error::log( __METHOD__ . ' called with invalid is_verified: ' . $is_verified );
|
1458 |
|
1459 |
return $count ? 0 : array();
|
1460 |
}
|
1479 |
*
|
1480 |
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
1481 |
*
|
1482 |
+
* @param int $upper_bound Returned source_ids should be lower than this, use null/0 for no upper bound.
|
1483 |
+
* @param int $limit Maximum number of source_ids to return. Required if not counting.
|
1484 |
+
* @param bool $count Just return a count of matching source_ids? Negates $limit, default false.
|
1485 |
*
|
1486 |
* @return array|int
|
1487 |
*
|
1496 |
}
|
1497 |
|
1498 |
/**
|
1499 |
+
* Get array of objects (i.e. different sizes of same attachment item)
|
1500 |
*
|
1501 |
+
* @return array
|
1502 |
+
*/
|
1503 |
+
public function objects() {
|
1504 |
+
$extra_info = $this->extra_info();
|
1505 |
+
if ( isset( $extra_info['objects'] ) && is_array( $extra_info['objects'] ) ) {
|
1506 |
+
// Make sure that the primary object key, if exists, comes first
|
1507 |
+
$array_keys = array_keys( $extra_info['objects'] );
|
1508 |
+
$primary_key = Item::primary_object_key();
|
1509 |
+
if ( in_array( $primary_key, $array_keys ) && $primary_key !== $array_keys[0] ) {
|
1510 |
+
$extra_info['objects'] = array_merge( array( $primary_key => null ), $extra_info['objects'] );
|
1511 |
+
}
|
1512 |
+
|
1513 |
+
return $extra_info['objects'];
|
1514 |
+
}
|
1515 |
+
|
1516 |
+
return array();
|
1517 |
+
}
|
1518 |
+
|
1519 |
+
/**
|
1520 |
+
* Set array of objects (i.e. different sizes of same attachment item)
|
1521 |
+
*
|
1522 |
+
* @param array $objects
|
1523 |
+
*/
|
1524 |
+
public function set_objects( $objects ) {
|
1525 |
+
$extra_info = $this->extra_info();
|
1526 |
+
|
1527 |
+
$extra_info['objects'] = $objects;
|
1528 |
+
$this->set_extra_info( $extra_info );
|
1529 |
+
}
|
1530 |
+
|
1531 |
+
/**
|
1532 |
+
* Synthesize a data struct to be used when passing information
|
1533 |
+
* about the current item to filters that assume the item is a
|
1534 |
+
* media library item.
|
1535 |
*
|
1536 |
* @return array
|
1537 |
*/
|
1538 |
+
public function item_data_for_acl_filter() {
|
1539 |
+
return array(
|
1540 |
+
'source_type' => $this->source_type(),
|
1541 |
+
'file' => $this->path( Item::primary_object_key() ),
|
1542 |
+
'sizes' => array_keys( $this->objects() ),
|
1543 |
+
);
|
1544 |
+
}
|
1545 |
+
|
1546 |
+
/**
|
1547 |
+
* Get absolute source file paths for offloaded files.
|
1548 |
+
*
|
1549 |
+
* @return array Associative array of object_key => path
|
1550 |
+
*/
|
1551 |
+
abstract public function full_source_paths();
|
1552 |
+
|
1553 |
+
/**
|
1554 |
+
* Get size name from file name.
|
1555 |
+
*
|
1556 |
+
* @return string
|
1557 |
+
*/
|
1558 |
+
abstract public function get_object_key_from_filename( $filename );
|
1559 |
+
|
1560 |
+
/**
|
1561 |
+
* Get the provider URL for an item
|
1562 |
+
*
|
1563 |
+
* @param string|null $object_key
|
1564 |
+
*
|
1565 |
+
* @return string|false
|
1566 |
+
*/
|
1567 |
+
public abstract function get_local_url( $object_key = null );
|
1568 |
+
|
1569 |
+
/**
|
1570 |
+
* Create a new item from the source id.
|
1571 |
+
*
|
1572 |
+
* @param int $source_id
|
1573 |
+
* @param array $options
|
1574 |
+
*
|
1575 |
+
* @return Item|WP_Error
|
1576 |
+
*/
|
1577 |
+
public static function create_from_source_id( $source_id, $options = array() ) {
|
1578 |
+
return new WP_Error(
|
1579 |
+
'exception',
|
1580 |
+
sprintf( 'Doing it wrong! Trying to create a base %s class instance from source ID %d', __CLASS__, $source_id )
|
1581 |
+
);
|
1582 |
+
}
|
1583 |
+
|
1584 |
+
/**
|
1585 |
+
* Return a year/month string for the item
|
1586 |
+
*
|
1587 |
+
* @return string
|
1588 |
+
*/
|
1589 |
+
protected function get_item_time() {
|
1590 |
+
return null;
|
1591 |
+
}
|
1592 |
+
|
1593 |
+
/**
|
1594 |
+
* Return an additional 'internal' prefix used by some item types
|
1595 |
+
*
|
1596 |
+
* @return string
|
1597 |
+
*/
|
1598 |
+
protected function get_internal_prefix() {
|
1599 |
+
return '';
|
1600 |
+
}
|
1601 |
+
|
1602 |
+
/**
|
1603 |
+
* Get item's new public prefix path for current settings.
|
1604 |
+
*
|
1605 |
+
* @param bool $use_object_versioning
|
1606 |
+
*
|
1607 |
+
* @return string
|
1608 |
+
*/
|
1609 |
+
public function get_new_item_prefix( $use_object_versioning = true ) {
|
1610 |
+
/** @var Amazon_S3_And_CloudFront $as3cf */
|
1611 |
+
global $as3cf;
|
1612 |
+
|
1613 |
+
$prefix = $as3cf->get_object_prefix();
|
1614 |
+
|
1615 |
+
$time = $this->get_item_time();
|
1616 |
+
$prefix .= AS3CF_Utils::trailingslash_prefix( $as3cf->get_dynamic_prefix( $time, static::$can_use_yearmonth ) );
|
1617 |
+
|
1618 |
+
if ( $use_object_versioning && static::can_use_object_versioning() && $as3cf->get_setting( 'object-versioning' ) ) {
|
1619 |
+
$prefix .= AS3CF_Utils::trailingslash_prefix( $as3cf->get_object_version_string() );
|
1620 |
+
}
|
1621 |
+
|
1622 |
+
return AS3CF_Utils::trailingslash_prefix( $prefix );
|
1623 |
+
}
|
1624 |
+
|
1625 |
+
/**
|
1626 |
+
* Get ACL for object key
|
1627 |
+
*
|
1628 |
+
* @param string $object_key Object key
|
1629 |
+
* @param string|null $bucket Optional bucket that ACL is potentially to be used with.
|
1630 |
+
*
|
1631 |
+
* @return string|null
|
1632 |
+
*/
|
1633 |
+
public function get_acl_for_object_key( $object_key, $bucket = null ) {
|
1634 |
+
/** @var Amazon_S3_And_CloudFront $as3cf */
|
1635 |
+
global $as3cf;
|
1636 |
+
|
1637 |
+
$acl = null;
|
1638 |
+
$use_acl = $as3cf->use_acl_for_intermediate_size( 0, $object_key, $bucket, $this );
|
1639 |
+
|
1640 |
+
if ( $use_acl ) {
|
1641 |
+
$acl = $this->is_private( $object_key ) ? $as3cf->get_storage_provider()->get_private_acl() : $as3cf->get_storage_provider()->get_default_acl();
|
1642 |
+
}
|
1643 |
+
|
1644 |
+
return $acl;
|
1645 |
+
}
|
1646 |
+
|
1647 |
+
/**
|
1648 |
+
* Search for all items that have the source path(s).
|
1649 |
+
*
|
1650 |
+
* @param array|string $paths Array of relative source paths.
|
1651 |
+
* @param array|int $exclude_source_ids Array of source_ids to exclude from search. Default, none.
|
1652 |
+
* @param bool $exact_match Use paths as supplied (true, default), or greedy match on path without extension (e.g. find edited too).
|
1653 |
+
* @param bool $first_only Only return first matched item sorted by source_id. Default false.
|
1654 |
+
*
|
1655 |
+
* @return array
|
1656 |
+
*/
|
1657 |
+
public static function get_by_source_path( $paths, $exclude_source_ids = array(), $exact_match = true, $first_only = false ) {
|
1658 |
+
global $wpdb;
|
1659 |
+
|
1660 |
+
if ( ! is_array( $paths ) && is_string( $paths ) && ! empty( $paths ) ) {
|
1661 |
+
$paths = array( $paths );
|
1662 |
+
}
|
1663 |
+
|
1664 |
+
if ( ! is_array( $paths ) || empty( $paths ) ) {
|
1665 |
+
return array();
|
1666 |
+
}
|
1667 |
+
|
1668 |
+
$paths = AS3CF_Utils::make_upload_file_paths_relative( array_unique( $paths ) );
|
1669 |
+
|
1670 |
+
$sql = '
|
1671 |
+
SELECT DISTINCT items.*
|
1672 |
+
FROM ' . static::items_table() . ' AS items USE INDEX (uidx_source_path, uidx_original_source_path)
|
1673 |
+
WHERE 1=1
|
1674 |
+
';
|
1675 |
+
|
1676 |
+
if ( ! empty( $exclude_source_ids ) ) {
|
1677 |
+
if ( ! is_array( $exclude_source_ids ) ) {
|
1678 |
+
$exclude_source_ids = array( $exclude_source_ids );
|
1679 |
+
}
|
1680 |
+
|
1681 |
+
$sql .= ' AND items.source_id NOT IN (' . join( ',', $exclude_source_ids ) . ')';
|
1682 |
+
}
|
1683 |
+
|
1684 |
+
if ( $exact_match ) {
|
1685 |
+
$sql .= " AND (items.source_path IN ('" . join( "','", $paths ) . "')";
|
1686 |
+
$sql .= " OR items.original_source_path IN ('" . join( "','", $paths ) . "'))";
|
1687 |
+
} else {
|
1688 |
+
$likes = array_map( function ( $path ) {
|
1689 |
+
$ext = '.' . pathinfo( $path, PATHINFO_EXTENSION );
|
1690 |
+
$path = substr_replace( $path, '%', -strlen( $ext ) );
|
1691 |
+
|
1692 |
+
return "items.source_path LIKE '" . $path . "' OR items.original_source_path LIKE '" . $path . "'";
|
1693 |
+
}, $paths );
|
1694 |
+
|
1695 |
+
$sql .= ' AND (' . join( ' OR ', $likes ) . ')';
|
1696 |
+
}
|
1697 |
+
|
1698 |
+
if ( $first_only ) {
|
1699 |
+
$sql .= ' ORDER BY items.source_id LIMIT 1';
|
1700 |
+
}
|
1701 |
+
|
1702 |
+
return array_map( 'static::create', $wpdb->get_results( $sql ) );
|
1703 |
+
}
|
1704 |
+
|
1705 |
+
/**
|
1706 |
+
* Update path and original path with a new prefix
|
1707 |
+
*
|
1708 |
+
* @param string $new_prefix
|
1709 |
+
*/
|
1710 |
+
public function update_path_prefix( $new_prefix ) {
|
1711 |
+
$this->set_path( $new_prefix . wp_basename( $this->path() ) );
|
1712 |
+
$this->set_original_path( $new_prefix . wp_basename( $this->original_path() ) );
|
1713 |
+
}
|
1714 |
+
|
1715 |
+
/**
|
1716 |
+
* Returns a link to the items edit page in WordPress
|
1717 |
+
*
|
1718 |
+
* @param object $error
|
1719 |
+
*
|
1720 |
+
* @return object|null Null or object containing properties 'url' and 'text'
|
1721 |
+
*/
|
1722 |
+
public static function admin_link( $error ) {
|
1723 |
+
return null;
|
1724 |
+
}
|
1725 |
+
|
1726 |
+
/**
|
1727 |
+
* Is the item served by provider.
|
1728 |
+
*
|
1729 |
+
* @param bool $skip_rewrite_check Still check if offloaded even if not currently rewriting URLs? Default: false
|
1730 |
+
* @param bool $skip_current_provider_check Skip checking if offloaded to current provider. Default: false, negated if $provider supplied
|
1731 |
+
* @param Storage_Provider|null $provider Provider where item is expected to be offloaded to. Default: currently configured provider
|
1732 |
+
* @param bool $check_is_verified Check that metadata is verified, has no effect if $skip_rewrite_check is true. Default: false
|
1733 |
+
*
|
1734 |
+
* @return bool
|
1735 |
+
*/
|
1736 |
+
public function served_by_provider( $skip_rewrite_check = false, $skip_current_provider_check = false, Storage_Provider $provider = null, $check_is_verified = false ) {
|
1737 |
+
/** @var Amazon_S3_And_CloudFront $as3cf */
|
1738 |
+
global $as3cf;
|
1739 |
+
|
1740 |
+
if ( ! $skip_rewrite_check && ! $as3cf->get_setting( 'serve-from-s3' ) ) {
|
1741 |
+
// Not serving provider URLs
|
1742 |
+
return false;
|
1743 |
+
}
|
1744 |
+
|
1745 |
+
if ( ! $skip_rewrite_check && ! empty( $check_is_verified ) && ! $this->is_verified() ) {
|
1746 |
+
// Offload not verified, treat as not offloaded.
|
1747 |
+
return false;
|
1748 |
+
}
|
1749 |
+
|
1750 |
+
if ( ! $skip_current_provider_check && empty( $provider ) ) {
|
1751 |
+
$provider = $as3cf->get_storage_provider();
|
1752 |
+
}
|
1753 |
+
|
1754 |
+
if ( ! empty( $provider ) && $provider::get_provider_key_name() !== $this->provider() ) {
|
1755 |
+
// File not uploaded to required provider
|
1756 |
+
return false;
|
1757 |
+
}
|
1758 |
+
|
1759 |
+
return true;
|
1760 |
+
}
|
1761 |
+
|
1762 |
+
/**
|
1763 |
+
* Does the item's files exist locally?
|
1764 |
+
*
|
1765 |
+
* @return bool
|
1766 |
+
*/
|
1767 |
+
public function exists_locally() {
|
1768 |
+
foreach ( $this->full_source_paths() as $path ) {
|
1769 |
+
if ( file_exists( $path ) ) {
|
1770 |
+
return true;
|
1771 |
+
}
|
1772 |
+
}
|
1773 |
+
|
1774 |
+
return false;
|
1775 |
+
}
|
1776 |
+
|
1777 |
+
/**
|
1778 |
+
* Get the provider URL for an item
|
1779 |
+
*
|
1780 |
+
* @param string $object_key
|
1781 |
+
* @param null|int $expires
|
1782 |
+
* @param array $headers
|
1783 |
+
*
|
1784 |
+
* @return string|WP_Error|bool
|
1785 |
+
*/
|
1786 |
+
public function get_provider_url( $object_key = null, $expires = null, $headers = array() ) {
|
1787 |
+
/** @var Amazon_S3_And_CloudFront $as3cf */
|
1788 |
+
global $as3cf;
|
1789 |
+
|
1790 |
+
if ( is_null( $object_key ) ) {
|
1791 |
+
$object_key = Item::primary_object_key();
|
1792 |
+
}
|
1793 |
+
|
1794 |
+
// Is a signed expiring URL required for the requested object?
|
1795 |
+
if ( is_null( $expires ) ) {
|
1796 |
+
$expires = $this->is_private( $object_key ) ? Amazon_S3_And_CloudFront::DEFAULT_EXPIRES : null;
|
1797 |
+
} else {
|
1798 |
+
$expires = $this->is_private( $object_key ) ? $expires : null;
|
1799 |
+
}
|
1800 |
+
|
1801 |
+
$scheme = $as3cf->get_url_scheme();
|
1802 |
+
$enable_delivery_domain = $as3cf->get_delivery_provider()->delivery_domain_allowed() ? $as3cf->get_setting( 'enable-delivery-domain' ) : false;
|
1803 |
+
$delivery_domain = $as3cf->get_setting( 'delivery-domain' );
|
1804 |
+
$item_path = $this->path( $object_key );
|
1805 |
+
|
1806 |
+
if ( ! $enable_delivery_domain || empty( $delivery_domain ) ) {
|
1807 |
+
$region = $this->region();
|
1808 |
+
|
1809 |
+
if ( is_wp_error( $region ) ) {
|
1810 |
+
return $region;
|
1811 |
+
}
|
1812 |
+
|
1813 |
+
$delivery_domain = $as3cf->get_storage_provider()->get_url_domain( $this->bucket(), $region, $expires );
|
1814 |
+
} else {
|
1815 |
+
$delivery_domain = AS3CF_Utils::sanitize_custom_domain( $delivery_domain );
|
1816 |
+
}
|
1817 |
+
|
1818 |
+
if ( ! is_null( $expires ) && $as3cf->is_plugin_setup( true ) ) {
|
1819 |
+
try {
|
1820 |
+
/**
|
1821 |
+
* Filters the expires time for private content
|
1822 |
+
*
|
1823 |
+
* @param int $expires The expires time in seconds
|
1824 |
+
*/
|
1825 |
+
$timestamp = time() + apply_filters( 'as3cf_expires', $expires );
|
1826 |
+
$url = $as3cf->get_delivery_provider()->get_signed_url( $this, $item_path, $delivery_domain, $scheme, $timestamp, $headers );
|
1827 |
+
|
1828 |
+
/**
|
1829 |
+
* Filters the secure URL for private content
|
1830 |
+
*
|
1831 |
+
* @param string $url The URL
|
1832 |
+
* @param Item $item The Item object
|
1833 |
+
* @param array $item_source The item source descriptor array
|
1834 |
+
* @param int $timestamp Expiry timestamp
|
1835 |
+
* @param array $headers Optional extra http headers
|
1836 |
+
*/
|
1837 |
+
return apply_filters( 'as3cf_get_item_secure_url', $url, $this, $this->get_item_source_array(), $timestamp, $headers );
|
1838 |
+
} catch ( Exception $e ) {
|
1839 |
+
return new WP_Error( 'exception', $e->getMessage() );
|
1840 |
+
}
|
1841 |
+
} else {
|
1842 |
+
try {
|
1843 |
+
$url = $as3cf->get_delivery_provider()->get_url( $this, $item_path, $delivery_domain, $scheme, $headers );
|
1844 |
+
|
1845 |
+
/**
|
1846 |
+
* Filters the URL for public content
|
1847 |
+
*
|
1848 |
+
* @param string $url The URL
|
1849 |
+
* @param Item $item The Item object
|
1850 |
+
* @param array $item_source The item source descriptor array
|
1851 |
+
* @param int $source_id The source ID of the object
|
1852 |
+
* @param int $timestamp Expiry timestamp
|
1853 |
+
* @param array $headers Optional extra http headers
|
1854 |
+
*/
|
1855 |
+
return apply_filters( 'as3cf_get_item_url', $url, $this, $this->get_item_source_array(), $expires, $headers );
|
1856 |
+
} catch ( Exception $e ) {
|
1857 |
+
return new WP_Error( 'exception', $e->getMessage() );
|
1858 |
+
}
|
1859 |
+
}
|
1860 |
+
}
|
1861 |
+
|
1862 |
+
/**
|
1863 |
+
* Update file sizes after removing local files for an item
|
1864 |
+
*
|
1865 |
+
* @param int $original_size
|
1866 |
+
* @param int $total_size
|
1867 |
+
*/
|
1868 |
+
public function update_filesize_after_remove_local( $original_size, $total_size ) {
|
1869 |
+
}
|
1870 |
+
|
1871 |
+
/**
|
1872 |
+
* Cleanup file sizes after getting item files back from the bucket
|
1873 |
+
*/
|
1874 |
+
public function update_filesize_after_download_local() {
|
1875 |
+
}
|
1876 |
+
|
1877 |
+
/**
|
1878 |
+
* If another item in current site shares full size *local* paths, only remove remote files not referenced by duplicates.
|
1879 |
+
* We reference local paths as they should be reflected one way or another remotely, including backups.
|
1880 |
+
*
|
1881 |
+
* @params Item $as3cf_item
|
1882 |
+
* @params array $paths
|
1883 |
+
*/
|
1884 |
+
public function remove_duplicate_paths( Item $as3cf_item, $paths ) {
|
1885 |
+
return $paths;
|
1886 |
+
}
|
1887 |
+
|
1888 |
+
/**
|
1889 |
+
* Verify that the extra info uses the new format set in plugin version 2.6.0
|
1890 |
+
* Update if needed
|
1891 |
+
*
|
1892 |
+
* @param array $extra_info
|
1893 |
+
* @param int $source_id
|
1894 |
+
* @param bool $is_private
|
1895 |
+
*
|
1896 |
+
* @since 2.6.0
|
1897 |
+
*/
|
1898 |
+
protected static function maybe_update_extra_info( &$extra_info, $source_id, $is_private ) {
|
1899 |
+
if ( ! is_array( $extra_info ) ) {
|
1900 |
+
return;
|
1901 |
+
}
|
1902 |
+
|
1903 |
+
// Compatibility fallback for if just an array of private sizes is supplied.
|
1904 |
+
$private_sizes = array();
|
1905 |
+
if ( ! isset( $extra_info['private_sizes'] ) && ! isset( $extra_info['private_prefix'] ) && ! isset( $extra_info['objects'] ) ) {
|
1906 |
+
$private_sizes = $extra_info;
|
1907 |
+
}
|
1908 |
+
|
1909 |
+
if ( ! isset( $extra_info['objects'] ) ) {
|
1910 |
+
$private_sizes = isset( $extra_info['private_sizes'] ) && is_array( $extra_info['private_sizes'] ) ? $extra_info['private_sizes'] : $private_sizes;
|
1911 |
+
$extra_info['objects'] = array();
|
1912 |
+
|
1913 |
+
$files = AS3CF_Utils::get_attachment_file_paths( $source_id, false );
|
1914 |
+
foreach ( $files as $object_key => $file ) {
|
1915 |
+
if ( 'file' === $object_key ) {
|
1916 |
+
continue;
|
1917 |
+
}
|
1918 |
+
|
1919 |
+
$new_object = array(
|
1920 |
+
'source_file' => wp_basename( $file ),
|
1921 |
+
'is_private' => Item::primary_object_key() === $object_key ? $is_private : in_array( $object_key, $private_sizes ),
|
1922 |
+
);
|
1923 |
+
|
1924 |
+
$extra_info['objects'][ $object_key ] = $new_object;
|
1925 |
+
}
|
1926 |
+
}
|
1927 |
+
|
1928 |
+
if ( isset( $extra_info['private_sizes'] ) ) {
|
1929 |
+
unset( $extra_info['private_sizes'] );
|
1930 |
+
}
|
1931 |
+
}
|
1932 |
+
|
1933 |
+
/**
|
1934 |
+
* Returns the item source description array for this item
|
1935 |
+
*
|
1936 |
+
* @return array Array with the format:
|
1937 |
+
* array(
|
1938 |
+
* 'id' => 1,
|
1939 |
+
* 'source_type' => 'foo-type',
|
1940 |
+
* )
|
1941 |
+
*/
|
1942 |
+
public function get_item_source_array() {
|
1943 |
+
return array(
|
1944 |
+
'id' => $this->source_id(),
|
1945 |
+
'source_type' => $this->source_type(),
|
1946 |
+
);
|
1947 |
+
}
|
1948 |
+
|
1949 |
+
/**
|
1950 |
+
* Returns an array keyed by offloaded source file name.
|
1951 |
+
*
|
1952 |
+
* Each entry is as per objects, but also includes an array of object_keys.
|
1953 |
+
*
|
1954 |
+
* @return array
|
1955 |
+
*/
|
1956 |
+
public function offloaded_files() {
|
1957 |
+
$offloaded_files = array();
|
1958 |
+
|
1959 |
+
foreach ( $this->objects() as $object_key => $object ) {
|
1960 |
+
if ( isset( $offloaded_files[ $object['source_file'] ] ) ) {
|
1961 |
+
$offloaded_files[ $object['source_file'] ]['object_keys'][] = $object_key;
|
1962 |
+
} else {
|
1963 |
+
$object['object_keys'] = array( $object_key );
|
1964 |
+
$offloaded_files[ $object['source_file'] ] = $object;
|
1965 |
+
}
|
1966 |
+
}
|
1967 |
+
|
1968 |
+
return $offloaded_files;
|
1969 |
+
}
|
1970 |
}
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
+
|
5 |
+
class Manifest {
|
6 |
+
/**
|
7 |
+
* @var array
|
8 |
+
*/
|
9 |
+
public $objects = array();
|
10 |
+
}
|
@@ -3,33 +3,65 @@
|
|
3 |
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
|
5 |
use Amazon_S3_And_CloudFront;
|
6 |
-
use WP_Error;
|
7 |
use AS3CF_Utils;
|
|
|
8 |
|
9 |
class Media_Library_Item extends Item {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
private static $attachment_counts = array();
|
11 |
private static $attachment_count_skips = array();
|
12 |
|
13 |
/**
|
14 |
* Item constructor.
|
15 |
*
|
16 |
-
* @param string $provider
|
17 |
-
* @param string $region
|
18 |
-
* @param string $bucket
|
19 |
-
* @param string $path
|
20 |
-
* @param bool $is_private
|
21 |
-
* @param int $source_id
|
22 |
-
* @param string $source_path
|
23 |
-
* @param string $original_filename
|
24 |
-
* @param array $extra_info
|
25 |
-
*
|
26 |
-
*
|
27 |
-
*
|
28 |
-
*
|
29 |
-
*
|
30 |
-
*
|
31 |
-
*
|
32 |
-
*
|
|
|
|
|
|
|
|
|
33 |
*/
|
34 |
public function __construct(
|
35 |
$provider,
|
@@ -43,7 +75,8 @@ class Media_Library_Item extends Item {
|
|
43 |
$extra_info = array(),
|
44 |
$id = null,
|
45 |
$originator = 0,
|
46 |
-
$is_verified = true
|
|
|
47 |
) {
|
48 |
// For Media Library items, the source path should be relative to the Media Library's uploads directory.
|
49 |
$uploads = wp_upload_dir();
|
@@ -52,155 +85,201 @@ class Media_Library_Item extends Item {
|
|
52 |
$source_path = AS3CF_Utils::unleadingslashit( substr( $source_path, strlen( $uploads['basedir'] ) ) );
|
53 |
}
|
54 |
|
55 |
-
$
|
56 |
-
$private_prefix =
|
57 |
|
58 |
// Ensure re-hydration is clean.
|
59 |
if ( ! empty( $extra_info ) && is_array( $extra_info ) ) {
|
60 |
-
if ( isset( $extra_info['private_sizes'] ) ) {
|
61 |
-
$private_sizes = $extra_info['private_sizes'];
|
62 |
-
}
|
63 |
if ( isset( $extra_info['private_prefix'] ) ) {
|
64 |
$private_prefix = $extra_info['private_prefix'];
|
65 |
}
|
66 |
-
|
67 |
-
|
68 |
-
if ( ! isset( $extra_info['private_sizes'] ) && ! isset( $extra_info['private_prefix'] ) ) {
|
69 |
-
$private_sizes = $extra_info;
|
70 |
}
|
71 |
}
|
72 |
|
73 |
$extra_info = array(
|
74 |
-
'
|
75 |
'private_prefix' => $private_prefix,
|
76 |
);
|
77 |
|
78 |
-
parent::__construct( $provider, $region, $bucket, $path, $is_private, $source_id, $source_path, $original_filename, $extra_info, $id, $originator, $is_verified );
|
79 |
}
|
80 |
|
81 |
/**
|
82 |
-
*
|
83 |
-
*
|
84 |
-
*
|
85 |
-
* @param bool $object_versioning_allowed Can an Object Versioning string be appended if setting turned on? Default true.
|
86 |
-
* @param int $originator Originator of new record. Optional, default standard (0).
|
87 |
*
|
88 |
-
* @return
|
89 |
*/
|
90 |
-
public
|
91 |
-
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
|
94 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
return new WP_Error(
|
96 |
'exception',
|
97 |
__( 'Empty Attachment ID passed to ' . __FUNCTION__, 'amazon-s3-and-cloudfront' )
|
98 |
);
|
99 |
}
|
100 |
|
101 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
|
103 |
-
if ( ! in_array( $originator, self::ORIGINATORS ) ) {
|
104 |
return new WP_Error(
|
105 |
'exception',
|
106 |
__( 'Invalid Originator passed to ' . __FUNCTION__, 'amazon-s3-and-cloudfront' )
|
107 |
);
|
108 |
}
|
109 |
|
110 |
-
// If we ever expand originators to include more pre-verified versions, this will need changing.
|
111 |
-
$is_verified = 0 === $originator;
|
112 |
-
|
113 |
/*
|
114 |
-
*
|
115 |
-
*/
|
116 |
-
|
117 |
-
$provider = $as3cf->get_storage_provider()->get_provider_key_name();
|
118 |
-
$region = $as3cf->get_setting( 'region' );
|
119 |
-
if ( is_wp_error( $region ) ) {
|
120 |
-
$region = '';
|
121 |
-
}
|
122 |
-
$bucket = $as3cf->get_setting( 'bucket' );
|
123 |
-
|
124 |
-
/*
|
125 |
-
* Derive local and remote paths.
|
126 |
*/
|
127 |
|
128 |
// Verify that get_attached_file will not blow up as it does not check the data it manipulates.
|
129 |
-
$attached_file_meta = get_post_meta( $
|
130 |
if ( ! is_string( $attached_file_meta ) ) {
|
131 |
return new WP_Error(
|
132 |
'exception',
|
133 |
-
sprintf( __( 'Media Library item with ID %d has damaged meta data', 'amazon-s3-and-cloudfront' ), $
|
134 |
);
|
135 |
}
|
136 |
unset( $attached_file_meta );
|
137 |
|
138 |
-
$source_path = get_attached_file( $
|
139 |
|
140 |
// Check for valid "full" file path otherwise we'll not be able to create offload path or download in the future.
|
141 |
if ( empty( $source_path ) ) {
|
142 |
return new WP_Error(
|
143 |
'exception',
|
144 |
-
sprintf( __( 'Media Library item with ID %d does not have a valid file path', 'amazon-s3-and-cloudfront' ), $
|
145 |
);
|
146 |
}
|
147 |
|
148 |
-
|
149 |
-
|
150 |
if ( is_wp_error( $attachment_metadata ) ) {
|
151 |
return $attachment_metadata;
|
152 |
}
|
153 |
|
154 |
-
|
155 |
-
$path = $prefix . wp_basename( $source_path );
|
156 |
-
|
157 |
-
// There may be an original image that can override the default original filename.
|
158 |
-
$original_filename = empty( $attachment_metadata['original_image'] ) ? null : $attachment_metadata['original_image'];
|
159 |
-
|
160 |
-
/*
|
161 |
-
* Private file handling.
|
162 |
-
*/
|
163 |
-
|
164 |
-
$acl = apply_filters( 'as3cf_upload_acl', $as3cf->get_storage_provider()->get_default_acl(), $attachment_metadata, $attachment_id );
|
165 |
-
$is_private = ! empty( $acl ) && $as3cf->get_storage_provider()->get_private_acl() === $acl;
|
166 |
-
|
167 |
-
// Maybe set private sizes and private prefix.
|
168 |
$extra_info = array(
|
169 |
-
'
|
170 |
-
'
|
171 |
);
|
172 |
|
173 |
-
|
174 |
-
$
|
175 |
|
|
|
176 |
foreach ( $file_paths as $size => $size_file_path ) {
|
177 |
-
|
178 |
-
|
179 |
-
if ( ! empty( $acl ) && $as3cf->get_storage_provider()->get_private_acl() === $acl ) {
|
180 |
-
$extra_info['private_sizes'][] = $size;
|
181 |
}
|
182 |
-
}
|
183 |
|
184 |
-
|
185 |
-
|
|
|
|
|
|
|
|
|
186 |
}
|
187 |
|
188 |
return new self(
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
$
|
195 |
$source_path,
|
196 |
$original_filename,
|
197 |
$extra_info,
|
198 |
null,
|
199 |
-
$originator,
|
200 |
-
$is_verified
|
|
|
201 |
);
|
202 |
}
|
203 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
204 |
/**
|
205 |
* (Re)initialize the static cache used for speeding up queries.
|
206 |
*/
|
@@ -214,7 +293,7 @@ class Media_Library_Item extends Item {
|
|
214 |
/**
|
215 |
* Get the item based on source id.
|
216 |
*
|
217 |
-
* @param
|
218 |
*
|
219 |
* @return bool|Media_Library_Item
|
220 |
*/
|
@@ -254,10 +333,10 @@ class Media_Library_Item extends Item {
|
|
254 |
}
|
255 |
|
256 |
if ( ! empty( $this->private_prefix() ) ) {
|
257 |
-
$size =
|
258 |
|
259 |
// Private path.
|
260 |
-
if ( $this->
|
261 |
return $this->private_prefix() . $this->normalized_path_dir() . $filename;
|
262 |
}
|
263 |
}
|
@@ -267,116 +346,36 @@ class Media_Library_Item extends Item {
|
|
267 |
}
|
268 |
|
269 |
/**
|
270 |
-
* Get absolute file paths
|
271 |
-
*
|
272 |
-
* @param integer $id
|
273 |
*
|
274 |
-
* @return array
|
275 |
*/
|
276 |
-
|
277 |
-
$
|
278 |
-
|
279 |
-
return $paths;
|
280 |
}
|
281 |
|
282 |
/**
|
283 |
-
*
|
284 |
-
*
|
285 |
-
* @param null|string $size
|
286 |
*
|
287 |
* @return string
|
288 |
*/
|
289 |
-
public function
|
290 |
-
|
291 |
-
|
292 |
-
if ( empty( $size ) ) {
|
293 |
-
return $path;
|
294 |
-
}
|
295 |
-
|
296 |
-
$meta = get_post_meta( $this->source_id(), '_wp_attachment_metadata', true );
|
297 |
-
if ( ! empty( $meta['sizes'][ $size ]['file'] ) ) {
|
298 |
-
$path = str_replace( wp_basename( $path ), $meta['sizes'][ $size ]['file'], $path );
|
299 |
-
}
|
300 |
-
|
301 |
-
return $path;
|
302 |
-
}
|
303 |
-
|
304 |
-
/**
|
305 |
-
* Get the array of thumbnail sizes that are private in the bucket.
|
306 |
-
*
|
307 |
-
* @return array
|
308 |
-
*/
|
309 |
-
public function private_sizes() {
|
310 |
-
$extra_info = $this->extra_info();
|
311 |
-
|
312 |
-
if ( ! empty( $extra_info['private_sizes'] ) ) {
|
313 |
-
// There was an issue with class re-hydration that meant empty private sizes embedded itself inside its key.
|
314 |
-
if (
|
315 |
-
isset( $extra_info['private_sizes']['private_sizes'] ) &&
|
316 |
-
is_array( $extra_info['private_sizes']['private_sizes'] ) &&
|
317 |
-
empty( $extra_info['private_sizes']['private_sizes'] )
|
318 |
-
) {
|
319 |
-
unset( $extra_info['private_sizes']['private_sizes'] );
|
320 |
-
}
|
321 |
-
|
322 |
-
return $extra_info['private_sizes'];
|
323 |
-
}
|
324 |
-
|
325 |
-
return array();
|
326 |
}
|
327 |
|
328 |
/**
|
329 |
-
*
|
330 |
*
|
331 |
-
* @param $
|
332 |
-
* @param $
|
333 |
-
*/
|
334 |
-
public function set_private_size( $size, $private ) {
|
335 |
-
if ( empty( $size ) || AS3CF_Utils::is_full_size( $size ) ) {
|
336 |
-
return;
|
337 |
-
}
|
338 |
-
|
339 |
-
$extra_info = $this->extra_info();
|
340 |
-
$private_sizes = $this->private_sizes();
|
341 |
-
if ( $private && ! in_array( $size, $private_sizes, true ) ) {
|
342 |
-
$private_sizes[] = $size;
|
343 |
-
}
|
344 |
-
if ( ! $private && in_array( $size, $private_sizes, true ) ) {
|
345 |
-
$private_sizes = array_diff( $private_sizes, array( $size ) );
|
346 |
-
}
|
347 |
-
$extra_info['private_sizes'] = $private_sizes;
|
348 |
-
|
349 |
-
$this->set_extra_info( $extra_info );
|
350 |
-
}
|
351 |
-
|
352 |
-
/**
|
353 |
-
* Get the private status for a specific size.
|
354 |
-
*
|
355 |
-
* @param string $size
|
356 |
-
*
|
357 |
-
* @return bool
|
358 |
-
*/
|
359 |
-
public function is_private_size( $size ) {
|
360 |
-
if ( AS3CF_Utils::is_full_size( $size ) ) {
|
361 |
-
return $this->is_private();
|
362 |
-
}
|
363 |
-
|
364 |
-
return in_array( $size, $this->private_sizes() );
|
365 |
-
}
|
366 |
-
|
367 |
-
/**
|
368 |
-
* Get the private prefix for attachment's private objects.
|
369 |
*
|
370 |
-
* @return string
|
371 |
*/
|
372 |
-
public function
|
373 |
-
|
374 |
-
|
375 |
-
if ( ! empty( $extra_info['private_prefix'] ) ) {
|
376 |
-
return \AS3CF_Utils::trailingslash_prefix( $extra_info['private_prefix'] );
|
377 |
-
}
|
378 |
|
379 |
-
return
|
380 |
}
|
381 |
|
382 |
/**
|
@@ -390,7 +389,7 @@ class Media_Library_Item extends Item {
|
|
390 |
* offloaded: Count of offloaded media for site (current blog id)
|
391 |
* not_offloaded: Difference between total and offloaded
|
392 |
*/
|
393 |
-
public static function
|
394 |
global $wpdb;
|
395 |
|
396 |
$transient_key = 'as3cf_' . get_current_blog_id() . '_attachment_counts';
|
@@ -402,19 +401,17 @@ class Media_Library_Item extends Item {
|
|
402 |
}
|
403 |
|
404 |
if ( $force || $skip_transient || false === ( $result = get_site_transient( $transient_key ) ) ) {
|
405 |
-
//
|
406 |
-
|
407 |
-
$
|
408 |
-
SELECT COUNT(DISTINCT p.`ID`) total, COUNT(DISTINCT i.`id`) offloaded
|
409 |
-
FROM " . $wpdb->posts . " AS p
|
410 |
-
STRAIGHT_JOIN " . $wpdb->postmeta . " AS m ON p.ID = m.post_id AND m.`meta_key` = '_wp_attached_file'
|
411 |
-
LEFT OUTER JOIN " . static::items_table() . " AS i ON p.`ID` = i.`source_id` AND i.`source_type` = 'media-library'
|
412 |
-
WHERE p.`post_type` = 'attachment'
|
413 |
-
";
|
414 |
|
415 |
-
$
|
|
|
|
|
416 |
|
417 |
-
$result['
|
|
|
|
|
418 |
|
419 |
ksort( $result );
|
420 |
|
@@ -434,9 +431,9 @@ class Media_Library_Item extends Item {
|
|
434 |
*
|
435 |
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
436 |
*
|
437 |
-
* @param
|
438 |
-
* @param
|
439 |
-
* @param bool
|
440 |
*
|
441 |
* @return array|int
|
442 |
*/
|
@@ -486,74 +483,12 @@ class Media_Library_Item extends Item {
|
|
486 |
$sql = $wpdb->prepare( $sql, $args );
|
487 |
|
488 |
if ( $count ) {
|
489 |
-
return $wpdb->get_var( $sql );
|
490 |
} else {
|
491 |
return array_map( 'intval', $wpdb->get_col( $sql ) );
|
492 |
}
|
493 |
}
|
494 |
|
495 |
-
/**
|
496 |
-
* Search for all items that have the source path(s).
|
497 |
-
*
|
498 |
-
* @param array|string $paths Array of relative source paths.
|
499 |
-
* @param array|int $exclude_source_ids Array of source_ids to exclude from search. Default, none.
|
500 |
-
* @param bool $exact_match Use paths as supplied (true, default), or greedy match on path without extension (e.g. find edited too).
|
501 |
-
* @param bool $first_only Only return first matched item sorted by source_id. Default false.
|
502 |
-
*
|
503 |
-
* @return array
|
504 |
-
*/
|
505 |
-
public static function get_by_source_path( $paths, $exclude_source_ids = array(), $exact_match = true, $first_only = false ) {
|
506 |
-
global $wpdb;
|
507 |
-
|
508 |
-
if ( ! is_array( $paths ) && is_string( $paths ) && ! empty( $paths ) ) {
|
509 |
-
$paths = array( $paths );
|
510 |
-
}
|
511 |
-
|
512 |
-
if ( ! is_array( $paths ) || empty( $paths ) ) {
|
513 |
-
return array();
|
514 |
-
}
|
515 |
-
|
516 |
-
$paths = \AS3CF_Utils::make_upload_file_paths_relative( $paths );
|
517 |
-
|
518 |
-
$args = array( static::$source_type );
|
519 |
-
|
520 |
-
$sql = '
|
521 |
-
SELECT DISTINCT items.*
|
522 |
-
FROM ' . static::items_table() . ' AS items USE INDEX (uidx_source_path, uidx_original_source_path)
|
523 |
-
WHERE items.source_type = %s
|
524 |
-
';
|
525 |
-
|
526 |
-
if ( ! empty( $exclude_source_ids ) ) {
|
527 |
-
if ( ! is_array( $exclude_source_ids ) ) {
|
528 |
-
$exclude_source_ids = array( $exclude_source_ids );
|
529 |
-
}
|
530 |
-
|
531 |
-
$sql .= ' AND items.source_id NOT IN (' . join( ',', $exclude_source_ids ) . ')';
|
532 |
-
}
|
533 |
-
|
534 |
-
if ( $exact_match ) {
|
535 |
-
$sql .= " AND (items.source_path IN ('" . join( "','", $paths ) . "')";
|
536 |
-
$sql .= " OR items.original_source_path IN ('" . join( "','", $paths ) . "'))";
|
537 |
-
} else {
|
538 |
-
$likes = array_map( function ( $path ) {
|
539 |
-
$ext = '.' . pathinfo( $path, PATHINFO_EXTENSION );
|
540 |
-
$path = substr_replace( $path, '%', -strlen( $ext ) );
|
541 |
-
|
542 |
-
return "items.source_path LIKE '" . $path . "' OR items.original_source_path LIKE '" . $path . "'";
|
543 |
-
}, $paths );
|
544 |
-
|
545 |
-
$sql .= ' AND (' . join( ' OR ', $likes ) . ')';
|
546 |
-
}
|
547 |
-
|
548 |
-
if ( $first_only ) {
|
549 |
-
$sql .= ' ORDER BY items.source_id LIMIT 1';
|
550 |
-
}
|
551 |
-
|
552 |
-
$sql = $wpdb->prepare( $sql, $args );
|
553 |
-
|
554 |
-
return array_map( 'static::create', $wpdb->get_results( $sql ) );
|
555 |
-
}
|
556 |
-
|
557 |
/**
|
558 |
* Finds Media Library items with same source_path and sets them as offloaded.
|
559 |
*/
|
@@ -601,9 +536,183 @@ class Media_Library_Item extends Item {
|
|
601 |
$this->extra_info()
|
602 |
);
|
603 |
$as3cf_item->save();
|
|
|
604 |
}
|
605 |
}
|
606 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
607 |
/*
|
608 |
* >>> LEGACY ROUTINES BEGIN >>>
|
609 |
*/
|
@@ -611,8 +720,8 @@ class Media_Library_Item extends Item {
|
|
611 |
/**
|
612 |
* Convert the provider info array for an attachment to item object.
|
613 |
*
|
614 |
-
* @param
|
615 |
-
* @param array
|
616 |
*
|
617 |
* @return bool|Media_Library_Item
|
618 |
*/
|
@@ -631,7 +740,7 @@ class Media_Library_Item extends Item {
|
|
631 |
$provider_info['region'],
|
632 |
$provider_info['bucket'],
|
633 |
$provider_info['key'],
|
634 |
-
isset( $provider_info['acl'] ) && false !== strpos( $provider_info['acl'], 'private' )
|
635 |
$source_id,
|
636 |
$attached_file,
|
637 |
wp_basename( $attached_file ),
|
3 |
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
|
5 |
use Amazon_S3_And_CloudFront;
|
|
|
6 |
use AS3CF_Utils;
|
7 |
+
use WP_Error;
|
8 |
|
9 |
class Media_Library_Item extends Item {
|
10 |
+
/**
|
11 |
+
* Source type name
|
12 |
+
*
|
13 |
+
* @var string
|
14 |
+
*/
|
15 |
+
protected static $source_type_name = 'Media Library Item';
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Internal source type identifier
|
19 |
+
*
|
20 |
+
* @var string
|
21 |
+
*/
|
22 |
+
protected static $source_type = 'media-library';
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Table that corresponds to this item type
|
26 |
+
*
|
27 |
+
* @var string
|
28 |
+
*/
|
29 |
+
protected static $source_table = 'posts';
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Foreign key (if any) in the $source_table
|
33 |
+
*
|
34 |
+
* @var string
|
35 |
+
*/
|
36 |
+
protected static $source_fk = 'id';
|
37 |
+
|
38 |
private static $attachment_counts = array();
|
39 |
private static $attachment_count_skips = array();
|
40 |
|
41 |
/**
|
42 |
* Item constructor.
|
43 |
*
|
44 |
+
* @param string $provider Storage provider key name, e.g. "aws".
|
45 |
+
* @param string $region Region for item's bucket.
|
46 |
+
* @param string $bucket Bucket for item.
|
47 |
+
* @param string $path Key path for item (full sized if type has thumbnails etc).
|
48 |
+
* @param bool $is_private Is the object private in the bucket.
|
49 |
+
* @param int $source_id ID that source has.
|
50 |
+
* @param string $source_path Path that source uses, could be relative or absolute depending on source.
|
51 |
+
* @param string $original_filename An optional filename with no path that was previously used for the item.
|
52 |
+
* @param array $extra_info An optional associative array of extra data to be associated with the item.
|
53 |
+
* Recognised keys:
|
54 |
+
* 'objects' => array of ...
|
55 |
+
* -- 'thumbnail' => array of ...
|
56 |
+
* -- -- 'source_file' => 'image-150x150.png'
|
57 |
+
* -- -- 'is_private' => false
|
58 |
+
* 'private_prefix' => 'private/'
|
59 |
+
* For backwards compatibility, if a simple array is supplied it is treated as
|
60 |
+
* private thumbnail sizes that should be private objects in the bucket.
|
61 |
+
* @param int $id Optional Item record ID.
|
62 |
+
* @param int $originator Optional originator of record from ORIGINATORS const.
|
63 |
+
* @param bool $is_verified Optional flag as to whether Item's objects are known to exist.
|
64 |
+
* @param bool $use_object_versioning Optional flag as to whether path prefix should use Object Versioning if type allows it.
|
65 |
*/
|
66 |
public function __construct(
|
67 |
$provider,
|
75 |
$extra_info = array(),
|
76 |
$id = null,
|
77 |
$originator = 0,
|
78 |
+
$is_verified = true,
|
79 |
+
$use_object_versioning = self::CAN_USE_OBJECT_VERSIONING
|
80 |
) {
|
81 |
// For Media Library items, the source path should be relative to the Media Library's uploads directory.
|
82 |
$uploads = wp_upload_dir();
|
85 |
$source_path = AS3CF_Utils::unleadingslashit( substr( $source_path, strlen( $uploads['basedir'] ) ) );
|
86 |
}
|
87 |
|
88 |
+
$objects = array();
|
89 |
+
$private_prefix = null;
|
90 |
|
91 |
// Ensure re-hydration is clean.
|
92 |
if ( ! empty( $extra_info ) && is_array( $extra_info ) ) {
|
|
|
|
|
|
|
93 |
if ( isset( $extra_info['private_prefix'] ) ) {
|
94 |
$private_prefix = $extra_info['private_prefix'];
|
95 |
}
|
96 |
+
if ( isset( $extra_info['objects'] ) ) {
|
97 |
+
$objects = $extra_info['objects'];
|
|
|
|
|
98 |
}
|
99 |
}
|
100 |
|
101 |
$extra_info = array(
|
102 |
+
'objects' => $objects,
|
103 |
'private_prefix' => $private_prefix,
|
104 |
);
|
105 |
|
106 |
+
parent::__construct( $provider, $region, $bucket, $path, $is_private, $source_id, $source_path, $original_filename, $extra_info, $id, $originator, $is_verified, $use_object_versioning );
|
107 |
}
|
108 |
|
109 |
/**
|
110 |
+
* Synthesize a data struct to be used when passing information
|
111 |
+
* about the current item to filters that assume the item is a
|
112 |
+
* media library item.
|
|
|
|
|
113 |
*
|
114 |
+
* @return array
|
115 |
*/
|
116 |
+
public function item_data_for_acl_filter() {
|
117 |
+
$item_data = parent::item_data_for_acl_filter();
|
118 |
+
$media_library_item_data = wp_get_attachment_metadata( $this->source_id(), true );
|
119 |
+
|
120 |
+
// Copy over specific elements only as i.e. 'size' may not be populated yet in $media_library_item_data
|
121 |
+
foreach ( array( 'file', 'original_image', 'image_meta' ) as $element ) {
|
122 |
+
if ( isset( $media_library_item_data[ $element ] ) ) {
|
123 |
+
$item_data[ $element ] = $media_library_item_data[ $element ];
|
124 |
+
}
|
125 |
+
}
|
126 |
|
127 |
+
return $item_data;
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Create a new item from the source id.
|
132 |
+
*
|
133 |
+
* @param int $source_id
|
134 |
+
* @param array $options
|
135 |
+
*
|
136 |
+
* @return Item|WP_Error
|
137 |
+
*/
|
138 |
+
public static function create_from_source_id( $source_id, $options = array() ) {
|
139 |
+
if ( empty( $source_id ) ) {
|
140 |
return new WP_Error(
|
141 |
'exception',
|
142 |
__( 'Empty Attachment ID passed to ' . __FUNCTION__, 'amazon-s3-and-cloudfront' )
|
143 |
);
|
144 |
}
|
145 |
|
146 |
+
$default_options = array(
|
147 |
+
'originator' => Item::ORIGINATORS['standard'],
|
148 |
+
'is_verified' => true,
|
149 |
+
'use_object_versioning' => static::can_use_object_versioning(),
|
150 |
+
);
|
151 |
+
|
152 |
+
$options = array_merge( $default_options, $options );
|
153 |
|
154 |
+
if ( ! in_array( $options['originator'], self::ORIGINATORS ) ) {
|
155 |
return new WP_Error(
|
156 |
'exception',
|
157 |
__( 'Invalid Originator passed to ' . __FUNCTION__, 'amazon-s3-and-cloudfront' )
|
158 |
);
|
159 |
}
|
160 |
|
|
|
|
|
|
|
161 |
/*
|
162 |
+
* Derive local path.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
*/
|
164 |
|
165 |
// Verify that get_attached_file will not blow up as it does not check the data it manipulates.
|
166 |
+
$attached_file_meta = get_post_meta( $source_id, '_wp_attached_file', true );
|
167 |
if ( ! is_string( $attached_file_meta ) ) {
|
168 |
return new WP_Error(
|
169 |
'exception',
|
170 |
+
sprintf( __( 'Media Library item with ID %d has damaged meta data', 'amazon-s3-and-cloudfront' ), $source_id )
|
171 |
);
|
172 |
}
|
173 |
unset( $attached_file_meta );
|
174 |
|
175 |
+
$source_path = get_attached_file( $source_id, true );
|
176 |
|
177 |
// Check for valid "full" file path otherwise we'll not be able to create offload path or download in the future.
|
178 |
if ( empty( $source_path ) ) {
|
179 |
return new WP_Error(
|
180 |
'exception',
|
181 |
+
sprintf( __( 'Media Library item with ID %d does not have a valid file path', 'amazon-s3-and-cloudfront' ), $source_id )
|
182 |
);
|
183 |
}
|
184 |
|
185 |
+
/** @var array|false|WP_Error $attachment_metadata */
|
186 |
+
$attachment_metadata = wp_get_attachment_metadata( $source_id, true );
|
187 |
if ( is_wp_error( $attachment_metadata ) ) {
|
188 |
return $attachment_metadata;
|
189 |
}
|
190 |
|
191 |
+
// Initialize extra info array with empty values
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
192 |
$extra_info = array(
|
193 |
+
'private_prefix' => null,
|
194 |
+
'objects' => array(),
|
195 |
);
|
196 |
|
197 |
+
// There may be an original image that can override the default original filename.
|
198 |
+
$original_filename = empty( $attachment_metadata['original_image'] ) ? null : $attachment_metadata['original_image'];
|
199 |
|
200 |
+
$file_paths = AS3CF_Utils::get_attachment_file_paths( $source_id, false, $attachment_metadata );
|
201 |
foreach ( $file_paths as $size => $size_file_path ) {
|
202 |
+
if ( $size === 'file' ) {
|
203 |
+
continue;
|
|
|
|
|
204 |
}
|
|
|
205 |
|
206 |
+
$new_object = array(
|
207 |
+
'source_file' => wp_basename( $size_file_path ),
|
208 |
+
'is_private' => false,
|
209 |
+
);
|
210 |
+
|
211 |
+
$extra_info['objects'][ $size ] = $new_object;
|
212 |
}
|
213 |
|
214 |
return new self(
|
215 |
+
'',
|
216 |
+
'',
|
217 |
+
'',
|
218 |
+
'',
|
219 |
+
false,
|
220 |
+
$source_id,
|
221 |
$source_path,
|
222 |
$original_filename,
|
223 |
$extra_info,
|
224 |
null,
|
225 |
+
$options['originator'],
|
226 |
+
$options['is_verified'],
|
227 |
+
$options['use_object_versioning']
|
228 |
);
|
229 |
}
|
230 |
|
231 |
+
/**
|
232 |
+
* Get attachment local URL.
|
233 |
+
*
|
234 |
+
* This is partly a direct copy of wp_get_attachment_url() from /wp-includes/post.php
|
235 |
+
* as we filter the URL in AS3CF and can't remove this filter using the current implementation
|
236 |
+
* of globals for class instances.
|
237 |
+
*
|
238 |
+
* @param string|null $object_key
|
239 |
+
*
|
240 |
+
* @return string|false
|
241 |
+
*/
|
242 |
+
public function get_local_url( $object_key = null ) {
|
243 |
+
/** @var Amazon_S3_And_CloudFront $as3cf */
|
244 |
+
global $as3cf;
|
245 |
+
$url = '';
|
246 |
+
|
247 |
+
// Get attached file.
|
248 |
+
if ( $file = get_post_meta( $this->source_id(), '_wp_attached_file', true ) ) {
|
249 |
+
// Get upload directory.
|
250 |
+
if ( ( $uploads = wp_upload_dir() ) && false === $uploads['error'] ) {
|
251 |
+
// Check that the upload base exists in the file location.
|
252 |
+
if ( 0 === strpos( $file, $uploads['basedir'] ) ) {
|
253 |
+
// Replace file location with url location.
|
254 |
+
$url = str_replace( $uploads['basedir'], $uploads['baseurl'], $file );
|
255 |
+
} elseif ( false !== strpos( $file, 'wp-content/uploads' ) ) {
|
256 |
+
$url = $uploads['baseurl'] . substr( $file, strpos( $file, 'wp-content/uploads' ) + 18 );
|
257 |
+
} else {
|
258 |
+
// It's a newly-uploaded file, therefore $file is relative to the basedir.
|
259 |
+
$url = $uploads['baseurl'] . "/$file";
|
260 |
+
}
|
261 |
+
}
|
262 |
+
}
|
263 |
+
|
264 |
+
if ( empty( $url ) ) {
|
265 |
+
return false;
|
266 |
+
}
|
267 |
+
|
268 |
+
$url = $as3cf->maybe_fix_local_subsite_url( $url );
|
269 |
+
|
270 |
+
if ( ! empty( $object_key ) ) {
|
271 |
+
$meta = get_post_meta( $this->source_id(), '_wp_attachment_metadata', true );
|
272 |
+
if ( empty( $meta['sizes'][ $object_key ]['file'] ) ) {
|
273 |
+
// No alternative sizes available, return
|
274 |
+
return $url;
|
275 |
+
}
|
276 |
+
|
277 |
+
$url = str_replace( wp_basename( $url ), $meta['sizes'][ $object_key ]['file'], $url );
|
278 |
+
}
|
279 |
+
|
280 |
+
return $url;
|
281 |
+
}
|
282 |
+
|
283 |
/**
|
284 |
* (Re)initialize the static cache used for speeding up queries.
|
285 |
*/
|
293 |
/**
|
294 |
* Get the item based on source id.
|
295 |
*
|
296 |
+
* @param int $source_id
|
297 |
*
|
298 |
* @return bool|Media_Library_Item
|
299 |
*/
|
333 |
}
|
334 |
|
335 |
if ( ! empty( $this->private_prefix() ) ) {
|
336 |
+
$size = $this->get_object_key_from_filename( $filename );
|
337 |
|
338 |
// Private path.
|
339 |
+
if ( $this->is_private( $size ) ) {
|
340 |
return $this->private_prefix() . $this->normalized_path_dir() . $filename;
|
341 |
}
|
342 |
}
|
346 |
}
|
347 |
|
348 |
/**
|
349 |
+
* Get absolute source file paths for offloaded files.
|
|
|
|
|
350 |
*
|
351 |
+
* @return array Associative array of object_key => path
|
352 |
*/
|
353 |
+
public function full_source_paths() {
|
354 |
+
return array_intersect_key( AS3CF_Utils::get_attachment_file_paths( $this->source_id(), false ), $this->objects() );
|
|
|
|
|
355 |
}
|
356 |
|
357 |
/**
|
358 |
+
* Get size name from file name
|
|
|
|
|
359 |
*
|
360 |
* @return string
|
361 |
*/
|
362 |
+
public function get_object_key_from_filename( $filename ) {
|
363 |
+
return AS3CF_Utils::get_intermediate_size_from_filename( $this->source_id(), basename( $filename ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
364 |
}
|
365 |
|
366 |
/**
|
367 |
+
* Get ACL for intermediate size.
|
368 |
*
|
369 |
+
* @param string $object_key Size name
|
370 |
+
* @param string|null $bucket Optional bucket that ACL is potentially to be used with.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
*
|
372 |
+
* @return string|null
|
373 |
*/
|
374 |
+
public function get_acl_for_object_key( $object_key, $bucket = null ) {
|
375 |
+
/** @var Amazon_S3_And_CloudFront $as3cf */
|
376 |
+
global $as3cf;
|
|
|
|
|
|
|
377 |
|
378 |
+
return $as3cf->get_acl_for_intermediate_size( $this->source_id(), $object_key, $bucket, $this );
|
379 |
}
|
380 |
|
381 |
/**
|
389 |
* offloaded: Count of offloaded media for site (current blog id)
|
390 |
* not_offloaded: Difference between total and offloaded
|
391 |
*/
|
392 |
+
public static function count_items( $skip_transient = false, $force = false ) {
|
393 |
global $wpdb;
|
394 |
|
395 |
$transient_key = 'as3cf_' . get_current_blog_id() . '_attachment_counts';
|
401 |
}
|
402 |
|
403 |
if ( $force || $skip_transient || false === ( $result = get_site_transient( $transient_key ) ) ) {
|
404 |
+
// Simplified media counting
|
405 |
+
$sql = "SELECT count(id) FROM {$wpdb->posts} WHERE post_type = 'attachment'";
|
406 |
+
$attachment_count = (int) $wpdb->get_var( $sql );
|
|
|
|
|
|
|
|
|
|
|
|
|
407 |
|
408 |
+
$sql = 'SELECT count(id) FROM ' . static::items_table() . ' WHERE source_type = %s';
|
409 |
+
$sql = $wpdb->prepare( $sql, static::$source_type );
|
410 |
+
$offloaded_count = (int) $wpdb->get_var( $sql );
|
411 |
|
412 |
+
$result['total'] = $attachment_count;
|
413 |
+
$result['offloaded'] = $offloaded_count;
|
414 |
+
$result['not_offloaded'] = max( $attachment_count - $offloaded_count, 0 );
|
415 |
|
416 |
ksort( $result );
|
417 |
|
431 |
*
|
432 |
* While source id isn't strictly unique, it is by source type, which is always used in queries based on called class.
|
433 |
*
|
434 |
+
* @param int $upper_bound Returned source_ids should be lower than this, use null/0 for no upper bound.
|
435 |
+
* @param int $limit Maximum number of source_ids to return. Required if not counting.
|
436 |
+
* @param bool $count Just return a count of matching source_ids? Negates $limit, default false.
|
437 |
*
|
438 |
* @return array|int
|
439 |
*/
|
483 |
$sql = $wpdb->prepare( $sql, $args );
|
484 |
|
485 |
if ( $count ) {
|
486 |
+
return (int) $wpdb->get_var( $sql );
|
487 |
} else {
|
488 |
return array_map( 'intval', $wpdb->get_col( $sql ) );
|
489 |
}
|
490 |
}
|
491 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
492 |
/**
|
493 |
* Finds Media Library items with same source_path and sets them as offloaded.
|
494 |
*/
|
536 |
$this->extra_info()
|
537 |
);
|
538 |
$as3cf_item->save();
|
539 |
+
$as3cf_item->duplicate_filesize_total( $this->source_id() );
|
540 |
}
|
541 |
}
|
542 |
|
543 |
+
/**
|
544 |
+
* Returns a link to the items edit page in WordPress
|
545 |
+
*
|
546 |
+
* @param object $error
|
547 |
+
*
|
548 |
+
* @return object|null Object containing url and link text
|
549 |
+
*/
|
550 |
+
public static function admin_link( $error ) {
|
551 |
+
return (object) array(
|
552 |
+
'url' => get_edit_post_link( $error->source_id ),
|
553 |
+
'text' => __( 'Edit', 'amazon-s3-and-cloudfront' ),
|
554 |
+
);
|
555 |
+
}
|
556 |
+
|
557 |
+
/**
|
558 |
+
* Return a year/month string for the item
|
559 |
+
*
|
560 |
+
* @return string
|
561 |
+
*/
|
562 |
+
protected function get_item_time() {
|
563 |
+
return $this->get_attachment_folder_year_month();
|
564 |
+
}
|
565 |
+
|
566 |
+
/**
|
567 |
+
* Get the year/month string for attachment's upload.
|
568 |
+
*
|
569 |
+
* Fall back to post date if attached, otherwise current date.
|
570 |
+
*
|
571 |
+
* @param array $data
|
572 |
+
*
|
573 |
+
* @return string
|
574 |
+
*/
|
575 |
+
private function get_attachment_folder_year_month( $data = array() ) {
|
576 |
+
if ( empty( $data ) ) {
|
577 |
+
$data = wp_get_attachment_metadata( $this->source_id(), true );
|
578 |
+
}
|
579 |
+
|
580 |
+
if ( isset( $data['file'] ) ) {
|
581 |
+
$time = $this->get_folder_time_from_url( $data['file'] );
|
582 |
+
}
|
583 |
+
|
584 |
+
if ( empty( $time ) && ( $local_url = wp_get_attachment_url( $this->source_id() ) ) ) {
|
585 |
+
$time = $this->get_folder_time_from_url( $local_url );
|
586 |
+
}
|
587 |
+
|
588 |
+
if ( empty( $time ) ) {
|
589 |
+
$time = date( 'Y/m' );
|
590 |
+
|
591 |
+
if ( ! ( $attach = get_post( $this->source_id() ) ) ) {
|
592 |
+
return $time;
|
593 |
+
}
|
594 |
+
|
595 |
+
if ( ! $attach->post_parent ) {
|
596 |
+
return $time;
|
597 |
+
}
|
598 |
+
|
599 |
+
if ( ! ( $post = get_post( $attach->post_parent ) ) ) {
|
600 |
+
return $time;
|
601 |
+
}
|
602 |
+
|
603 |
+
if ( substr( $post->post_date_gmt, 0, 4 ) > 0 ) {
|
604 |
+
return date( 'Y/m', strtotime( $post->post_date_gmt . ' +0000' ) );
|
605 |
+
}
|
606 |
+
}
|
607 |
+
|
608 |
+
return $time;
|
609 |
+
}
|
610 |
+
|
611 |
+
/**
|
612 |
+
* Get the upload folder time from given URL
|
613 |
+
*
|
614 |
+
* @param string $url
|
615 |
+
*
|
616 |
+
* @return null|string YYYY/MM format.
|
617 |
+
*/
|
618 |
+
private function get_folder_time_from_url( $url ) {
|
619 |
+
if ( ! is_string( $url ) ) {
|
620 |
+
return null;
|
621 |
+
}
|
622 |
+
|
623 |
+
preg_match( '@[0-9]{4}/[0-9]{2}/@', $url, $matches );
|
624 |
+
|
625 |
+
if ( isset( $matches[0] ) ) {
|
626 |
+
return untrailingslashit( $matches[0] );
|
627 |
+
}
|
628 |
+
|
629 |
+
return null;
|
630 |
+
}
|
631 |
+
|
632 |
+
/**
|
633 |
+
* Update filesize and as3cf_filesize_total metadata on the underlying media library item
|
634 |
+
* after removing the local file.
|
635 |
+
*
|
636 |
+
* @param int $original_size
|
637 |
+
* @param int $total_size
|
638 |
+
*/
|
639 |
+
public function update_filesize_after_remove_local( $original_size, $total_size ) {
|
640 |
+
update_post_meta( $this->source_id(), 'as3cf_filesize_total', $total_size );
|
641 |
+
|
642 |
+
if ( 0 < $original_size && ( $data = get_post_meta( $this->source_id(), '_wp_attachment_metadata', true ) ) ) {
|
643 |
+
if ( empty( $data['filesize'] ) ) {
|
644 |
+
$data['filesize'] = $original_size;
|
645 |
+
|
646 |
+
// Update metadata with filesize
|
647 |
+
update_post_meta( $this->source_id(), '_wp_attachment_metadata', $data );
|
648 |
+
}
|
649 |
+
}
|
650 |
+
}
|
651 |
+
|
652 |
+
/**
|
653 |
+
* Cleanup filesize and as3cf_filesize_total metadata on the underlying media library item
|
654 |
+
* after downloading a file back from the bucket
|
655 |
+
*/
|
656 |
+
public function update_filesize_after_download_local() {
|
657 |
+
$data = get_post_meta( $this->source_id(), '_wp_attachment_metadata', true );
|
658 |
+
|
659 |
+
/*
|
660 |
+
* Audio and video have a filesize added to metadata by default, but images and anything else don't.
|
661 |
+
* Note: Could have used `wp_generate_attachment_metadata` here to test whether default metadata has 'filesize',
|
662 |
+
* 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.
|
663 |
+
*/
|
664 |
+
if (
|
665 |
+
! empty( $data ) &&
|
666 |
+
( empty( $data['mime_type'] ) ||
|
667 |
+
0 === strpos( $data['mime_type'], 'image/' ) ||
|
668 |
+
! ( 0 === strpos( $data['mime_type'], 'audio/' ) || 0 === strpos( $data['mime_type'], 'video/' ) ) )
|
669 |
+
) {
|
670 |
+
unset( $data['filesize'] );
|
671 |
+
update_post_meta( $this->source_id(), '_wp_attachment_metadata', $data );
|
672 |
+
}
|
673 |
+
|
674 |
+
delete_post_meta( $this->source_id(), 'as3cf_filesize_total' );
|
675 |
+
}
|
676 |
+
|
677 |
+
/**
|
678 |
+
* Duplicate 'as3cf_filesize_total' meta if it exists for an attachment.
|
679 |
+
*
|
680 |
+
* @param int $attachment_id
|
681 |
+
*/
|
682 |
+
public function duplicate_filesize_total( $attachment_id ) {
|
683 |
+
if ( ! ( $filesize = get_post_meta( $attachment_id, 'as3cf_filesize_total', true ) ) ) {
|
684 |
+
// No filesize to duplicate.
|
685 |
+
return;
|
686 |
+
}
|
687 |
+
|
688 |
+
update_post_meta( $this->source_id(), 'as3cf_filesize_total', $filesize );
|
689 |
+
}
|
690 |
+
|
691 |
+
/**
|
692 |
+
* If another item in current site shares full size *local* paths, only remove remote files not referenced by duplicates.
|
693 |
+
* We reference local paths as they should be reflected one way or another remotely, including backups.
|
694 |
+
*
|
695 |
+
* @params Item $as3cf_item
|
696 |
+
* @params array $paths
|
697 |
+
*/
|
698 |
+
public function remove_duplicate_paths( Item $as3cf_item, $paths ) {
|
699 |
+
$full_size_paths = AS3CF_Utils::fullsize_paths( $as3cf_item->full_source_paths() );
|
700 |
+
$as3cf_items_with_paths = static::get_by_source_path( $full_size_paths, array( $as3cf_item->source_id() ), false );
|
701 |
+
|
702 |
+
$duplicate_paths = array();
|
703 |
+
|
704 |
+
foreach ( $as3cf_items_with_paths as $as3cf_item_with_path ) {
|
705 |
+
/* @var Media_Library_Item $as3cf_item_with_path */
|
706 |
+
$duplicate_paths += array_values( AS3CF_Utils::get_attachment_file_paths( $as3cf_item_with_path->source_id(), false, false, true ) );
|
707 |
+
}
|
708 |
+
|
709 |
+
if ( ! empty( $duplicate_paths ) ) {
|
710 |
+
$paths = array_diff( $paths, $duplicate_paths );
|
711 |
+
}
|
712 |
+
|
713 |
+
return $paths;
|
714 |
+
}
|
715 |
+
|
716 |
/*
|
717 |
* >>> LEGACY ROUTINES BEGIN >>>
|
718 |
*/
|
720 |
/**
|
721 |
* Convert the provider info array for an attachment to item object.
|
722 |
*
|
723 |
+
* @param int $source_id
|
724 |
+
* @param array $provider_info
|
725 |
*
|
726 |
* @return bool|Media_Library_Item
|
727 |
*/
|
740 |
$provider_info['region'],
|
741 |
$provider_info['bucket'],
|
742 |
$provider_info['key'],
|
743 |
+
isset( $provider_info['acl'] ) && false !== strpos( $provider_info['acl'], 'private' ),
|
744 |
$source_id,
|
745 |
$attached_file,
|
746 |
wp_basename( $attached_file ),
|
@@ -0,0 +1,209 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
+
|
5 |
+
use AS3CF_Error;
|
6 |
+
use WP_Error;
|
7 |
+
|
8 |
+
class Remove_Local_Handler extends Item_Handler {
|
9 |
+
/**
|
10 |
+
* @var string
|
11 |
+
*/
|
12 |
+
protected static $item_handler_key = 'remove-local';
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Keep track of individual files we've already attempted to remove.
|
16 |
+
*
|
17 |
+
* @var array
|
18 |
+
*/
|
19 |
+
private $remove_blocked = array();
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Keep track of size of individual files we've already attempted to remove.
|
23 |
+
*
|
24 |
+
* @var array
|
25 |
+
*/
|
26 |
+
private $removed_size = array();
|
27 |
+
|
28 |
+
/**
|
29 |
+
* If remove the primary file, we want to update the 'filesize'.
|
30 |
+
*
|
31 |
+
* @var int
|
32 |
+
*/
|
33 |
+
private $removed_primary_size = array();
|
34 |
+
|
35 |
+
/**
|
36 |
+
* The default options that should be used if none supplied.
|
37 |
+
*
|
38 |
+
* @return array
|
39 |
+
*/
|
40 |
+
public static function default_options() {
|
41 |
+
return array(
|
42 |
+
'verify_exists_on_provider' => false,
|
43 |
+
'provider_keys' => array(),
|
44 |
+
'files_to_remove' => array(),
|
45 |
+
);
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Create manifest for local removal.
|
50 |
+
*
|
51 |
+
* @param Item $as3cf_item
|
52 |
+
* @param array $options
|
53 |
+
*
|
54 |
+
* @return Manifest|WP_Error
|
55 |
+
*/
|
56 |
+
protected function pre_handle( Item $as3cf_item, array $options ) {
|
57 |
+
$manifest = new Manifest();
|
58 |
+
$source_id = $as3cf_item->source_id();
|
59 |
+
$primary_file = '';
|
60 |
+
$files_to_remove = array();
|
61 |
+
|
62 |
+
// Note: Unable to use Item::full_size_paths() here
|
63 |
+
// as source item's metadata may not be up-to-date yet.
|
64 |
+
foreach ( $as3cf_item->objects() as $object_key => $object ) {
|
65 |
+
$file = $as3cf_item->full_source_path( $object_key );
|
66 |
+
|
67 |
+
if ( in_array( $file, $this->remove_blocked ) ) {
|
68 |
+
continue;
|
69 |
+
}
|
70 |
+
|
71 |
+
if ( 0 < count( $options['files_to_remove'] ) && ! in_array( $file, $options['files_to_remove'] ) ) {
|
72 |
+
continue;
|
73 |
+
}
|
74 |
+
|
75 |
+
// If needed, make sure this item exists among the provider keys.
|
76 |
+
if ( true === $options['verify_exists_on_provider'] ) {
|
77 |
+
if ( empty( $options['provider_keys'][ $source_id ] ) ) {
|
78 |
+
continue;
|
79 |
+
}
|
80 |
+
|
81 |
+
if ( ! in_array( $as3cf_item->provider_key( $object_key ), $options['provider_keys'][ $source_id ] ) ) {
|
82 |
+
continue;
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
if ( file_exists( $file ) ) {
|
87 |
+
$files_to_remove[] = $file;
|
88 |
+
|
89 |
+
if ( Item::primary_object_key() === $object_key ) {
|
90 |
+
$primary_file = $file;
|
91 |
+
}
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Filters array of local files before being removed from server.
|
97 |
+
*
|
98 |
+
* @param array $files_to_remove Array of paths to be removed
|
99 |
+
* @param Item $as3cf_item The Item object
|
100 |
+
* @param array $item_source Item source descriptor array
|
101 |
+
*/
|
102 |
+
$filtered_files_to_remove = apply_filters( 'as3cf_remove_local_files', $files_to_remove, $as3cf_item, $as3cf_item->get_item_source_array() );
|
103 |
+
|
104 |
+
// Ensure fileset is unique and does not contain files already blocked.
|
105 |
+
$filtered_files_to_remove = array_unique( array_diff( $filtered_files_to_remove, $this->remove_blocked ) );
|
106 |
+
|
107 |
+
// If filter removes files from list, block attempts to remove them in later calls.
|
108 |
+
$this->remove_blocked = array_merge( $this->remove_blocked, array_diff( $files_to_remove, $filtered_files_to_remove ) );
|
109 |
+
|
110 |
+
foreach ( $filtered_files_to_remove as $file ) {
|
111 |
+
// Filter may have added some files to check for existence.
|
112 |
+
if ( ! in_array( $file, $files_to_remove ) ) {
|
113 |
+
if ( ! file_exists( $file ) ) {
|
114 |
+
continue;
|
115 |
+
}
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Filter individual files that might still be kept local.
|
120 |
+
*
|
121 |
+
* @param bool $preserve Should the file be kept on the server?
|
122 |
+
* @param string $file Full path to the local file
|
123 |
+
*/
|
124 |
+
if ( false !== apply_filters( 'as3cf_preserve_file_from_local_removal', false, $file ) ) {
|
125 |
+
$this->remove_blocked[] = $file;
|
126 |
+
continue;
|
127 |
+
}
|
128 |
+
|
129 |
+
$manifest->objects[] = array(
|
130 |
+
'file' => $file,
|
131 |
+
'size' => filesize( $file ),
|
132 |
+
'is_primary' => $file === $primary_file,
|
133 |
+
);
|
134 |
+
}
|
135 |
+
|
136 |
+
return $manifest;
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Delete local files described in the manifest object array.
|
141 |
+
*
|
142 |
+
* @param Item $as3cf_item
|
143 |
+
* @param Manifest $manifest
|
144 |
+
* @param array $options
|
145 |
+
*
|
146 |
+
* @return bool|WP_Error
|
147 |
+
*/
|
148 |
+
protected function handle_item( Item $as3cf_item, Manifest $manifest, array $options ) {
|
149 |
+
foreach ( $manifest->objects as &$file_to_remove ) {
|
150 |
+
$file = $file_to_remove['file'];
|
151 |
+
|
152 |
+
$file_to_remove['remove_result'] = array( 'status' => self::STATUS_OK );
|
153 |
+
|
154 |
+
if ( ! @unlink( $file ) ) {
|
155 |
+
$this->remove_blocked[] = $file;
|
156 |
+
|
157 |
+
$file_to_remove['remove_result']['status'] = self::STATUS_FAILED;
|
158 |
+
$file_to_remove['remove_result']['message'] = "Error removing local file at $file";
|
159 |
+
|
160 |
+
if ( ! file_exists( $file ) ) {
|
161 |
+
$file_to_remove['remove_result']['message'] = "Error removing local file. Couldn't find the file at $file";
|
162 |
+
} else if ( ! is_writable( $file ) ) {
|
163 |
+
$file_to_remove['remove_result']['message'] = "Error removing local file. Ownership or permissions are mis-configured for $file";
|
164 |
+
}
|
165 |
+
}
|
166 |
+
}
|
167 |
+
|
168 |
+
return true;
|
169 |
+
}
|
170 |
+
|
171 |
+
/**
|
172 |
+
* Perform post handle tasks.
|
173 |
+
*
|
174 |
+
* @param Item $as3cf_item
|
175 |
+
* @param Manifest $manifest
|
176 |
+
* @param array $options
|
177 |
+
*
|
178 |
+
* @return bool|WP_Error
|
179 |
+
*/
|
180 |
+
protected function post_handle( Item $as3cf_item, Manifest $manifest, array $options ) {
|
181 |
+
if ( empty( $manifest->objects ) ) {
|
182 |
+
return true;
|
183 |
+
}
|
184 |
+
|
185 |
+
// Assume we didn't touch the primary file.
|
186 |
+
$this->removed_primary_size[ $as3cf_item->source_id() ] = 0;
|
187 |
+
|
188 |
+
foreach ( $manifest->objects as $file_to_remove ) {
|
189 |
+
if ( $file_to_remove['remove_result']['status'] !== self::STATUS_OK ) {
|
190 |
+
AS3CF_Error::log( $file_to_remove['remove_result']['message'] );
|
191 |
+
continue;
|
192 |
+
}
|
193 |
+
|
194 |
+
if ( empty( $this->removed_size[ $as3cf_item->source_id() ] ) ) {
|
195 |
+
$this->removed_size[ $as3cf_item->source_id() ] = $file_to_remove['size'];
|
196 |
+
} else {
|
197 |
+
$this->removed_size[ $as3cf_item->source_id() ] += $file_to_remove['size'];
|
198 |
+
}
|
199 |
+
|
200 |
+
if ( $file_to_remove['is_primary'] ) {
|
201 |
+
$this->removed_primary_size[ $as3cf_item->source_id() ] = $file_to_remove['size'];
|
202 |
+
}
|
203 |
+
}
|
204 |
+
|
205 |
+
$as3cf_item->update_filesize_after_remove_local( $this->removed_primary_size[ $as3cf_item->source_id() ], $this->removed_size[ $as3cf_item->source_id() ] );
|
206 |
+
|
207 |
+
return true;
|
208 |
+
}
|
209 |
+
}
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
+
|
5 |
+
use AS3CF_Error;
|
6 |
+
use Exception;
|
7 |
+
use WP_Error;
|
8 |
+
|
9 |
+
class Remove_Provider_Handler extends Item_Handler {
|
10 |
+
/**
|
11 |
+
* @var string
|
12 |
+
*/
|
13 |
+
protected static $item_handler_key = 'remove-provider';
|
14 |
+
|
15 |
+
/**
|
16 |
+
* The default options that should be used if none supplied.
|
17 |
+
*
|
18 |
+
* @return array
|
19 |
+
*/
|
20 |
+
public static function default_options() {
|
21 |
+
return array(
|
22 |
+
'object_keys' => array(),
|
23 |
+
'offloaded_files' => array(),
|
24 |
+
);
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Create manifest for removal from provider.
|
29 |
+
*
|
30 |
+
* @param Item $as3cf_item
|
31 |
+
* @param array $options
|
32 |
+
*
|
33 |
+
* @return Manifest|WP_Error
|
34 |
+
*/
|
35 |
+
protected function pre_handle( Item $as3cf_item, array $options ) {
|
36 |
+
$manifest = new Manifest();
|
37 |
+
$paths = array();
|
38 |
+
|
39 |
+
if ( ! empty( $options['object_keys'] ) && ! is_array( $options['object_keys'] ) ) {
|
40 |
+
return new WP_Error( 'remove-error', __( 'Invalid object_keys option provided.', 'amazon-s3-and-cloudfront' ) );
|
41 |
+
}
|
42 |
+
|
43 |
+
if ( ! empty( $options['offloaded_files'] ) && ! is_array( $options['offloaded_files'] ) ) {
|
44 |
+
return new WP_Error( 'remove-error', __( 'Invalid offloaded_files option provided.', 'amazon-s3-and-cloudfront' ) );
|
45 |
+
}
|
46 |
+
|
47 |
+
if ( ! empty( $options['object_keys'] ) && ! empty( $options['offloaded_files'] ) ) {
|
48 |
+
return new WP_Error( 'remove-error', __( 'Providing both object_keys and offloaded_files options is not supported.', 'amazon-s3-and-cloudfront' ) );
|
49 |
+
}
|
50 |
+
|
51 |
+
if ( empty( $options['offloaded_files'] ) ) {
|
52 |
+
foreach ( $as3cf_item->objects() as $object_key => $object ) {
|
53 |
+
if ( 0 < count( $options['object_keys'] ) && ! in_array( $object_key, $options['object_keys'] ) ) {
|
54 |
+
continue;
|
55 |
+
}
|
56 |
+
$paths[ $object_key ] = $as3cf_item->full_source_path( $object_key );
|
57 |
+
}
|
58 |
+
} else {
|
59 |
+
foreach ( $options['offloaded_files'] as $filename => $object ) {
|
60 |
+
$paths[ $filename ] = $as3cf_item->full_source_path_for_filename( $filename );
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Filters array of source files before being removed from provider.
|
66 |
+
*
|
67 |
+
* @param array $paths Array of local paths to be removed from provider
|
68 |
+
* @param Item $as3cf_item The Item object
|
69 |
+
* @param array $item_source The item source descriptor array
|
70 |
+
*/
|
71 |
+
$paths = apply_filters( 'as3cf_remove_source_files_from_provider', $paths, $as3cf_item, $as3cf_item->get_item_source_array() );
|
72 |
+
$paths = array_unique( $paths );
|
73 |
+
|
74 |
+
// Remove local source paths that other items may have offloaded.
|
75 |
+
$paths = $as3cf_item->remove_duplicate_paths( $as3cf_item, $paths );
|
76 |
+
|
77 |
+
// Nothing to do, shortcut out.
|
78 |
+
if ( empty( $paths ) ) {
|
79 |
+
return $manifest;
|
80 |
+
}
|
81 |
+
|
82 |
+
if ( empty( $options['offloaded_files'] ) ) {
|
83 |
+
foreach ( $paths as $object_key => $path ) {
|
84 |
+
$manifest->objects[] = array(
|
85 |
+
'Key' => $as3cf_item->provider_key( $object_key ),
|
86 |
+
);
|
87 |
+
}
|
88 |
+
} else {
|
89 |
+
foreach ( $paths as $filename => $path ) {
|
90 |
+
$manifest->objects[] = array(
|
91 |
+
'Key' => $as3cf_item->provider_key_for_filename( $filename, $options['offloaded_files'][ $filename ]['is_private'] ),
|
92 |
+
);
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
return $manifest;
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Delete provider objects described in the manifest object array
|
101 |
+
*
|
102 |
+
* @param Item $as3cf_item
|
103 |
+
* @param Manifest $manifest
|
104 |
+
* @param array $options
|
105 |
+
*
|
106 |
+
* @return bool|WP_Error
|
107 |
+
*/
|
108 |
+
protected function handle_item( Item $as3cf_item, Manifest $manifest, array $options ) {
|
109 |
+
$chunks = array_chunk( $manifest->objects, 1000 );
|
110 |
+
$region = $as3cf_item->region();
|
111 |
+
$bucket = $as3cf_item->bucket();
|
112 |
+
|
113 |
+
try {
|
114 |
+
foreach ( $chunks as $chunk ) {
|
115 |
+
$this->as3cf->get_provider_client( $region )->delete_objects( array(
|
116 |
+
'Bucket' => $bucket,
|
117 |
+
'Objects' => $chunk,
|
118 |
+
) );
|
119 |
+
}
|
120 |
+
} catch ( Exception $e ) {
|
121 |
+
AS3CF_Error::log( 'Error removing files from bucket: ' . $e->getMessage() );
|
122 |
+
|
123 |
+
return new WP_Error( 'remove-error', $e->getMessage() );
|
124 |
+
}
|
125 |
+
|
126 |
+
return true;
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Perform post handle tasks.
|
131 |
+
*
|
132 |
+
* @param Item $as3cf_item
|
133 |
+
* @param Manifest $manifest
|
134 |
+
* @param array $options
|
135 |
+
*
|
136 |
+
* @return bool|WP_Error
|
137 |
+
*/
|
138 |
+
protected function post_handle( Item $as3cf_item, Manifest $manifest, array $options ) {
|
139 |
+
return true;
|
140 |
+
}
|
141 |
+
}
|
@@ -0,0 +1,449 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Items;
|
4 |
+
|
5 |
+
use AS3CF_Error;
|
6 |
+
use AS3CF_Utils;
|
7 |
+
use Exception;
|
8 |
+
use WP_Error;
|
9 |
+
|
10 |
+
class Upload_Handler extends Item_Handler {
|
11 |
+
/**
|
12 |
+
* @var string
|
13 |
+
*/
|
14 |
+
protected static $item_handler_key = 'upload';
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Keep track of individual files we've already attempted to upload
|
18 |
+
*
|
19 |
+
* @var array
|
20 |
+
*/
|
21 |
+
protected $attempted_upload = array();
|
22 |
+
|
23 |
+
/**
|
24 |
+
* The default options that should be used if none supplied.
|
25 |
+
*
|
26 |
+
* @return array
|
27 |
+
*/
|
28 |
+
public static function default_options() {
|
29 |
+
return array(
|
30 |
+
'offloaded_files' => array(),
|
31 |
+
);
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Prepare item for uploading by running filters, updating
|
36 |
+
*
|
37 |
+
* @param Item $as3cf_item
|
38 |
+
* @param array $options
|
39 |
+
*
|
40 |
+
* @return Manifest|WP_Error
|
41 |
+
*/
|
42 |
+
protected function pre_handle( Item $as3cf_item, array $options ) {
|
43 |
+
$manifest = new Manifest();
|
44 |
+
$source_type_name = $this->as3cf->get_source_type_name( $as3cf_item->source_type() );
|
45 |
+
$primary_key = Item::primary_object_key();
|
46 |
+
|
47 |
+
// Check for valid file path before attempting upload
|
48 |
+
if ( empty( $as3cf_item->source_path() ) ) {
|
49 |
+
$error_msg = sprintf( __( '%s with id %d does not have a valid file path', 'amazon-s3-and-cloudfront' ), $source_type_name, $as3cf_item->source_id() );
|
50 |
+
|
51 |
+
return $this->return_handler_error( $error_msg );
|
52 |
+
}
|
53 |
+
|
54 |
+
// Ensure path is a string
|
55 |
+
if ( ! is_string( $as3cf_item->source_path() ) ) {
|
56 |
+
$error_msg = sprintf( __( '%s with id %d. Provided path is not a string', 'amazon-s3-and-cloudfront' ), $source_type_name, $as3cf_item->source_id() );
|
57 |
+
|
58 |
+
return $this->return_handler_error( $error_msg );
|
59 |
+
}
|
60 |
+
|
61 |
+
// Ensure primary source file exists for new offload.
|
62 |
+
if ( empty( $as3cf_item->id() ) && ! file_exists( $as3cf_item->full_source_path( $primary_key ) ) ) {
|
63 |
+
$error_msg = sprintf( __( 'Primary file %s does not exist', 'amazon-s3-and-cloudfront' ), $as3cf_item->full_source_path( $primary_key ) );
|
64 |
+
|
65 |
+
return $this->return_handler_error( $error_msg );
|
66 |
+
}
|
67 |
+
|
68 |
+
// Get primary file's stats.
|
69 |
+
$file_name = wp_basename( $as3cf_item->source_path() );
|
70 |
+
$file_type = wp_check_filetype_and_ext( $as3cf_item->source_path(), $file_name );
|
71 |
+
$allowed_types = $this->as3cf->get_allowed_mime_types();
|
72 |
+
|
73 |
+
// check mime type of file is in allowed provider mime types
|
74 |
+
if ( ! in_array( $file_type['type'], $allowed_types, true ) ) {
|
75 |
+
$error_msg = sprintf( __( 'Mime type %s is not allowed', 'amazon-s3-and-cloudfront' ), $file_type['type'] );
|
76 |
+
|
77 |
+
return $this->return_handler_error( $error_msg );
|
78 |
+
}
|
79 |
+
|
80 |
+
$default_acl = $this->as3cf->get_storage_provider()->get_default_acl();
|
81 |
+
$private_acl = $this->as3cf->get_storage_provider()->get_private_acl();
|
82 |
+
|
83 |
+
foreach ( $as3cf_item->objects() as $object_key => $object ) {
|
84 |
+
// Avoid attempting uploading to an item that doesn't have the primary file in place.
|
85 |
+
if ( $primary_key !== $object_key && empty( $as3cf_item->id() ) && ! isset( $manifest->objects[ $primary_key ] ) ) {
|
86 |
+
continue;
|
87 |
+
}
|
88 |
+
|
89 |
+
$source_path = $as3cf_item->full_source_path( $object_key );
|
90 |
+
|
91 |
+
// If the file has already been offloaded,
|
92 |
+
// don't try and (fail to) re-offload if the file isn't available.
|
93 |
+
if ( $this->in_offloaded_files( $object['source_file'], $options ) && ! file_exists( $source_path ) ) {
|
94 |
+
continue;
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* This filter allows you to change the public/private status of an individual file associated
|
99 |
+
* with an uploaded item before it's uploaded to the provider.
|
100 |
+
*
|
101 |
+
* @param bool $is_private Should the object be private?
|
102 |
+
* @param string $object_key A unique file identifier for a composite item, e.g. image's "size" such as full, small, medium, large.
|
103 |
+
* @param Item $as3cf_item The item being uploaded.
|
104 |
+
*
|
105 |
+
* @return bool
|
106 |
+
*/
|
107 |
+
$is_private = apply_filters( 'as3cf_upload_object_key_as_private', $as3cf_item->is_private( $object_key ), $object_key, $as3cf_item );
|
108 |
+
$as3cf_item->set_is_private( $is_private, $object_key );
|
109 |
+
|
110 |
+
$object_acl = $as3cf_item->is_private( $object_key ) ? $private_acl : $default_acl;
|
111 |
+
|
112 |
+
$args = array(
|
113 |
+
'Bucket' => $as3cf_item->bucket(),
|
114 |
+
'Key' => $as3cf_item->path( $object_key ),
|
115 |
+
'SourceFile' => $source_path,
|
116 |
+
'ContentType' => AS3CF_Utils::get_mime_type( $object['source_file'] ),
|
117 |
+
'CacheControl' => 'max-age=31536000',
|
118 |
+
);
|
119 |
+
|
120 |
+
// Only set ACL if actually required, some storage provider and bucket settings disable changing ACL.
|
121 |
+
if ( ! empty( $object_acl ) && $this->as3cf->use_acl_for_intermediate_size( 0, $object_key, $as3cf_item->bucket(), $as3cf_item ) ) {
|
122 |
+
$args['ACL'] = $object_acl;
|
123 |
+
}
|
124 |
+
|
125 |
+
// TODO: Remove GZIP functionality.
|
126 |
+
// Handle gzip on supported items
|
127 |
+
if (
|
128 |
+
$this->should_gzip_file( $source_path, $as3cf_item->source_type() ) &&
|
129 |
+
false !== ( $gzip_body = gzencode( file_get_contents( $source_path ) ) )
|
130 |
+
) {
|
131 |
+
unset( $args['SourceFile'] );
|
132 |
+
|
133 |
+
$args['Body'] = $gzip_body;
|
134 |
+
$args['ContentEncoding'] = 'gzip';
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* This filter allows you to change the arguments passed to the cloud storage SDK client when
|
139 |
+
* offloading a file to the bucket.
|
140 |
+
*
|
141 |
+
* Note: It is possible to change the destination 'Bucket' only while processing the primary object_key.
|
142 |
+
* All other object_keys will use the same bucket as the item's primary object.
|
143 |
+
* The 'Key' should be the "public" Key path. If a private prefix is configured
|
144 |
+
* for use with signed CloudFront URLs or similar, that prefix will be added later.
|
145 |
+
* A change to the 'Key' will only be handled when processing the primary object key.
|
146 |
+
*
|
147 |
+
* @param array $args Information to be sent to storage provider during offload (e.g. PutObject)
|
148 |
+
* @param int $source_id Original file's unique ID for its source type
|
149 |
+
* @param string $object_key A unique file identifier for a composite item, e.g. image's "size" such as full, small, medium, large
|
150 |
+
* @param bool $copy True if the object is being copied between buckets
|
151 |
+
* @param array $item_source Item source array containing source type and id
|
152 |
+
*
|
153 |
+
* @return array
|
154 |
+
*/
|
155 |
+
$args = apply_filters( 'as3cf_object_meta', $args, $as3cf_item->source_id(), $object_key, false, $as3cf_item->get_item_source_array() );
|
156 |
+
|
157 |
+
// If the bucket is changed by the filter while processing the primary object,
|
158 |
+
// we should try and use that bucket for the item.
|
159 |
+
// If the bucket name is invalid, revert to configured bucket but log it.
|
160 |
+
// We don't abort here as ephemeral filesystems need to be accounted for,
|
161 |
+
// and the configured bucket is at least known to work.
|
162 |
+
if ( $primary_key === $object_key && $as3cf_item->bucket() !== $args['Bucket'] && empty( $as3cf_item->id() ) ) {
|
163 |
+
$bucket = $this->as3cf->check_bucket( $args['Bucket'] );
|
164 |
+
|
165 |
+
if ( $bucket ) {
|
166 |
+
$region = $this->as3cf->get_bucket_region( $bucket, true );
|
167 |
+
|
168 |
+
if ( is_wp_error( $region ) ) {
|
169 |
+
unset( $region );
|
170 |
+
}
|
171 |
+
}
|
172 |
+
|
173 |
+
if ( empty( $bucket ) || empty( $region ) ) {
|
174 |
+
$mesg = sprintf(
|
175 |
+
__( 'Bucket name "%1$s" is invalid, using "%2$s" instead.', 'amazon-s3-and-cloudfront' ),
|
176 |
+
$args['Bucket'],
|
177 |
+
$as3cf_item->bucket()
|
178 |
+
);
|
179 |
+
AS3CF_Error::log( $mesg );
|
180 |
+
$args['Bucket'] = $as3cf_item->bucket();
|
181 |
+
} else {
|
182 |
+
$args['Bucket'] = $bucket;
|
183 |
+
$as3cf_item->set_bucket( $bucket );
|
184 |
+
$as3cf_item->set_region( $region );
|
185 |
+
}
|
186 |
+
|
187 |
+
unset( $bucket, $region );
|
188 |
+
} elseif ( $primary_key === $object_key && $as3cf_item->bucket() !== $args['Bucket'] && ! empty( $as3cf_item->id() ) ) {
|
189 |
+
$args['Bucket'] = $as3cf_item->bucket();
|
190 |
+
AS3CF_Error::log( __( 'The bucket may not be changed via filters for a previously offloaded item.', 'amazon-s3-and-cloudfront' ) );
|
191 |
+
} elseif ( $primary_key !== $object_key && $as3cf_item->bucket() !== $args['Bucket'] ) {
|
192 |
+
$args['Bucket'] = $as3cf_item->bucket();
|
193 |
+
}
|
194 |
+
|
195 |
+
// If the Key has been changed for the primary object key, then that should be reflected in the item.
|
196 |
+
if ( $primary_key === $object_key && $as3cf_item->path( $object_key ) !== $args['Key'] && empty( $as3cf_item->id() ) ) {
|
197 |
+
$prefix = AS3CF_Utils::trailingslash_prefix( dirname( $args['Key'] ) );
|
198 |
+
|
199 |
+
if ( $prefix === '.' ) {
|
200 |
+
$prefix = '';
|
201 |
+
}
|
202 |
+
|
203 |
+
$as3cf_item->update_path_prefix( $prefix );
|
204 |
+
|
205 |
+
// If the filter tried to use a different filename too, log it.
|
206 |
+
if ( wp_basename( $args['Key'] ) !== wp_basename( $as3cf_item->path( $object_key ) ) ) {
|
207 |
+
$mesg = sprintf(
|
208 |
+
__( 'The offloaded filename must not be changed, "%1$s" has been used instead of "%2$s".', 'amazon-s3-and-cloudfront' ),
|
209 |
+
wp_basename( $as3cf_item->path( $object_key ) ),
|
210 |
+
wp_basename( $args['Key'] )
|
211 |
+
);
|
212 |
+
AS3CF_Error::log( $mesg );
|
213 |
+
}
|
214 |
+
} elseif ( $primary_key === $object_key && $as3cf_item->path( $object_key ) !== $args['Key'] && ! empty( $as3cf_item->id() ) ) {
|
215 |
+
$args['Key'] = $as3cf_item->path( $object_key );
|
216 |
+
AS3CF_Error::log( __( 'The key may not be changed via filters for a previously offloaded item.', 'amazon-s3-and-cloudfront' ) );
|
217 |
+
} elseif ( $primary_key !== $object_key && $as3cf_item->path( $object_key ) !== $args['Key'] ) {
|
218 |
+
$args['Key'] = $as3cf_item->path( $object_key );
|
219 |
+
}
|
220 |
+
|
221 |
+
// If ACL has been set, does the object's is_private need updating?
|
222 |
+
$is_private = ! empty( $args['ACL'] ) && $private_acl === $args['ACL'] || $as3cf_item->is_private( $object_key );
|
223 |
+
$as3cf_item->set_is_private( $is_private, $object_key );
|
224 |
+
|
225 |
+
// Protect against filter use and only set ACL if actually required, some storage provider and bucket settings disable changing ACL.
|
226 |
+
if ( isset( $args['ACL'] ) && ! $this->as3cf->use_acl_for_intermediate_size( 0, $object_key, $as3cf_item->bucket(), $as3cf_item ) ) {
|
227 |
+
unset( $args['ACL'] );
|
228 |
+
}
|
229 |
+
|
230 |
+
// Adjust the actual Key to add the private prefix before uploading.
|
231 |
+
if ( $as3cf_item->is_private( $object_key ) ) {
|
232 |
+
$args['Key'] = $as3cf_item->provider_key( $object_key );
|
233 |
+
}
|
234 |
+
|
235 |
+
// If we've already attempted to offload this source file, leave it out of the manifest.
|
236 |
+
if ( in_array( md5( serialize( $args ) ), $this->attempted_upload ) ) {
|
237 |
+
continue;
|
238 |
+
}
|
239 |
+
|
240 |
+
if ( $primary_key === $object_key ) {
|
241 |
+
/**
|
242 |
+
* Actions fires when an Item's primary file might be offloaded.
|
243 |
+
*
|
244 |
+
* This action gives notice that an Item is being processed for upload to a bucket,
|
245 |
+
* and the given arguments represent the primary file's potential offload location.
|
246 |
+
* However, if the current process is for picking up extra files associated with the item,
|
247 |
+
* the indicated primary file may not actually be offloaded if it does not exist
|
248 |
+
* on the server but has already been offloaded.
|
249 |
+
*
|
250 |
+
* @param Item $as3cf_item The Item whose files are being offloaded.
|
251 |
+
* @param array $args The arguments that could be used to offload the primary file.
|
252 |
+
*/
|
253 |
+
do_action( 'as3cf_pre_upload_object', $as3cf_item, $args );
|
254 |
+
}
|
255 |
+
|
256 |
+
$manifest->objects[ $object_key ]['args'] = $args;
|
257 |
+
}
|
258 |
+
|
259 |
+
return $manifest;
|
260 |
+
}
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Upload item files to remote storage provider
|
264 |
+
*
|
265 |
+
* @param Item $as3cf_item
|
266 |
+
* @param Manifest $manifest
|
267 |
+
* @param array $options
|
268 |
+
*
|
269 |
+
* @return bool|WP_Error
|
270 |
+
*/
|
271 |
+
protected function handle_item( Item $as3cf_item, Manifest $manifest, array $options ) {
|
272 |
+
try {
|
273 |
+
$provider_client = $this->as3cf->get_provider_client( $as3cf_item->region() );
|
274 |
+
} catch ( Exception $e ) {
|
275 |
+
return $this->return_handler_error( $e->getMessage() );
|
276 |
+
}
|
277 |
+
|
278 |
+
foreach ( $manifest->objects as $object_key => &$object ) {
|
279 |
+
$args = $object['args'];
|
280 |
+
|
281 |
+
$object['upload_result'] = array(
|
282 |
+
'status' => null,
|
283 |
+
'message' => null,
|
284 |
+
);
|
285 |
+
|
286 |
+
if ( ! file_exists( $args['SourceFile'] ) ) {
|
287 |
+
$error_msg = sprintf( __( 'File %s does not exist', 'amazon-s3-and-cloudfront' ), $args['SourceFile'] );
|
288 |
+
|
289 |
+
$object['upload_result']['status'] = self::STATUS_FAILED;
|
290 |
+
$object['upload_result']['message'] = $error_msg;
|
291 |
+
|
292 |
+
// If the missing source file is the primary file, abort the whole process.
|
293 |
+
if ( Item::primary_object_key() === $object_key ) {
|
294 |
+
return false;
|
295 |
+
}
|
296 |
+
|
297 |
+
continue;
|
298 |
+
}
|
299 |
+
|
300 |
+
$this->attempted_upload[] = md5( serialize( $args ) );
|
301 |
+
|
302 |
+
// Try to do the upload
|
303 |
+
try {
|
304 |
+
$provider_client->upload_object( $args );
|
305 |
+
|
306 |
+
$object['upload_result']['status'] = self::STATUS_OK;
|
307 |
+
} catch ( Exception $e ) {
|
308 |
+
$error_msg = sprintf( __( 'Error offloading %1$s to provider: %2$s', 'amazon-s3-and-cloudfront' ), $args['SourceFile'], $e->getMessage() );
|
309 |
+
|
310 |
+
$object['upload_result']['status'] = self::STATUS_FAILED;
|
311 |
+
$object['upload_result']['message'] = $error_msg;
|
312 |
+
}
|
313 |
+
}
|
314 |
+
|
315 |
+
return true;
|
316 |
+
}
|
317 |
+
|
318 |
+
/**
|
319 |
+
* Handle local housekeeping after uploads.
|
320 |
+
*
|
321 |
+
* @param Item $as3cf_item
|
322 |
+
* @param Manifest $manifest
|
323 |
+
* @param array $options
|
324 |
+
*
|
325 |
+
* @return bool|WP_Error
|
326 |
+
*/
|
327 |
+
protected function post_handle( Item $as3cf_item, Manifest $manifest, array $options ) {
|
328 |
+
$item_objects = $as3cf_item->objects();
|
329 |
+
$errors = new WP_Error;
|
330 |
+
$i = 1;
|
331 |
+
|
332 |
+
// Reconcile the Item's objects with their manifest status.
|
333 |
+
foreach ( $item_objects as $object_key => $object ) {
|
334 |
+
// If there was no attempt made to offload the file,
|
335 |
+
// then remove it from list of offloaded objects.
|
336 |
+
// However, if the source file has previously been offloaded,
|
337 |
+
// we should just skip any further processing of it
|
338 |
+
// as the associated objects are still offloaded.
|
339 |
+
if ( ! isset( $manifest->objects[ $object_key ]['upload_result']['status'] ) ) {
|
340 |
+
if ( empty( $options['offloaded_files'][ $object['source_file'] ] ) ) {
|
341 |
+
unset( $item_objects[ $object_key ] );
|
342 |
+
}
|
343 |
+
continue;
|
344 |
+
}
|
345 |
+
|
346 |
+
// If the upload didn't succeed, we need to remove the object/size from the item.
|
347 |
+
// However, if the source file has previously been offloaded, we should just log the error.
|
348 |
+
if ( $manifest->objects[ $object_key ]['upload_result']['status'] !== self::STATUS_OK ) {
|
349 |
+
if ( empty( $options['offloaded_files'][ $object['source_file'] ] ) ) {
|
350 |
+
unset( $item_objects[ $object_key ] );
|
351 |
+
}
|
352 |
+
$errors->add( 'upload-object-' . $i++, $manifest->objects[ $object_key ]['upload_result']['message'] );
|
353 |
+
}
|
354 |
+
}
|
355 |
+
|
356 |
+
// Set the potentially changed list of offloaded objects.
|
357 |
+
$as3cf_item->set_objects( $item_objects );
|
358 |
+
|
359 |
+
// Only save if we have the primary file uploaded.
|
360 |
+
if ( isset( $item_objects[ Item::primary_object_key() ] ) ) {
|
361 |
+
$as3cf_item->save();
|
362 |
+
}
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Fires action after uploading finishes
|
366 |
+
*
|
367 |
+
* @param Item $as3cf_item The item that was just uploaded
|
368 |
+
*/
|
369 |
+
do_action( 'as3cf_post_upload_item', $as3cf_item );
|
370 |
+
|
371 |
+
if ( count( $errors->get_error_codes() ) ) {
|
372 |
+
return $errors;
|
373 |
+
}
|
374 |
+
|
375 |
+
return true;
|
376 |
+
}
|
377 |
+
|
378 |
+
/**
|
379 |
+
* Should gzip file
|
380 |
+
*
|
381 |
+
* @param string $file_path
|
382 |
+
* @param string $source_type
|
383 |
+
*
|
384 |
+
* @return bool
|
385 |
+
*/
|
386 |
+
protected function should_gzip_file( $file_path, $source_type ) {
|
387 |
+
$file_type = wp_check_filetype_and_ext( $file_path, $file_path );
|
388 |
+
$mimes = $this->get_mime_types_to_gzip( $source_type );
|
389 |
+
|
390 |
+
if ( in_array( $file_type, $mimes ) && is_readable( $file_path ) ) {
|
391 |
+
return true;
|
392 |
+
}
|
393 |
+
|
394 |
+
return false;
|
395 |
+
}
|
396 |
+
|
397 |
+
/**
|
398 |
+
* Get mime types to gzip
|
399 |
+
*
|
400 |
+
* @param string $source_type
|
401 |
+
*
|
402 |
+
* @return array
|
403 |
+
*/
|
404 |
+
protected function get_mime_types_to_gzip( $source_type ) {
|
405 |
+
/**
|
406 |
+
* Return array of mime types that needs to be gzipped before upload
|
407 |
+
*
|
408 |
+
* @param array $mime_types The array of mime types
|
409 |
+
* @param bool $media_library If the uploaded file is part of the media library
|
410 |
+
* @param string $source_type The source type of the uploaded item
|
411 |
+
*/
|
412 |
+
return apply_filters(
|
413 |
+
'as3cf_gzip_mime_types',
|
414 |
+
array(
|
415 |
+
'css' => 'text/css',
|
416 |
+
'eot' => 'application/vnd.ms-fontobject',
|
417 |
+
'html' => 'text/html',
|
418 |
+
'ico' => 'image/x-icon',
|
419 |
+
'js' => 'application/javascript',
|
420 |
+
'json' => 'application/json',
|
421 |
+
'otf' => 'application/x-font-opentype',
|
422 |
+
'rss' => 'application/rss+xml',
|
423 |
+
'svg' => 'image/svg+xml',
|
424 |
+
'ttf' => 'application/x-font-ttf',
|
425 |
+
'woff' => 'application/font-woff',
|
426 |
+
'woff2' => 'application/font-woff2',
|
427 |
+
'xml' => 'application/xml',
|
428 |
+
),
|
429 |
+
'media_library' === $source_type,
|
430 |
+
$source_type
|
431 |
+
);
|
432 |
+
}
|
433 |
+
|
434 |
+
/**
|
435 |
+
* Has the given file name already been offloaded?
|
436 |
+
*
|
437 |
+
* @param string $filename
|
438 |
+
* @param array $options
|
439 |
+
*
|
440 |
+
* @return bool
|
441 |
+
*/
|
442 |
+
private function in_offloaded_files( $filename, $options ) {
|
443 |
+
if ( empty( $options['offloaded_files'] ) ) {
|
444 |
+
return false;
|
445 |
+
}
|
446 |
+
|
447 |
+
return array_key_exists( $filename, $options['offloaded_files'] );
|
448 |
+
}
|
449 |
+
}
|
@@ -572,11 +572,12 @@ abstract class Storage_Provider extends Provider {
|
|
572 |
/**
|
573 |
* Get object keys from multiple clients.
|
574 |
*
|
575 |
-
* @param array
|
|
|
576 |
*
|
577 |
* @return array
|
578 |
*/
|
579 |
-
public static function get_keys_from_regions( array $regions ) {
|
580 |
$keys = array();
|
581 |
|
582 |
foreach ( $regions as $region ) {
|
@@ -591,7 +592,7 @@ abstract class Storage_Provider extends Provider {
|
|
591 |
|
592 |
if ( ! empty( $region_keys ) ) {
|
593 |
foreach ( $region_keys as $attachment_id => $found_keys ) {
|
594 |
-
$keys[ $attachment_id ] = AS3CF_Utils::validate_attachment_keys( $attachment_id, $found_keys );
|
595 |
}
|
596 |
}
|
597 |
}
|
572 |
/**
|
573 |
* Get object keys from multiple clients.
|
574 |
*
|
575 |
+
* @param array $regions
|
576 |
+
* @param string $source_type
|
577 |
*
|
578 |
* @return array
|
579 |
*/
|
580 |
+
public static function get_keys_from_regions( array $regions, $source_type ) {
|
581 |
$keys = array();
|
582 |
|
583 |
foreach ( $regions as $region ) {
|
592 |
|
593 |
if ( ! empty( $region_keys ) ) {
|
594 |
foreach ( $region_keys as $attachment_id => $found_keys ) {
|
595 |
+
$keys[ $attachment_id ] = AS3CF_Utils::validate_attachment_keys( $attachment_id, $found_keys, $source_type );
|
596 |
}
|
597 |
}
|
598 |
}
|
@@ -2,6 +2,8 @@
|
|
2 |
|
3 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
4 |
|
|
|
|
|
5 |
/**
|
6 |
* Upgrade_EDD_Replace_URLs Class
|
7 |
*
|
@@ -82,7 +84,12 @@ class Upgrade_EDD_Replace_URLs extends Upgrade {
|
|
82 |
continue;
|
83 |
}
|
84 |
|
85 |
-
|
|
|
|
|
|
|
|
|
|
|
86 |
$attachments[ $key ]['file'] = $url;
|
87 |
}
|
88 |
}
|
2 |
|
3 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
4 |
|
5 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
6 |
+
|
7 |
/**
|
8 |
* Upgrade_EDD_Replace_URLs Class
|
9 |
*
|
84 |
continue;
|
85 |
}
|
86 |
|
87 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $attachment['attachment_id'] );
|
88 |
+
if ( empty( $as3cf_item ) ) {
|
89 |
+
continue;
|
90 |
+
}
|
91 |
+
|
92 |
+
if ( $url = $as3cf_item->get_local_url() ) {
|
93 |
$attachments[ $key ]['file'] = $url;
|
94 |
}
|
95 |
}
|
@@ -52,24 +52,25 @@ class Upgrade_File_Sizes extends Upgrade {
|
|
52 |
/**
|
53 |
* Get the total file sizes for an attachment and associated files.
|
54 |
*
|
55 |
-
* @param mixed $
|
56 |
*
|
57 |
* @return bool
|
|
|
58 |
*/
|
59 |
-
protected function upgrade_item( $
|
60 |
-
$provider_object = unserialize( $
|
61 |
if ( false === $provider_object ) {
|
62 |
-
AS3CF_Error::log( 'Failed to unserialize offload meta for attachment ' . $
|
63 |
$this->error_count++;
|
64 |
|
65 |
return false;
|
66 |
}
|
67 |
|
68 |
// Using Media_Library_Item::get_by_source_id falls back to legacy metadata and substitutes in defaults and potentially missing values.
|
69 |
-
$as3cf_item = Media_Library_Item::get_by_source_id( $
|
70 |
|
71 |
if ( ! $as3cf_item ) {
|
72 |
-
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $
|
73 |
$this->error_count++;
|
74 |
|
75 |
return false;
|
@@ -96,7 +97,7 @@ class Upgrade_File_Sizes extends Upgrade {
|
|
96 |
// List objects for the attachment
|
97 |
$result = $provider_client->list_objects( $args );
|
98 |
} catch ( Exception $e ) {
|
99 |
-
AS3CF_Error::log( 'Error listing objects of prefix ' . $search_prefix . ' for attachment ' . $
|
100 |
$this->error_count++;
|
101 |
|
102 |
return false;
|
@@ -124,19 +125,19 @@ class Upgrade_File_Sizes extends Upgrade {
|
|
124 |
}
|
125 |
|
126 |
if ( 0 === $file_size_total ) {
|
127 |
-
AS3CF_Error::log( 'Total file size for the attachment is 0: ' . $
|
128 |
$this->error_count++;
|
129 |
|
130 |
return false;
|
131 |
}
|
132 |
|
133 |
// Update the main file size for the attachment
|
134 |
-
$meta = get_post_meta( $
|
135 |
$meta['filesize'] = $main_file_size;
|
136 |
-
update_post_meta( $
|
137 |
|
138 |
// Add the total file size for all image sizes
|
139 |
-
update_post_meta( $
|
140 |
|
141 |
return true;
|
142 |
}
|
52 |
/**
|
53 |
* Get the total file sizes for an attachment and associated files.
|
54 |
*
|
55 |
+
* @param mixed $item
|
56 |
*
|
57 |
* @return bool
|
58 |
+
* @throws Exception
|
59 |
*/
|
60 |
+
protected function upgrade_item( $item ) {
|
61 |
+
$provider_object = unserialize( $item->provider_object );
|
62 |
if ( false === $provider_object ) {
|
63 |
+
AS3CF_Error::log( 'Failed to unserialize offload meta for attachment ' . $item->ID . ': ' . $item->provider_object );
|
64 |
$this->error_count++;
|
65 |
|
66 |
return false;
|
67 |
}
|
68 |
|
69 |
// Using Media_Library_Item::get_by_source_id falls back to legacy metadata and substitutes in defaults and potentially missing values.
|
70 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $item->ID );
|
71 |
|
72 |
if ( ! $as3cf_item ) {
|
73 |
+
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $item->ID . ' from legacy offload metadata.' );
|
74 |
$this->error_count++;
|
75 |
|
76 |
return false;
|
97 |
// List objects for the attachment
|
98 |
$result = $provider_client->list_objects( $args );
|
99 |
} catch ( Exception $e ) {
|
100 |
+
AS3CF_Error::log( 'Error listing objects of prefix ' . $search_prefix . ' for attachment ' . $item->ID . ' in bucket: ' . $e->getMessage() );
|
101 |
$this->error_count++;
|
102 |
|
103 |
return false;
|
125 |
}
|
126 |
|
127 |
if ( 0 === $file_size_total ) {
|
128 |
+
AS3CF_Error::log( 'Total file size for the attachment is 0: ' . $item->ID );
|
129 |
$this->error_count++;
|
130 |
|
131 |
return false;
|
132 |
}
|
133 |
|
134 |
// Update the main file size for the attachment
|
135 |
+
$meta = get_post_meta( $item->ID, '_wp_attachment_metadata', true );
|
136 |
$meta['filesize'] = $main_file_size;
|
137 |
+
update_post_meta( $item->ID, '_wp_attachment_metadata', $meta );
|
138 |
|
139 |
// Add the total file size for all image sizes
|
140 |
+
update_post_meta( $item->ID, 'wpos3_filesize_total', $file_size_total );
|
141 |
|
142 |
return true;
|
143 |
}
|
@@ -3,6 +3,7 @@
|
|
3 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
4 |
|
5 |
use AS3CF_Utils;
|
|
|
6 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\Batch_Limits_Exceeded_Exception;
|
7 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\Too_Many_Errors_Exception;
|
8 |
|
@@ -110,37 +111,34 @@ abstract class Upgrade_Filter_Post extends Upgrade {
|
|
110 |
}
|
111 |
|
112 |
/**
|
113 |
-
* Upgrade
|
114 |
*
|
115 |
-
* @param mixed $
|
116 |
*
|
117 |
* @return bool
|
118 |
* @throws Batch_Limits_Exceeded_Exception
|
119 |
* @throws Too_Many_Errors_Exception
|
120 |
*
|
121 |
*/
|
122 |
-
protected function upgrade_item( $
|
123 |
$limit = apply_filters( 'as3cf_update_' . $this->upgrade_name . '_sql_limit', 100000 );
|
124 |
$where_highest_id = $this->last_post_id;
|
125 |
$where_lowest_id = max( $where_highest_id - $limit, 0 );
|
126 |
|
127 |
while ( true ) {
|
128 |
-
$this->find_and_replace_attachment_urls( $
|
129 |
|
130 |
if ( $where_lowest_id <= 0 ) {
|
131 |
// Batch completed
|
132 |
return true;
|
133 |
}
|
134 |
|
135 |
-
$where_highest_id
|
136 |
-
$where_lowest_id
|
|
|
137 |
|
138 |
$this->check_batch_limits();
|
139 |
}
|
140 |
-
|
141 |
-
$this->last_post_id = $where_lowest_id;
|
142 |
-
|
143 |
-
return false;
|
144 |
}
|
145 |
|
146 |
/**
|
@@ -161,12 +159,17 @@ abstract class Upgrade_Filter_Post extends Upgrade {
|
|
161 |
* @param int $where_highest_id
|
162 |
*/
|
163 |
protected function find_and_replace_attachment_urls( $attachment_id, $where_lowest_id, $where_highest_id ) {
|
164 |
-
$meta
|
165 |
-
$backups
|
166 |
-
$file_path
|
|
|
|
|
|
|
|
|
|
|
167 |
|
168 |
-
$new_url = $
|
169 |
-
$old_url = $this->as3cf->maybe_remove_query_string( $
|
170 |
|
171 |
if ( empty( $old_url ) || empty( $new_url ) ) {
|
172 |
return;
|
3 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
4 |
|
5 |
use AS3CF_Utils;
|
6 |
+
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
7 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\Batch_Limits_Exceeded_Exception;
|
8 |
use DeliciousBrains\WP_Offload_Media\Upgrades\Exceptions\Too_Many_Errors_Exception;
|
9 |
|
111 |
}
|
112 |
|
113 |
/**
|
114 |
+
* Upgrade item.
|
115 |
*
|
116 |
+
* @param mixed $item
|
117 |
*
|
118 |
* @return bool
|
119 |
* @throws Batch_Limits_Exceeded_Exception
|
120 |
* @throws Too_Many_Errors_Exception
|
121 |
*
|
122 |
*/
|
123 |
+
protected function upgrade_item( $item ) {
|
124 |
$limit = apply_filters( 'as3cf_update_' . $this->upgrade_name . '_sql_limit', 100000 );
|
125 |
$where_highest_id = $this->last_post_id;
|
126 |
$where_lowest_id = max( $where_highest_id - $limit, 0 );
|
127 |
|
128 |
while ( true ) {
|
129 |
+
$this->find_and_replace_attachment_urls( $item->ID, $where_lowest_id, $where_highest_id );
|
130 |
|
131 |
if ( $where_lowest_id <= 0 ) {
|
132 |
// Batch completed
|
133 |
return true;
|
134 |
}
|
135 |
|
136 |
+
$where_highest_id = $where_lowest_id;
|
137 |
+
$where_lowest_id = max( $where_lowest_id - $limit, 0 );
|
138 |
+
$this->last_post_id = $where_lowest_id;
|
139 |
|
140 |
$this->check_batch_limits();
|
141 |
}
|
|
|
|
|
|
|
|
|
142 |
}
|
143 |
|
144 |
/**
|
159 |
* @param int $where_highest_id
|
160 |
*/
|
161 |
protected function find_and_replace_attachment_urls( $attachment_id, $where_lowest_id, $where_highest_id ) {
|
162 |
+
$meta = wp_get_attachment_metadata( $attachment_id, true );
|
163 |
+
$backups = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
|
164 |
+
$file_path = get_attached_file( $attachment_id, true );
|
165 |
+
$as3cf_item = Item::get_by_source_id( $attachment_id );
|
166 |
+
|
167 |
+
if ( empty( $as3cf_item ) ) {
|
168 |
+
return;
|
169 |
+
}
|
170 |
|
171 |
+
$new_url = $as3cf_item->get_local_url();
|
172 |
+
$old_url = $this->as3cf->maybe_remove_query_string( $as3cf_item->get_provider_url() );
|
173 |
|
174 |
if ( empty( $old_url ) || empty( $new_url ) ) {
|
175 |
return;
|
@@ -0,0 +1,152 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Upgrade extra info in custom objects table.
|
4 |
+
*
|
5 |
+
* @package amazon-s3-and-cloudfront
|
6 |
+
* @subpackage Classes/Upgrades/Upgrade_Item_Extra_Data
|
7 |
+
* @copyright Copyright (c) 2021, Delicious Brains
|
8 |
+
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
|
9 |
+
* @since 2.6.0
|
10 |
+
*/
|
11 |
+
|
12 |
+
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
13 |
+
|
14 |
+
use AS3CF_Error;
|
15 |
+
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
16 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Upgrade_Item_Extra_Data Class
|
20 |
+
*
|
21 |
+
* This class handles updating extra info in the custom objects table.
|
22 |
+
*
|
23 |
+
* @since 2.6.0
|
24 |
+
*/
|
25 |
+
class Upgrade_Item_Extra_Data extends Upgrade {
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @var int
|
29 |
+
*/
|
30 |
+
protected $upgrade_id = 10;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* @var string
|
34 |
+
*/
|
35 |
+
protected $upgrade_name = 'item_extra_data';
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @var string 'metadata', 'attachment'
|
39 |
+
*/
|
40 |
+
protected $upgrade_type = 'metadata';
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Get running update text.
|
44 |
+
*
|
45 |
+
* @return string
|
46 |
+
*/
|
47 |
+
protected function get_running_update_text() {
|
48 |
+
return __( 'and updating metadata about offloaded items to new format.', 'amazon-s3-and-cloudfront' );
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Update extra_info in items table
|
53 |
+
*
|
54 |
+
* @param $item
|
55 |
+
*
|
56 |
+
* @return bool
|
57 |
+
*/
|
58 |
+
protected function upgrade_item( $item ) {
|
59 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $item->source_id );
|
60 |
+
|
61 |
+
if ( ! $as3cf_item ) {
|
62 |
+
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $item->source_id . '.' );
|
63 |
+
$this->error_count++;
|
64 |
+
|
65 |
+
return false;
|
66 |
+
}
|
67 |
+
|
68 |
+
$result = $as3cf_item->save();
|
69 |
+
|
70 |
+
if ( is_wp_error( $result ) ) {
|
71 |
+
AS3CF_Error::log( 'Error saving item: ' . $result->get_error_message() );
|
72 |
+
$this->error_count++;
|
73 |
+
|
74 |
+
return false;
|
75 |
+
}
|
76 |
+
|
77 |
+
return true;
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Get a count of all items to be processed.
|
82 |
+
* for the whole site
|
83 |
+
*
|
84 |
+
* @return int
|
85 |
+
*/
|
86 |
+
protected function count_items_to_process() {
|
87 |
+
return $this->count_items_with_old_extra_info( $this->blog_prefix );
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Get all items to be processed.
|
92 |
+
*
|
93 |
+
* @param string $prefix Table prefix for blog.
|
94 |
+
* @param int $limit
|
95 |
+
* @param bool|mixed $offset
|
96 |
+
*
|
97 |
+
* @return array
|
98 |
+
*/
|
99 |
+
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
100 |
+
$attachments = $this->get_items_with_old_extra_info( $prefix, false, $limit );
|
101 |
+
|
102 |
+
return $attachments;
|
103 |
+
}
|
104 |
+
|
105 |
+
/**
|
106 |
+
* Get a count of items that have legacy extra info.
|
107 |
+
*
|
108 |
+
* @param string $prefix Table prefix for blog.
|
109 |
+
*
|
110 |
+
* @return int
|
111 |
+
*/
|
112 |
+
protected function count_items_with_old_extra_info( $prefix ) {
|
113 |
+
$count = $this->get_items_with_old_extra_info( $prefix, true );
|
114 |
+
|
115 |
+
return $count;
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Wrapper for database call to get items with legacy extra info.
|
120 |
+
*
|
121 |
+
* @param string $prefix Table prefix for blog.
|
122 |
+
* @param bool $count return count of attachments
|
123 |
+
* @param null|int $limit
|
124 |
+
*
|
125 |
+
* @return mixed
|
126 |
+
*/
|
127 |
+
protected function get_items_with_old_extra_info( $prefix, $count = false, $limit = null ) {
|
128 |
+
global $wpdb;
|
129 |
+
|
130 |
+
$table = Item::ITEMS_TABLE;
|
131 |
+
|
132 |
+
$sql = "
|
133 |
+
FROM {$prefix}{$table}
|
134 |
+
WHERE extra_info NOT LIKE '%s:7:\"objects\"%' AND source_type='media-library'
|
135 |
+
";
|
136 |
+
|
137 |
+
if ( $count ) {
|
138 |
+
$sql = 'SELECT COUNT(source_id)' . $sql;
|
139 |
+
|
140 |
+
return $wpdb->get_var( $sql );
|
141 |
+
}
|
142 |
+
|
143 |
+
$sql = 'SELECT source_id' . $sql;
|
144 |
+
$sql .= ' ORDER BY id';
|
145 |
+
|
146 |
+
if ( $limit && $limit > 0 ) {
|
147 |
+
$sql .= sprintf( ' LIMIT %d', (int) $limit );
|
148 |
+
}
|
149 |
+
|
150 |
+
return $wpdb->get_results( $sql, OBJECT );
|
151 |
+
}
|
152 |
+
}
|
@@ -12,7 +12,6 @@
|
|
12 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
13 |
|
14 |
use AS3CF_Error;
|
15 |
-
use DeliciousBrains\WP_Offload_Media\Items\Item;
|
16 |
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
17 |
|
18 |
/**
|
@@ -51,23 +50,23 @@ class Upgrade_Items_Table extends Upgrade {
|
|
51 |
/**
|
52 |
* Move an attachment's provider object data from the postmeta table to the custom as3cf_objects table.
|
53 |
*
|
54 |
-
* @param mixed $
|
55 |
*
|
56 |
* @return bool
|
57 |
*/
|
58 |
-
protected function upgrade_item( $
|
59 |
// Make sure legacy metadata isn't broken.
|
60 |
-
$provider_object = unserialize( $
|
61 |
|
62 |
if ( false === $provider_object ) {
|
63 |
-
AS3CF_Error::log( 'Failed to unserialize legacy offload metadata for attachment ' . $
|
64 |
$this->error_count++;
|
65 |
|
66 |
return false;
|
67 |
}
|
68 |
|
69 |
-
if ( empty( $
|
70 |
-
AS3CF_Error::log( 'Attachment with ID ' . $
|
71 |
$this->error_count++;
|
72 |
|
73 |
return false;
|
@@ -77,10 +76,10 @@ class Upgrade_Items_Table extends Upgrade {
|
|
77 |
// If we're here we already know there's legacy metadata and that there isn't a new items table record yet,
|
78 |
// or there's legacy metadata and an existing items table record that we can just re-save without issue before deleting legacy metadata.
|
79 |
// An existing items table entry takes precedence over legacy metadata to avoid accidental overrides from migrations, custom code or other plugins.
|
80 |
-
$as3cf_item = Media_Library_Item::get_by_source_id( $
|
81 |
|
82 |
if ( ! $as3cf_item ) {
|
83 |
-
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $
|
84 |
$this->error_count++;
|
85 |
|
86 |
return false;
|
@@ -96,7 +95,7 @@ class Upgrade_Items_Table extends Upgrade {
|
|
96 |
}
|
97 |
|
98 |
// Delete old metadata.
|
99 |
-
return delete_post_meta( $
|
100 |
}
|
101 |
|
102 |
/**
|
12 |
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
13 |
|
14 |
use AS3CF_Error;
|
|
|
15 |
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
16 |
|
17 |
/**
|
50 |
/**
|
51 |
* Move an attachment's provider object data from the postmeta table to the custom as3cf_objects table.
|
52 |
*
|
53 |
+
* @param mixed $item
|
54 |
*
|
55 |
* @return bool
|
56 |
*/
|
57 |
+
protected function upgrade_item( $item ) {
|
58 |
// Make sure legacy metadata isn't broken.
|
59 |
+
$provider_object = unserialize( $item->provider_object );
|
60 |
|
61 |
if ( false === $provider_object ) {
|
62 |
+
AS3CF_Error::log( 'Failed to unserialize legacy offload metadata for attachment ' . $item->ID . ': ' . $item->provider_object );
|
63 |
$this->error_count++;
|
64 |
|
65 |
return false;
|
66 |
}
|
67 |
|
68 |
+
if ( empty( $item->source_path ) ) {
|
69 |
+
AS3CF_Error::log( 'Attachment with ID ' . $item->ID . ' with legacy offload metadata has no local file path.' );
|
70 |
$this->error_count++;
|
71 |
|
72 |
return false;
|
76 |
// If we're here we already know there's legacy metadata and that there isn't a new items table record yet,
|
77 |
// or there's legacy metadata and an existing items table record that we can just re-save without issue before deleting legacy metadata.
|
78 |
// An existing items table entry takes precedence over legacy metadata to avoid accidental overrides from migrations, custom code or other plugins.
|
79 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $item->ID );
|
80 |
|
81 |
if ( ! $as3cf_item ) {
|
82 |
+
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $item->ID . ' from legacy offload metadata.' );
|
83 |
$this->error_count++;
|
84 |
|
85 |
return false;
|
95 |
}
|
96 |
|
97 |
// Delete old metadata.
|
98 |
+
return delete_post_meta( $item->ID, 'amazonS3_info' );
|
99 |
}
|
100 |
|
101 |
/**
|
@@ -52,20 +52,20 @@ class Upgrade_Meta_WP_Error extends Upgrade {
|
|
52 |
/**
|
53 |
* Rebuild the attachment metadata for an attachment
|
54 |
*
|
55 |
-
* @param mixed $
|
56 |
*
|
57 |
* @return bool
|
58 |
*/
|
59 |
-
protected function upgrade_item( $
|
60 |
-
$provider_object = unserialize( $
|
61 |
if ( false === $provider_object ) {
|
62 |
-
AS3CF_Error::log( 'Failed to unserialize offload meta for attachment ' . $
|
63 |
$this->error_count++;
|
64 |
|
65 |
return false;
|
66 |
}
|
67 |
|
68 |
-
$file = get_attached_file( $
|
69 |
|
70 |
if ( ! file_exists( $file ) ) {
|
71 |
// Copy back the file to the server if doesn't exist so we can successfully
|
@@ -85,11 +85,11 @@ class Upgrade_Meta_WP_Error extends Upgrade {
|
|
85 |
}
|
86 |
|
87 |
// Remove corrupted meta
|
88 |
-
delete_post_meta( $
|
89 |
|
90 |
require_once ABSPATH . '/wp-admin/includes/image.php';
|
91 |
// Generate new attachment meta
|
92 |
-
wp_update_attachment_metadata( $
|
93 |
|
94 |
return true;
|
95 |
}
|
52 |
/**
|
53 |
* Rebuild the attachment metadata for an attachment
|
54 |
*
|
55 |
+
* @param mixed $item
|
56 |
*
|
57 |
* @return bool
|
58 |
*/
|
59 |
+
protected function upgrade_item( $item ) {
|
60 |
+
$provider_object = unserialize( $item->provider_object );
|
61 |
if ( false === $provider_object ) {
|
62 |
+
AS3CF_Error::log( 'Failed to unserialize offload meta for attachment ' . $item->ID . ': ' . $item->provider_object );
|
63 |
$this->error_count++;
|
64 |
|
65 |
return false;
|
66 |
}
|
67 |
|
68 |
+
$file = get_attached_file( $item->ID, true );
|
69 |
|
70 |
if ( ! file_exists( $file ) ) {
|
71 |
// Copy back the file to the server if doesn't exist so we can successfully
|
85 |
}
|
86 |
|
87 |
// Remove corrupted meta
|
88 |
+
delete_post_meta( $item->ID, '_wp_attachment_metadata' );
|
89 |
|
90 |
require_once ABSPATH . '/wp-admin/includes/image.php';
|
91 |
// Generate new attachment meta
|
92 |
+
wp_update_attachment_metadata( $item->ID, wp_generate_attachment_metadata( $item->ID, $file ) );
|
93 |
|
94 |
return true;
|
95 |
}
|
@@ -50,24 +50,24 @@ class Upgrade_Region_Meta extends Upgrade {
|
|
50 |
/**
|
51 |
* Get the region for the bucket where an attachment is located, update the S3 meta.
|
52 |
*
|
53 |
-
* @param mixed $
|
54 |
*
|
55 |
* @return bool
|
56 |
*/
|
57 |
-
protected function upgrade_item( $
|
58 |
-
$provider_object = unserialize( $
|
59 |
if ( false === $provider_object ) {
|
60 |
-
AS3CF_Error::log( 'Failed to unserialize offload meta for attachment ' . $
|
61 |
$this->error_count++;
|
62 |
|
63 |
return false;
|
64 |
}
|
65 |
|
66 |
// Using Media_Library_Item::get_by_source_id falls back to legacy metadata and substitutes in defaults and potentially missing values.
|
67 |
-
$as3cf_item = Media_Library_Item::get_by_source_id( $
|
68 |
|
69 |
if ( ! $as3cf_item ) {
|
70 |
-
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $
|
71 |
$this->error_count++;
|
72 |
|
73 |
return false;
|
@@ -76,10 +76,10 @@ class Upgrade_Region_Meta extends Upgrade {
|
|
76 |
// Update legacy amazonS3_info record with region required for subsequent upgrades.
|
77 |
$provider_object['region'] = $as3cf_item->region();
|
78 |
|
79 |
-
$result = update_post_meta( $
|
80 |
|
81 |
if ( false === $result ) {
|
82 |
-
AS3CF_Error::log( 'Error updating region in legacy offload metadata for attachment ' . $
|
83 |
$this->error_count++;
|
84 |
|
85 |
return false;
|
50 |
/**
|
51 |
* Get the region for the bucket where an attachment is located, update the S3 meta.
|
52 |
*
|
53 |
+
* @param mixed $item
|
54 |
*
|
55 |
* @return bool
|
56 |
*/
|
57 |
+
protected function upgrade_item( $item ) {
|
58 |
+
$provider_object = unserialize( $item->provider_object );
|
59 |
if ( false === $provider_object ) {
|
60 |
+
AS3CF_Error::log( 'Failed to unserialize offload meta for attachment ' . $item->ID . ': ' . $item->provider_object );
|
61 |
$this->error_count++;
|
62 |
|
63 |
return false;
|
64 |
}
|
65 |
|
66 |
// Using Media_Library_Item::get_by_source_id falls back to legacy metadata and substitutes in defaults and potentially missing values.
|
67 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $item->ID );
|
68 |
|
69 |
if ( ! $as3cf_item ) {
|
70 |
+
AS3CF_Error::log( 'Could not construct item for attachment with ID ' . $item->ID . ' from legacy offload metadata.' );
|
71 |
$this->error_count++;
|
72 |
|
73 |
return false;
|
76 |
// Update legacy amazonS3_info record with region required for subsequent upgrades.
|
77 |
$provider_object['region'] = $as3cf_item->region();
|
78 |
|
79 |
+
$result = update_post_meta( $item->ID, 'amazonS3_info', $provider_object );
|
80 |
|
81 |
if ( false === $result ) {
|
82 |
+
AS3CF_Error::log( 'Error updating region in legacy offload metadata for attachment ' . $item->ID );
|
83 |
$this->error_count++;
|
84 |
|
85 |
return false;
|
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace DeliciousBrains\WP_Offload_Media\Upgrades;
|
4 |
+
|
5 |
+
use DeliciousBrains\WP_Offload_Media\Pro\Sidebar_Presenter;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Upgrade_Tools_Errors Class
|
9 |
+
*
|
10 |
+
* This class handles updating internal error info from previous tools executions
|
11 |
+
*
|
12 |
+
* @since 2.6.0
|
13 |
+
*/
|
14 |
+
class Upgrade_Tools_Errors extends Upgrade {
|
15 |
+
|
16 |
+
/**
|
17 |
+
* @var int
|
18 |
+
*/
|
19 |
+
protected $upgrade_id = 9;
|
20 |
+
|
21 |
+
/**
|
22 |
+
* @var string
|
23 |
+
*/
|
24 |
+
protected $upgrade_name = 'tools_error';
|
25 |
+
|
26 |
+
/**
|
27 |
+
* @var string 'metadata', 'attachment'
|
28 |
+
*/
|
29 |
+
protected $upgrade_type = 'metadata';
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Get running update text.
|
33 |
+
*
|
34 |
+
* @return string
|
35 |
+
*/
|
36 |
+
protected function get_running_update_text() {
|
37 |
+
return __( 'and reformatting internal data about previous errors from tools .', 'amazon-s3-and-cloudfront' );
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Get an array of tool names that may have saved error info
|
42 |
+
*
|
43 |
+
* @param string $prefix
|
44 |
+
* @param int $limit
|
45 |
+
* @param bool|mixed $offset
|
46 |
+
*
|
47 |
+
* @return array
|
48 |
+
*/
|
49 |
+
protected function get_items_to_process( $prefix, $limit, $offset = false ) {
|
50 |
+
global $as3cf;
|
51 |
+
|
52 |
+
if ( get_class( $as3cf ) !== 'Amazon_S3_And_CloudFront_Pro' ) {
|
53 |
+
return array();
|
54 |
+
}
|
55 |
+
|
56 |
+
$sidebar_presenter = Sidebar_Presenter::get_instance( $as3cf );
|
57 |
+
$tools = $sidebar_presenter->get_all_tools();
|
58 |
+
|
59 |
+
return array_keys( $tools );
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Update saved errors for a tool.
|
64 |
+
*
|
65 |
+
* @param mixed $item
|
66 |
+
*
|
67 |
+
* @return bool
|
68 |
+
*/
|
69 |
+
protected function upgrade_item( $item ) {
|
70 |
+
global $as3cf;
|
71 |
+
|
72 |
+
if ( empty( $item ) || ! is_string( $item ) ) {
|
73 |
+
// We really don't want to this upgrade to fail,
|
74 |
+
// broken notices can still be dismissed, so just move on.
|
75 |
+
return true;
|
76 |
+
}
|
77 |
+
|
78 |
+
$sidebar_presenter = Sidebar_Presenter::get_instance( $as3cf );
|
79 |
+
$tools = $sidebar_presenter->get_all_tools();
|
80 |
+
|
81 |
+
if ( ! empty( $tools[ $item ] ) ) {
|
82 |
+
$tool = $tools[ $item ];
|
83 |
+
|
84 |
+
$errors = $tool->get_errors();
|
85 |
+
$new_errors = array();
|
86 |
+
|
87 |
+
if ( ! empty( $errors ) ) {
|
88 |
+
foreach ( $errors as $blog_id => $blog ) {
|
89 |
+
foreach ( $blog as $attachment_id => $messages ) {
|
90 |
+
$new_errors[] = (object) array(
|
91 |
+
'blog_id' => $blog_id,
|
92 |
+
'source_type' => 'media-library',
|
93 |
+
'source_id' => $attachment_id,
|
94 |
+
'messages' => (array) $messages,
|
95 |
+
);
|
96 |
+
}
|
97 |
+
}
|
98 |
+
|
99 |
+
$tool->update_errors( $new_errors );
|
100 |
+
}
|
101 |
+
}
|
102 |
+
|
103 |
+
return true;
|
104 |
+
}
|
105 |
+
}
|
@@ -21,7 +21,7 @@ use WP_Error;
|
|
21 |
/**
|
22 |
* Upgrade Class
|
23 |
*
|
24 |
-
* This class handles updates to
|
25 |
*
|
26 |
* @since 0.6.2
|
27 |
*/
|
@@ -113,7 +113,7 @@ abstract class Upgrade {
|
|
113 |
protected $items_processed;
|
114 |
|
115 |
/**
|
116 |
-
* @var mixed Last
|
117 |
*/
|
118 |
protected $last_item;
|
119 |
|
@@ -143,8 +143,8 @@ abstract class Upgrade {
|
|
143 |
protected $session;
|
144 |
|
145 |
const STATUS_RUNNING = 1;
|
146 |
-
const STATUS_ERROR
|
147 |
-
const STATUS_PAUSED
|
148 |
|
149 |
/**
|
150 |
* Start it up
|
@@ -244,13 +244,13 @@ abstract class Upgrade {
|
|
244 |
abstract protected function get_items_to_process( $prefix, $limit, $offset = false );
|
245 |
|
246 |
/**
|
247 |
-
* Upgrade
|
248 |
*
|
249 |
-
* @param mixed $
|
250 |
*
|
251 |
* @return bool
|
252 |
*/
|
253 |
-
abstract protected function upgrade_item( $
|
254 |
|
255 |
/**
|
256 |
* Get running update text.
|
@@ -500,6 +500,7 @@ abstract class Upgrade {
|
|
500 |
* Calculate progress.
|
501 |
*
|
502 |
* @return bool|float
|
|
|
503 |
*/
|
504 |
protected function calculate_progress() {
|
505 |
$this->boot_session();
|
@@ -510,9 +511,9 @@ abstract class Upgrade {
|
|
510 |
} else {
|
511 |
// Set up any per-site state
|
512 |
$this->switch_to_blog( get_current_blog_id() );
|
513 |
-
$counts = Media_Library_Item::
|
514 |
|
515 |
-
// If there are no
|
516 |
// and protect against division by zero.
|
517 |
if ( ! $counts['total'] ) {
|
518 |
return false;
|
21 |
/**
|
22 |
* Upgrade Class
|
23 |
*
|
24 |
+
* This class handles updates to offloaded items.
|
25 |
*
|
26 |
* @since 0.6.2
|
27 |
*/
|
113 |
protected $items_processed;
|
114 |
|
115 |
/**
|
116 |
+
* @var mixed Last item processed.
|
117 |
*/
|
118 |
protected $last_item;
|
119 |
|
143 |
protected $session;
|
144 |
|
145 |
const STATUS_RUNNING = 1;
|
146 |
+
const STATUS_ERROR = 2;
|
147 |
+
const STATUS_PAUSED = 3;
|
148 |
|
149 |
/**
|
150 |
* Start it up
|
244 |
abstract protected function get_items_to_process( $prefix, $limit, $offset = false );
|
245 |
|
246 |
/**
|
247 |
+
* Upgrade item.
|
248 |
*
|
249 |
+
* @param mixed $item
|
250 |
*
|
251 |
* @return bool
|
252 |
*/
|
253 |
+
abstract protected function upgrade_item( $item );
|
254 |
|
255 |
/**
|
256 |
* Get running update text.
|
500 |
* Calculate progress.
|
501 |
*
|
502 |
* @return bool|float
|
503 |
+
* @throws Batch_Limits_Exceeded_Exception
|
504 |
*/
|
505 |
protected function calculate_progress() {
|
506 |
$this->boot_session();
|
511 |
} else {
|
512 |
// Set up any per-site state
|
513 |
$this->switch_to_blog( get_current_blog_id() );
|
514 |
+
$counts = Media_Library_Item::count_items();
|
515 |
|
516 |
+
// If there are no items, disable progress calculation
|
517 |
// and protect against division by zero.
|
518 |
if ( ! $counts['total'] ) {
|
519 |
return false;
|
@@ -1,4 +1,7 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
2 |
if ( ! function_exists( 'as3cf_get_attachment_url' ) ) {
|
3 |
/**
|
4 |
* Get the url of the file from provider, may be a signed expiring URL if associated file is set as private.
|
@@ -12,10 +15,7 @@ if ( ! function_exists( 'as3cf_get_attachment_url' ) ) {
|
|
12 |
* @return string|bool|WP_Error
|
13 |
*/
|
14 |
function as3cf_get_attachment_url( $post_id, $size = null, $skip_rewrite_check = false ) {
|
15 |
-
|
16 |
-
global $as3cf;
|
17 |
-
|
18 |
-
return $as3cf->get_attachment_url( $post_id, null, $size, null, array(), $skip_rewrite_check );
|
19 |
}
|
20 |
}
|
21 |
if ( ! function_exists( 'as3cf_get_secure_attachment_url' ) ) {
|
@@ -32,9 +32,11 @@ if ( ! function_exists( 'as3cf_get_secure_attachment_url' ) ) {
|
|
32 |
* @return string|bool|WP_Error
|
33 |
*/
|
34 |
function as3cf_get_secure_attachment_url( $post_id, $expires = 900, $size = null, $skip_rewrite_check = false ) {
|
35 |
-
|
36 |
-
|
|
|
|
|
37 |
|
38 |
-
return
|
39 |
}
|
40 |
}
|
1 |
<?php
|
2 |
+
|
3 |
+
use DeliciousBrains\WP_Offload_Media\Items\Media_Library_Item;
|
4 |
+
|
5 |
if ( ! function_exists( 'as3cf_get_attachment_url' ) ) {
|
6 |
/**
|
7 |
* Get the url of the file from provider, may be a signed expiring URL if associated file is set as private.
|
15 |
* @return string|bool|WP_Error
|
16 |
*/
|
17 |
function as3cf_get_attachment_url( $post_id, $size = null, $skip_rewrite_check = false ) {
|
18 |
+
return as3cf_get_secure_attachment_url( $post_id, null, $size, $skip_rewrite_check );
|
|
|
|
|
|
|
19 |
}
|
20 |
}
|
21 |
if ( ! function_exists( 'as3cf_get_secure_attachment_url' ) ) {
|
32 |
* @return string|bool|WP_Error
|
33 |
*/
|
34 |
function as3cf_get_secure_attachment_url( $post_id, $expires = 900, $size = null, $skip_rewrite_check = false ) {
|
35 |
+
$as3cf_item = Media_Library_Item::get_by_source_id( $post_id );
|
36 |
+
if ( ! empty( $as3cf_item ) && ! is_wp_error( $as3cf_item ) && $as3cf_item->served_by_provider( $skip_rewrite_check ) ) {
|
37 |
+
return $as3cf_item->get_provider_url( $size, $expires );
|
38 |
+
}
|
39 |
|
40 |
+
return false;
|
41 |
}
|
42 |
}
|
@@ -8,7 +8,7 @@ msgid ""
|
|
8 |
msgstr ""
|
9 |
"Project-Id-Version: amazon-s3-and-cloudfront\n"
|
10 |
"Report-Msgid-Bugs-To: nom@deliciousbrains.com\n"
|
11 |
-
"POT-Creation-Date:
|
12 |
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
13 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
14 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
@@ -17,17 +17,17 @@ msgstr ""
|
|
17 |
"Content-Type: text/plain; charset=UTF-8\n"
|
18 |
"Content-Transfer-Encoding: 8bit\n"
|
19 |
|
20 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
21 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
22 |
msgid "Offload Media Lite"
|
23 |
msgstr ""
|
24 |
|
25 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
26 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
27 |
msgid "Unknown"
|
28 |
msgstr ""
|
29 |
|
30 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
31 |
#: view/bucket-select.php:87
|
32 |
#: view/delivery-provider-select.php:129
|
33 |
#: view/delivery-provider-select.php:149
|
@@ -38,223 +38,185 @@ msgstr ""
|
|
38 |
msgid "defined in wp-config.php"
|
39 |
msgstr ""
|
40 |
|
41 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
42 |
-
#, php-format
|
43 |
-
msgid "Media Library item ID %d. Provided path is not a string"
|
44 |
-
msgstr ""
|
45 |
-
|
46 |
-
#: classes/amazon-s3-and-cloudfront.php:1430
|
47 |
-
#: classes/items/media-library-item.php:133
|
48 |
-
#, php-format
|
49 |
-
msgid "Media Library item with ID %d has damaged meta data"
|
50 |
-
msgstr ""
|
51 |
-
|
52 |
-
#: classes/amazon-s3-and-cloudfront.php:1441
|
53 |
-
#: classes/items/media-library-item.php:144
|
54 |
-
#, php-format
|
55 |
-
msgid "Media Library item with ID %d does not have a valid file path"
|
56 |
-
msgstr ""
|
57 |
-
|
58 |
-
#: classes/amazon-s3-and-cloudfront.php:1492
|
59 |
-
#: classes/amazon-s3-and-cloudfront.php:1718
|
60 |
-
#, php-format
|
61 |
-
msgid "File %s does not exist"
|
62 |
-
msgstr ""
|
63 |
-
|
64 |
-
#: classes/amazon-s3-and-cloudfront.php:1522
|
65 |
-
#, php-format
|
66 |
-
msgid "Mime type %s is not allowed"
|
67 |
-
msgstr ""
|
68 |
-
|
69 |
-
#: classes/amazon-s3-and-cloudfront.php:1533
|
70 |
-
msgid "Already offloaded to a different provider"
|
71 |
-
msgstr ""
|
72 |
-
|
73 |
-
#: classes/amazon-s3-and-cloudfront.php:1641
|
74 |
-
#: classes/amazon-s3-and-cloudfront.php:1732
|
75 |
-
#, php-format
|
76 |
-
msgid "Error offloading %s to provider: %s"
|
77 |
-
msgstr ""
|
78 |
-
|
79 |
-
#: classes/amazon-s3-and-cloudfront.php:2855
|
80 |
msgid "This action can only be performed through an admin screen."
|
81 |
msgstr ""
|
82 |
|
83 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
84 |
msgid "Cheatin’ eh?"
|
85 |
msgstr ""
|
86 |
|
87 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
88 |
msgid "You do not have sufficient permissions to access this page."
|
89 |
msgstr ""
|
90 |
|
91 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
92 |
msgid "Error Getting Bucket Region"
|
93 |
msgstr ""
|
94 |
|
95 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
96 |
#, php-format
|
97 |
msgid "There was an error attempting to get the region of the bucket %s: %s"
|
98 |
msgstr ""
|
99 |
|
100 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
101 |
msgid ""
|
102 |
"This is a test file to check if the user has write permission to the bucket. "
|
103 |
"Delete me if found."
|
104 |
msgstr ""
|
105 |
|
106 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
107 |
#, php-format
|
108 |
msgid ""
|
109 |
"There was an error attempting to check the permissions of the bucket %s: %s"
|
110 |
msgstr ""
|
111 |
|
112 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
113 |
msgid "Error creating bucket"
|
114 |
msgstr ""
|
115 |
|
116 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
117 |
msgid "Bucket name too short."
|
118 |
msgstr ""
|
119 |
|
120 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
121 |
msgid "Bucket name too long."
|
122 |
msgstr ""
|
123 |
|
124 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
125 |
msgid ""
|
126 |
"Invalid character. Bucket names can contain lowercase letters, numbers, "
|
127 |
"periods and hyphens."
|
128 |
msgstr ""
|
129 |
|
130 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
131 |
msgid "Error saving bucket"
|
132 |
msgstr ""
|
133 |
|
134 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
135 |
msgid "Error fetching buckets"
|
136 |
msgstr ""
|
137 |
|
138 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
139 |
msgid "Error getting URL preview: "
|
140 |
msgstr ""
|
141 |
|
142 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
143 |
msgid "The changes you made will be lost if you navigate away from this page"
|
144 |
msgstr ""
|
145 |
|
146 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
147 |
msgid "Getting diagnostic info..."
|
148 |
msgstr ""
|
149 |
|
150 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
151 |
msgid "Error getting diagnostic info: "
|
152 |
msgstr ""
|
153 |
|
154 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
155 |
msgctxt "placeholder for hidden access key, 39 char max"
|
156 |
msgid "-- not shown --"
|
157 |
msgstr ""
|
158 |
|
159 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
160 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
161 |
msgid "Settings saved."
|
162 |
msgstr ""
|
163 |
|
164 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
165 |
msgid "Cheatin' eh?"
|
166 |
msgstr ""
|
167 |
|
168 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
169 |
#, php-format
|
170 |
msgid "Could not set new Delivery Provider: %s"
|
171 |
msgstr ""
|
172 |
|
173 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
174 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
175 |
msgid "No bucket name provided."
|
176 |
msgstr ""
|
177 |
|
178 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
179 |
msgid "Bucket name not valid."
|
180 |
msgstr ""
|
181 |
|
182 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
183 |
msgid "No region provided."
|
184 |
msgstr ""
|
185 |
|
186 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
187 |
#, php-format
|
188 |
msgctxt "Trying to change public access setting for given provider's bucket."
|
189 |
msgid "Can't change Block All Public Access setting for %s buckets."
|
190 |
msgstr ""
|
191 |
|
192 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
193 |
msgid "No block public access setting provided."
|
194 |
msgstr ""
|
195 |
|
196 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
197 |
msgid "Storage Provider not configured with access credentials."
|
198 |
msgstr ""
|
199 |
|
200 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
201 |
msgid "Could not change Block All Public Access status for bucket."
|
202 |
msgstr ""
|
203 |
|
204 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
205 |
msgid ""
|
206 |
"<strong>Failed to Enable Block All Public Access</strong> — We could "
|
207 |
"not enable Block All Public Access. You will need to log in to the AWS "
|
208 |
"Console and do it manually."
|
209 |
msgstr ""
|
210 |
|
211 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
212 |
msgid ""
|
213 |
"<strong>Failed to Disable Block All Public Access</strong> — We could "
|
214 |
"not disable Block All Public Access. You will need to log in to the AWS "
|
215 |
"Console and do it manually."
|
216 |
msgstr ""
|
217 |
|
218 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
219 |
#: view/provider-select.php:329
|
220 |
msgctxt "placeholder for hidden secret access key, 39 char max"
|
221 |
msgid "-- not shown --"
|
222 |
msgstr ""
|
223 |
|
224 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
225 |
msgid "Key File not valid JSON."
|
226 |
msgstr ""
|
227 |
|
228 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
229 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
230 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
231 |
msgctxt "missing form field"
|
232 |
msgid " not provided."
|
233 |
msgstr ""
|
234 |
|
235 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
236 |
msgctxt "Show the media library tab"
|
237 |
msgid "Media Library"
|
238 |
msgstr ""
|
239 |
|
240 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
241 |
msgctxt "Show the addons tab"
|
242 |
msgid "Addons"
|
243 |
msgstr ""
|
244 |
|
245 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
246 |
msgctxt "Show the support tab"
|
247 |
msgid "Support"
|
248 |
msgstr ""
|
249 |
|
250 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
251 |
#, php-format
|
252 |
msgid ""
|
253 |
"<strong>WP Offload Media</strong> — The file %s has been given %s "
|
254 |
"permissions in the bucket."
|
255 |
msgstr ""
|
256 |
|
257 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
258 |
msgid ""
|
259 |
"<strong>WP Offload Media Requirement Missing</strong> — Looks like you "
|
260 |
"don't have an image manipulation library installed on this server and "
|
@@ -262,7 +224,7 @@ msgid ""
|
|
262 |
"Please setup GD or ImageMagick."
|
263 |
msgstr ""
|
264 |
|
265 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
266 |
#, php-format
|
267 |
msgid ""
|
268 |
"<strong>Missing Table</strong> — One or more required database tables "
|
@@ -270,18 +232,18 @@ msgid ""
|
|
270 |
"details. %s"
|
271 |
msgstr ""
|
272 |
|
273 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
274 |
#, php-format
|
275 |
msgid ""
|
276 |
"<a href=\"%s\">Define your access keys</a> to enable write access to the "
|
277 |
"bucket"
|
278 |
msgstr ""
|
279 |
|
280 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
281 |
msgid "Quick Start Guide"
|
282 |
msgstr ""
|
283 |
|
284 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
285 |
#, php-format
|
286 |
msgid ""
|
287 |
"Looks like we don't have write access to this bucket. It's likely that the "
|
@@ -290,7 +252,7 @@ msgid ""
|
|
290 |
"correctly."
|
291 |
msgstr ""
|
292 |
|
293 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
294 |
#, php-format
|
295 |
msgid ""
|
296 |
"Looks like we don't have access to the buckets. It's likely that the user "
|
@@ -298,39 +260,39 @@ msgid ""
|
|
298 |
"Please see our %s for instructions on setting up permissions correctly."
|
299 |
msgstr ""
|
300 |
|
301 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
302 |
msgid "WP Offload Media Activation"
|
303 |
msgstr ""
|
304 |
|
305 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
306 |
msgid ""
|
307 |
"WP Offload Media Lite and WP Offload Media cannot both be active. We've "
|
308 |
"automatically deactivated WP Offload Media Lite."
|
309 |
msgstr ""
|
310 |
|
311 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
312 |
msgid "WP Offload Media Lite Activation"
|
313 |
msgstr ""
|
314 |
|
315 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
316 |
msgid ""
|
317 |
"WP Offload Media Lite and WP Offload Media cannot both be active. We've "
|
318 |
"automatically deactivated WP Offload Media."
|
319 |
msgstr ""
|
320 |
|
321 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
322 |
msgid "More info »"
|
323 |
msgstr ""
|
324 |
|
325 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
326 |
msgid "this doc"
|
327 |
msgstr ""
|
328 |
|
329 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
330 |
msgid "WP Offload Media Feature Removed"
|
331 |
msgstr ""
|
332 |
|
333 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
334 |
#, php-format
|
335 |
msgid ""
|
336 |
"You had the \"Always non-SSL\" option selected in your settings, but we've "
|
@@ -341,68 +303,21 @@ msgid ""
|
|
341 |
"to the old behavior."
|
342 |
msgstr ""
|
343 |
|
344 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
345 |
-
msgid "Offload"
|
346 |
-
msgstr ""
|
347 |
-
|
348 |
-
#: classes/amazon-s3-and-cloudfront.php:5484
|
349 |
-
msgid "No"
|
350 |
-
msgstr ""
|
351 |
-
|
352 |
-
#: classes/amazon-s3-and-cloudfront.php:5489
|
353 |
-
msgctxt "Storage provider key name"
|
354 |
-
msgid "Storage Provider"
|
355 |
-
msgstr ""
|
356 |
-
|
357 |
-
#: classes/amazon-s3-and-cloudfront.php:5490
|
358 |
-
msgctxt "Storage provider name"
|
359 |
-
msgid "Storage Provider"
|
360 |
-
msgstr ""
|
361 |
-
|
362 |
-
#: classes/amazon-s3-and-cloudfront.php:5491
|
363 |
-
msgctxt "Bucket name"
|
364 |
-
msgid "Bucket"
|
365 |
-
msgstr ""
|
366 |
-
|
367 |
-
#: classes/amazon-s3-and-cloudfront.php:5492
|
368 |
-
msgctxt "Path to file in bucket"
|
369 |
-
msgid "Path"
|
370 |
-
msgstr ""
|
371 |
-
|
372 |
-
#: classes/amazon-s3-and-cloudfront.php:5493
|
373 |
-
msgctxt "Location of bucket"
|
374 |
-
msgid "Region"
|
375 |
-
msgstr ""
|
376 |
-
|
377 |
-
#: classes/amazon-s3-and-cloudfront.php:5494
|
378 |
-
msgctxt "Access control list of the file in bucket"
|
379 |
-
msgid "Access"
|
380 |
-
msgstr ""
|
381 |
-
|
382 |
-
#: classes/amazon-s3-and-cloudfront.php:5495
|
383 |
-
msgid "URL"
|
384 |
-
msgstr ""
|
385 |
-
|
386 |
-
#: classes/amazon-s3-and-cloudfront.php:5496
|
387 |
-
msgctxt "Whether or not metadata has been verified"
|
388 |
-
msgid "Verified"
|
389 |
-
msgstr ""
|
390 |
-
|
391 |
-
#: classes/amazon-s3-and-cloudfront.php:5749
|
392 |
msgid "Assets Pull"
|
393 |
msgstr ""
|
394 |
|
395 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
396 |
msgid ""
|
397 |
"An addon for WP Offload Media to serve your site's JS, CSS, and other "
|
398 |
"enqueued assets from Amazon CloudFront or another CDN."
|
399 |
msgstr ""
|
400 |
|
401 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
402 |
msgid "Feature"
|
403 |
msgstr ""
|
404 |
|
405 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
406 |
#, php-format
|
407 |
msgid ""
|
408 |
"<strong>Amazon Web Services Plugin No Longer Required</strong> — As of "
|
@@ -413,7 +328,7 @@ msgid ""
|
|
413 |
"plugin, it should be safe to deactivate and delete it. %2$s"
|
414 |
msgstr ""
|
415 |
|
416 |
-
#: classes/amazon-s3-and-cloudfront.php:
|
417 |
#, php-format
|
418 |
msgid ""
|
419 |
"<strong>WP Offload Media Settings Moved</strong> — You now define your "
|
@@ -546,34 +461,174 @@ msgstr ""
|
|
546 |
msgid "Settings"
|
547 |
msgstr ""
|
548 |
|
549 |
-
#: classes/as3cf-plugin-compatibility.php:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
550 |
#, php-format
|
551 |
msgid "The local directory %s does not exist and could not be created."
|
552 |
msgstr ""
|
553 |
|
554 |
-
#: classes/
|
555 |
-
#: classes/as3cf-plugin-compatibility.php:652
|
556 |
#: classes/upgrades/upgrade-meta-wp-error.php:81
|
557 |
#, php-format
|
558 |
msgid ""
|
559 |
"There was an error attempting to download the file %s from the bucket: %s"
|
560 |
msgstr ""
|
561 |
|
562 |
-
#: classes/
|
563 |
#, php-format
|
564 |
-
msgid ""
|
565 |
-
"<strong>Warning:</strong> This site is using PHP %1$s, in a future update WP "
|
566 |
-
"Offload Media will require PHP %2$s or later. %3$s"
|
567 |
msgstr ""
|
568 |
|
569 |
-
#: classes/items/media-library-item.php:
|
570 |
msgid "Empty Attachment ID passed to "
|
571 |
msgstr ""
|
572 |
|
573 |
-
#: classes/items/media-library-item.php:
|
574 |
msgid "Invalid Originator passed to "
|
575 |
msgstr ""
|
576 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
577 |
#: classes/providers/delivery/another-cdn.php:47
|
578 |
#: classes/providers/delivery/digitalocean-spaces-cdn.php:83
|
579 |
msgid "Fast, No Private Media"
|
@@ -644,7 +699,7 @@ msgid ""
|
|
644 |
"running in the background to update URLs in your post content. %2$s"
|
645 |
msgstr ""
|
646 |
|
647 |
-
#: classes/upgrades/upgrade-edd-replace-urls.php:
|
648 |
msgid "and ensuring that only the local URL exists in EDD post meta."
|
649 |
msgstr ""
|
650 |
|
@@ -666,25 +721,29 @@ msgid ""
|
|
666 |
"running in the background to update URLs in your post excerpts. %2$s"
|
667 |
msgstr ""
|
668 |
|
669 |
-
#: classes/upgrades/upgrade-filter-post.php:
|
670 |
#, php-format
|
671 |
msgid ""
|
672 |
"<strong>Paused Upgrade</strong><br>The find & replace to update URLs has "
|
673 |
"been paused. %s"
|
674 |
msgstr ""
|
675 |
|
676 |
-
#: classes/upgrades/upgrade-filter-post.php:
|
677 |
msgid "See our documentation"
|
678 |
msgstr ""
|
679 |
|
680 |
-
#: classes/upgrades/upgrade-filter-post.php:
|
681 |
#, php-format
|
682 |
msgid ""
|
683 |
"%s for details on why we’re doing this, why it runs slowly, and how to "
|
684 |
"make it run faster."
|
685 |
msgstr ""
|
686 |
|
687 |
-
#: classes/upgrades/upgrade-
|
|
|
|
|
|
|
|
|
688 |
msgid ""
|
689 |
"and updating the plugin's metadata to use a faster storage method. During "
|
690 |
"the update the site's total offloaded media count may be inaccurate but will "
|
@@ -703,6 +762,10 @@ msgid ""
|
|
703 |
"style=\"white-space:nowrap;\">(e.g. s3-us-west-2.amazonaws.com)</span>."
|
704 |
msgstr ""
|
705 |
|
|
|
|
|
|
|
|
|
706 |
#: classes/upgrades/upgrade-wpos3-to-as3cf.php:36
|
707 |
msgid ""
|
708 |
"and updating the metadata to use key names compatible with the current "
|
@@ -751,12 +814,12 @@ msgstr ""
|
|
751 |
msgid " (%s%% Complete)"
|
752 |
msgstr ""
|
753 |
|
754 |
-
#: classes/upgrades/upgrade.php:
|
755 |
#, php-format
|
756 |
msgid "Every %d Minutes"
|
757 |
msgstr ""
|
758 |
|
759 |
-
#: classes/upgrades/upgrade.php:
|
760 |
#, php-format
|
761 |
msgid ""
|
762 |
"<strong>Settings Locked Temporarily</strong> — You can't change any of "
|
@@ -787,15 +850,15 @@ msgctxt "Install plugin now"
|
|
787 |
msgid "Install Now"
|
788 |
msgstr ""
|
789 |
|
790 |
-
#: view/attachment-metabox.php:
|
791 |
msgid "This item has not been offloaded yet."
|
792 |
msgstr ""
|
793 |
|
794 |
-
#: view/attachment-metabox.php:
|
795 |
msgid "File does not exist on server"
|
796 |
msgstr ""
|
797 |
|
798 |
-
#: view/attachment-metabox.php:
|
799 |
msgid "File exists on server"
|
800 |
msgstr ""
|
801 |
|
8 |
msgstr ""
|
9 |
"Project-Id-Version: amazon-s3-and-cloudfront\n"
|
10 |
"Report-Msgid-Bugs-To: nom@deliciousbrains.com\n"
|
11 |
+
"POT-Creation-Date: 2022-03-09 13:52+0000\n"
|
12 |
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
13 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
14 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
17 |
"Content-Type: text/plain; charset=UTF-8\n"
|
18 |
"Content-Transfer-Encoding: 8bit\n"
|
19 |
|
20 |
+
#: classes/amazon-s3-and-cloudfront.php:195
|
21 |
+
#: classes/amazon-s3-and-cloudfront.php:196
|
22 |
msgid "Offload Media Lite"
|
23 |
msgstr ""
|
24 |
|
25 |
+
#: classes/amazon-s3-and-cloudfront.php:436
|
26 |
+
#: classes/amazon-s3-and-cloudfront.php:453
|
27 |
msgid "Unknown"
|
28 |
msgstr ""
|
29 |
|
30 |
+
#: classes/amazon-s3-and-cloudfront.php:534
|
31 |
#: view/bucket-select.php:87
|
32 |
#: view/delivery-provider-select.php:129
|
33 |
#: view/delivery-provider-select.php:149
|
38 |
msgid "defined in wp-config.php"
|
39 |
msgstr ""
|
40 |
|
41 |
+
#: classes/amazon-s3-and-cloudfront.php:1521
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
msgid "This action can only be performed through an admin screen."
|
43 |
msgstr ""
|
44 |
|
45 |
+
#: classes/amazon-s3-and-cloudfront.php:1523
|
46 |
msgid "Cheatin’ eh?"
|
47 |
msgstr ""
|
48 |
|
49 |
+
#: classes/amazon-s3-and-cloudfront.php:1525
|
50 |
msgid "You do not have sufficient permissions to access this page."
|
51 |
msgstr ""
|
52 |
|
53 |
+
#: classes/amazon-s3-and-cloudfront.php:1849
|
54 |
msgid "Error Getting Bucket Region"
|
55 |
msgstr ""
|
56 |
|
57 |
+
#: classes/amazon-s3-and-cloudfront.php:1850
|
58 |
#, php-format
|
59 |
msgid "There was an error attempting to get the region of the bucket %s: %s"
|
60 |
msgstr ""
|
61 |
|
62 |
+
#: classes/amazon-s3-and-cloudfront.php:1953
|
63 |
msgid ""
|
64 |
"This is a test file to check if the user has write permission to the bucket. "
|
65 |
"Delete me if found."
|
66 |
msgstr ""
|
67 |
|
68 |
+
#: classes/amazon-s3-and-cloudfront.php:1959
|
69 |
#, php-format
|
70 |
msgid ""
|
71 |
"There was an error attempting to check the permissions of the bucket %s: %s"
|
72 |
msgstr ""
|
73 |
|
74 |
+
#: classes/amazon-s3-and-cloudfront.php:2077
|
75 |
msgid "Error creating bucket"
|
76 |
msgstr ""
|
77 |
|
78 |
+
#: classes/amazon-s3-and-cloudfront.php:2078
|
79 |
msgid "Bucket name too short."
|
80 |
msgstr ""
|
81 |
|
82 |
+
#: classes/amazon-s3-and-cloudfront.php:2079
|
83 |
msgid "Bucket name too long."
|
84 |
msgstr ""
|
85 |
|
86 |
+
#: classes/amazon-s3-and-cloudfront.php:2080
|
87 |
msgid ""
|
88 |
"Invalid character. Bucket names can contain lowercase letters, numbers, "
|
89 |
"periods and hyphens."
|
90 |
msgstr ""
|
91 |
|
92 |
+
#: classes/amazon-s3-and-cloudfront.php:2081
|
93 |
msgid "Error saving bucket"
|
94 |
msgstr ""
|
95 |
|
96 |
+
#: classes/amazon-s3-and-cloudfront.php:2082
|
97 |
msgid "Error fetching buckets"
|
98 |
msgstr ""
|
99 |
|
100 |
+
#: classes/amazon-s3-and-cloudfront.php:2083
|
101 |
msgid "Error getting URL preview: "
|
102 |
msgstr ""
|
103 |
|
104 |
+
#: classes/amazon-s3-and-cloudfront.php:2084
|
105 |
msgid "The changes you made will be lost if you navigate away from this page"
|
106 |
msgstr ""
|
107 |
|
108 |
+
#: classes/amazon-s3-and-cloudfront.php:2085
|
109 |
msgid "Getting diagnostic info..."
|
110 |
msgstr ""
|
111 |
|
112 |
+
#: classes/amazon-s3-and-cloudfront.php:2086
|
113 |
msgid "Error getting diagnostic info: "
|
114 |
msgstr ""
|
115 |
|
116 |
+
#: classes/amazon-s3-and-cloudfront.php:2087
|
117 |
msgctxt "placeholder for hidden access key, 39 char max"
|
118 |
msgid "-- not shown --"
|
119 |
msgstr ""
|
120 |
|
121 |
+
#: classes/amazon-s3-and-cloudfront.php:2089
|
122 |
+
#: classes/amazon-s3-and-cloudfront.php:4210
|
123 |
msgid "Settings saved."
|
124 |
msgstr ""
|
125 |
|
126 |
+
#: classes/amazon-s3-and-cloudfront.php:2211
|
127 |
msgid "Cheatin' eh?"
|
128 |
msgstr ""
|
129 |
|
130 |
+
#: classes/amazon-s3-and-cloudfront.php:2284
|
131 |
#, php-format
|
132 |
msgid "Could not set new Delivery Provider: %s"
|
133 |
msgstr ""
|
134 |
|
135 |
+
#: classes/amazon-s3-and-cloudfront.php:2359
|
136 |
+
#: classes/amazon-s3-and-cloudfront.php:2489
|
137 |
msgid "No bucket name provided."
|
138 |
msgstr ""
|
139 |
|
140 |
+
#: classes/amazon-s3-and-cloudfront.php:2368
|
141 |
msgid "Bucket name not valid."
|
142 |
msgstr ""
|
143 |
|
144 |
+
#: classes/amazon-s3-and-cloudfront.php:2381
|
145 |
msgid "No region provided."
|
146 |
msgstr ""
|
147 |
|
148 |
+
#: classes/amazon-s3-and-cloudfront.php:2458
|
149 |
#, php-format
|
150 |
msgctxt "Trying to change public access setting for given provider's bucket."
|
151 |
msgid "Can't change Block All Public Access setting for %s buckets."
|
152 |
msgstr ""
|
153 |
|
154 |
+
#: classes/amazon-s3-and-cloudfront.php:2467
|
155 |
msgid "No block public access setting provided."
|
156 |
msgstr ""
|
157 |
|
158 |
+
#: classes/amazon-s3-and-cloudfront.php:2480
|
159 |
msgid "Storage Provider not configured with access credentials."
|
160 |
msgstr ""
|
161 |
|
162 |
+
#: classes/amazon-s3-and-cloudfront.php:2507
|
163 |
msgid "Could not change Block All Public Access status for bucket."
|
164 |
msgstr ""
|
165 |
|
166 |
+
#: classes/amazon-s3-and-cloudfront.php:2524
|
167 |
msgid ""
|
168 |
"<strong>Failed to Enable Block All Public Access</strong> — We could "
|
169 |
"not enable Block All Public Access. You will need to log in to the AWS "
|
170 |
"Console and do it manually."
|
171 |
msgstr ""
|
172 |
|
173 |
+
#: classes/amazon-s3-and-cloudfront.php:2526
|
174 |
msgid ""
|
175 |
"<strong>Failed to Disable Block All Public Access</strong> — We could "
|
176 |
"not disable Block All Public Access. You will need to log in to the AWS "
|
177 |
"Console and do it manually."
|
178 |
msgstr ""
|
179 |
|
180 |
+
#: classes/amazon-s3-and-cloudfront.php:2561
|
181 |
#: view/provider-select.php:329
|
182 |
msgctxt "placeholder for hidden secret access key, 39 char max"
|
183 |
msgid "-- not shown --"
|
184 |
msgstr ""
|
185 |
|
186 |
+
#: classes/amazon-s3-and-cloudfront.php:2584
|
187 |
msgid "Key File not valid JSON."
|
188 |
msgstr ""
|
189 |
|
190 |
+
#: classes/amazon-s3-and-cloudfront.php:2604
|
191 |
+
#: classes/amazon-s3-and-cloudfront.php:2618
|
192 |
+
#: classes/amazon-s3-and-cloudfront.php:2627
|
193 |
msgctxt "missing form field"
|
194 |
msgid " not provided."
|
195 |
msgstr ""
|
196 |
|
197 |
+
#: classes/amazon-s3-and-cloudfront.php:2670
|
198 |
msgctxt "Show the media library tab"
|
199 |
msgid "Media Library"
|
200 |
msgstr ""
|
201 |
|
202 |
+
#: classes/amazon-s3-and-cloudfront.php:2671
|
203 |
msgctxt "Show the addons tab"
|
204 |
msgid "Addons"
|
205 |
msgstr ""
|
206 |
|
207 |
+
#: classes/amazon-s3-and-cloudfront.php:2672
|
208 |
msgctxt "Show the support tab"
|
209 |
msgid "Support"
|
210 |
msgstr ""
|
211 |
|
212 |
+
#: classes/amazon-s3-and-cloudfront.php:2849
|
213 |
#, php-format
|
214 |
msgid ""
|
215 |
"<strong>WP Offload Media</strong> — The file %s has been given %s "
|
216 |
"permissions in the bucket."
|
217 |
msgstr ""
|
218 |
|
219 |
+
#: classes/amazon-s3-and-cloudfront.php:2868
|
220 |
msgid ""
|
221 |
"<strong>WP Offload Media Requirement Missing</strong> — Looks like you "
|
222 |
"don't have an image manipulation library installed on this server and "
|
224 |
"Please setup GD or ImageMagick."
|
225 |
msgstr ""
|
226 |
|
227 |
+
#: classes/amazon-s3-and-cloudfront.php:2892
|
228 |
#, php-format
|
229 |
msgid ""
|
230 |
"<strong>Missing Table</strong> — One or more required database tables "
|
232 |
"details. %s"
|
233 |
msgstr ""
|
234 |
|
235 |
+
#: classes/amazon-s3-and-cloudfront.php:3714
|
236 |
#, php-format
|
237 |
msgid ""
|
238 |
"<a href=\"%s\">Define your access keys</a> to enable write access to the "
|
239 |
"bucket"
|
240 |
msgstr ""
|
241 |
|
242 |
+
#: classes/amazon-s3-and-cloudfront.php:3721
|
243 |
msgid "Quick Start Guide"
|
244 |
msgstr ""
|
245 |
|
246 |
+
#: classes/amazon-s3-and-cloudfront.php:3723
|
247 |
#, php-format
|
248 |
msgid ""
|
249 |
"Looks like we don't have write access to this bucket. It's likely that the "
|
252 |
"correctly."
|
253 |
msgstr ""
|
254 |
|
255 |
+
#: classes/amazon-s3-and-cloudfront.php:3725
|
256 |
#, php-format
|
257 |
msgid ""
|
258 |
"Looks like we don't have access to the buckets. It's likely that the user "
|
260 |
"Please see our %s for instructions on setting up permissions correctly."
|
261 |
msgstr ""
|
262 |
|
263 |
+
#: classes/amazon-s3-and-cloudfront.php:3895
|
264 |
msgid "WP Offload Media Activation"
|
265 |
msgstr ""
|
266 |
|
267 |
+
#: classes/amazon-s3-and-cloudfront.php:3896
|
268 |
msgid ""
|
269 |
"WP Offload Media Lite and WP Offload Media cannot both be active. We've "
|
270 |
"automatically deactivated WP Offload Media Lite."
|
271 |
msgstr ""
|
272 |
|
273 |
+
#: classes/amazon-s3-and-cloudfront.php:3898
|
274 |
msgid "WP Offload Media Lite Activation"
|
275 |
msgstr ""
|
276 |
|
277 |
+
#: classes/amazon-s3-and-cloudfront.php:3899
|
278 |
msgid ""
|
279 |
"WP Offload Media Lite and WP Offload Media cannot both be active. We've "
|
280 |
"automatically deactivated WP Offload Media."
|
281 |
msgstr ""
|
282 |
|
283 |
+
#: classes/amazon-s3-and-cloudfront.php:3953
|
284 |
msgid "More info »"
|
285 |
msgstr ""
|
286 |
|
287 |
+
#: classes/amazon-s3-and-cloudfront.php:4022
|
288 |
msgid "this doc"
|
289 |
msgstr ""
|
290 |
|
291 |
+
#: classes/amazon-s3-and-cloudfront.php:4024
|
292 |
msgid "WP Offload Media Feature Removed"
|
293 |
msgstr ""
|
294 |
|
295 |
+
#: classes/amazon-s3-and-cloudfront.php:4025
|
296 |
#, php-format
|
297 |
msgid ""
|
298 |
"You had the \"Always non-SSL\" option selected in your settings, but we've "
|
303 |
"to the old behavior."
|
304 |
msgstr ""
|
305 |
|
306 |
+
#: classes/amazon-s3-and-cloudfront.php:4173
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
307 |
msgid "Assets Pull"
|
308 |
msgstr ""
|
309 |
|
310 |
+
#: classes/amazon-s3-and-cloudfront.php:4174
|
311 |
msgid ""
|
312 |
"An addon for WP Offload Media to serve your site's JS, CSS, and other "
|
313 |
"enqueued assets from Amazon CloudFront or another CDN."
|
314 |
msgstr ""
|
315 |
|
316 |
+
#: classes/amazon-s3-and-cloudfront.php:4178
|
317 |
msgid "Feature"
|
318 |
msgstr ""
|
319 |
|
320 |
+
#: classes/amazon-s3-and-cloudfront.php:4224
|
321 |
#, php-format
|
322 |
msgid ""
|
323 |
"<strong>Amazon Web Services Plugin No Longer Required</strong> — As of "
|
328 |
"plugin, it should be safe to deactivate and delete it. %2$s"
|
329 |
msgstr ""
|
330 |
|
331 |
+
#: classes/amazon-s3-and-cloudfront.php:4256
|
332 |
#, php-format
|
333 |
msgid ""
|
334 |
"<strong>WP Offload Media Settings Moved</strong> — You now define your "
|
461 |
msgid "Settings"
|
462 |
msgstr ""
|
463 |
|
464 |
+
#: classes/as3cf-plugin-compatibility.php:949
|
465 |
+
#, php-format
|
466 |
+
msgid ""
|
467 |
+
"<strong>Warning:</strong> This site is using PHP %1$s, in a future update WP "
|
468 |
+
"Offload Media will require PHP %2$s or later. %3$s"
|
469 |
+
msgstr ""
|
470 |
+
|
471 |
+
#: classes/integrations/media-library.php:205
|
472 |
+
#, php-format
|
473 |
+
msgid "Can't create item from media library item %d"
|
474 |
+
msgstr ""
|
475 |
+
|
476 |
+
#: classes/integrations/media-library.php:497
|
477 |
+
msgid "Offload"
|
478 |
+
msgstr ""
|
479 |
+
|
480 |
+
#: classes/integrations/media-library.php:923
|
481 |
+
msgid "No"
|
482 |
+
msgstr ""
|
483 |
+
|
484 |
+
#: classes/integrations/media-library.php:933
|
485 |
+
msgctxt "Storage provider key name"
|
486 |
+
msgid "Storage Provider"
|
487 |
+
msgstr ""
|
488 |
+
|
489 |
+
#: classes/integrations/media-library.php:934
|
490 |
+
msgctxt "Storage provider name"
|
491 |
+
msgid "Storage Provider"
|
492 |
+
msgstr ""
|
493 |
+
|
494 |
+
#: classes/integrations/media-library.php:935
|
495 |
+
msgctxt "Bucket name"
|
496 |
+
msgid "Bucket"
|
497 |
+
msgstr ""
|
498 |
+
|
499 |
+
#: classes/integrations/media-library.php:936
|
500 |
+
msgctxt "Path to file in bucket"
|
501 |
+
msgid "Path"
|
502 |
+
msgstr ""
|
503 |
+
|
504 |
+
#: classes/integrations/media-library.php:937
|
505 |
+
msgctxt "Location of bucket"
|
506 |
+
msgid "Region"
|
507 |
+
msgstr ""
|
508 |
+
|
509 |
+
#: classes/integrations/media-library.php:938
|
510 |
+
msgctxt "Access control list of the file in bucket"
|
511 |
+
msgid "Access"
|
512 |
+
msgstr ""
|
513 |
+
|
514 |
+
#: classes/integrations/media-library.php:939
|
515 |
+
msgid "URL"
|
516 |
+
msgstr ""
|
517 |
+
|
518 |
+
#: classes/integrations/media-library.php:940
|
519 |
+
msgctxt "Whether or not metadata has been verified"
|
520 |
+
msgid "Verified"
|
521 |
+
msgstr ""
|
522 |
+
|
523 |
+
#: classes/items/download-handler.php:84
|
524 |
+
msgid ""
|
525 |
+
"%1$s with ID %d is offloaded to a different provider than currently "
|
526 |
+
"configured"
|
527 |
+
msgstr ""
|
528 |
+
|
529 |
+
#: classes/items/download-handler.php:151
|
530 |
#, php-format
|
531 |
msgid "The local directory %s does not exist and could not be created."
|
532 |
msgstr ""
|
533 |
|
534 |
+
#: classes/items/download-handler.php:152
|
|
|
535 |
#: classes/upgrades/upgrade-meta-wp-error.php:81
|
536 |
#, php-format
|
537 |
msgid ""
|
538 |
"There was an error attempting to download the file %s from the bucket: %s"
|
539 |
msgstr ""
|
540 |
|
541 |
+
#: classes/items/download-handler.php:158
|
542 |
#, php-format
|
543 |
+
msgid "Error downloading %1$s from bucket: %2$s"
|
|
|
|
|
544 |
msgstr ""
|
545 |
|
546 |
+
#: classes/items/media-library-item.php:142
|
547 |
msgid "Empty Attachment ID passed to "
|
548 |
msgstr ""
|
549 |
|
550 |
+
#: classes/items/media-library-item.php:157
|
551 |
msgid "Invalid Originator passed to "
|
552 |
msgstr ""
|
553 |
|
554 |
+
#: classes/items/media-library-item.php:170
|
555 |
+
#, php-format
|
556 |
+
msgid "Media Library item with ID %d has damaged meta data"
|
557 |
+
msgstr ""
|
558 |
+
|
559 |
+
#: classes/items/media-library-item.php:181
|
560 |
+
#, php-format
|
561 |
+
msgid "Media Library item with ID %d does not have a valid file path"
|
562 |
+
msgstr ""
|
563 |
+
|
564 |
+
#: classes/items/media-library-item.php:553
|
565 |
+
msgid "Edit"
|
566 |
+
msgstr ""
|
567 |
+
|
568 |
+
#: classes/items/remove-provider-handler.php:40
|
569 |
+
msgid "Invalid object_keys option provided."
|
570 |
+
msgstr ""
|
571 |
+
|
572 |
+
#: classes/items/remove-provider-handler.php:44
|
573 |
+
msgid "Invalid offloaded_files option provided."
|
574 |
+
msgstr ""
|
575 |
+
|
576 |
+
#: classes/items/remove-provider-handler.php:48
|
577 |
+
msgid ""
|
578 |
+
"Providing both object_keys and offloaded_files options is not supported."
|
579 |
+
msgstr ""
|
580 |
+
|
581 |
+
#: classes/items/upload-handler.php:49
|
582 |
+
#, php-format
|
583 |
+
msgid "%s with id %d does not have a valid file path"
|
584 |
+
msgstr ""
|
585 |
+
|
586 |
+
#: classes/items/upload-handler.php:56
|
587 |
+
#, php-format
|
588 |
+
msgid "%s with id %d. Provided path is not a string"
|
589 |
+
msgstr ""
|
590 |
+
|
591 |
+
#: classes/items/upload-handler.php:63
|
592 |
+
#, php-format
|
593 |
+
msgid "Primary file %s does not exist"
|
594 |
+
msgstr ""
|
595 |
+
|
596 |
+
#: classes/items/upload-handler.php:75
|
597 |
+
#, php-format
|
598 |
+
msgid "Mime type %s is not allowed"
|
599 |
+
msgstr ""
|
600 |
+
|
601 |
+
#: classes/items/upload-handler.php:175
|
602 |
+
#, php-format
|
603 |
+
msgid "Bucket name \"%1$s\" is invalid, using \"%2$s\" instead."
|
604 |
+
msgstr ""
|
605 |
+
|
606 |
+
#: classes/items/upload-handler.php:190
|
607 |
+
msgid ""
|
608 |
+
"The bucket may not be changed via filters for a previously offloaded item."
|
609 |
+
msgstr ""
|
610 |
+
|
611 |
+
#: classes/items/upload-handler.php:208
|
612 |
+
#, php-format
|
613 |
+
msgid ""
|
614 |
+
"The offloaded filename must not be changed, \"%1$s\" has been used instead "
|
615 |
+
"of \"%2$s\"."
|
616 |
+
msgstr ""
|
617 |
+
|
618 |
+
#: classes/items/upload-handler.php:216
|
619 |
+
msgid "The key may not be changed via filters for a previously offloaded item."
|
620 |
+
msgstr ""
|
621 |
+
|
622 |
+
#: classes/items/upload-handler.php:287
|
623 |
+
#, php-format
|
624 |
+
msgid "File %s does not exist"
|
625 |
+
msgstr ""
|
626 |
+
|
627 |
+
#: classes/items/upload-handler.php:308
|
628 |
+
#, php-format
|
629 |
+
msgid "Error offloading %1$s to provider: %2$s"
|
630 |
+
msgstr ""
|
631 |
+
|
632 |
#: classes/providers/delivery/another-cdn.php:47
|
633 |
#: classes/providers/delivery/digitalocean-spaces-cdn.php:83
|
634 |
msgid "Fast, No Private Media"
|
699 |
"running in the background to update URLs in your post content. %2$s"
|
700 |
msgstr ""
|
701 |
|
702 |
+
#: classes/upgrades/upgrade-edd-replace-urls.php:38
|
703 |
msgid "and ensuring that only the local URL exists in EDD post meta."
|
704 |
msgstr ""
|
705 |
|
721 |
"running in the background to update URLs in your post excerpts. %2$s"
|
722 |
msgstr ""
|
723 |
|
724 |
+
#: classes/upgrades/upgrade-filter-post.php:391
|
725 |
#, php-format
|
726 |
msgid ""
|
727 |
"<strong>Paused Upgrade</strong><br>The find & replace to update URLs has "
|
728 |
"been paused. %s"
|
729 |
msgstr ""
|
730 |
|
731 |
+
#: classes/upgrades/upgrade-filter-post.php:400
|
732 |
msgid "See our documentation"
|
733 |
msgstr ""
|
734 |
|
735 |
+
#: classes/upgrades/upgrade-filter-post.php:406
|
736 |
#, php-format
|
737 |
msgid ""
|
738 |
"%s for details on why we’re doing this, why it runs slowly, and how to "
|
739 |
"make it run faster."
|
740 |
msgstr ""
|
741 |
|
742 |
+
#: classes/upgrades/upgrade-item-extra-data.php:48
|
743 |
+
msgid "and updating metadata about offloaded items to new format."
|
744 |
+
msgstr ""
|
745 |
+
|
746 |
+
#: classes/upgrades/upgrade-items-table.php:47
|
747 |
msgid ""
|
748 |
"and updating the plugin's metadata to use a faster storage method. During "
|
749 |
"the update the site's total offloaded media count may be inaccurate but will "
|
762 |
"style=\"white-space:nowrap;\">(e.g. s3-us-west-2.amazonaws.com)</span>."
|
763 |
msgstr ""
|
764 |
|
765 |
+
#: classes/upgrades/upgrade-tools-errors.php:37
|
766 |
+
msgid "and reformatting internal data about previous errors from tools ."
|
767 |
+
msgstr ""
|
768 |
+
|
769 |
#: classes/upgrades/upgrade-wpos3-to-as3cf.php:36
|
770 |
msgid ""
|
771 |
"and updating the metadata to use key names compatible with the current "
|
814 |
msgid " (%s%% Complete)"
|
815 |
msgstr ""
|
816 |
|
817 |
+
#: classes/upgrades/upgrade.php:630
|
818 |
#, php-format
|
819 |
msgid "Every %d Minutes"
|
820 |
msgstr ""
|
821 |
|
822 |
+
#: classes/upgrades/upgrade.php:957
|
823 |
#, php-format
|
824 |
msgid ""
|
825 |
"<strong>Settings Locked Temporarily</strong> — You can't change any of "
|
850 |
msgid "Install Now"
|
851 |
msgstr ""
|
852 |
|
853 |
+
#: view/attachment-metabox.php:27
|
854 |
msgid "This item has not been offloaded yet."
|
855 |
msgstr ""
|
856 |
|
857 |
+
#: view/attachment-metabox.php:63
|
858 |
msgid "File does not exist on server"
|
859 |
msgstr ""
|
860 |
|
861 |
+
#: view/attachment-metabox.php:71
|
862 |
msgid "File exists on server"
|
863 |
msgstr ""
|
864 |
|
@@ -2,9 +2,9 @@
|
|
2 |
Contributors: bradt, deliciousbrains, ianmjones
|
3 |
Tags: uploads, amazon, s3, amazon s3, digitalocean, digitalocean spaces, google cloud storage, gcs, mirror, admin, media, cdn, cloudfront
|
4 |
Requires at least: 4.9
|
5 |
-
Tested up to: 5.
|
6 |
-
Requires PHP: 5.
|
7 |
-
Stable tag: 2.
|
8 |
License: GPLv3
|
9 |
|
10 |
Copies files to Amazon S3, DigitalOcean Spaces or Google Cloud Storage as they are uploaded to the Media Library. Optionally configure Amazon CloudFront or another CDN for faster delivery.
|
@@ -67,6 +67,10 @@ If you upgrade to the pro version of [WP Offload Media](https://deliciousbrains.
|
|
67 |
|
68 |
== Upgrade Notice ==
|
69 |
|
|
|
|
|
|
|
|
|
70 |
= 2.3 =
|
71 |
This is a major upgrade that switches to using a custom table for storing data about offloaded Media Library items. Once upgraded you will not be able to downgrade without restoring data from a backup.
|
72 |
|
@@ -81,6 +85,16 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
|
|
81 |
|
82 |
== Changelog ==
|
83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
= WP Offload Media Lite 2.5.5 - 2021-07-19 =
|
85 |
* Bug fix: Signed GCS URLs broken when updating a post
|
86 |
* Bug fix: Incorrect mime type set on scaled image's bucket object when thumbnail format differs from original file's format
|
2 |
Contributors: bradt, deliciousbrains, ianmjones
|
3 |
Tags: uploads, amazon, s3, amazon s3, digitalocean, digitalocean spaces, google cloud storage, gcs, mirror, admin, media, cdn, cloudfront
|
4 |
Requires at least: 4.9
|
5 |
+
Tested up to: 5.9
|
6 |
+
Requires PHP: 5.6
|
7 |
+
Stable tag: 2.6.0
|
8 |
License: GPLv3
|
9 |
|
10 |
Copies files to Amazon S3, DigitalOcean Spaces or Google Cloud Storage as they are uploaded to the Media Library. Optionally configure Amazon CloudFront or another CDN for faster delivery.
|
67 |
|
68 |
== Upgrade Notice ==
|
69 |
|
70 |
+
= 2.6 =
|
71 |
+
This is a major upgrade that updates the format of information stored about offloaded Media Library items. Once upgraded you will not be able to downgrade without restoring data from a backup.
|
72 |
+
This version requires PHP 5.6+
|
73 |
+
|
74 |
= 2.3 =
|
75 |
This is a major upgrade that switches to using a custom table for storing data about offloaded Media Library items. Once upgraded you will not be able to downgrade without restoring data from a backup.
|
76 |
|
85 |
|
86 |
== Changelog ==
|
87 |
|
88 |
+
= WP Offload Media Lite 2.6 - 2022-03-09 =
|
89 |
+
* [Release Summary Blog Post](https://deliciousbrains.com/wp-offload-media-2-6-released/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
|
90 |
+
* New: WP Offload Media is now compatible with WordPress 5.9 and Full Site Editing
|
91 |
+
* Improvement: Offloaded thumbnail sizes are now tracked for better handling of changes to registered sizes
|
92 |
+
* Improvement: Offloads and other storage provider actions are faster
|
93 |
+
* Bug fix: URL rewriting now works in the Full Site Editor
|
94 |
+
* Bug fix: Offloaded images are now shown when re-editing a Block Template or Template Part
|
95 |
+
* Bug fix: URL rewriting now works for Widgets migrated to a Widget Sidebar Block
|
96 |
+
* Bug fix: Objects are no longer left in the bucket when deleting a Media Library item with many changes to its thumbnail sizes
|
97 |
+
|
98 |
= WP Offload Media Lite 2.5.5 - 2021-07-19 =
|
99 |
* Bug fix: Signed GCS URLs broken when updating a post
|
100 |
* Bug fix: Incorrect mime type set on scaled image's bucket object when thumbnail format differs from original file's format
|
@@ -1,4 +1,8 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
|
|
2 |
/** @var Amazon_S3_And_CloudFront|Amazon_S3_And_CloudFront_Pro $this */
|
3 |
/** @var array|bool $provider_object */
|
4 |
/** @var WP_Post $post */
|
@@ -13,6 +17,9 @@ $is_removable = $is_current_provider && in_array( 'remove', $available_act
|
|
13 |
$is_copyable = $local_file_exists && in_array( 'copy', $available_actions ) && ( $is_current_provider || empty( $provider_object ) );
|
14 |
$is_downloadable = ! $local_file_exists && in_array( 'download', $available_actions ) && $is_current_provider;
|
15 |
$is_local_removable = $is_current_provider && $local_file_exists && in_array( 'remove_local', $available_actions );
|
|
|
|
|
|
|
16 |
?>
|
17 |
<div class="s3-details">
|
18 |
<?php if ( ! $provider_object ) : ?>
|
@@ -21,49 +28,49 @@ $is_local_removable = $is_current_provider && $local_file_exists && in_array( 'r
|
|
21 |
</div>
|
22 |
<?php else : ?>
|
23 |
<div class="misc-pub-section">
|
24 |
-
<div class="s3-key"><?php echo $
|
25 |
<input type="text" id="as3cf-provider" class="widefat<?php echo $provider_class; ?>" readonly="readonly" value="<?php echo $provider_name; ?>">
|
26 |
</div>
|
27 |
<div class="misc-pub-section">
|
28 |
-
<div class="s3-key"><?php echo $
|
29 |
<input type="text" id="as3cf-bucket" class="widefat" readonly="readonly" value="<?php echo $provider_object['bucket']; ?>">
|
30 |
</div>
|
31 |
<div class="misc-pub-section">
|
32 |
-
<div class="s3-key"><?php echo $
|
33 |
<input type="text" id="as3cf-key" class="widefat" readonly="readonly" value="<?php echo $provider_object['key']; ?>">
|
34 |
</div>
|
35 |
<?php if ( isset( $provider_object['region'] ) && $provider_object['region'] ) : ?>
|
36 |
<div class="misc-pub-section">
|
37 |
-
<div class="s3-key"><?php echo $
|
38 |
<div id="as3cf-region" class="s3-value"><?php echo $provider_object['region']; ?></div>
|
39 |
</div>
|
40 |
<?php endif; ?>
|
41 |
<div class="misc-pub-section">
|
42 |
-
<div class="s3-key"><?php echo $
|
43 |
<div id="as3cf-acl" class="s3-value">
|
44 |
-
<?php echo $
|
45 |
</div>
|
46 |
</div>
|
47 |
<?php
|
48 |
if ( isset( $provider_object['is_verified'] ) && empty( $provider_object['is_verified'] ) ) : ?>
|
49 |
<div class="misc-pub-section">
|
50 |
-
<div class="s3-key"><?php echo $
|
51 |
-
<div id="as3cf-is-verified" class="s3-value"><?php echo $
|
52 |
</div>
|
53 |
<?php endif; ?>
|
54 |
<?php if ( $is_downloadable ) : ?>
|
55 |
<div class="misc-pub-section">
|
56 |
<div class="not-copied"><?php _e( 'File does not exist on server', 'amazon-s3-and-cloudfront' ); ?></div>
|
57 |
-
<a id="as3cf-download-action" href="<?php echo $
|
58 |
-
<?php echo $
|
59 |
</a>
|
60 |
</div>
|
61 |
<?php endif; ?>
|
62 |
<?php if ( $is_local_removable ) : ?>
|
63 |
<div class="misc-pub-section">
|
64 |
<div class="not-copied"><?php _e( 'File exists on server', 'amazon-s3-and-cloudfront' ); ?></div>
|
65 |
-
<a id="as3cf-remove-local-action" href="<?php echo $
|
66 |
-
<?php echo $
|
67 |
</a>
|
68 |
</div>
|
69 |
<?php endif; ?>
|
@@ -75,15 +82,15 @@ $is_local_removable = $is_current_provider && $local_file_exists && in_array( 'r
|
|
75 |
<div class="s3-actions">
|
76 |
<?php if ( $is_removable ) : ?>
|
77 |
<div class="remove-action">
|
78 |
-
<a id="as3cf-remove-action" href="<?php echo $
|
79 |
-
<?php echo $
|
80 |
</a>
|
81 |
</div>
|
82 |
<?php endif; ?>
|
83 |
<?php if ( $is_copyable ) : ?>
|
84 |
<div class="copy-action">
|
85 |
-
<a id="as3cf-copy-action" href="<?php echo $
|
86 |
-
<?php echo $
|
87 |
</a>
|
88 |
</div>
|
89 |
<?php endif; ?>
|
1 |
<?php
|
2 |
+
|
3 |
+
use DeliciousBrains\WP_Offload_Media\Integrations\Media_Library;
|
4 |
+
use DeliciousBrains\WP_Offload_Media\Pro\Integrations\Media_Library_Pro;
|
5 |
+
|
6 |
/** @var Amazon_S3_And_CloudFront|Amazon_S3_And_CloudFront_Pro $this */
|
7 |
/** @var array|bool $provider_object */
|
8 |
/** @var WP_Post $post */
|
17 |
$is_copyable = $local_file_exists && in_array( 'copy', $available_actions ) && ( $is_current_provider || empty( $provider_object ) );
|
18 |
$is_downloadable = ! $local_file_exists && in_array( 'download', $available_actions ) && $is_current_provider;
|
19 |
$is_local_removable = $is_current_provider && $local_file_exists && in_array( 'remove_local', $available_actions );
|
20 |
+
|
21 |
+
/** @var Media_Library|Media_Library_Pro $media_integration */
|
22 |
+
$media_integration = $this->get_integration_manager()->get_integration( 'mlib' );
|
23 |
?>
|
24 |
<div class="s3-details">
|
25 |
<?php if ( ! $provider_object ) : ?>
|
28 |
</div>
|
29 |
<?php else : ?>
|
30 |
<div class="misc-pub-section">
|
31 |
+
<div class="s3-key"><?php echo $media_integration->get_media_action_strings( 'provider' ); ?>:</div>
|
32 |
<input type="text" id="as3cf-provider" class="widefat<?php echo $provider_class; ?>" readonly="readonly" value="<?php echo $provider_name; ?>">
|
33 |
</div>
|
34 |
<div class="misc-pub-section">
|
35 |
+
<div class="s3-key"><?php echo $media_integration->get_media_action_strings( 'bucket' ); ?>:</div>
|
36 |
<input type="text" id="as3cf-bucket" class="widefat" readonly="readonly" value="<?php echo $provider_object['bucket']; ?>">
|
37 |
</div>
|
38 |
<div class="misc-pub-section">
|
39 |
+
<div class="s3-key"><?php echo $media_integration->get_media_action_strings( 'key' ); ?>:</div>
|
40 |
<input type="text" id="as3cf-key" class="widefat" readonly="readonly" value="<?php echo $provider_object['key']; ?>">
|
41 |
</div>
|
42 |
<?php if ( isset( $provider_object['region'] ) && $provider_object['region'] ) : ?>
|
43 |
<div class="misc-pub-section">
|
44 |
+
<div class="s3-key"><?php echo $media_integration->get_media_action_strings( 'region' ); ?>:</div>
|
45 |
<div id="as3cf-region" class="s3-value"><?php echo $provider_object['region']; ?></div>
|
46 |
</div>
|
47 |
<?php endif; ?>
|
48 |
<div class="misc-pub-section">
|
49 |
+
<div class="s3-key"><?php echo $media_integration->get_media_action_strings( 'acl' ); ?>:</div>
|
50 |
<div id="as3cf-acl" class="s3-value">
|
51 |
+
<?php echo $media_integration->get_acl_value_string( $provider_object['acl'], $post->ID ); ?>
|
52 |
</div>
|
53 |
</div>
|
54 |
<?php
|
55 |
if ( isset( $provider_object['is_verified'] ) && empty( $provider_object['is_verified'] ) ) : ?>
|
56 |
<div class="misc-pub-section">
|
57 |
+
<div class="s3-key"><?php echo $media_integration->get_media_action_strings( 'is_verified' ); ?>:</div>
|
58 |
+
<div id="as3cf-is-verified" class="s3-value"><?php echo $media_integration->get_media_action_strings( 'not_verified' ); ?></div>
|
59 |
</div>
|
60 |
<?php endif; ?>
|
61 |
<?php if ( $is_downloadable ) : ?>
|
62 |
<div class="misc-pub-section">
|
63 |
<div class="not-copied"><?php _e( 'File does not exist on server', 'amazon-s3-and-cloudfront' ); ?></div>
|
64 |
+
<a id="as3cf-download-action" href="<?php echo $media_integration->get_media_action_url( 'download', $post->ID, $sendback ); ?>">
|
65 |
+
<?php echo $media_integration->get_media_action_strings( 'download' ); ?>
|
66 |
</a>
|
67 |
</div>
|
68 |
<?php endif; ?>
|
69 |
<?php if ( $is_local_removable ) : ?>
|
70 |
<div class="misc-pub-section">
|
71 |
<div class="not-copied"><?php _e( 'File exists on server', 'amazon-s3-and-cloudfront' ); ?></div>
|
72 |
+
<a id="as3cf-remove-local-action" href="<?php echo $media_integration->get_media_action_url( 'remove_local', $post->ID, $sendback ); ?>">
|
73 |
+
<?php echo $media_integration->get_media_action_strings( 'remove_local' ); ?>
|
74 |
</a>
|
75 |
</div>
|
76 |
<?php endif; ?>
|
82 |
<div class="s3-actions">
|
83 |
<?php if ( $is_removable ) : ?>
|
84 |
<div class="remove-action">
|
85 |
+
<a id="as3cf-remove-action" href="<?php echo $media_integration->get_media_action_url( 'remove', $post->ID, $sendback ); ?>">
|
86 |
+
<?php echo $media_integration->get_media_action_strings( 'remove' ); ?>
|
87 |
</a>
|
88 |
</div>
|
89 |
<?php endif; ?>
|
90 |
<?php if ( $is_copyable ) : ?>
|
91 |
<div class="copy-action">
|
92 |
+
<a id="as3cf-copy-action" href="<?php echo $media_integration->get_media_action_url( 'copy', $post->ID, $sendback ); ?>" class="button button-secondary">
|
93 |
+
<?php echo $media_integration->get_media_action_strings( 'copy' ); ?>
|
94 |
</a>
|
95 |
</div>
|
96 |
<?php endif; ?>
|
@@ -4,8 +4,8 @@ Plugin Name: WP Offload Media Lite
|
|
4 |
Plugin URI: http://wordpress.org/extend/plugins/amazon-s3-and-cloudfront/
|
5 |
Description: Automatically copies media uploads to Amazon S3, DigitalOcean Spaces or Google Cloud Storage for storage and delivery. Optionally configure Amazon CloudFront or another CDN for even faster delivery.
|
6 |
Author: Delicious Brains
|
7 |
-
Version: 2.
|
8 |
-
Author URI: https://deliciousbrains.com
|
9 |
Network: True
|
10 |
Text Domain: amazon-s3-and-cloudfront
|
11 |
Domain Path: /languages/
|
@@ -26,7 +26,7 @@ Domain Path: /languages/
|
|
26 |
// Then completely rewritten.
|
27 |
*/
|
28 |
|
29 |
-
$GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'] = '2.
|
30 |
|
31 |
require_once dirname( __FILE__ ) . '/classes/as3cf-compatibility-check.php';
|
32 |
|
4 |
Plugin URI: http://wordpress.org/extend/plugins/amazon-s3-and-cloudfront/
|
5 |
Description: Automatically copies media uploads to Amazon S3, DigitalOcean Spaces or Google Cloud Storage for storage and delivery. Optionally configure Amazon CloudFront or another CDN for even faster delivery.
|
6 |
Author: Delicious Brains
|
7 |
+
Version: 2.6.0
|
8 |
+
Author URI: https://deliciousbrains.com/?utm_campaign=WP%2BOffload%2BS3&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting
|
9 |
Network: True
|
10 |
Text Domain: amazon-s3-and-cloudfront
|
11 |
Domain Path: /languages/
|
26 |
// Then completely rewritten.
|
27 |
*/
|
28 |
|
29 |
+
$GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'] = '2.6.0';
|
30 |
|
31 |
require_once dirname( __FILE__ ) . '/classes/as3cf-compatibility-check.php';
|
32 |
|