diff --git a/README.md b/README.md
index bcefea57..92090551 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
**Requires at least:** 4.9
**Tested up to:** 5.5
**Requires PHP:** 5.5
-**Stable tag:** 2.4.4
+**Stable tag:** 2.5
**License:** GPLv3
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.
@@ -89,6 +89,13 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
## Changelog ##
+### WP Offload Media Lite 2.5 - 2020-11-11 ###
+* [Release Summary Blog Post](https://deliciousbrains.com/wp-offload-media-2-5-released/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
+* Improvement: [Error notice shown](https://deliciousbrains.com/wp-offload-media/doc/missing-table-error-notice/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting) when plugin's required custom table(s) missing
+* Improvement: [Diagnostic Info](https://deliciousbrains.com/wp-offload-media/doc/missing-table-error-notice/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting#diagnostic-info) shows status of plugin's required custom tables
+* Bug fix: wp_get_original_image_path function does not return provider URL when local files removed
+* Bug fix: File missing notices recorded in debug.log when regenerating thumbnails and Remove Files From Server turned on
+
### WP Offload Media Lite 2.4.4 - 2020-09-08 ###
* Improvement: Updated AWS PHP SDK to v3.151.6
* Bug fix: Files for duplicate thumbnail sizes not removed from server after initial offload
diff --git a/assets/css/attachment.css b/assets/css/attachment.css
index b998bae9..e2fe7253 100644
--- a/assets/css/attachment.css
+++ b/assets/css/attachment.css
@@ -1 +1 @@
-#s3-actions.postbox .inside{margin:0;padding:0}#s3-actions.postbox a,#s3-actions.postbox a:hover{text-decoration:none}#s3-actions.postbox .s3-details{padding:6px 0}#s3-actions.postbox .s3-details .misc-pub-section{clear:both;float:left;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}#s3-actions.postbox .s3-details .misc-pub-section .s3-key{float:left;width:20%;white-space:nowrap}#s3-actions.postbox .s3-details .misc-pub-section .s3-value{font-weight:bold;float:left;width:80%}#s3-actions.postbox .s3-details .misc-pub-section input.error{color:#a00}#s3-actions.postbox .s3-details .not-copied{color:#666}#s3-actions.postbox .s3-actions{padding:10px;clear:both;border-top:1px solid #ddd;border-bottom:1px solid #ddd;background:#f5f5f5}#s3-actions.postbox .s3-actions .copy-action{text-align:right;float:right;line-height:23px}#s3-actions.postbox .s3-actions .remove-action{line-height:28px;vertical-align:middle;text-align:left;float:left}#s3-actions.postbox .s3-actions .remove-action a.local-warning{color:#a00}#s3-actions.postbox .s3-actions .remove-action a.local-warning:hover{color:#f00}
+#s3-actions.postbox .inside{margin:0;padding:0}#s3-actions.postbox a,#s3-actions.postbox a:hover{text-decoration:none}#s3-actions.postbox .s3-details{padding:6px 0}#s3-actions.postbox .s3-details .misc-pub-section{clear:both;float:left;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}#s3-actions.postbox .s3-details .misc-pub-section .s3-key{float:left;width:20%;white-space:nowrap}#s3-actions.postbox .s3-details .misc-pub-section .s3-value{font-weight:bold;float:left;width:80%}#s3-actions.postbox .s3-details .misc-pub-section .s3-value .more-info{font-weight:lighter}#s3-actions.postbox .s3-details .misc-pub-section input.error{color:#a00}#s3-actions.postbox .s3-details .not-copied{color:#666}#s3-actions.postbox .s3-actions{padding:10px;clear:both;border-top:1px solid #ddd;border-bottom:1px solid #ddd;background:#f5f5f5}#s3-actions.postbox .s3-actions .copy-action{text-align:right;float:right;line-height:23px}#s3-actions.postbox .s3-actions .remove-action{line-height:28px;vertical-align:middle;text-align:left;float:left}#s3-actions.postbox .s3-actions .remove-action a.local-warning{color:#a00}#s3-actions.postbox .s3-actions .remove-action a.local-warning:hover{color:#f00}
diff --git a/assets/js/media.js b/assets/js/media.js
index 45aef6c0..9a7e9185 100644
--- a/assets/js/media.js
+++ b/assets/js/media.js
@@ -63,7 +63,7 @@ var test = {};
return;
}
var $detailsHtml = this.$el.find( '.attachment-info .details' );
- var html = this.generateDetails( response, [ 'provider_name', 'region', 'bucket', 'key', 'acl' ] );
+ var html = this.generateDetails( response, [ 'provider_name', 'region', 'bucket', 'key', 'acl', 'is_verified' ] );
$detailsHtml.append( html );
},
@@ -89,6 +89,16 @@ var test = {};
}
}
+ if ( 'is_verified' === key ) {
+ value = Boolean( parseInt( value ) );
+
+ if ( value ) {
+ return;
+ }
+
+ value = as3cf_media.strings[ 'not_verified' ];
+ }
+
html += template( {
key: key,
label: as3cf_media.strings[ key ],
diff --git a/assets/js/media.min.js b/assets/js/media.min.js
index 195e0b87..60db9f8f 100644
--- a/assets/js/media.min.js
+++ b/assets/js/media.min.js
@@ -1 +1 @@
-var test={};!function(a,b){var c=wp.media,d=c.view.Attachment.Details.TwoColumn;c.view.Attachment.Details.TwoColumn=d.extend({events:function(){return b.extend({},d.prototype.events,{"click .local-warning":"confirmS3Removal","click #as3cfpro-toggle-acl":"toggleACL"})},render:function(){this.fetchS3Details(this.model.get("id"))},fetchS3Details:function(a){wp.ajax.send("as3cf_get_attachment_provider_details",{data:{_nonce:as3cf_media.nonces.get_attachment_provider_details,id:a}}).done(b.bind(this.renderView,this))},renderView:function(a){d.prototype.render.apply(this),this.renderActionLinks(a),this.renderS3Details(a)},renderActionLinks:function(c){var d=c&&c.links||[],e=this.$el.find(".actions"),f=a("
",{"class":"s3-actions"}),g=[];b(d).each(function(a){g.push(a)}),f.append(g.join(" | ")),e.append(f)},renderS3Details:function(a){if(a&&a.provider_object){var b=this.$el.find(".attachment-info .details"),c=this.generateDetails(a,["provider_name","region","bucket","key","acl"]);b.append(c)}},generateDetails:function(a,c){var d="",e=b.template('<%= label %>: <%= value %>
');return b(c).each(function(c){if(a.provider_object[c]){var f=a.provider_object[c];if("acl"===c&&(f=a.provider_object[c].name,a.acl_toggle)){var g=b.template('<%= value %>');f=g({title:a.provider_object[c].title,acl:a.provider_object[c].acl,value:f})}d+=e({key:c,label:as3cf_media.strings[c],value:f})}}),d},confirmS3Removal:function(a){if(!confirm(as3cfpro_media.strings.local_warning))return a.preventDefault(),a.stopImmediatePropagation(),!1},toggleACL:function(c){c.preventDefault();var d=a("#as3cfpro-toggle-acl"),e=d.data("currentacl"),f=as3cfpro_media.settings.private_acl;d.hide(),d.after(''+as3cfpro_media.strings.updating_acl+""),e===as3cfpro_media.settings.private_acl&&(f=as3cfpro_media.settings.default_acl),wp.ajax.send("as3cfpro_update_acl",{data:{_ajax_nonce:as3cfpro_media.nonces.singular_update_acl,id:this.model.get("id"),acl:f}}).done(b.bind(this.updateACL,this)).fail(b.bind(this.renderACLError,this))},renderACLError:function(){a("#as3cfpro-updating").remove(),a("#as3cfpro-toggle-acl").show(),alert(as3cfpro_media.strings.change_acl_error)},updateACL:function(b){if(null==b.acl_display||null==b.title||null==b.acl||null==b.url)return void this.renderACLError();this.model.set("url",b.url),this.render();var c=a("#as3cfpro-toggle-acl");a("#as3cfpro-updating").remove(),c.text(b.acl_display),c.attr("title",b.title),c.data("currentacl",b.acl),c.show()}})}(jQuery,_);
\ No newline at end of file
+var test={};!function(a,b){var c=wp.media,d=c.view.Attachment.Details.TwoColumn;c.view.Attachment.Details.TwoColumn=d.extend({events:function(){return b.extend({},d.prototype.events,{"click .local-warning":"confirmS3Removal","click #as3cfpro-toggle-acl":"toggleACL"})},render:function(){this.fetchS3Details(this.model.get("id"))},fetchS3Details:function(a){wp.ajax.send("as3cf_get_attachment_provider_details",{data:{_nonce:as3cf_media.nonces.get_attachment_provider_details,id:a}}).done(b.bind(this.renderView,this))},renderView:function(a){d.prototype.render.apply(this),this.renderActionLinks(a),this.renderS3Details(a)},renderActionLinks:function(c){var d=c&&c.links||[],e=this.$el.find(".actions"),f=a("",{"class":"s3-actions"}),g=[];b(d).each(function(a){g.push(a)}),f.append(g.join(" | ")),e.append(f)},renderS3Details:function(a){if(a&&a.provider_object){var b=this.$el.find(".attachment-info .details"),c=this.generateDetails(a,["provider_name","region","bucket","key","acl","is_verified"]);b.append(c)}},generateDetails:function(a,c){var d="",e=b.template('<%= label %>: <%= value %>
');return b(c).each(function(c){if(a.provider_object[c]){var f=a.provider_object[c];if("acl"===c&&(f=a.provider_object[c].name,a.acl_toggle)){var g=b.template('<%= value %>');f=g({title:a.provider_object[c].title,acl:a.provider_object[c].acl,value:f})}if("is_verified"===c){if(f=Boolean(parseInt(f)))return;f=as3cf_media.strings.not_verified}d+=e({key:c,label:as3cf_media.strings[c],value:f})}}),d},confirmS3Removal:function(a){if(!confirm(as3cfpro_media.strings.local_warning))return a.preventDefault(),a.stopImmediatePropagation(),!1},toggleACL:function(c){c.preventDefault();var d=a("#as3cfpro-toggle-acl"),e=d.data("currentacl"),f=as3cfpro_media.settings.private_acl;d.hide(),d.after(''+as3cfpro_media.strings.updating_acl+""),e===as3cfpro_media.settings.private_acl&&(f=as3cfpro_media.settings.default_acl),wp.ajax.send("as3cfpro_update_acl",{data:{_ajax_nonce:as3cfpro_media.nonces.singular_update_acl,id:this.model.get("id"),acl:f}}).done(b.bind(this.updateACL,this)).fail(b.bind(this.renderACLError,this))},renderACLError:function(){a("#as3cfpro-updating").remove(),a("#as3cfpro-toggle-acl").show(),alert(as3cfpro_media.strings.change_acl_error)},updateACL:function(b){if(null==b.acl_display||null==b.title||null==b.acl||null==b.url)return void this.renderACLError();this.model.set("url",b.url),this.render();var c=a("#as3cfpro-toggle-acl");a("#as3cfpro-updating").remove(),c.text(b.acl_display),c.attr("title",b.title),c.data("currentacl",b.acl),c.show()}})}(jQuery,_);
\ No newline at end of file
diff --git a/assets/sass/attachment.scss b/assets/sass/attachment.scss
index 7de9a845..fd3be86b 100644
--- a/assets/sass/attachment.scss
+++ b/assets/sass/attachment.scss
@@ -3,9 +3,11 @@
margin: 0;
padding: 0;
}
+
a, a:hover {
text-decoration: none;
}
+
.s3-details {
padding: 6px 0;
@@ -22,19 +24,27 @@
width: 20%;
white-space: nowrap;
}
+
.s3-value {
font-weight: bold;
float: left;
width: 80%;
+
+ .more-info {
+ font-weight: lighter;
+ }
}
+
input.error {
color: #a00;
}
}
+
.not-copied {
color: #666;
}
}
+
.s3-actions {
padding: 10px;
clear: both;
@@ -56,6 +66,7 @@
a.local-warning {
color: #a00;
+
&:hover {
color: #f00;
}
diff --git a/classes/amazon-s3-and-cloudfront.php b/classes/amazon-s3-and-cloudfront.php
index 2c340ecc..08afe974 100644
--- a/classes/amazon-s3-and-cloudfront.php
+++ b/classes/amazon-s3-and-cloudfront.php
@@ -1,6 +1,7 @@
get_object_prefix() );
$prefix .= AS3CF_Utils::trailingslash_prefix( $this->get_dynamic_prefix( $time ) );
- if ( $this->get_setting( 'object-versioning' ) ) {
+ if ( ! empty( $object_versioning_allowed ) && $this->get_setting( 'object-versioning' ) ) {
$prefix .= AS3CF_Utils::trailingslash_prefix( $this->get_object_version_string() );
}
@@ -2339,19 +2349,20 @@ public function get_file_prefix( $time = null ) {
/**
* Get attachment's new public prefix path for current settings.
*
- * @param int $post_id Attachment ID
- * @param array $metadata Optional attachment metadata
+ * @param int $post_id Attachment ID
+ * @param array $metadata Optional attachment metadata
+ * @param bool $object_versioning_allowed Can an Object Versioning string be appended if setting turned on? Default true.
*
* @return string
*/
- public function get_new_attachment_prefix( $post_id, $metadata = null ) {
+ public function get_new_attachment_prefix( $post_id, $metadata = null, $object_versioning_allowed = true ) {
if ( empty( $metadata ) ) {
$metadata = wp_get_attachment_metadata( $post_id, true );
}
$time = $this->get_attachment_folder_year_month( $post_id, $metadata );
- return $this->get_file_prefix( $time );
+ return $this->get_file_prefix( $time, $object_versioning_allowed );
}
/**
@@ -2459,15 +2470,9 @@ public function get_attachment_provider_url( $post_id, Media_Library_Item $as3cf
// Is a signed expiring URL required for the requested object?
if ( is_null( $expires ) ) {
- if ( is_null( $size ) && $as3cf_item->is_private() ) {
- // Full size URL private
- $expires = self::DEFAULT_EXPIRES;
- }
-
- if ( ! is_null( $size ) && $as3cf_item->is_private_size( $size ) ) {
- // Alternative size URL private
- $expires = self::DEFAULT_EXPIRES;
- }
+ $expires = $as3cf_item->is_private_size( $size ) ? self::DEFAULT_EXPIRES : null;
+ } else {
+ $expires = $as3cf_item->is_private_size( $size ) ? $expires : null;
}
$item_path = $as3cf_item->path();
@@ -2734,10 +2739,11 @@ protected function maybe_sign_intermediate_size( $url, $attachment_id, $size, $a
* @param bool $skip_rewrite_check Still check if offloaded even if not currently rewriting URLs? Default: false
* @param bool $skip_current_provider_check Skip checking if offloaded to current provider. Default: false, negated if $provider supplied
* @param Storage_Provider|null $provider Provider where attachment expected to be offloaded to. Default: currently configured provider
+ * @param bool $check_is_verified Check that metadata is verified, has no effect if $skip_rewrite_check is true. Default: false
*
* @return bool|Media_Library_Item
*/
- public function is_attachment_served_by_provider( $attachment_id, $skip_rewrite_check = false, $skip_current_provider_check = false, Storage_Provider $provider = null ) {
+ 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 ) {
if ( ! $skip_rewrite_check && ! $this->get_setting( 'serve-from-s3' ) ) {
// Not serving provider URLs
return false;
@@ -2750,6 +2756,11 @@ public function is_attachment_served_by_provider( $attachment_id, $skip_rewrite_
return false;
}
+ if ( ! $skip_rewrite_check && ! empty( $check_is_verified ) && ! $as3cf_item->is_verified() ) {
+ // Offload not verified, treat as not offloaded.
+ return false;
+ }
+
if ( ! $skip_current_provider_check && empty( $provider ) ) {
$provider = $this->get_storage_provider();
}
@@ -2791,6 +2802,9 @@ function update_attached_file( $file, $attachment_id ) {
* unless we know who the calling process is and we are happy
* to copy the file back to the server to be used.
*
+ * @handles get_attached_file
+ * @handles wp_get_original_image_path
+ *
* @param string $file
* @param int $attachment_id
*
@@ -3404,6 +3418,7 @@ public function plugin_load() {
$this->handle_post_request();
$this->http_prepare_download_log();
$this->check_for_gd_imagick();
+ $this->check_for_items_table();
do_action( 'as3cf_plugin_load' );
}
@@ -4127,10 +4142,11 @@ function is_pro() {
* Make admin notice for when object ACL has changed
*
* @param Media_Library_Item $as3cf_item
+ * @param string|null $size
*/
- function make_acl_admin_notice( Media_Library_Item $as3cf_item ) {
- $filename = wp_basename( $as3cf_item->path() );
- $acl = $as3cf_item->is_private() ? $this->get_storage_provider()->get_private_acl() : $this->get_storage_provider()->get_default_acl();
+ function make_acl_admin_notice( Media_Library_Item $as3cf_item, $size = null ) {
+ $filename = wp_basename( $as3cf_item->path( $size ) );
+ $acl = $as3cf_item->is_private_size( $size ) ? $this->get_storage_provider()->get_private_acl() : $this->get_storage_provider()->get_default_acl();
$acl_name = $this->get_acl_display_name( $acl );
$text = sprintf( __( 'WP Offload Media — The file %s has been given %s permissions in the bucket.', 'amazon-s3-and-cloudfront' ), "{$filename}", "{$acl_name}" );
@@ -4157,6 +4173,44 @@ function check_for_gd_imagick() {
}
}
+ /**
+ * Ensure items table(s) exists in the database
+ */
+ private function check_for_items_table() {
+ if ( ! $this->is_plugin_setup( true ) ) {
+ // No notice until plugin is setup
+ return;
+ }
+
+ if ( is_multisite() && ! is_network_admin() ) {
+ return;
+ }
+
+ $missing_tables = $this->get_db_init_status( false );
+
+ if ( count( $missing_tables ) !== 0 ) {
+ $this->notices->add_notice(
+ sprintf(
+ __( 'Missing Table — One or more required database tables are missing, please check the Diagnostic Info in the Support tab for details. %s', 'amazon-s3-and-cloudfront' ),
+ $this->more_info_link(
+ '/wp-offload-media/doc/missing-table-error-notice',
+ 'missing-table'
+ )
+ ),
+ array(
+ 'custom_id' => 'items_table_error',
+ 'type' => 'error',
+ 'dismissible' => false,
+ 'flash' => false,
+ 'only_show_to_user' => false,
+ 'only_show_in_settings' => true,
+ )
+ );
+ } else {
+ $this->notices->remove_notice_by_id( 'items_table_error' );
+ }
+ }
+
/**
* Output image size names and dimensions to a string
*
@@ -4498,6 +4552,32 @@ function output_diagnostic_info( $escape = true ) {
$output .= esc_html( $this->get_setting( 'post_meta_version' ) );
$output .= "\r\n\r\n";
+ /*
+ * Items db tables status
+ */
+
+ $db_init_statuses = $this->get_db_init_status( true );
+ $missing_tables = $this->get_db_init_status( false );
+
+ $output .= "Custom tables:\r\n";
+ if ( count( $missing_tables ) === 0 ) {
+ $output .= $db_init_statuses[1]['name'] . ': Ok';
+ $output .= "\r\n";
+ } else {
+ // Output the first 5 missing tables
+ $table_count = 0;
+ foreach ( $missing_tables as $missing_table ) {
+ $table_count++;
+ if ( $table_count > 5 ) {
+ break;
+ }
+ $output .= $missing_table['name'] . ': ';
+ $output .= $missing_table['status'] ? 'Ok' : 'Missing';
+ $output .= "\r\n";
+ }
+ }
+ $output .= "\r\n";
+
$storage_provider = $this->get_storage_provider();
if ( empty( $storage_provider ) ) {
@@ -5064,6 +5144,48 @@ public function media_counts( $skip_transient = false, $force = false ) {
return $attachment_counts;
}
+ /**
+ * Check the existence of the items table (as3cf_items). Returns an array with one row per
+ * possible database prefix (multisite support).
+ *
+ * @param bool $all Return all tables or just missing tables. Defaults to all/true.
+ * @param bool $skip_transient Whether to force database query and skip transient, default false.
+ *
+ * @return array
+ */
+ private function get_db_init_status( $all = true, $skip_transient = false ) {
+ global $wpdb;
+
+ if ( $skip_transient || false === ( $db_init_status = get_site_transient( 'as3cf_db_init_status' ) ) ) {
+ $table_prefixes = $this->get_all_blog_table_prefixes();
+
+ $db_init_status = array();
+
+ foreach ( $table_prefixes as $blog_id => $table_prefix ) {
+ $table_name = $table_prefix . Item::ITEMS_TABLE;
+
+ $db_init_status[ $blog_id ] = array(
+ 'name' => $table_name,
+ 'status' => false,
+ );
+
+ if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table_name ) ) === $table_name ) {
+ $db_init_status[ $blog_id ]['status'] = true;
+ }
+ }
+
+ set_site_transient( 'as3cf_db_init_status', $db_init_status, 5 * MINUTE_IN_SECONDS );
+ }
+
+ if ( ! $all ) {
+ $db_init_status = array_filter( $db_init_status, function ( $table ) {
+ return false === $table['status'];
+ } );
+ }
+
+ return $db_init_status;
+ }
+
/**
* Display a notice after either lite or pro plugin has been auto deactivated
*/
@@ -5110,13 +5232,16 @@ protected function get_utm_source() {
/**
* More info link.
*
- * @param string $path
- * @param string $utm_content
- * @param string $hash
+ * @param string $path Relative path on DBI site
+ * @param string $utm_content Optional utm_content value.
+ * @param string $hash Optional hash anchor value without the '#'.
+ * @param string $text Optional override of link text.
+ * @param string $prefix Optional non-linked prefix text.
+ * @param string $suffix Optional non-linked suffix text.
*
* @return string
*/
- public function more_info_link( $path, $utm_content = '', $hash = '' ) {
+ public function more_info_link( $path, $utm_content = '', $hash = '', $text = '', $prefix = '', $suffix = '' ) {
$args = array(
'utm_campaign' => 'support+docs',
);
@@ -5125,11 +5250,14 @@ public function more_info_link( $path, $utm_content = '', $hash = '' ) {
$args['utm_content'] = $utm_content;
}
+ $text = empty( $text ) ? __( 'More info »', 'amazon-s3-and-cloudfront' ) : $text;
+ $prefix = empty( $prefix ) ? '' : $prefix;
+ $suffix = empty( $suffix ) ? '' : $suffix;
+
$url = $this->dbrains_url( $path, $args, $hash );
- $text = __( 'More info »', 'amazon-s3-and-cloudfront' );
$link = AS3CF_Utils::dbrains_link( $url, $text );
- return sprintf( '%s', $link );
+ return sprintf( '%s%s%s', $prefix, $link, $suffix );
}
/**
@@ -5344,6 +5472,10 @@ public function get_formatted_provider_info( $id ) {
* @return array|string
*/
public function get_media_action_strings( $string = null ) {
+ $not_verified_value = __( 'No', 'amazon-s3-and-cloudfront' );
+ $not_verified_value .= ' ';
+ $not_verified_value .= $this->more_info_link( '/wp-offload-media/doc/add-metadata-tool/', 'os3+attachment+metabox', 'analyze-and-repair', 'More Info', '(', ')' );
+
$strings = apply_filters( 'as3cf_media_action_strings', array(
'provider' => _x( 'Storage Provider', 'Storage provider key name', 'amazon-s3-and-cloudfront' ),
'provider_name' => _x( 'Storage Provider', 'Storage provider name', 'amazon-s3-and-cloudfront' ),
@@ -5352,6 +5484,8 @@ public function get_media_action_strings( $string = null ) {
'region' => _x( 'Region', 'Location of bucket', 'amazon-s3-and-cloudfront' ),
'acl' => _x( 'Access', 'Access control list of the file in bucket', 'amazon-s3-and-cloudfront' ),
'url' => __( 'URL', 'amazon-s3-and-cloudfront' ),
+ 'is_verified' => _x( 'Verified', 'Whether or not metadata has been verified', 'amazon-s3-and-cloudfront' ),
+ 'not_verified' => $not_verified_value,
) );
if ( ! is_null( $string ) ) {
diff --git a/classes/as3cf-filter.php b/classes/as3cf-filter.php
index 41e62991..13ae845d 100644
--- a/classes/as3cf-filter.php
+++ b/classes/as3cf-filter.php
@@ -582,7 +582,7 @@ protected function push_to_url_pairs( &$url_pairs, $attachment_id, $find, &$to_c
*
* @return null|string
*/
- protected function get_size_string_from_url( $attachment_id, $url ) {
+ public function get_size_string_from_url( $attachment_id, $url ) {
$meta = get_post_meta( $attachment_id, '_wp_attachment_metadata', true );
if ( empty( $meta['sizes'] ) ) {
@@ -848,8 +848,8 @@ protected function should_filter_content() {
*
* @return string
*/
- protected function remove_aws_query_strings( $content, $base_url = '' ) {
- $pattern = '\?[^\s"<\?]*(?:X-Amz-Algorithm|AWSAccessKeyId)=[^\s"<\?]+';
+ public static function remove_aws_query_strings( $content, $base_url = '' ) {
+ $pattern = '\?[^\s"<\?]*(?:X-Amz-Algorithm|AWSAccessKeyId|Key-Pair-Id)=[^\s"<\?]+';
$group = 0;
if ( ! is_string( $content ) ) {
diff --git a/classes/as3cf-plugin-compatibility.php b/classes/as3cf-plugin-compatibility.php
index 61c6362a..16454811 100644
--- a/classes/as3cf-plugin-compatibility.php
+++ b/classes/as3cf-plugin-compatibility.php
@@ -46,6 +46,16 @@ class AS3CF_Plugin_Compatibility {
*/
private $removed_files = array();
+ /**
+ * @var bool
+ */
+ protected $generate_attachment_metadata_done = false;
+
+ /**
+ * @var bool
+ */
+ protected $wait_for_generate_attachment_metadata = false;
+
/**
* @param Amazon_S3_And_CloudFront $as3cf
*/
@@ -118,6 +128,7 @@ function compatibility_init_if_setup() {
* Regenerate Thumbnails v3+ and other REST-API using plugins that need a local file.
*/
add_filter( 'rest_dispatch_request', array( $this, 'rest_dispatch_request_copy_back_to_local' ), 10, 4 );
+ add_filter( 'as3cf_wait_for_generate_attachment_metadata', array( $this, 'wait_for_generate_attachment_metadata' ) );
/*
* WP-CLI Compatibility
@@ -171,6 +182,8 @@ public function enable_get_attached_file_copy_back_to_local() {
$this,
'prevent_copy_back_to_local_after_remove',
), 10, 4 );
+
+ add_filter( 'wp_generate_attachment_metadata', array( $this, 'wp_generate_attachment_metadata' ) );
}
/**
@@ -219,6 +232,37 @@ function is_ajax() {
return false;
}
+ /**
+ * Handler for wp_generate_attachment_metadata. Updates class
+ * member variable when the filter has fired.
+ *
+ * @handles wp_generate_attachment_metadata
+ *
+ * @param $metadata
+ *
+ * @return mixed
+ */
+ public function wp_generate_attachment_metadata( $metadata ) {
+ $this->generate_attachment_metadata_done = true;
+ return $metadata;
+ }
+
+ /**
+ * Are we waiting for the wp_generate_attachment_metadata filter and
+ * if so, has it run yet?
+ *
+ * @handles as3cf_wait_for_generate_attachment_metadata
+ *
+ * @return bool
+ */
+ public function wait_for_generate_attachment_metadata() {
+ if ( ! $this->wait_for_generate_attachment_metadata ) {
+ return false;
+ }
+
+ return ! $this->generate_attachment_metadata_done;
+ }
+
/**
* Check the current request is a specific one based on action and
* optional context
@@ -983,6 +1027,8 @@ public function rest_dispatch_request_copy_back_to_local( $dispatch_result, $req
foreach ( $routes as $match_route ) {
if ( preg_match( '@' . $match_route . '@i', $route ) ) {
$this->enable_get_attached_file_copy_back_to_local();
+ $this->wait_for_generate_attachment_metadata = true;
+ $this->generate_attachment_metadata_done = false;
break;
}
}
diff --git a/classes/as3cf-utils.php b/classes/as3cf-utils.php
index abd06766..ad0f8b0a 100644
--- a/classes/as3cf-utils.php
+++ b/classes/as3cf-utils.php
@@ -111,6 +111,21 @@ public static function remove_size_from_filename( $url, $remove_extension = fals
return $url;
}
+ /**
+ * Is the given size recognized as the full sized image?
+ *
+ * @param string|null $size
+ *
+ * @return bool
+ */
+ public static function is_full_size( $size ) {
+ if ( empty( $size ) || in_array( $size, array( 'full', 'original' ) ) ) {
+ return true;
+ }
+
+ return false;
+ }
+
/**
* Reduce the given URL down to the simplest version of itself.
*
diff --git a/classes/filters/as3cf-local-to-s3.php b/classes/filters/as3cf-local-to-s3.php
index 609e3cc0..6aa83366 100644
--- a/classes/filters/as3cf-local-to-s3.php
+++ b/classes/filters/as3cf-local-to-s3.php
@@ -202,7 +202,7 @@ protected function get_base_url( $attachment_id ) {
*
* @return bool|int
*/
- protected function get_attachment_id_from_url( $url ) {
+ public function get_attachment_id_from_url( $url ) {
$results = $this->get_attachment_ids_from_urls( array( $url ) );
if ( empty( $results ) ) {
diff --git a/classes/items/item.php b/classes/items/item.php
index 3f7a6c26..cff0576f 100644
--- a/classes/items/item.php
+++ b/classes/items/item.php
@@ -8,6 +8,10 @@
abstract class Item {
const ITEMS_TABLE = 'as3cf_items';
+ const ORIGINATORS = array(
+ 'standard' => 0,
+ 'metadata-tool' => 1,
+ );
protected static $source_type = 'media-library';
protected static $source_table = 'posts';
@@ -41,6 +45,8 @@ abstract class Item {
private $source_path;
private $original_source_path;
private $extra_info;
+ private $originator;
+ private $is_verified;
/**
* Item constructor.
@@ -54,9 +60,24 @@ abstract class Item {
* @param string $source_path Path that source uses, could be relative or absolute depending on source.
* @param string $original_filename An optional filename with no path that was previously used for the item.
* @param array $extra_info An optional array of extra data specific to the source type.
- * @param null $id Optional Item record ID.
+ * @param int $id Optional Item record ID.
+ * @param int $originator Optional originator of record from ORIGINATORS const.
+ * @param bool $is_verified Optional flag as to whether Item's objects are known to exist.
*/
- public function __construct( $provider, $region, $bucket, $path, $is_private, $source_id, $source_path, $original_filename = null, $extra_info = array(), $id = null ) {
+ public function __construct(
+ $provider,
+ $region,
+ $bucket,
+ $path,
+ $is_private,
+ $source_id,
+ $source_path,
+ $original_filename = null,
+ $extra_info = array(),
+ $id = null,
+ $originator = 0,
+ $is_verified = true
+ ) {
$this->provider = $provider;
$this->region = $region;
$this->bucket = $bucket;
@@ -65,6 +86,8 @@ public function __construct( $provider, $region, $bucket, $path, $is_private, $s
$this->source_id = $source_id;
$this->source_path = $source_path;
$this->extra_info = serialize( $extra_info );
+ $this->originator = $originator;
+ $this->is_verified = $is_verified;
if ( empty( $original_filename ) ) {
$this->original_path = $path;
@@ -394,7 +417,7 @@ private static function install_table( $table_name ) {
$sql = "
CREATE TABLE {$table_name} (
- id BIGINT(20) NOT NULL AUTO_INCREMENT,
+ id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
provider VARCHAR(18) NOT NULL,
region VARCHAR(255) NOT NULL,
bucket VARCHAR(255) NOT NULL,
@@ -402,17 +425,20 @@ private static function install_table( $table_name ) {
original_path VARCHAR(1024) NOT NULL,
is_private BOOLEAN NOT NULL DEFAULT 0,
source_type VARCHAR(18) NOT NULL,
- source_id BIGINT(20) NOT NULL,
+ source_id BIGINT(20) UNSIGNED NOT NULL,
source_path VARCHAR(1024) NOT NULL,
original_source_path VARCHAR(1024) NOT NULL,
extra_info LONGTEXT,
+ originator TINYINT UNSIGNED NOT NULL DEFAULT 0,
+ is_verified BOOLEAN NOT NULL DEFAULT 1,
PRIMARY KEY (id),
UNIQUE KEY uidx_path (path(190), id),
UNIQUE KEY uidx_original_path (original_path(190), id),
UNIQUE KEY uidx_source_path (source_path(190), id),
UNIQUE KEY uidx_original_source_path (original_source_path(190), id),
UNIQUE KEY uidx_source (source_type, source_id),
- UNIQUE KEY uidx_provider_bucket (provider, bucket(190), id)
+ UNIQUE KEY uidx_provider_bucket (provider, bucket(190), id),
+ UNIQUE KEY uidx_is_verified_originator (is_verified, originator, id)
) $charset_collate;
";
dbDelta( $sql );
@@ -438,6 +464,8 @@ public function key_values( $include_id = false ) {
'source_path' => $this->source_path,
'original_source_path' => $this->original_source_path,
'extra_info' => $this->extra_info,
+ 'originator' => $this->originator,
+ 'is_verified' => $this->is_verified,
);
if ( $include_id && ! empty( $this->id ) ) {
@@ -491,6 +519,8 @@ private function key_formats( $include_id = false ) {
'source_path' => '%s',
'original_source_path' => '%s',
'extra_info' => '%s',
+ 'originator' => '%d',
+ 'is_verified' => '%d',
);
if ( $include_id && ! empty( $this->id ) ) {
@@ -600,7 +630,9 @@ protected static function create( $object, $add_to_object_cache = false ) {
$object->source_path,
wp_basename( $object->original_source_path ),
$extra_info,
- $object->id
+ $object->id,
+ $object->originator,
+ $object->is_verified
);
if ( $add_to_object_cache ) {
@@ -743,6 +775,15 @@ public function is_private() {
return (bool) $this->is_private;
}
+ /**
+ * Setter for item's is_private value
+ *
+ * @param bool $private
+ */
+ public function set_is_private( $private ) {
+ $this->is_private = (bool) $private;
+ }
+
/**
* Getter for item's source_id value.
*
@@ -779,6 +820,42 @@ public function extra_info() {
return unserialize( $this->extra_info );
}
+ /**
+ * Setter for extra_info value
+ *
+ * @param array $extra_info
+ */
+ protected function set_extra_info( $extra_info ) {
+ $this->extra_info = serialize( $extra_info );
+ }
+
+ /**
+ * Getter for item's originator value.
+ *
+ * @return integer
+ */
+ public function originator() {
+ return $this->originator;
+ }
+
+ /**
+ * Getter for item's is_verified value.
+ *
+ * @return bool
+ */
+ public function is_verified() {
+ return (bool) $this->is_verified;
+ }
+
+ /**
+ * Setter for item's is_verified value
+ *
+ * @param bool $is_verified
+ */
+ public function set_is_verified( $is_verified ) {
+ $this->is_verified = (bool) $is_verified;
+ }
+
/**
* Get normalized object path dir.
*
@@ -890,7 +967,7 @@ public static function get_source_id_by_remote_url( $url ) {
}
// Regardless of whether 1 or many items found, must validate match.
- $path = ltrim( $parts['path'], '/' );
+ $path = AS3CF_Utils::decode_filename_in_path( ltrim( $parts['path'], '/' ) );
foreach ( $results as $result ) {
$as3cf_item = static::create( $result );
@@ -924,10 +1001,12 @@ public static function get_source_id_by_remote_url( $url ) {
* @param integer $upper_bound Returned source_ids should be lower than this, use null/0 for no upper bound.
* @param integer $limit Maximum number of source_ids to return. Required if not counting.
* @param bool $count Just return a count of matching source_ids? Negates $limit, default false.
+ * @param int $originator Optionally restrict to only records with given originator type from ORIGINATORS const.
+ * @param bool $is_verified Optionally restrict to only records that either are or are not verified.
*
* @return array|int
*/
- public static function get_source_ids( $upper_bound, $limit, $count = false ) {
+ public static function get_source_ids( $upper_bound, $limit, $count = false, $originator = null, $is_verified = null ) {
global $wpdb;
$args = array( static::$source_type );
@@ -945,6 +1024,30 @@ public static function get_source_ids( $upper_bound, $limit, $count = false ) {
$args[] = $upper_bound;
}
+ // If an originator type given, check that it is valid before continuing and using.
+ if ( null !== $originator ) {
+ if ( is_int( $originator ) && in_array( $originator, self::ORIGINATORS ) ) {
+ $sql .= ' AND originator = %d';
+ $args[] = $originator;
+ } else {
+ \AS3CF_Error::log( __METHOD__ . ' called with invalid originator: ' . $originator );
+
+ return $count ? 0 : array();
+ }
+ }
+
+ // If an is_verified value given, check that it is valid before continuing and using.
+ if ( null !== $is_verified ) {
+ if ( is_bool( $is_verified ) ) {
+ $sql .= ' AND is_verified = %d';
+ $args[] = (int) $is_verified;
+ } else {
+ \AS3CF_Error::log( __METHOD__ . ' called with invalid is_verified: ' . $is_verified );
+
+ return $count ? 0 : array();
+ }
+ }
+
if ( ! $count ) {
$sql .= ' ORDER BY source_id DESC LIMIT %d';
$args[] = $limit;
diff --git a/classes/items/media-library-item.php b/classes/items/media-library-item.php
index fb601ab4..78354791 100644
--- a/classes/items/media-library-item.php
+++ b/classes/items/media-library-item.php
@@ -27,9 +27,24 @@ class Media_Library_Item extends Item {
* 'private_prefix' => 'private/'
* For backwards compatibility, if a simple array is supplied it is treated as
* private thumbnail sizes that should be private objects in the bucket.
- * @param null $id Optional Item record ID.
+ * @param int $id Optional Item record ID.
+ * @param int $originator Optional originator of record from ORIGINATORS const.
+ * @param bool $is_verified Optional flag as to whether Item's objects are known to exist.
*/
- public function __construct( $provider, $region, $bucket, $path, $is_private, $source_id, $source_path, $original_filename = null, $extra_info = array(), $id = null ) {
+ public function __construct(
+ $provider,
+ $region,
+ $bucket,
+ $path,
+ $is_private,
+ $source_id,
+ $source_path,
+ $original_filename = null,
+ $extra_info = array(),
+ $id = null,
+ $originator = 0,
+ $is_verified = true
+ ) {
// For Media Library items, the source path should be relative to the Media Library's uploads directory.
$uploads = wp_upload_dir();
@@ -60,7 +75,130 @@ public function __construct( $provider, $region, $bucket, $path, $is_private, $s
'private_prefix' => $private_prefix,
);
- parent::__construct( $provider, $region, $bucket, $path, $is_private, $source_id, $source_path, $original_filename, $extra_info, $id );
+ parent::__construct( $provider, $region, $bucket, $path, $is_private, $source_id, $source_path, $original_filename, $extra_info, $id, $originator, $is_verified );
+ }
+
+ /**
+ * Get a new Media_Library_Item with all data derived from attachment data and current settings.
+ *
+ * @param int $attachment_id Attachment ID to construct record from.
+ * @param bool $object_versioning_allowed Can an Object Versioning string be appended if setting turned on? Default true.
+ * @param int $originator Originator of new record. Optional, default standard (0).
+ *
+ * @return Media_Library_Item|WP_Error
+ */
+ public static function create_from_attachment( $attachment_id, $object_versioning_allowed = true, $originator = 0 ) {
+ /** @var Amazon_S3_And_CloudFront $as3cf */
+ global $as3cf;
+
+ if ( empty( $attachment_id ) ) {
+ return new WP_Error(
+ 'exception',
+ __( 'Empty Attachment ID passed to ' . __FUNCTION__, 'amazon-s3-and-cloudfront' )
+ );
+ }
+
+ $object_versioning_allowed = empty( $object_versioning_allowed ) ? false : true;
+
+ if ( ! in_array( $originator, self::ORIGINATORS ) ) {
+ return new WP_Error(
+ 'exception',
+ __( 'Invalid Originator passed to ' . __FUNCTION__, 'amazon-s3-and-cloudfront' )
+ );
+ }
+
+ // If we ever expand originators to include more pre-verified versions, this will need changing.
+ $is_verified = 0 === $originator;
+
+ /*
+ * Provider basics.
+ */
+
+ $provider = $as3cf->get_storage_provider()->get_provider_key_name();
+ $region = $as3cf->get_setting( 'region' );
+ if ( is_wp_error( $region ) ) {
+ $region = '';
+ }
+ $bucket = $as3cf->get_setting( 'bucket' );
+
+ /*
+ * Derive local and remote paths.
+ */
+
+ // Verify that get_attached_file will not blow up as it does not check the data it manipulates.
+ $attached_file_meta = get_post_meta( $attachment_id, '_wp_attached_file', true );
+ if ( ! is_string( $attached_file_meta ) ) {
+ return new WP_Error(
+ 'exception',
+ sprintf( __( 'Media Library item with ID %d has damaged meta data', 'amazon-s3-and-cloudfront' ), $attachment_id )
+ );
+ }
+ unset( $attached_file_meta );
+
+ $source_path = get_attached_file( $attachment_id, true );
+
+ // Check for valid "full" file path otherwise we'll not be able to create offload path or download in the future.
+ if ( empty( $source_path ) ) {
+ return new WP_Error(
+ 'exception',
+ sprintf( __( 'Media Library item with ID %d does not have a valid file path', 'amazon-s3-and-cloudfront' ), $attachment_id )
+ );
+ }
+
+ $attachment_metadata = wp_get_attachment_metadata( $attachment_id, true );
+
+ if ( is_wp_error( $attachment_metadata ) ) {
+ return $attachment_metadata;
+ }
+
+ $prefix = $as3cf->get_new_attachment_prefix( $attachment_id, $attachment_metadata, $object_versioning_allowed );
+ $path = $prefix . wp_basename( $source_path );
+
+ // There may be an original image that can override the default original filename.
+ $original_filename = empty( $attachment_metadata['original_image'] ) ? null : $attachment_metadata['original_image'];
+
+ /*
+ * Private file handling.
+ */
+
+ $acl = apply_filters( 'as3cf_upload_acl', $as3cf->get_storage_provider()->get_default_acl(), $attachment_metadata, $attachment_id );
+ $is_private = ! empty( $acl ) && $as3cf->get_storage_provider()->get_private_acl() === $acl;
+
+ // Maybe set private sizes and private prefix.
+ $extra_info = array(
+ 'private_sizes' => array(),
+ 'private_prefix' => '',
+ );
+
+ $file_paths = AS3CF_Utils::get_attachment_file_paths( $attachment_id, false, $attachment_metadata );
+ $file_paths = array_diff( $file_paths, array( $source_path ) );
+
+ foreach ( $file_paths as $size => $size_file_path ) {
+ $acl = apply_filters( 'as3cf_upload_acl_sizes', $as3cf->get_storage_provider()->get_default_acl(), $size, $attachment_id, $attachment_metadata );
+
+ if ( ! empty( $acl ) && $as3cf->get_storage_provider()->get_private_acl() === $acl ) {
+ $extra_info['private_sizes'][] = $size;
+ }
+ }
+
+ if ( $as3cf->private_prefix_enabled() ) {
+ $extra_info['private_prefix'] = AS3CF_Utils::trailingslash_prefix( $as3cf->get_setting( 'signed-urls-object-prefix', '' ) );
+ }
+
+ return new self(
+ $provider,
+ $region,
+ $bucket,
+ $path,
+ $is_private,
+ $attachment_id,
+ $source_path,
+ $original_filename,
+ $extra_info,
+ null,
+ $originator,
+ $is_verified
+ );
}
/**
@@ -141,6 +279,28 @@ protected function source_paths( $id ) {
return $paths;
}
+ /**
+ * Getter for item's path value, optionally for a specific size
+ *
+ * @param null|string $size
+ *
+ * @return string
+ */
+ public function path( $size = null ) {
+ $path = parent::path();
+
+ if ( empty( $size ) ) {
+ return $path;
+ }
+
+ $meta = get_post_meta( $this->source_id(), '_wp_attachment_metadata', true );
+ if ( ! empty( $meta['sizes'][ $size ]['file'] ) ) {
+ $path = str_replace( wp_basename( $path ), $meta['sizes'][ $size ]['file'], $path );
+ }
+
+ return $path;
+ }
+
/**
* Get the array of thumbnail sizes that are private in the bucket.
*
@@ -165,6 +325,30 @@ public function private_sizes() {
return array();
}
+ /**
+ * Set the private status for a specific size.
+ *
+ * @param $size
+ * @param $private
+ */
+ public function set_private_size( $size, $private ) {
+ if ( empty( $size ) || AS3CF_Utils::is_full_size( $size ) ) {
+ return;
+ }
+
+ $extra_info = $this->extra_info();
+ $private_sizes = $this->private_sizes();
+ if ( $private && ! in_array( $size, $private_sizes, true ) ) {
+ $private_sizes[] = $size;
+ }
+ if ( ! $private && in_array( $size, $private_sizes, true ) ) {
+ $private_sizes = array_diff( $private_sizes, array( $size ) );
+ }
+ $extra_info['private_sizes'] = $private_sizes;
+
+ $this->set_extra_info( $extra_info );
+ }
+
/**
* Get the private status for a specific size.
*
@@ -173,7 +357,7 @@ public function private_sizes() {
* @return bool
*/
public function is_private_size( $size ) {
- if ( empty( $size ) || in_array( $size, array( 'full', 'original' ) ) ) {
+ if ( AS3CF_Utils::is_full_size( $size ) ) {
return $this->is_private();
}
diff --git a/languages/amazon-s3-and-cloudfront-en.pot b/languages/amazon-s3-and-cloudfront-en.pot
index 27a91e02..450a764d 100644
--- a/languages/amazon-s3-and-cloudfront-en.pot
+++ b/languages/amazon-s3-and-cloudfront-en.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: amazon-s3-and-cloudfront\n"
"Report-Msgid-Bugs-To: nom@deliciousbrains.com\n"
-"POT-Creation-Date: 2020-09-08 12:17+0100\n"
+"POT-Creation-Date: 2020-11-11 11:45+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -17,17 +17,17 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: classes/amazon-s3-and-cloudfront.php:165
#: classes/amazon-s3-and-cloudfront.php:166
+#: classes/amazon-s3-and-cloudfront.php:167
msgid "Offload Media Lite"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:400
-#: classes/amazon-s3-and-cloudfront.php:417
+#: classes/amazon-s3-and-cloudfront.php:402
+#: classes/amazon-s3-and-cloudfront.php:419
msgid "Unknown"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:489
+#: classes/amazon-s3-and-cloudfront.php:491
#: view/bucket-select.php:87
#: view/delivery-provider-select.php:129
#: view/delivery-provider-select.php:149
@@ -38,221 +38,223 @@ msgstr ""
msgid "defined in wp-config.php"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:1413
+#: classes/amazon-s3-and-cloudfront.php:1422
#, php-format
msgid "Media Library item ID %d. Provided path is not a string"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:1421
+#: classes/amazon-s3-and-cloudfront.php:1430
+#: classes/items/media-library-item.php:133
#, php-format
msgid "Media Library item with ID %d has damaged meta data"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:1432
+#: classes/amazon-s3-and-cloudfront.php:1441
+#: classes/items/media-library-item.php:144
#, php-format
msgid "Media Library item with ID %d does not have a valid file path"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:1483
-#: classes/amazon-s3-and-cloudfront.php:1708
+#: classes/amazon-s3-and-cloudfront.php:1492
+#: classes/amazon-s3-and-cloudfront.php:1717
#, php-format
msgid "File %s does not exist"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:1512
+#: classes/amazon-s3-and-cloudfront.php:1521
#, php-format
msgid "Mime type %s is not allowed"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:1523
+#: classes/amazon-s3-and-cloudfront.php:1532
msgid "Already offloaded to a different provider"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:1631
-#: classes/amazon-s3-and-cloudfront.php:1722
+#: classes/amazon-s3-and-cloudfront.php:1640
+#: classes/amazon-s3-and-cloudfront.php:1731
#, php-format
msgid "Error offloading %s to provider: %s"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:2840
+#: classes/amazon-s3-and-cloudfront.php:2854
msgid "This action can only be performed through an admin screen."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:2842
+#: classes/amazon-s3-and-cloudfront.php:2856
msgid "Cheatin’ eh?"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:2844
+#: classes/amazon-s3-and-cloudfront.php:2858
msgid "You do not have sufficient permissions to access this page."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3168
+#: classes/amazon-s3-and-cloudfront.php:3182
msgid "Error Getting Bucket Region"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3169
+#: classes/amazon-s3-and-cloudfront.php:3183
#, php-format
msgid "There was an error attempting to get the region of the bucket %s: %s"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3272
+#: classes/amazon-s3-and-cloudfront.php:3286
msgid ""
"This is a test file to check if the user has write permission to the bucket. "
"Delete me if found."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3278
+#: classes/amazon-s3-and-cloudfront.php:3292
#, php-format
msgid ""
"There was an error attempting to check the permissions of the bucket %s: %s"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3374
+#: classes/amazon-s3-and-cloudfront.php:3388
msgid "Error creating bucket"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3375
+#: classes/amazon-s3-and-cloudfront.php:3389
msgid "Bucket name too short."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3376
+#: classes/amazon-s3-and-cloudfront.php:3390
msgid "Bucket name too long."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3377
+#: classes/amazon-s3-and-cloudfront.php:3391
msgid ""
"Invalid character. Bucket names can contain lowercase letters, numbers, "
"periods and hyphens."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3378
+#: classes/amazon-s3-and-cloudfront.php:3392
msgid "Error saving bucket"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3379
+#: classes/amazon-s3-and-cloudfront.php:3393
msgid "Error fetching buckets"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3380
+#: classes/amazon-s3-and-cloudfront.php:3394
msgid "Error getting URL preview: "
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3381
+#: classes/amazon-s3-and-cloudfront.php:3395
msgid "The changes you made will be lost if you navigate away from this page"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3382
+#: classes/amazon-s3-and-cloudfront.php:3396
msgid "Getting diagnostic info..."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3383
+#: classes/amazon-s3-and-cloudfront.php:3397
msgid "Error getting diagnostic info: "
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3384
+#: classes/amazon-s3-and-cloudfront.php:3398
msgctxt "placeholder for hidden access key, 39 char max"
msgid "-- not shown --"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3386
-#: classes/amazon-s3-and-cloudfront.php:5643
+#: classes/amazon-s3-and-cloudfront.php:3400
+#: classes/amazon-s3-and-cloudfront.php:5777
msgid "Settings saved."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3507
+#: classes/amazon-s3-and-cloudfront.php:3522
msgid "Cheatin' eh?"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3580
+#: classes/amazon-s3-and-cloudfront.php:3595
#, php-format
msgid "Could not set new Delivery Provider: %s"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3655
-#: classes/amazon-s3-and-cloudfront.php:3785
+#: classes/amazon-s3-and-cloudfront.php:3670
+#: classes/amazon-s3-and-cloudfront.php:3800
msgid "No bucket name provided."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3664
+#: classes/amazon-s3-and-cloudfront.php:3679
msgid "Bucket name not valid."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3677
+#: classes/amazon-s3-and-cloudfront.php:3692
msgid "No region provided."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3754
+#: classes/amazon-s3-and-cloudfront.php:3769
#, php-format
msgctxt "Trying to change public access setting for given provider's bucket."
msgid "Can't change Block All Public Access setting for %s buckets."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3763
+#: classes/amazon-s3-and-cloudfront.php:3778
msgid "No block public access setting provided."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3776
+#: classes/amazon-s3-and-cloudfront.php:3791
msgid "Storage Provider not configured with access credentials."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3803
+#: classes/amazon-s3-and-cloudfront.php:3818
msgid "Could not change Block All Public Access status for bucket."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3820
+#: classes/amazon-s3-and-cloudfront.php:3835
msgid ""
"Failed to Enable Block All Public Access — We could "
"not enable Block All Public Access. You will need to log in to the AWS "
"Console and do it manually."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3822
+#: classes/amazon-s3-and-cloudfront.php:3837
msgid ""
"Failed to Disable Block All Public Access — We could "
"not disable Block All Public Access. You will need to log in to the AWS "
"Console and do it manually."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3857
+#: classes/amazon-s3-and-cloudfront.php:3872
#: view/provider-select.php:329
msgctxt "placeholder for hidden secret access key, 39 char max"
msgid "-- not shown --"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3880
+#: classes/amazon-s3-and-cloudfront.php:3895
msgid "Key File not valid JSON."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3892
-#: classes/amazon-s3-and-cloudfront.php:3906
-#: classes/amazon-s3-and-cloudfront.php:3915
+#: classes/amazon-s3-and-cloudfront.php:3907
+#: classes/amazon-s3-and-cloudfront.php:3921
+#: classes/amazon-s3-and-cloudfront.php:3930
msgctxt "missing form field"
msgid " not provided."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3958
+#: classes/amazon-s3-and-cloudfront.php:3973
msgctxt "Show the media library tab"
msgid "Media Library"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3959
+#: classes/amazon-s3-and-cloudfront.php:3974
msgctxt "Show the addons tab"
msgid "Addons"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:3960
+#: classes/amazon-s3-and-cloudfront.php:3975
msgctxt "Show the support tab"
msgid "Support"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:4135
+#: classes/amazon-s3-and-cloudfront.php:4151
#, php-format
msgid ""
"WP Offload Media — The file %s has been given %s "
"permissions in the bucket."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:4154
+#: classes/amazon-s3-and-cloudfront.php:4170
msgid ""
"WP Offload Media Requirement Missing — Looks like you "
"don't have an image manipulation library installed on this server and "
@@ -260,18 +262,26 @@ msgid ""
"Please setup GD or ImageMagick."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:4936
+#: classes/amazon-s3-and-cloudfront.php:4194
+#, php-format
+msgid ""
+"Missing Table — One or more required database tables "
+"are missing, please check the Diagnostic Info in the Support tab for "
+"details. %s"
+msgstr ""
+
+#: classes/amazon-s3-and-cloudfront.php:5016
#, php-format
msgid ""
"Define your access keys to enable write access to the "
"bucket"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:4943
+#: classes/amazon-s3-and-cloudfront.php:5023
msgid "Quick Start Guide"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:4945
+#: classes/amazon-s3-and-cloudfront.php:5025
#, php-format
msgid ""
"Looks like we don't have write access to this bucket. It's likely that the "
@@ -280,7 +290,7 @@ msgid ""
"correctly."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:4947
+#: classes/amazon-s3-and-cloudfront.php:5027
#, php-format
msgid ""
"Looks like we don't have access to the buckets. It's likely that the user "
@@ -288,39 +298,39 @@ msgid ""
"Please see our %s for instructions on setting up permissions correctly."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5073
+#: classes/amazon-s3-and-cloudfront.php:5195
msgid "WP Offload Media Activation"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5074
+#: classes/amazon-s3-and-cloudfront.php:5196
msgid ""
"WP Offload Media Lite and WP Offload Media cannot both be active. We've "
"automatically deactivated WP Offload Media Lite."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5076
+#: classes/amazon-s3-and-cloudfront.php:5198
msgid "WP Offload Media Lite Activation"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5077
+#: classes/amazon-s3-and-cloudfront.php:5199
msgid ""
"WP Offload Media Lite and WP Offload Media cannot both be active. We've "
"automatically deactivated WP Offload Media."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5129
+#: classes/amazon-s3-and-cloudfront.php:5253
msgid "More info »"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5205
+#: classes/amazon-s3-and-cloudfront.php:5333
msgid "this doc"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5207
+#: classes/amazon-s3-and-cloudfront.php:5335
msgid "WP Offload Media Feature Removed"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5208
+#: classes/amazon-s3-and-cloudfront.php:5336
#, php-format
msgid ""
"You had the \"Always non-SSL\" option selected in your settings, but we've "
@@ -331,59 +341,68 @@ msgid ""
"to the old behavior."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5243
+#: classes/amazon-s3-and-cloudfront.php:5371
msgid "Offload"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5348
+#: classes/amazon-s3-and-cloudfront.php:5475
+msgid "No"
+msgstr ""
+
+#: classes/amazon-s3-and-cloudfront.php:5480
msgctxt "Storage provider key name"
msgid "Storage Provider"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5349
+#: classes/amazon-s3-and-cloudfront.php:5481
msgctxt "Storage provider name"
msgid "Storage Provider"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5350
+#: classes/amazon-s3-and-cloudfront.php:5482
msgctxt "Bucket name"
msgid "Bucket"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5351
+#: classes/amazon-s3-and-cloudfront.php:5483
msgctxt "Path to file in bucket"
msgid "Path"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5352
+#: classes/amazon-s3-and-cloudfront.php:5484
msgctxt "Location of bucket"
msgid "Region"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5353
+#: classes/amazon-s3-and-cloudfront.php:5485
msgctxt "Access control list of the file in bucket"
msgid "Access"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5354
+#: classes/amazon-s3-and-cloudfront.php:5486
msgid "URL"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5606
+#: classes/amazon-s3-and-cloudfront.php:5487
+msgctxt "Whether or not metadata has been verified"
+msgid "Verified"
+msgstr ""
+
+#: classes/amazon-s3-and-cloudfront.php:5740
msgid "Assets Pull"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5607
+#: classes/amazon-s3-and-cloudfront.php:5741
msgid ""
"An addon for WP Offload Media to serve your site's JS, CSS, and other "
"enqueued assets from Amazon CloudFront or another CDN."
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5611
+#: classes/amazon-s3-and-cloudfront.php:5745
msgid "Feature"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5657
+#: classes/amazon-s3-and-cloudfront.php:5791
#, php-format
msgid ""
"Amazon Web Services Plugin No Longer Required — As of "
@@ -394,7 +413,7 @@ msgid ""
"plugin, it should be safe to deactivate and delete it. %2$s"
msgstr ""
-#: classes/amazon-s3-and-cloudfront.php:5689
+#: classes/amazon-s3-and-cloudfront.php:5823
#, php-format
msgid ""
"WP Offload Media Settings Moved — You now define your "
@@ -527,26 +546,34 @@ msgstr ""
msgid "Settings"
msgstr ""
-#: classes/as3cf-plugin-compatibility.php:595
+#: classes/as3cf-plugin-compatibility.php:639
#, php-format
msgid "The local directory %s does not exist and could not be created."
msgstr ""
-#: classes/as3cf-plugin-compatibility.php:596
-#: classes/as3cf-plugin-compatibility.php:608
+#: classes/as3cf-plugin-compatibility.php:640
+#: classes/as3cf-plugin-compatibility.php:652
#: classes/upgrades/upgrade-meta-wp-error.php:81
#, php-format
msgid ""
"There was an error attempting to download the file %s from the bucket: %s"
msgstr ""
-#: classes/as3cf-plugin-compatibility.php:933
+#: classes/as3cf-plugin-compatibility.php:977
#, php-format
msgid ""
"Warning: This site is using PHP %1$s, in a future update WP "
"Offload Media will require PHP %2$s or later. %3$s"
msgstr ""
+#: classes/items/media-library-item.php:97
+msgid "Empty Attachment ID passed to "
+msgstr ""
+
+#: classes/items/media-library-item.php:106
+msgid "Invalid Originator passed to "
+msgstr ""
+
#: classes/providers/delivery/another-cdn.php:47
#: classes/providers/delivery/digitalocean-spaces-cdn.php:83
msgid "Fast, No Private Media"
@@ -764,11 +791,11 @@ msgstr ""
msgid "This item has not been offloaded yet."
msgstr ""
-#: view/attachment-metabox.php:49
+#: view/attachment-metabox.php:56
msgid "File does not exist on server"
msgstr ""
-#: view/attachment-metabox.php:57
+#: view/attachment-metabox.php:64
msgid "File exists on server"
msgstr ""
diff --git a/readme.txt b/readme.txt
index 3ef49ec8..2183dc5a 100644
--- a/readme.txt
+++ b/readme.txt
@@ -4,7 +4,7 @@ Tags: uploads, amazon, s3, amazon s3, digitalocean, digitalocean spaces, google
Requires at least: 4.9
Tested up to: 5.5
Requires PHP: 5.5
-Stable tag: 2.4.4
+Stable tag: 2.5
License: GPLv3
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.
@@ -81,6 +81,13 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
== Changelog ==
+= WP Offload Media Lite 2.5 - 2020-11-11 =
+* [Release Summary Blog Post](https://deliciousbrains.com/wp-offload-media-2-5-released/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
+* Improvement: [Error notice shown](https://deliciousbrains.com/wp-offload-media/doc/missing-table-error-notice/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting) when plugin's required custom table(s) missing
+* Improvement: [Diagnostic Info](https://deliciousbrains.com/wp-offload-media/doc/missing-table-error-notice/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting#diagnostic-info) shows status of plugin's required custom tables
+* Bug fix: wp_get_original_image_path function does not return provider URL when local files removed
+* Bug fix: File missing notices recorded in debug.log when regenerating thumbnails and Remove Files From Server turned on
+
= WP Offload Media Lite 2.4.4 - 2020-09-08 =
* Improvement: Updated AWS PHP SDK to v3.151.6
* Bug fix: Files for duplicate thumbnail sizes not removed from server after initial offload
diff --git a/view/attachment-metabox.php b/view/attachment-metabox.php
index 040b7a56..bb92e32e 100644
--- a/view/attachment-metabox.php
+++ b/view/attachment-metabox.php
@@ -44,6 +44,13 @@
get_acl_value_string( $provider_object['acl'], $post->ID ); ?>
+
+
+
get_media_action_strings( 'is_verified' ); ?>:
+
get_media_action_strings( 'not_verified' ); ?>
+
+
diff --git a/wordpress-s3.php b/wordpress-s3.php
index 4dad4200..0faad4a3 100644
--- a/wordpress-s3.php
+++ b/wordpress-s3.php
@@ -4,7 +4,7 @@
Plugin URI: http://wordpress.org/extend/plugins/amazon-s3-and-cloudfront/
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.
Author: Delicious Brains
-Version: 2.4.4
+Version: 2.5
Author URI: https://deliciousbrains.com/
Network: True
Text Domain: amazon-s3-and-cloudfront
@@ -26,7 +26,7 @@
// Then completely rewritten.
*/
-$GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'] = '2.4.4';
+$GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'] = '2.5';
require_once dirname( __FILE__ ) . '/classes/as3cf-compatibility-check.php';