WP Offload S3 Lite - Version 1.2

Version Description

= 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

Download this release

Release Info

Developer deliciousbrains
Plugin Icon 128x128 WP Offload S3 Lite
Version 1.2
Comparing to
See all releases

Code changes from version 1.1.6 to 1.2

Files changed (34) hide show
  1. README.md +22 -11
  2. assets/js/modal.js +4 -4
  3. assets/js/modal.min.js +1 -1
  4. assets/js/script.js +32 -42
  5. assets/js/script.min.js +1 -1
  6. classes/amazon-s3-and-cloudfront.php +190 -258
  7. classes/as3cf-filter.php +212 -41
  8. classes/as3cf-notices.php +2 -9
  9. classes/as3cf-plugin-compatibility.php +54 -211
  10. classes/as3cf-upgrade.php +0 -600
  11. classes/as3cf-utils.php +264 -1
  12. classes/filters/as3cf-local-to-s3.php +13 -40
  13. classes/filters/as3cf-s3-to-local.php +7 -23
  14. classes/upgrades/exceptions/batch-limits-exceeded-exception.php +7 -0
  15. classes/upgrades/exceptions/no-more-blogs-exception.php +7 -0
  16. classes/upgrades/exceptions/too-many-errors-exception.php +7 -0
  17. classes/upgrades/network-upgrade.php +95 -0
  18. classes/upgrades/{as3cf-filter-post-content.php → upgrade-content-replace-urls.php} +12 -15
  19. classes/upgrades/{as3cf-filter-edd.php → upgrade-edd-replace-urls.php} +8 -27
  20. classes/upgrades/{as3cf-file-sizes.php → upgrade-file-sizes.php} +25 -66
  21. classes/upgrades/{as3cf-filter-post-excerpt.php → upgrade-filter-post-excerpt.php} +3 -6
  22. classes/{as3cf-upgrade-filter-post.php → upgrades/upgrade-filter-post.php} +106 -242
  23. classes/upgrades/{as3cf-meta-wp-error.php → upgrade-meta-wp-error.php} +10 -22
  24. classes/upgrades/{as3cf-region-meta.php → upgrade-region-meta.php} +9 -20
  25. classes/upgrades/upgrade.php +939 -0
  26. languages/amazon-s3-and-cloudfront-en.pot +125 -146
  27. readme.txt +22 -11
  28. view/bucket-setting.php +9 -1
  29. view/domain-setting.php +1 -1
  30. view/settings-tabs.php +2 -3
  31. view/settings.php +8 -8
  32. view/sidebar.php +15 -4
  33. view/wordpress-org-support.php +5 -1
  34. wordpress-s3.php +4 -12
README.md CHANGED
@@ -1,9 +1,9 @@
1
# WP Offload S3 Lite #
2
**Contributors:** bradt, deliciousbrains
3
**Tags:** uploads, amazon, s3, amazon s3, mirror, admin, media, cdn, cloudfront
4
- **Requires at least:** 4.4
5
- **Tested up to:** 4.7.3
6
- **Stable tag:** 1.1.6
7
**License:** GPLv3
8
9
Copies files to Amazon S3 as they are uploaded to the Media Library. Optionally configure Amazon CloudFront for faster delivery.
@@ -22,12 +22,12 @@ If you're adding this plugin to a site that's been around for a while, your exis
22
23
* Upload existing Media Library to Amazon S3
24
* Control Amazon S3 files from the Media Library
25
- * [Assets addon](https://deliciousbrains.com/wp-offload-s3/?utm_source=wordpress.org&utm_medium=web&utm_content=desc&utm_campaign=os3-free-plugin#assets-addon) - Serve your CSS & JS from Amazon S3/CloudFront
26
- * [WooCommerce addon](https://deliciousbrains.com/wp-offload-s3/?utm_source=wordpress.org&utm_medium=web&utm_content=desc&utm_campaign=os3-free-plugin#woocommerce-addon)
27
- * [Easy Digital Downloads addon](https://deliciousbrains.com/wp-offload-s3/?utm_source=wordpress.org&utm_medium=web&utm_content=desc&utm_campaign=os3-free-plugin#edd-addon)
28
* PriorityExpert™ email support
29
30
- [Compare pro vs free →](http://deliciousbrains.com/wp-offload-s3/upgrade/?utm_source=wordpress.org&utm_medium=web&utm_content=desc&utm_campaign=os3-free-plugin)
31
32
The video below runs through the pro upgrade features...
33
@@ -48,7 +48,7 @@ which is a fork of [Amazon S3 for WordPress](http://wordpress.org/extend/plugins
48
49
### What are the minimum requirements? ###
50
51
- You can see the minimum requirements [here](https://deliciousbrains.com/wp-offload-s3/pricing/?utm_source=wordpress.org&utm_medium=web&utm_content=desc&utm_campaign=os3-free-plugin#requirements).
52
53
## Screenshots ##
54
@@ -69,6 +69,17 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
69
70
## Changelog ##
71
72
### WP Offload S3 Lite 1.1.6 - 2017-03-13 ###
73
* New: Compatibility with [Advanced Custom Fields](https://wordpress.org/plugins/advanced-custom-fields/)
74
* New: `as3cf_filter_post_local_to_s3` and `as3cf_filter_post_s3_to_local` filters added for filtering S3 URLs in custom content
@@ -118,7 +129,7 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
118
119
### WP Offload S3 Lite 1.0.5 - 2016-09-01 ###
120
* New: Compatibility with WordPress 4.6
121
- * Improvement: No longer delete plugin data on uninstall. Manual removal possible, as per this [doc](https://deliciousbrains.com/wp-offload-s3/doc/uninstall/)
122
123
### WP Offload S3 Lite 1.0.4 - 2016-05-30 ###
124
* New: Now using simpler Force HTTPS setting, removed redundant Always Use HTTP setting
@@ -224,8 +235,8 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
224
* Bug fix: Accidentally released the sidebar for after we launch the pro version
225
226
### WP Offload S3 0.9.1 - 2015-07-29 ###
227
- * Improvement: Access denied sample IAM policy replaced with link to [Quick Start Guide](https://deliciousbrains.com/wp-offload-s3/doc/quick-start-guide/)
228
- * Improvement: Access denied messages on bucket selection or bucket creation now link to [Quick Start Guide](https://deliciousbrains.com/wp-offload-s3/doc/quick-start-guide/)
229
* Improvement: Object expires time can now be filtered using the `as3cf_object_meta` filter
230
* Bug fix: Error not always shown when S3 bucket inaccessible due to incorrect permissions
231
* Bug fix: Permission checks fail when S3 bucket is in a non-default region and defined by `AS3CF_BUCKET` constant
1
# WP Offload S3 Lite #
2
**Contributors:** bradt, deliciousbrains
3
**Tags:** uploads, amazon, s3, amazon s3, mirror, admin, media, cdn, cloudfront
4
+ **Requires at least:** 4.6
5
+ **Tested up to:** 4.8
6
+ **Stable tag:** 1.2
7
**License:** GPLv3
8
9
Copies files to Amazon S3 as they are uploaded to the Media Library. Optionally configure Amazon CloudFront for faster delivery.
22
23
* Upload existing Media Library to Amazon S3
24
* Control Amazon S3 files from the Media Library
25
+ * [Assets addon](https://deliciousbrains.com/wp-offload-s3/?utm_campaign=WP%2BOffload%2BS3&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting&utm_content=assets%2Baddon#addons) - Serve your CSS & JS from Amazon S3/CloudFront
26
+ * [WooCommerce addon](https://deliciousbrains.com/wp-offload-s3/?utm_campaign=WP%2BOffload%2BS3&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting&utm_content=woocommerce%2Baddon#addons)
27
+ * [Easy Digital Downloads addon](https://deliciousbrains.com/wp-offload-s3/?utm_campaign=WP%2BOffload%2BS3&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting&utm_content=edd%2Baddon#addons)
28
* PriorityExpert™ email support
29
30
+ [Compare pro vs free →](https://deliciousbrains.com/wp-offload-s3/upgrade/?utm_campaign=WP%2BOffload%2BS3&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
31
32
The video below runs through the pro upgrade features...
33
48
49
### What are the minimum requirements? ###
50
51
+ You can see the minimum requirements [here](https://deliciousbrains.com/wp-offload-s3/pricing/?utm_campaign=WP%2BOffload%2BS3&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting&utm_content=requirements#requirements).
52
53
## Screenshots ##
54
69
70
## Changelog ##
71
72
+ ### WP Offload S3 Lite 1.2 - 2017-06-19 ###
73
+ * New: Compatibility with WordPress 4.8
74
+ * New: Support for WP CLI `wp media regenerate`
75
+ * Improvement: Intermediate image sizes are now passed through the `as3cf_object_meta` filter
76
+ * Improvement: Content filtering cache now uses the external object when available
77
+ * Bug fix: Timeouts on large multisite installs due to excessive database queries on upgrade routines
78
+ * Bug fix: Video files with private ACL not working with WordPress's default media player
79
+ * Bug fix: Bucket permissions check not using configured path
80
+ * Bug fix: WordPress image editor sometimes shows a 404 when 'Remove Files From Server' enabled
81
+ * Bug fix: Notice: Undefined index: region
82
+
83
### WP Offload S3 Lite 1.1.6 - 2017-03-13 ###
84
* New: Compatibility with [Advanced Custom Fields](https://wordpress.org/plugins/advanced-custom-fields/)
85
* New: `as3cf_filter_post_local_to_s3` and `as3cf_filter_post_s3_to_local` filters added for filtering S3 URLs in custom content
129
130
### WP Offload S3 Lite 1.0.5 - 2016-09-01 ###
131
* New: Compatibility with WordPress 4.6
132
+ * Improvement: No longer delete plugin data on uninstall. Manual removal possible, as per this [doc](https://deliciousbrains.com/wp-offload-s3/doc/uninstall/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
133
134
### WP Offload S3 Lite 1.0.4 - 2016-05-30 ###
135
* New: Now using simpler Force HTTPS setting, removed redundant Always Use HTTP setting
235
* Bug fix: Accidentally released the sidebar for after we launch the pro version
236
237
### WP Offload S3 0.9.1 - 2015-07-29 ###
238
+ * Improvement: Access denied sample IAM policy replaced with link to [Quick Start Guide](https://deliciousbrains.com/wp-offload-s3/doc/quick-start-guide/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
239
+ * Improvement: Access denied messages on bucket selection or bucket creation now link to [Quick Start Guide](https://deliciousbrains.com/wp-offload-s3/doc/quick-start-guide/?utm_campaign=changelogs&utm_source=wordpress.org&utm_medium=free%2Bplugin%2Blisting)
240
* Improvement: Object expires time can now be filtered using the `as3cf_object_meta` filter
241
* Bug fix: Error not always shown when S3 bucket inaccessible due to incorrect permissions
242
* Bug fix: Permission checks fail when S3 bucket is in a non-default region and defined by `AS3CF_BUCKET` constant
assets/js/modal.js CHANGED
@@ -101,13 +101,13 @@ var as3cfModal = (function( $ ) {
101
var target = $( '#as3cf-modal' ).data( 'as3cf-modal-target' );
102
103
$( '#as3cf-overlay' ).fadeOut( 150, function() {
104
- if ( 'function' === typeof callback ) {
105
- callback( target );
106
- }
107
-
108
$( 'body' ).removeClass( 'as3cf-modal-open' );
109
110
$( this ).remove();
111
} );
112
113
$( 'body' ).trigger( 'as3cf-modal-close', [ target ] );
101
var target = $( '#as3cf-modal' ).data( 'as3cf-modal-target' );
102
103
$( '#as3cf-overlay' ).fadeOut( 150, function() {
104
$( 'body' ).removeClass( 'as3cf-modal-open' );
105
106
$( this ).remove();
107
+
108
+ if ( 'function' === typeof callback ) {
109
+ callback( target );
110
+ }
111
} );
112
113
$( 'body' ).trigger( 'as3cf-modal-close', [ target ] );
assets/js/modal.min.js CHANGED
@@ -1 +1 @@
1
- var as3cfModal=function(a){function b(a){return a.replace(/[^a-z]/g,"")}var c={prefix:"as3cf",loading:!1,dismissible:!0},d={};return c.exists=function(c){var e=b(c);return void 0!==d[e]||!!a(c).length},c.open=function(e,f,g){var h=b(e);a("body").append('<div id="as3cf-overlay"></div>');var i=a("#as3cf-overlay");c.dismissible?i.append('<div id="as3cf-modal"><span class="close-as3cf-modal">×</span></div>'):i.append('<div id="as3cf-modal"></div>');var j=a("#as3cf-modal");if(void 0===d[h]){var k=a(e);d[h]=k.clone(!0).css("display","block"),k.remove()}j.data("as3cf-modal-target",e).append(d[h]),void 0!==g&&j.addClass(g),"function"==typeof f&&f(e),a("body").addClass("as3cf-modal-open"),i.fadeIn(150),j.fadeIn(150),a("body").trigger("as3cf-modal-open",[e])},c.close=function(b){if(!c.loading&&c.dismissible){var d=a("#as3cf-modal").data("as3cf-modal-target");a("#as3cf-overlay").fadeOut(150,function(){"function"==typeof b&&b(d),a("body").removeClass("as3cf-modal-open"),a(this).remove()}),a("body").trigger("as3cf-modal-close",[d])}},c.setLoadingState=function(a){c.loading=a},c.setDismissibleState=function(a){c.dismissible=a},a(document).ready(function(){a("body").on("click","[data-as3cf-modal]",function(b){b.preventDefault(),c.open(a(this).data("as3cf-modal")+"."+c.prefix)}),a("body").on("click","#as3cf-overlay, .close-as3cf-modal",function(a){return a.preventDefault(),a.target===this&&void c.close()})}),c}(jQuery);
1
+ var as3cfModal=function(a){function b(a){return a.replace(/[^a-z]/g,"")}var c={prefix:"as3cf",loading:!1,dismissible:!0},d={};return c.exists=function(c){var e=b(c);return void 0!==d[e]||!!a(c).length},c.open=function(e,f,g){var h=b(e);a("body").append('<div id="as3cf-overlay"></div>');var i=a("#as3cf-overlay");c.dismissible?i.append('<div id="as3cf-modal"><span class="close-as3cf-modal">×</span></div>'):i.append('<div id="as3cf-modal"></div>');var j=a("#as3cf-modal");if(void 0===d[h]){var k=a(e);d[h]=k.clone(!0).css("display","block"),k.remove()}j.data("as3cf-modal-target",e).append(d[h]),void 0!==g&&j.addClass(g),"function"==typeof f&&f(e),a("body").addClass("as3cf-modal-open"),i.fadeIn(150),j.fadeIn(150),a("body").trigger("as3cf-modal-open",[e])},c.close=function(b){if(!c.loading&&c.dismissible){var d=a("#as3cf-modal").data("as3cf-modal-target");a("#as3cf-overlay").fadeOut(150,function(){a("body").removeClass("as3cf-modal-open"),a(this).remove(),"function"==typeof b&&b(d)}),a("body").trigger("as3cf-modal-close",[d])}},c.setLoadingState=function(a){c.loading=a},c.setDismissibleState=function(a){c.dismissible=a},a(document).ready(function(){a("body").on("click","[data-as3cf-modal]",function(b){b.preventDefault(),c.open(a(this).data("as3cf-modal")+"."+c.prefix)}),a("body").on("click","#as3cf-overlay, .close-as3cf-modal",function(a){return a.preventDefault(),a.target===this&&void c.close()})}),c}(jQuery);
assets/js/script.js CHANGED
@@ -459,7 +459,12 @@
459
460
setBucketLink();
461
462
- as3cfModal.close( unlockBucketSelect );
463
},
464
465
/**
@@ -623,15 +628,6 @@
623
} );
624
}
625
626
- /**
627
- * Reset the bucket select lock
628
- */
629
- function unlockBucketSelect( target ) {
630
-
631
- // Unlock setting the bucket
632
- as3cf.buckets.bucketSelectLock = false;
633
- }
634
-
635
/*
636
* Toggle the lost files notice
637
*/
@@ -654,47 +650,41 @@
654
}
655
}
656
657
$( document ).ready( function() {
658
659
// Tabs
660
// --------------------
661
662
// Move any compatibility errors below the nav tabs
663
var $navTabs = $( '.wrap.aws-main .nav-tab-wrapper' );
664
$( '.aws-compatibility-notice, div.updated, div.error, div.notice' ).not( '.below-h2, .inline' ).insertAfter( $navTabs );
665
666
- // Check for hash in url and switch tabs accordingly
667
- if ( window.location.hash ) {
668
- var hash = window.location.hash.substring( 1 );
669
- as3cf.tabs.toggle( hash, true );
670
- } else {
671
-
672
- // Default settings tab
673
- $activeTab = $( '#tab-' + as3cf.tabs.defaultTab );
674
- $( '.aws-main' ).attr( 'data-tab', as3cf.tabs.defaultTab );
675
- }
676
-
677
- $( '.aws-main' ).on( 'click', '.nav-tab', function( e ) {
678
- e.preventDefault();
679
- if ( $( this ).hasClass( 'nav-tab-active' ) ) {
680
- return;
681
- }
682
- var nextTab = $( this ).attr( 'data-tab' );
683
- as3cf.tabs.toggle( nextTab );
684
- if ( 'media' === nextTab ) {
685
-
686
- // As it's the default remove the hash
687
- window.location.hash = '';
688
- if ( 'function' === typeof window.history.replaceState && '#' === window.location.href.slice( -1 ) ) {
689
-
690
- // Strip the # if still on the end of the URL
691
- history.replaceState( {}, '', window.location.href.slice( 0, -1 ) );
692
- }
693
- } else {
694
- window.location.hash = nextTab;
695
- }
696
- } );
697
-
698
// Settings
699
// --------------------
700
459
460
setBucketLink();
461
462
+ as3cfModal.close( function() {
463
+ $activeTab.trigger( 'bucket-change', [ canWrite ] );
464
+
465
+ // Unlock setting the bucket
466
+ as3cf.buckets.bucketSelectLock = false;
467
+ } );
468
},
469
470
/**
628
} );
629
}
630
631
/*
632
* Toggle the lost files notice
633
*/
650
}
651
}
652
653
+ /**
654
+ * Update the UI with the current active tab set in the URL hash.
655
+ */
656
+ function renderCurrentTab() {
657
+
658
+ // If rendering the default tab, or a bare hash clean the hash.
659
+ if ( '#' + as3cf.tabs.defaultTab === location.hash ) {
660
+ location.hash = '';
661
+
662
+ return;
663
+ }
664
+
665
+ // Strip the # if still on the end of the URL
666
+ if ( 'function' === typeof history.replaceState && '#' === location.href.slice( -1 ) ) {
667
+ history.replaceState( {}, '', location.href.slice( 0, -1 ) );
668
+ }
669
+
670
+ as3cf.tabs.toggle( location.hash.replace( '#', '' ), true );
671
+ }
672
+
673
$( document ).ready( function() {
674
675
// Tabs
676
// --------------------
677
+ renderCurrentTab();
678
+
679
+ /**
680
+ * Set the hashchange callback to update the rendered active tab.
681
+ */
682
+ window.onhashchange = renderCurrentTab;
683
684
// Move any compatibility errors below the nav tabs
685
var $navTabs = $( '.wrap.aws-main .nav-tab-wrapper' );
686
$( '.aws-compatibility-notice, div.updated, div.error, div.notice' ).not( '.below-h2, .inline' ).insertAfter( $navTabs );
687
688
// Settings
689
// --------------------
690
assets/js/script.min.js CHANGED
@@ -1 +1 @@
1
- !function(a,b){function c(b){return a("#"+b+" .as3cf-main-settings form").find("input:not(.no-compare)").serialize()}function d(a){var b=k.find("#"+a),c=b.find("input[type=checkbox]");b.toggleClass("on").find("span").toggleClass("checked");var d=b.find("span.on").hasClass("checked");c.attr("checked",d).trigger("change")}function e(b){var c=b.next(".as3cf-validation-error"),d=a("#"+k.attr("id")+' form button[type="submit"]'),e=/[^a-zA-Z0-9\.\-]/;e.test(b.val())?(c.show(),d.attr("disabled",!0)):(c.hide(),d.attr("disabled",!1))}function f(){var c=a("#"+b.prefix+"-bucket").val(),d=k.find('input[name="object-prefix"]'),e=d.val();""!==e&&(e="&prefix="+encodeURIComponent(e));var f=as3cf.aws_bucket_link+c+e;a("#"+b.prefix+"-view-bucket").attr("href",f)}function g(){a(".as3cf-url-preview").html("Generating...");var b={_nonce:as3cf.nonces.get_url_preview};a.each(a("#tab-"+as3cf.tabs.defaultTab+" .as3cf-main-settings form").serializeArray(),function(c,d){var e=d.name,f=d.value;e=e.replace("[]",""),b[e]=void 0===b[e]?f:a.isArray(b[e])?b[e].concat(f):[b[e],f]}),b.action="as3cf-get-url-preview",a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:b,error:function(a,b,c){alert(as3cf.strings.get_url_preview_error+c)},success:function(b,c,d){"undefined"!=typeof b.success?a(".as3cf-url-preview").html(b.url):alert(as3cf.strings.get_url_preview_error+b.error)}})}function h(a){as3cf.buckets.bucketSelectLock=!1}function i(){a("#as3cf-remove-local-file").is(":checked")&&a("#as3cf-serve-from-s3").is(":not(:checked)")?a("#as3cf-lost-files-notice").show():a("#as3cf-lost-files-notice").hide()}function j(){a("#as3cf-remove-local-file").is(":checked")?a("#as3cf-remove-local-notice").show():a("#as3cf-remove-local-notice").hide()}var k,l={},m=/[^a-z0-9.-]/,n=!1,o=a(".as3cf-tab");as3cf.tabs={defaultTab:"media",toggle:function(c,d){c=as3cf.tabs.sanitizeHash(c),o.hide(),k=a("#tab-"+c),k.show(),a(".nav-tab").removeClass("nav-tab-active"),a('a.nav-tab[data-tab="'+c+'"]').addClass("nav-tab-active"),a(".aws-main").attr("data-tab",c),k.attr("data-prefix")&&(b.prefix=k.attr("data-prefix")),d||a(".as3cf-updated").removeClass("show"),"support"===c&&as3cf.tabs.getDiagnosticInfo()},getDiagnosticInfo:function(){var b=a(".debug-log-textarea");b.html(as3cf.strings.get_diagnostic_info);var c={action:"as3cf-get-diagnostic-info",_nonce:as3cf.nonces.get_diagnostic_info};a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:c,error:function(a,c,d){b.html(d)},success:function(a,c,d){"undefined"!=typeof a.success?b.html(a.diagnostic_info):(b.html(as3cf.strings.get_diagnostic_info_error),b.append(a.error))}})},sanitizeHash:function(b){var c=a("#tab-"+b);return 0===c.length&&(b=as3cf.tabs.defaultTab),b}},as3cf.buckets={validLength:3,bucketSelectLock:!1,loadList:function(c){"undefined"==typeof c&&(c=!1);var d=a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-list"),e=a("#"+b.prefix+"-bucket").val();if(!1===c&&d.find("li").length>1)return a(".as3cf-bucket-list a").removeClass("selected"),a('.as3cf-bucket-list a[data-bucket="'+e+'"]').addClass("selected"),void this.scrollToSelected();d.html('<li class="loading">'+d.attr("data-working")+"</li>");var f={action:b.prefix+"-get-buckets",_nonce:window[b.prefix.replace(/-/g,"_")].nonces.get_buckets},g=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:f,error:function(a,b,c){d.html(""),g.showError(as3cf.strings.get_buckets_error,c,"as3cf-bucket-select")},success:function(b,c,f){d.html(""),"undefined"!=typeof b.success?(a(".as3cf-bucket-error").hide(),a(b.buckets).each(function(a,b){var c=b.Name===e?"selected":"";d.append('<li><a class="'+c+'" href="#" data-bucket="'+b.Name+'"><span class="bucket"><span class="dashicons dashicons-portfolio"></span> '+b.Name+'</span><span class="spinner"></span></span></a></li>')}),g.scrollToSelected()):g.showError(as3cf.strings.get_buckets_error,b.error,"as3cf-bucket-select")}})},scrollToSelected:function(){if(a(".as3cf-bucket-list a.selected").length){var b=a("ul.as3cf-bucket-list li").first().position().top+150;a(".as3cf-bucket-list").animate({scrollTop:a("ul.as3cf-bucket-list li a.selected").position().top-b})}},resetModal:function(){var c=a(".as3cf-bucket-container."+b.prefix);!1===k.hasClass("as3cf-has-bucket")||"manual"===a("#"+b.prefix+"-bucket-select").val()?(c.find(".as3cf-bucket-manual").show().siblings().hide(),c.find(".bucket-actions.manual").show().siblings(".bucket-actions").hide()):(c.find(".as3cf-bucket-select").show().siblings().hide(),c.find(".bucket-actions.select").show().siblings(".bucket-actions").hide(),this.loadList(n),n=!1),c.find(".as3cf-bucket-error").hide();var d=a("#"+b.prefix+"-bucket").val();c.find(".as3cf-bucket-manual .as3cf-bucket-name").val(d),this.bucketSelectLock=!1},saveManual:function(){var c=a(".as3cf-bucket-container."+b.prefix+" .as3cf-manual-save-bucket-form"),d=c.find(".as3cf-bucket-name"),e=c.find("button[type=submit]"),f=d.val(),g=e.first().text();if(f===a("#"+b.prefix+"-active-bucket").text())return a(".as3cf-bucket-error").hide(),k.addClass("as3cf-has-bucket"),void b.close();a(".as3cf-bucket-error").hide(),e.text(e.attr("data-working")),e.prop("disabled",!0);var h={action:b.prefix+"-manual-save-bucket",bucket_name:f,_nonce:window[b.prefix.replace(/-/g,"_")].nonces.manual_bucket},i=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:h,error:function(a,b,c){e.text(g),i.showError(as3cf.strings.save_bucket_error,c,"as3cf-bucket-manual")},success:function(c,d,h){e.text(g),e.prop("disabled",!1),"undefined"!=typeof c.success?(i.set(f,c.region,c.can_write),a("#"+b.prefix+"-bucket-select").val("manual"),a(".as3cf-bucket-list a").removeClass("selected").filter('[data-bucket="'+f+'"]').addClass("selected"),n=!0):i.showError(as3cf.strings.save_bucket_error,c.error,"as3cf-bucket-manual")}})},saveSelected:function(c){var d=a(".as3cf-bucket-list");if(!this.bucketSelectLock){if(this.bucketSelectLock=!0,c.hasClass("selected"))return k.addClass("as3cf-has-bucket"),void b.close();var e=a(".as3cf-bucket-list a.selected").attr("data-bucket");a(".as3cf-bucket-list a").removeClass("selected"),c.addClass("selected"),d.addClass("saving"),c.find(".spinner").show().css("visibility","visible");var f=c.attr("data-bucket"),g={action:b.prefix+"-save-bucket",bucket_name:f,_nonce:window[b.prefix.replace(/-/g,"_")].nonces.save_bucket},h=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:g,error:function(b,c,f){d.removeClass("saving"),h.showError(as3cf.strings.save_bucket_error,f,"as3cf-bucket-select"),a(".as3cf-bucket-list a").removeClass("selected"),a('.as3cf-bucket-list a[data-bucket="'+e+'"]').addClass("selected")},success:function(g,i,j){c.find(".spinner").hide().css("visibility","hidden"),d.removeClass("saving"),"undefined"!=typeof g.success?(h.set(f,g.region,g.can_write),a("#"+b.prefix+"-bucket-select").val("")):(h.showError(as3cf.strings.save_bucket_error,g.error,"as3cf-bucket-select"),a(".as3cf-bucket-list a").removeClass("selected"),a('.as3cf-bucket-list a[data-bucket="'+e+'"]').addClass("selected"))}})}},disabledButtons:function(){if(0!==a(".as3cf-bucket-container."+b.prefix+" .as3cf-create-bucket-form").length){var c=a(".as3cf-bucket-container."+b.prefix+" .as3cf-create-bucket-form"),d=a(".as3cf-bucket-container."+b.prefix+" .as3cf-manual-save-bucket-form");c.find(".as3cf-bucket-name").val().length<3?c.find("button[type=submit]").attr("disabled",!0):c.find("button[type=submit]").attr("disabled",!1),d.find(".as3cf-bucket-name").val().length<3?d.find("button[type=submit]").attr("disabled",!0):d.find("button[type=submit]").attr("disabled",!1)}},showError:function(b,c,d){var e=a(".as3cf-bucket-container").children(":visible"),f=e.find(".as3cf-bucket-error");d="undefined"==typeof d?null:d,d&&!e.hasClass(d)||(f.find("span.title").html(b+" &mdash;"),f.find("span.message").html(c),f.show(),this.bucketSelectLock=!1)},set:function(e,i,j){var m=a(".as3cf-bucket-container."+b.prefix+" .as3cf-manual-save-bucket-form"),n=a("#"+b.prefix+"-active-bucket");if("as3cf"===b.prefix&&0===n.text().trim().length){d("as3cf-copy-to-s3-wrap"),d("as3cf-serve-from-s3-wrap");var o=k.attr("id");l[o]=c(o)}a(".as3cf-error.fatal").hide(),n.text(e),m.find(".as3cf-bucket-name").val(e),a("#"+b.prefix+"-bucket").val(e),a("#"+b.prefix+"-region").val(i),a(".updated").not(".as3cf-notice").show(),k.addClass("as3cf-has-bucket"),k.find(".as3cf-can-write-error").toggle(!j),k.find(".as3cf-bucket-error").hide(),"as3cf"===b.prefix&&g(),f(),b.close(h)},create:function(){var c=a(".as3cf-bucket-container."+b.prefix+" .as3cf-create-bucket-form"),d=c.find(".as3cf-bucket-name"),e=c.find(".bucket-create-region"),f=c.find("button[type=submit]"),g=d.val(),h=f.text();a(".as3cf-bucket-error").hide(),f.text(f.attr("data-working")),f.prop("disabled",!0);var i={action:b.prefix+"-create-bucket",bucket_name:g,_nonce:window[b.prefix.replace(/-/g,"_")].nonces.create_bucket};e.val()&&(i.region=e.val());var j=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:i,error:function(a,b,c){f.text(h),j.showError(as3cf.strings.create_bucket_error,c,"as3cf-bucket-create")},success:function(b,c,e){f.text(h),f.prop("disabled",!1),"undefined"!=typeof b.success?(j.set(g,b.region,b.can_write),a(".as3cf-bucket-select-region").hide(),a(".as3cf-bucket-select-region").removeAttr("selected"),d.val(""),f.attr("disabled",!0),n=!0):j.showError(as3cf.strings.create_bucket_error,b.error,"as3cf-bucket-create")}})},isValidName:function(a){return!(a.length<3||a.length>63)&&!0!==m.test(a)},updateNameNotice:function(b){var c=null;!0===m.test(b)?c=as3cf.strings.create_bucket_invalid_chars:b.length<3?c=as3cf.strings.create_bucket_name_short:b.length>63&&(c=as3cf.strings.create_bucket_name_long),c&&b.length>0?a(".as3cf-invalid-bucket-name").html(c):a(".as3cf-invalid-bucket-name").html("")}},a(document).ready(function(){var h=a(".wrap.aws-main .nav-tab-wrapper");if(a(".aws-compatibility-notice, div.updated, div.error, div.notice").not(".below-h2, .inline").insertAfter(h),window.location.hash){var m=window.location.hash.substring(1);as3cf.tabs.toggle(m,!0)}else k=a("#tab-"+as3cf.tabs.defaultTab),a(".aws-main").attr("data-tab",as3cf.tabs.defaultTab);a(".aws-main").on("click",".nav-tab",function(b){if(b.preventDefault(),!a(this).hasClass("nav-tab-active")){var c=a(this).attr("data-tab");as3cf.tabs.toggle(c),"media"===c?(window.location.hash="","function"==typeof window.history.replaceState&&"#"===window.location.href.slice(-1)&&history.replaceState({},"",window.location.href.slice(0,-1))):window.location.hash=c}}),o.length&&o.each(function(a,b){l[b.id]=c(b.id)}),a(window).on("beforeunload.as3cf-settings",function(){if(!a.isEmptyObject(l)){var b=k.attr("id");return c(b)!==l[b]?as3cf.strings.save_alert:void 0}}),a(document).on("submit",".as3cf-main-settings form",function(b){a(window).off("beforeunload.as3cf-settings")}),a(".as3cf-switch").on("click",function(b){a(this).hasClass("disabled")||d(a(this).attr("id"))}),o.on("change",".sub-toggle",function(b){var c=a(this).attr("id");a(".as3cf-setting."+c).toggleClass("hide")}),a(".as3cf-domain").on("change",'input[type="radio"]',function(b){var c=a(this).closest('input:radio[name="domain"]:checked'),d=c.val(),e=a(this).parents(".as3cf-domain").find(".as3cf-setting.cloudfront"),f="cloudfront"===d;e.toggleClass("hide",!f)}),a(".url-preview").on("change","input",function(a){g()}),i(),a("#as3cf-serve-from-s3,#as3cf-remove-local-file").on("change",function(a){i()}),j(),a("#as3cf-remove-local-file").on("change",function(a){j()}),a('.as3cf-setting input[type="text"]').keypress(function(a){if(13===a.which)return a.preventDefault(),!1}),a('input[name="cloudfront"]').on("keyup",function(b){e(a(this))}),a('input[name="domain"]').on("change",function(b){var c=a(this),d=a("#"+k.attr("id")+' form button[type="submit"]');"cloudfront"!==c.val()?d.attr("disabled",!1):e(c.next(".as3cf-setting").find('input[name="cloudfront"]'))}),a('input[name="object-prefix"]').on("change",function(a){f()}),a("#tab-media > .as3cf-bucket-error").detach().insertAfter(".as3cf-bucket-container h3"),a("body").on("click",".bucket-action-manual",function(c){c.preventDefault(),a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-manual").show().siblings().hide()}),a("body").on("click",".bucket-action-browse",function(c){c.preventDefault(),a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-select").show().siblings().hide(),as3cf.buckets.loadList(n),n=!1}),a("body").on("click",".bucket-action-create",function(c){c.preventDefault(),a(".as3cf-bucket-name").val(""),a(".as3cf-invalid-bucket-name").html(""),a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-create").show().siblings().hide()}),a("body").on("click",".bucket-action-cancel",function(a){a.preventDefault(),as3cf.buckets.resetModal()}),a("body").on("click",".bucket-action-save",function(a){a.preventDefault(),as3cf.buckets.saveManual()}),a("body").on("click",'.as3cf-create-bucket-form button[type="submit"]',function(a){a.preventDefault(),as3cf.buckets.create()}),a("body").on("click",".bucket-action-refresh",function(a){a.preventDefault(),as3cf.buckets.loadList(!0)}),a("body").on("click",".as3cf-bucket-list a",function(b){b.preventDefault(),as3cf.buckets.saveSelected(a(this))}),a(".as3cf-bucket-container").on("click","a.js-link",function(b){return b.preventDefault(),window.open(a(this).attr("href")),!1}),a("body").on("as3cf-modal-open",function(c,d){if(".as3cf-bucket-container."+b.prefix===d){as3cf.buckets.resetModal();var e=a(".as3cf-bucket-manual h3").data("modal-title");a(".as3cf-bucket-manual h3").text(e),as3cf.buckets.disabledButtons()}}),as3cf.buckets.disabledButtons(),a("body").on("input keyup",".as3cf-create-bucket-form .as3cf-bucket-name",function(c){var d=a(this).val(),e=a(".as3cf-bucket-container."+b.prefix+" .as3cf-create-bucket-form");as3cf.buckets.isValidName(d)?e.find("button[type=submit]").removeAttr("disabled"):e.find("button[type=submit]").attr("disabled",!0),as3cf.buckets.updateNameNotice(d)}),a("body").on("input keyup",".as3cf-manual-save-bucket-form .as3cf-bucket-name",function(c){var d=a(".as3cf-bucket-container."+b.prefix+" .as3cf-manual-save-bucket-form");d.find(".as3cf-bucket-name").val().length<as3cf.buckets.validLength?d.find("button[type=submit]").attr("disabled",!0):d.find("button[type=submit]").removeAttr("disabled")})})}(jQuery,as3cfModal);
1
+ !function(a,b){function c(b){return a("#"+b+" .as3cf-main-settings form").find("input:not(.no-compare)").serialize()}function d(a){var b=k.find("#"+a),c=b.find("input[type=checkbox]");b.toggleClass("on").find("span").toggleClass("checked");var d=b.find("span.on").hasClass("checked");c.attr("checked",d).trigger("change")}function e(b){var c=b.next(".as3cf-validation-error"),d=a("#"+k.attr("id")+' form button[type="submit"]'),e=/[^a-zA-Z0-9\.\-]/;e.test(b.val())?(c.show(),d.attr("disabled",!0)):(c.hide(),d.attr("disabled",!1))}function f(){var c=a("#"+b.prefix+"-bucket").val(),d=k.find('input[name="object-prefix"]'),e=d.val();""!==e&&(e="&prefix="+encodeURIComponent(e));var f=as3cf.aws_bucket_link+c+e;a("#"+b.prefix+"-view-bucket").attr("href",f)}function g(){a(".as3cf-url-preview").html("Generating...");var b={_nonce:as3cf.nonces.get_url_preview};a.each(a("#tab-"+as3cf.tabs.defaultTab+" .as3cf-main-settings form").serializeArray(),function(c,d){var e=d.name,f=d.value;e=e.replace("[]",""),b[e]=void 0===b[e]?f:a.isArray(b[e])?b[e].concat(f):[b[e],f]}),b.action="as3cf-get-url-preview",a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:b,error:function(a,b,c){alert(as3cf.strings.get_url_preview_error+c)},success:function(b,c,d){"undefined"!=typeof b.success?a(".as3cf-url-preview").html(b.url):alert(as3cf.strings.get_url_preview_error+b.error)}})}function h(){a("#as3cf-remove-local-file").is(":checked")&&a("#as3cf-serve-from-s3").is(":not(:checked)")?a("#as3cf-lost-files-notice").show():a("#as3cf-lost-files-notice").hide()}function i(){a("#as3cf-remove-local-file").is(":checked")?a("#as3cf-remove-local-notice").show():a("#as3cf-remove-local-notice").hide()}function j(){return"#"+as3cf.tabs.defaultTab===location.hash?void(location.hash=""):("function"==typeof history.replaceState&&"#"===location.href.slice(-1)&&history.replaceState({},"",location.href.slice(0,-1)),void as3cf.tabs.toggle(location.hash.replace("#",""),!0))}var k,l={},m=/[^a-z0-9.-]/,n=!1,o=a(".as3cf-tab");as3cf.tabs={defaultTab:"media",toggle:function(c,d){c=as3cf.tabs.sanitizeHash(c),o.hide(),k=a("#tab-"+c),k.show(),a(".nav-tab").removeClass("nav-tab-active"),a('a.nav-tab[data-tab="'+c+'"]').addClass("nav-tab-active"),a(".aws-main").attr("data-tab",c),k.attr("data-prefix")&&(b.prefix=k.attr("data-prefix")),d||a(".as3cf-updated").removeClass("show"),"support"===c&&as3cf.tabs.getDiagnosticInfo()},getDiagnosticInfo:function(){var b=a(".debug-log-textarea");b.html(as3cf.strings.get_diagnostic_info);var c={action:"as3cf-get-diagnostic-info",_nonce:as3cf.nonces.get_diagnostic_info};a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:c,error:function(a,c,d){b.html(d)},success:function(a,c,d){"undefined"!=typeof a.success?b.html(a.diagnostic_info):(b.html(as3cf.strings.get_diagnostic_info_error),b.append(a.error))}})},sanitizeHash:function(b){var c=a("#tab-"+b);return 0===c.length&&(b=as3cf.tabs.defaultTab),b}},as3cf.buckets={validLength:3,bucketSelectLock:!1,loadList:function(c){"undefined"==typeof c&&(c=!1);var d=a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-list"),e=a("#"+b.prefix+"-bucket").val();if(!1===c&&d.find("li").length>1)return a(".as3cf-bucket-list a").removeClass("selected"),a('.as3cf-bucket-list a[data-bucket="'+e+'"]').addClass("selected"),void this.scrollToSelected();d.html('<li class="loading">'+d.attr("data-working")+"</li>");var f={action:b.prefix+"-get-buckets",_nonce:window[b.prefix.replace(/-/g,"_")].nonces.get_buckets},g=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:f,error:function(a,b,c){d.html(""),g.showError(as3cf.strings.get_buckets_error,c,"as3cf-bucket-select")},success:function(b,c,f){d.html(""),"undefined"!=typeof b.success?(a(".as3cf-bucket-error").hide(),a(b.buckets).each(function(a,b){var c=b.Name===e?"selected":"";d.append('<li><a class="'+c+'" href="#" data-bucket="'+b.Name+'"><span class="bucket"><span class="dashicons dashicons-portfolio"></span> '+b.Name+'</span><span class="spinner"></span></span></a></li>')}),g.scrollToSelected()):g.showError(as3cf.strings.get_buckets_error,b.error,"as3cf-bucket-select")}})},scrollToSelected:function(){if(a(".as3cf-bucket-list a.selected").length){var b=a("ul.as3cf-bucket-list li").first().position().top+150;a(".as3cf-bucket-list").animate({scrollTop:a("ul.as3cf-bucket-list li a.selected").position().top-b})}},resetModal:function(){var c=a(".as3cf-bucket-container."+b.prefix);!1===k.hasClass("as3cf-has-bucket")||"manual"===a("#"+b.prefix+"-bucket-select").val()?(c.find(".as3cf-bucket-manual").show().siblings().hide(),c.find(".bucket-actions.manual").show().siblings(".bucket-actions").hide()):(c.find(".as3cf-bucket-select").show().siblings().hide(),c.find(".bucket-actions.select").show().siblings(".bucket-actions").hide(),this.loadList(n),n=!1),c.find(".as3cf-bucket-error").hide();var d=a("#"+b.prefix+"-bucket").val();c.find(".as3cf-bucket-manual .as3cf-bucket-name").val(d),this.bucketSelectLock=!1},saveManual:function(){var c=a(".as3cf-bucket-container."+b.prefix+" .as3cf-manual-save-bucket-form"),d=c.find(".as3cf-bucket-name"),e=c.find("button[type=submit]"),f=d.val(),g=e.first().text();if(f===a("#"+b.prefix+"-active-bucket").text())return a(".as3cf-bucket-error").hide(),k.addClass("as3cf-has-bucket"),void b.close();a(".as3cf-bucket-error").hide(),e.text(e.attr("data-working")),e.prop("disabled",!0);var h={action:b.prefix+"-manual-save-bucket",bucket_name:f,_nonce:window[b.prefix.replace(/-/g,"_")].nonces.manual_bucket},i=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:h,error:function(a,b,c){e.text(g),i.showError(as3cf.strings.save_bucket_error,c,"as3cf-bucket-manual")},success:function(c,d,h){e.text(g),e.prop("disabled",!1),"undefined"!=typeof c.success?(i.set(f,c.region,c.can_write),a("#"+b.prefix+"-bucket-select").val("manual"),a(".as3cf-bucket-list a").removeClass("selected").filter('[data-bucket="'+f+'"]').addClass("selected"),n=!0):i.showError(as3cf.strings.save_bucket_error,c.error,"as3cf-bucket-manual")}})},saveSelected:function(c){var d=a(".as3cf-bucket-list");if(!this.bucketSelectLock){if(this.bucketSelectLock=!0,c.hasClass("selected"))return k.addClass("as3cf-has-bucket"),void b.close();var e=a(".as3cf-bucket-list a.selected").attr("data-bucket");a(".as3cf-bucket-list a").removeClass("selected"),c.addClass("selected"),d.addClass("saving"),c.find(".spinner").show().css("visibility","visible");var f=c.attr("data-bucket"),g={action:b.prefix+"-save-bucket",bucket_name:f,_nonce:window[b.prefix.replace(/-/g,"_")].nonces.save_bucket},h=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:g,error:function(b,c,f){d.removeClass("saving"),h.showError(as3cf.strings.save_bucket_error,f,"as3cf-bucket-select"),a(".as3cf-bucket-list a").removeClass("selected"),a('.as3cf-bucket-list a[data-bucket="'+e+'"]').addClass("selected")},success:function(g,i,j){c.find(".spinner").hide().css("visibility","hidden"),d.removeClass("saving"),"undefined"!=typeof g.success?(h.set(f,g.region,g.can_write),a("#"+b.prefix+"-bucket-select").val("")):(h.showError(as3cf.strings.save_bucket_error,g.error,"as3cf-bucket-select"),a(".as3cf-bucket-list a").removeClass("selected"),a('.as3cf-bucket-list a[data-bucket="'+e+'"]').addClass("selected"))}})}},disabledButtons:function(){if(0!==a(".as3cf-bucket-container."+b.prefix+" .as3cf-create-bucket-form").length){var c=a(".as3cf-bucket-container."+b.prefix+" .as3cf-create-bucket-form"),d=a(".as3cf-bucket-container."+b.prefix+" .as3cf-manual-save-bucket-form");c.find(".as3cf-bucket-name").val().length<3?c.find("button[type=submit]").attr("disabled",!0):c.find("button[type=submit]").attr("disabled",!1),d.find(".as3cf-bucket-name").val().length<3?d.find("button[type=submit]").attr("disabled",!0):d.find("button[type=submit]").attr("disabled",!1)}},showError:function(b,c,d){var e=a(".as3cf-bucket-container").children(":visible"),f=e.find(".as3cf-bucket-error");d="undefined"==typeof d?null:d,d&&!e.hasClass(d)||(f.find("span.title").html(b+" &mdash;"),f.find("span.message").html(c),f.show(),this.bucketSelectLock=!1)},set:function(e,h,i){var j=a(".as3cf-bucket-container."+b.prefix+" .as3cf-manual-save-bucket-form"),m=a("#"+b.prefix+"-active-bucket");if("as3cf"===b.prefix&&0===m.text().trim().length){d("as3cf-copy-to-s3-wrap"),d("as3cf-serve-from-s3-wrap");var n=k.attr("id");l[n]=c(n)}a(".as3cf-error.fatal").hide(),m.text(e),j.find(".as3cf-bucket-name").val(e),a("#"+b.prefix+"-bucket").val(e),a("#"+b.prefix+"-region").val(h),a(".updated").not(".as3cf-notice").show(),k.addClass("as3cf-has-bucket"),k.find(".as3cf-can-write-error").toggle(!i),k.find(".as3cf-bucket-error").hide(),"as3cf"===b.prefix&&g(),f(),b.close(function(){k.trigger("bucket-change",[i]),as3cf.buckets.bucketSelectLock=!1})},create:function(){var c=a(".as3cf-bucket-container."+b.prefix+" .as3cf-create-bucket-form"),d=c.find(".as3cf-bucket-name"),e=c.find(".bucket-create-region"),f=c.find("button[type=submit]"),g=d.val(),h=f.text();a(".as3cf-bucket-error").hide(),f.text(f.attr("data-working")),f.prop("disabled",!0);var i={action:b.prefix+"-create-bucket",bucket_name:g,_nonce:window[b.prefix.replace(/-/g,"_")].nonces.create_bucket};e.val()&&(i.region=e.val());var j=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:i,error:function(a,b,c){f.text(h),j.showError(as3cf.strings.create_bucket_error,c,"as3cf-bucket-create")},success:function(b,c,e){f.text(h),f.prop("disabled",!1),"undefined"!=typeof b.success?(j.set(g,b.region,b.can_write),a(".as3cf-bucket-select-region").hide(),a(".as3cf-bucket-select-region").removeAttr("selected"),d.val(""),f.attr("disabled",!0),n=!0):j.showError(as3cf.strings.create_bucket_error,b.error,"as3cf-bucket-create")}})},isValidName:function(a){return!(a.length<3||a.length>63)&&!0!==m.test(a)},updateNameNotice:function(b){var c=null;!0===m.test(b)?c=as3cf.strings.create_bucket_invalid_chars:b.length<3?c=as3cf.strings.create_bucket_name_short:b.length>63&&(c=as3cf.strings.create_bucket_name_long),c&&b.length>0?a(".as3cf-invalid-bucket-name").html(c):a(".as3cf-invalid-bucket-name").html("")}},a(document).ready(function(){j(),window.onhashchange=j;var m=a(".wrap.aws-main .nav-tab-wrapper");a(".aws-compatibility-notice, div.updated, div.error, div.notice").not(".below-h2, .inline").insertAfter(m),o.length&&o.each(function(a,b){l[b.id]=c(b.id)}),a(window).on("beforeunload.as3cf-settings",function(){if(!a.isEmptyObject(l)){var b=k.attr("id");return c(b)!==l[b]?as3cf.strings.save_alert:void 0}}),a(document).on("submit",".as3cf-main-settings form",function(b){a(window).off("beforeunload.as3cf-settings")}),a(".as3cf-switch").on("click",function(b){a(this).hasClass("disabled")||d(a(this).attr("id"))}),o.on("change",".sub-toggle",function(b){var c=a(this).attr("id");a(".as3cf-setting."+c).toggleClass("hide")}),a(".as3cf-domain").on("change",'input[type="radio"]',function(b){var c=a(this).closest('input:radio[name="domain"]:checked'),d=c.val(),e=a(this).parents(".as3cf-domain").find(".as3cf-setting.cloudfront"),f="cloudfront"===d;e.toggleClass("hide",!f)}),a(".url-preview").on("change","input",function(a){g()}),h(),a("#as3cf-serve-from-s3,#as3cf-remove-local-file").on("change",function(a){h()}),i(),a("#as3cf-remove-local-file").on("change",function(a){i()}),a('.as3cf-setting input[type="text"]').keypress(function(a){if(13===a.which)return a.preventDefault(),!1}),a('input[name="cloudfront"]').on("keyup",function(b){e(a(this))}),a('input[name="domain"]').on("change",function(b){var c=a(this),d=a("#"+k.attr("id")+' form button[type="submit"]');"cloudfront"!==c.val()?d.attr("disabled",!1):e(c.next(".as3cf-setting").find('input[name="cloudfront"]'))}),a('input[name="object-prefix"]').on("change",function(a){f()}),a("#tab-media > .as3cf-bucket-error").detach().insertAfter(".as3cf-bucket-container h3"),a("body").on("click",".bucket-action-manual",function(c){c.preventDefault(),a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-manual").show().siblings().hide()}),a("body").on("click",".bucket-action-browse",function(c){c.preventDefault(),a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-select").show().siblings().hide(),as3cf.buckets.loadList(n),n=!1}),a("body").on("click",".bucket-action-create",function(c){c.preventDefault(),a(".as3cf-bucket-name").val(""),a(".as3cf-invalid-bucket-name").html(""),a(".as3cf-bucket-container."+b.prefix+" .as3cf-bucket-create").show().siblings().hide()}),a("body").on("click",".bucket-action-cancel",function(a){a.preventDefault(),as3cf.buckets.resetModal()}),a("body").on("click",".bucket-action-save",function(a){a.preventDefault(),as3cf.buckets.saveManual()}),a("body").on("click",'.as3cf-create-bucket-form button[type="submit"]',function(a){a.preventDefault(),as3cf.buckets.create()}),a("body").on("click",".bucket-action-refresh",function(a){a.preventDefault(),as3cf.buckets.loadList(!0)}),a("body").on("click",".as3cf-bucket-list a",function(b){b.preventDefault(),as3cf.buckets.saveSelected(a(this))}),a(".as3cf-bucket-container").on("click","a.js-link",function(b){return b.preventDefault(),window.open(a(this).attr("href")),!1}),a("body").on("as3cf-modal-open",function(c,d){if(".as3cf-bucket-container."+b.prefix===d){as3cf.buckets.resetModal();var e=a(".as3cf-bucket-manual h3").data("modal-title");a(".as3cf-bucket-manual h3").text(e),as3cf.buckets.disabledButtons()}}),as3cf.buckets.disabledButtons(),a("body").on("input keyup",".as3cf-create-bucket-form .as3cf-bucket-name",function(c){var d=a(this).val(),e=a(".as3cf-bucket-container."+b.prefix+" .as3cf-create-bucket-form");as3cf.buckets.isValidName(d)?e.find("button[type=submit]").removeAttr("disabled"):e.find("button[type=submit]").attr("disabled",!0),as3cf.buckets.updateNameNotice(d)}),a("body").on("input keyup",".as3cf-manual-save-bucket-form .as3cf-bucket-name",function(c){var d=a(".as3cf-bucket-container."+b.prefix+" .as3cf-manual-save-bucket-form");d.find(".as3cf-bucket-name").val().length<as3cf.buckets.validLength?d.find("button[type=submit]").attr("disabled",!0):d.find("button[type=submit]").removeAttr("disabled")})})}(jQuery,as3cfModal);
classes/amazon-s3-and-cloudfront.php CHANGED
@@ -1,5 +1,12 @@
1
<?php
2
3
class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
4
5
/**
@@ -115,12 +122,12 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
115
$this->plugin_title = __( 'Offload S3 Lite', 'amazon-s3-and-cloudfront' );
116
$this->plugin_menu_title = __( 'S3 and CloudFront', 'amazon-s3-and-cloudfront' );
117
118
- new AS3CF_Upgrade_Region_Meta( $this );
119
- new AS3CF_Upgrade_File_Sizes( $this );
120
- new AS3CF_Upgrade_Meta_WP_Error( $this );
121
- new AS3CF_Upgrade_Content_Replace_URLs( $this );
122
- new AS3CF_Upgrade_EDD_Replace_URLs( $this );
123
- new AS3CF_Upgrade_Filter_Post_Excerpt( $this );
124
125
// Plugin setup
126
add_action( 'aws_admin_menu', array( $this, 'admin_menu' ) );
@@ -150,7 +157,8 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
150
add_filter( 'wp_prepare_attachment_for_js', array( $this, 'maybe_encode_wp_prepare_attachment_for_js', ), 99, 3 );
151
add_filter( 'image_get_intermediate_size', array( $this, 'maybe_encode_image_get_intermediate_size' ), 99, 3 );
152
add_filter( 'get_attached_file', array( $this, 'get_attached_file' ), 10, 2 );
153
- add_filter( 'wp_audio_shortcode', array( $this, 'wp_audio_shortcode' ), 100, 5 );
154
155
// Communication with S3, plugin needs to be setup
156
add_filter( 'wp_handle_upload_prefilter', array( $this, 'wp_handle_upload_prefilter' ), 1 );
@@ -213,14 +221,14 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
213
'key' => $key,
214
'disabled' => false,
215
'disabled_attr' => '',
216
- 'tr_class' => '',
217
'setting_msg' => '',
218
);
219
220
if ( false !== $is_defined ) {
221
$args['disabled'] = true;
222
$args['disabled_attr'] = 'disabled="disabled"';
223
- $args['tr_class'] = 'as3cf-defined-setting';
224
$args['setting_msg'] = '<span class="as3cf-defined-in-config">' . __( 'defined in wp-config.php', 'as3cf' ) . '</span>';
225
}
226
@@ -385,8 +393,10 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
385
}
386
387
// Store the region for future use
388
- parent::set_setting( 'region', $region );
389
- $this->save_settings();
390
391
return $region;
392
}
@@ -779,7 +789,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
779
$prefix = $this->normalize_object_prefix( $s3object['key'] );
780
$bucket = $s3object['bucket'];
781
$region = $this->get_s3object_region( $s3object );
782
- $paths = $this->get_attachment_file_paths( $post_id, false, false, $remove_backup_sizes );
783
$paths = apply_filters( 'as3cf_remove_attachment_paths', $paths, $post_id, $s3object, $remove_backup_sizes );
784
785
if ( is_wp_error( $region ) ) {
@@ -845,9 +855,13 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
845
}
846
847
// upload attachment to S3
848
- $data = $this->upload_attachment_to_s3( $post_id, $data );
849
850
- return $data;
851
}
852
853
/**
@@ -979,28 +993,27 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
979
$args['ContentEncoding'] = 'gzip';
980
}
981
982
- $args = apply_filters( 'as3cf_object_meta', $args, $post_id );
983
984
do_action( 'as3cf_upload_attachment_pre_remove', $post_id, $s3object, $prefix, $args );
985
986
$files_to_remove = array();
987
988
- if ( file_exists( $file_path ) ) {
989
- try {
990
- $s3client->putObject( $args );
991
- $files_to_remove[] = $file_path;
992
- } catch ( Exception $e ) {
993
- $error_msg = sprintf( __( 'Error uploading %s to S3: %s', 'amazon-s3-and-cloudfront' ), $file_path, $e->getMessage() );
994
995
- return $this->return_upload_error( $error_msg, $return_metadata );
996
- }
997
}
998
999
delete_post_meta( $post_id, 'amazonS3_info' );
1000
1001
add_post_meta( $post_id, 'amazonS3_info', $s3object );
1002
1003
- $file_paths = $this->get_attachment_file_paths( $post_id, true, $data );
1004
$additional_images = array();
1005
1006
$filesize_total = 0;
@@ -1028,7 +1041,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1028
if ( ! in_array( $file_path, $files_to_remove ) ) {
1029
$acl = apply_filters( 'as3cf_upload_acl_sizes', self::DEFAULT_ACL, $size, $post_id, $data );
1030
1031
- $additional_images[] = array(
1032
'Key' => $prefix . wp_basename( $file_path ),
1033
'SourceFile' => $file_path,
1034
'ACL' => $acl,
@@ -1039,7 +1052,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1039
$s3object_sizes[ $size ]['acl'] = $acl;
1040
}
1041
1042
- if ( $remove_local_files_setting ) {
1043
// Record the file size for the additional image
1044
$bytes = filesize( $file_path );
1045
if ( false !== $bytes ) {
@@ -1049,13 +1062,21 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1049
}
1050
}
1051
1052
- foreach ( $additional_images as $image ) {
1053
try {
1054
- $args = array_merge( $args, $image );
1055
$s3client->putObject( $args );
1056
$files_to_remove[] = $image['SourceFile'];
1057
} catch ( Exception $e ) {
1058
- AS3CF_Error::log( 'Error uploading ' . $args['SourceFile'] . ' to S3: ' . $e->getMessage() );
1059
}
1060
}
1061
@@ -1101,6 +1122,10 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1101
1102
do_action( 'wpos3_post_upload_attachment', $post_id, $s3object );
1103
1104
if ( ! is_null( $return_metadata ) ) {
1105
// If the attachment metadata is supplied, return it
1106
return $data;
@@ -1168,7 +1193,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1168
}
1169
1170
/**
1171
- * Helper to return meta data on upload error
1172
*
1173
* @param string $error_msg
1174
* @param array|null $return
@@ -1176,12 +1201,13 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1176
* @return array|WP_Error
1177
*/
1178
protected function return_upload_error( $error_msg, $return = null ) {
1179
if ( is_null( $return ) ) {
1180
return new WP_Error( 'exception', $error_msg );
1181
}
1182
1183
- AS3CF_Error::log( $error_msg );
1184
-
1185
return $return;
1186
}
1187
@@ -1429,8 +1455,8 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1429
}
1430
1431
$s3client = $this->get_s3client( $region );
1432
- $prefix = ltrim( trailingslashit( $this->get_object_prefix() ), '/' );
1433
- $prefix .= ltrim( trailingslashit( $this->get_dynamic_prefix( $time ) ), '/' );
1434
1435
return $s3client->doesObjectExist( $bucket, $prefix . $filename );
1436
}
@@ -1464,7 +1490,15 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1464
* @return mixed
1465
*/
1466
public function get_attachment_s3_info( $post_id ) {
1467
- return apply_filters( 'as3cf_get_attachment_s3_info', get_post_meta( $post_id, 'amazonS3_info', true ), $post_id );
1468
}
1469
1470
/**
@@ -1502,9 +1536,9 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1502
* @param array $headers Header overrides for request
1503
* @param bool $skip_rewrite_check
1504
*
1505
- * @return mixed|void|WP_Error
1506
*/
1507
- function get_secure_attachment_url( $post_id, $expires = null, $size = null, $headers = array(), $skip_rewrite_check = false ) {
1508
if ( is_null( $expires ) ) {
1509
$expires = self::DEFAULT_EXPIRES;
1510
}
@@ -1561,12 +1595,10 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1561
*/
1562
function get_object_prefix( $toggle_setting = 'enable-object-prefix' ) {
1563
if ( $this->get_setting( $toggle_setting ) ) {
1564
- $prefix = trim( $this->get_setting( 'object-prefix' ) );
1565
- } else {
1566
- $prefix = '';
1567
}
1568
1569
- return $prefix;
1570
}
1571
1572
/**
@@ -1576,12 +1608,12 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1576
*
1577
* @return string
1578
*/
1579
- function get_file_prefix( $time = null ) {
1580
- $prefix = ltrim( trailingslashit( $this->get_object_prefix() ), '/' );
1581
- $prefix .= ltrim( trailingslashit( $this->get_dynamic_prefix( $time ) ), '/' );
1582
1583
if ( $this->get_setting( 'object-versioning' ) ) {
1584
- $prefix .= $this->get_object_version_string();
1585
}
1586
1587
return $prefix;
@@ -2423,7 +2455,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2423
*
2424
* @return Aws\S3\S3Client
2425
*/
2426
- function get_s3client( $region = false, $force = false ) {
2427
if ( is_null( $this->s3client ) || $force ) {
2428
2429
$args = array(
@@ -2577,34 +2609,30 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2577
}
2578
}
2579
2580
if ( isset( self::$buckets_check[ $bucket ] ) ) {
2581
return self::$buckets_check[ $bucket ];
2582
}
2583
2584
- $file_name = 'as3cf-permission-check.txt';
2585
$file_contents = __( 'This is a test file to check if the user has write permission to S3. Delete me if found.', 'amazon-s3-and-cloudfront' );
2586
2587
- $path = $this->get_object_prefix();
2588
- $key = $path . $file_name;
2589
-
2590
- $args = array(
2591
- 'Bucket' => $bucket,
2592
- 'Key' => $key,
2593
- 'Body' => $file_contents,
2594
- 'ACL' => 'public-read',
2595
- );
2596
-
2597
try {
2598
- // need to set region for buckets in non default region
2599
- if ( is_null( $region ) ) {
2600
- $region = $this->get_setting( 'region' );
2601
-
2602
- if ( is_wp_error( $region ) ) {
2603
- return $region;
2604
- }
2605
- }
2606
// attempt to create the test file
2607
- $this->get_s3client( $region, true )->putObject( $args );
2608
// delete it straight away if created
2609
$this->get_s3client()->deleteObject( array(
2610
'Bucket' => $bucket,
@@ -2657,15 +2685,12 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2657
wp_register_script( 'as3cf-modal', $src, array( 'jquery' ), $version, true );
2658
}
2659
2660
- function plugin_load() {
2661
- $version = $this->get_asset_version();
2662
- $suffix = $this->get_asset_suffix();
2663
-
2664
- $src = plugins_url( 'assets/css/styles.css', $this->plugin_file_path );
2665
- wp_enqueue_style( 'as3cf-styles', $src, array( 'as3cf-modal' ), $version );
2666
-
2667
- $src = plugins_url( 'assets/js/script' . $suffix . '.js', $this->plugin_file_path );
2668
- wp_enqueue_script( 'as3cf-script', $src, array( 'jquery', 'as3cf-modal' ), $version, true );
2669
2670
wp_localize_script( 'as3cf-script',
2671
'as3cf',
@@ -3029,7 +3054,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
3029
*
3030
* @return array|bool|WP_Error
3031
*/
3032
- function set_attachment_acl_on_s3( $post_id, $s3object, $acl ) {
3033
// Return early if already set to the desired ACL
3034
if ( isset( $s3object['acl'] ) && $acl === $s3object['acl'] ) {
3035
return false;
@@ -3689,80 +3714,6 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
3689
return $table_prefixes;
3690
}
3691
3692
- /**
3693
- * Get file paths for all attachment versions.
3694
- *
3695
- * @param int $attachment_id
3696
- * @param bool $exists_locally
3697
- * @param array|bool $meta
3698
- * @param bool $include_backups
3699
- *
3700
- * @return array
3701
- */
3702
- public function get_attachment_file_paths( $attachment_id, $exists_locally = true, $meta = false, $include_backups = true ) {
3703
- $file_path = get_attached_file( $attachment_id, true );
3704
- $paths = array(
3705
- 'original' => $file_path,
3706
- );
3707
-
3708
- if ( ! $meta ) {
3709
- $meta = get_post_meta( $attachment_id, '_wp_attachment_metadata', true );
3710
- }
3711
-
3712
- if ( is_wp_error( $meta ) ) {
3713
- return $paths;
3714
- }
3715
-
3716
- $file_name = wp_basename( $file_path );
3717
-
3718
- // If file edited, current file name might be different.
3719
- if ( isset( $meta['file'] ) ) {
3720
- $paths['file'] = str_replace( $file_name, wp_basename( $meta['file'] ), $file_path );
3721
- }
3722
-
3723
- // Thumb
3724
- if ( isset( $meta['thumb'] ) ) {
3725
- $paths['thumb'] = str_replace( $file_name, $meta['thumb'], $file_path );
3726
- }
3727
-
3728
- // Sizes
3729
- if ( isset( $meta['sizes'] ) ) {
3730
- foreach ( $meta['sizes'] as $size => $file ) {
3731
- if ( isset( $file['file'] ) ) {
3732
- $paths[ $size ] = str_replace( $file_name, $file['file'], $file_path );
3733
- }
3734
- }
3735
- }
3736
-
3737
- $backups = get_post_meta( $attachment_id, '_wp_attachment_backup_sizes', true );
3738
-
3739
- // Backups
3740
- if ( $include_backups && is_array( $backups ) ) {
3741
- foreach ( $backups as $size => $file ) {
3742
- if ( isset( $file['file'] ) ) {
3743
- $paths[ $size ] = str_replace( $file_name, $file['file'], $file_path );
3744
- }
3745
- }
3746
- }
3747
-
3748
- // Allow other processes to add files to be uploaded
3749
- $paths = apply_filters( 'as3cf_attachment_file_paths', $paths, $attachment_id, $meta );
3750
-
3751
- // Remove duplicates
3752
- $paths = array_unique( $paths );
3753
-
3754
- // Remove paths that don't exist
3755
- if ( $exists_locally ) {
3756
- foreach ( $paths as $key => $path ) {
3757
- if ( ! file_exists( $path ) ) {
3758
- unset( $paths[ $key ] );
3759
- }
3760
- }
3761
- }
3762
-
3763
- return $paths;
3764
- }
3765
-
3766
/**
3767
* Get the access denied bucket error notice message
3768
*
@@ -3771,12 +3722,15 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
3771
* @return string
3772
*/
3773
function get_access_denied_notice_message( $single = true ) {
3774
- $quick_start = sprintf( '<a class="js-link" href="%s">%s</a>', 'https://deliciousbrains.com/wp-offload-s3/doc/quick-start-guide/#bucket-restrictions', __( 'Quick Start Guide', 'amazon-s3-and-cloudfront' ) );
3775
3776
$message = sprintf( __( "Looks like we don't have write access to this bucket. It's likely that the user you've provided access keys for hasn't been granted the correct permissions. Please see our %s for instructions on setting up permissions correctly.", 'amazon-s3-and-cloudfront' ), $quick_start );
3777
if ( ! $single ) {
3778
$message = sprintf( __( "Looks like we don't have access to the buckets. It's likely that the user you've provided access keys for hasn't been granted the correct permissions. Please see our %s for instructions on setting up permissions correctly.", 'amazon-s3-and-cloudfront' ), $quick_start );
3779
-
3780
}
3781
3782
return $message;
@@ -3914,7 +3868,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
3914
's3' => $all_media_s3,
3915
);
3916
3917
- set_site_transient( 'wpos3_attachment_counts', $attachment_counts, 2 * HOUR_IN_SECONDS );
3918
}
3919
3920
return $attachment_counts;
@@ -3955,69 +3909,49 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
3955
}
3956
3957
/**
3958
- * Create a More Info campaign url for given url.
3959
- *
3960
- * @param string $url
3961
*
3962
* @return string
3963
*/
3964
- private function more_info_campaign_url( $url ) {
3965
- $campaign = $this->is_pro() ? 'os3-pro-plugin' : 'os3-free-plugin';
3966
- $url .= '?utm_source=insideplugin&utm_medium=web&utm_content=more-info&utm_campaign=' . $campaign;
3967
-
3968
- return $url;
3969
}
3970
3971
/**
3972
- * Create a site link for given url, link text and optional anchor, usually with campaign.
3973
- *
3974
- * TODO: Update *all* hardcoded https://deliciousbrains.com urls to use relative path
3975
- * that this function then prepends with configured base URL.
3976
- * https://github.com/deliciousbrains/wp-aws/issues/1291
3977
*
3978
- * @param string $url
3979
- * @param string $text
3980
- * @param string $hash Optional anchor text.
3981
- * @param bool $append_campaign
3982
*
3983
* @return string
3984
*/
3985
- public function dbrains_link( $url, $text, $hash = '', $append_campaign = true ) {
3986
- if ( $append_campaign ) {
3987
- $url = $this->more_info_campaign_url( $url );
3988
- }
3989
3990
- if ( ! empty( $hash ) ) {
3991
- $url .= '#' . $hash;
3992
}
3993
3994
- return sprintf( '<a href="%s">%s</a>', esc_url( $url ), esc_html( $text ) );
3995
- }
3996
-
3997
- /**
3998
- * More info link
3999
- *
4000
- * @param string $url
4001
- * @param string $hash
4002
- * @param bool $append_campaign
4003
- *
4004
- * @return string
4005
- */
4006
- public function more_info_link( $url, $hash = '', $append_campaign = true ) {
4007
- $link = $this->dbrains_link( $url, __( 'More info', 'amazon-s3-and-cloudfront' ), $hash, $append_campaign );
4008
4009
return sprintf( '<span class="more-info">%s &raquo;</span>', $link );
4010
}
4011
4012
/**
4013
- * Settings more info link
4014
*
4015
* @param string $hash
4016
*
4017
* @return string
4018
*/
4019
- public function settings_more_info_link( $hash ) {
4020
- return $this->more_info_link( 'https://deliciousbrains.com/wp-offload-s3/doc/settings/', $hash );
4021
}
4022
4023
/**
@@ -4094,8 +4028,10 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
4094
'flash' => false,
4095
);
4096
4097
- $doc_url = 'https://deliciousbrains.com/wp-offload-s3/doc/force-http-setting/';
4098
- $doc_link = $this->dbrains_link( $doc_url, __( 'this doc' ) );
4099
4100
$message = sprintf( '<strong>%s</strong> &mdash; ', __( 'WP Offload S3 Feature Removed', 'amazon-s3-and-cloudfront' ) );
4101
$message .= sprintf( __( 'You had the "Always non-SSL" option selected in your settings, but we\'ve removed this option in version 1.3. We\'ll now use HTTPS when the request is HTTPS and regular HTTP when the request is HTTP. This should work fine for your site, but please take a poke around and make sure things are working ok. See %s for more details on why we did this and how you can revert back to the old behavior.', 'amazon-s3-and-cloudfront' ), $doc_link );
@@ -4245,31 +4181,20 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
4245
* Load media assets.
4246
*/
4247
public function load_media_assets() {
4248
- $version = $this->get_asset_version();
4249
- $suffix = $this->get_asset_suffix();
4250
-
4251
- $src = plugins_url( 'assets/css/media.css', $this->plugin_file_path );
4252
- wp_enqueue_style( 'as3cf-media-styles', $src, array( 'as3cf-modal' ), $version );
4253
-
4254
- $src = plugins_url( 'assets/js/media' . $suffix . '.js', $this->plugin_file_path );
4255
- wp_enqueue_script(
4256
- 'as3cf-media-script',
4257
- $src,
4258
- array( 'jquery', 'media-views', 'media-grid', 'wp-util' ),
4259
- $version,
4260
- true
4261
- );
4262
4263
- wp_localize_script(
4264
- 'as3cf-media-script',
4265
- 'as3cf_media',
4266
- array(
4267
'strings' => $this->get_media_action_strings(),
4268
'nonces' => array(
4269
'get_attachment_s3_details' => wp_create_nonce( 'get-attachment-s3-details' ),
4270
),
4271
- )
4272
- );
4273
}
4274
4275
/**
@@ -4313,18 +4238,14 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
4313
* @param $hook_suffix
4314
*/
4315
public function load_attachment_assets( $hook_suffix ) {
4316
- $version = $this->get_asset_version();
4317
- $suffix = $this->get_asset_suffix();
4318
-
4319
global $post;
4320
- if ( 'post.php' != $hook_suffix || 'attachment' != $post->post_type ) {
4321
return;
4322
}
4323
4324
- $src = plugins_url( 'assets/css/attachment.css', $this->plugin_file_path );
4325
- wp_enqueue_style( 'as3cf-pro-attachment-styles', $src, array( 'as3cf-modal' ), $version );
4326
4327
- do_action( 'as3cf_load_attachment_assets', $version, $suffix );
4328
}
4329
4330
/**
@@ -4353,36 +4274,6 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
4353
return ( '.' === $directory ) ? '' : $directory . '/';
4354
}
4355
4356
- /**
4357
- * Remove scheme from URL.
4358
- *
4359
- * @param string $url
4360
- *
4361
- * @return string
4362
- */
4363
- public function remove_scheme( $url ) {
4364
- return preg_replace( '/^(?:http|https):/', '', $url );
4365
- }
4366
-
4367
- /**
4368
- * Remove size from filename (image[-100x100].jpeg).
4369
- *
4370
- * @param string $url
4371
- * @param bool $remove_extension
4372
- *
4373
- * @return string
4374
- */
4375
- public function remove_size_from_filename( $url, $remove_extension = false ) {
4376
- $url = preg_replace( '/^(\S+)-[0-9]{1,4}x[0-9]{1,4}(\.[a-zA-Z0-9\.]{2,})?/', '$1$2', $url );
4377
-
4378
- if ( $remove_extension ) {
4379
- $ext = pathinfo( $url, PATHINFO_EXTENSION );
4380
- $url = str_replace( ".$ext", '', $url );
4381
- }
4382
-
4383
- return $url;
4384
- }
4385
-
4386
/**
4387
* Has the given attachment been uploaded by this instance?
4388
*
@@ -4399,19 +4290,19 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
4399
}
4400
4401
/**
4402
- * Filters the audio shortcode output to remove "&_=NN" params from source.src as it breaks signed URLs.
4403
*
4404
- * @param string $html Audio shortcode HTML output.
4405
- * @param array $atts Array of audio shortcode attributes.
4406
- * @param string $audio Audio file.
4407
* @param int $post_id Post ID.
4408
- * @param string $library Media library used for the audio shortcode.
4409
*
4410
* @return string
4411
*
4412
* Note: Depends on 30377.4.diff from https://core.trac.wordpress.org/ticket/30377
4413
*/
4414
- public function wp_audio_shortcode( $html, $atts, $audio, $post_id, $library ) {
4415
$html = preg_replace( '/&#038;_=[0-9]+/', '', $html );
4416
4417
return $html;
@@ -4435,4 +4326,45 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
4435
4436
return $url;
4437
}
4438
}
1
<?php
2
3
+ use DeliciousBrains\WP_Offload_S3\Upgrades\Upgrade_Content_Replace_URLs;
4
+ use DeliciousBrains\WP_Offload_S3\Upgrades\Upgrade_EDD_Replace_URLs;
5
+ use DeliciousBrains\WP_Offload_S3\Upgrades\Upgrade_File_Sizes;
6
+ use DeliciousBrains\WP_Offload_S3\Upgrades\Upgrade_Filter_Post_Excerpt;
7
+ use DeliciousBrains\WP_Offload_S3\Upgrades\Upgrade_Meta_WP_Error;
8
+ use DeliciousBrains\WP_Offload_S3\Upgrades\Upgrade_Region_Meta;
9
+
10
class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
11
12
/**
122
$this->plugin_title = __( 'Offload S3 Lite', 'amazon-s3-and-cloudfront' );
123
$this->plugin_menu_title = __( 'S3 and CloudFront', 'amazon-s3-and-cloudfront' );
124
125
+ new Upgrade_Region_Meta( $this );
126
+ new Upgrade_File_Sizes( $this );
127
+ new Upgrade_Meta_WP_Error( $this );
128
+ new Upgrade_Content_Replace_URLs( $this );
129
+ new Upgrade_EDD_Replace_URLs( $this );
130
+ new Upgrade_Filter_Post_Excerpt( $this );
131
132
// Plugin setup
133
add_action( 'aws_admin_menu', array( $this, 'admin_menu' ) );
157
add_filter( 'wp_prepare_attachment_for_js', array( $this, 'maybe_encode_wp_prepare_attachment_for_js', ), 99, 3 );
158
add_filter( 'image_get_intermediate_size', array( $this, 'maybe_encode_image_get_intermediate_size' ), 99, 3 );
159
add_filter( 'get_attached_file', array( $this, 'get_attached_file' ), 10, 2 );
160
+ add_filter( 'wp_audio_shortcode', array( $this, 'wp_media_shortcode' ), 100, 5 );
161
+ add_filter( 'wp_video_shortcode', array( $this, 'wp_media_shortcode' ), 100, 5 );
162
163
// Communication with S3, plugin needs to be setup
164
add_filter( 'wp_handle_upload_prefilter', array( $this, 'wp_handle_upload_prefilter' ), 1 );
221
'key' => $key,
222
'disabled' => false,
223
'disabled_attr' => '',
224
+ 'tr_class' => str_replace( '_', '-', $this->plugin_prefix . '-' . $key . '-container' ),
225
'setting_msg' => '',
226
);
227
228
if ( false !== $is_defined ) {
229
$args['disabled'] = true;
230
$args['disabled_attr'] = 'disabled="disabled"';
231
+ $args['tr_class'] .= ' as3cf-defined-setting';
232
$args['setting_msg'] = '<span class="as3cf-defined-in-config">' . __( 'defined in wp-config.php', 'as3cf' ) . '</span>';
233
}
234
393
}
394
395
// Store the region for future use
396
+ if ( is_string( $region ) ) {
397
+ parent::set_setting( 'region', $region );
398
+ $this->save_settings();
399
+ }
400
401
return $region;
402
}
789
$prefix = $this->normalize_object_prefix( $s3object['key'] );
790
$bucket = $s3object['bucket'];
791
$region = $this->get_s3object_region( $s3object );
792
+ $paths = AS3CF_Utils::get_attachment_file_paths( $post_id, false, false, $remove_backup_sizes );
793
$paths = apply_filters( 'as3cf_remove_attachment_paths', $paths, $post_id, $s3object, $remove_backup_sizes );
794
795
if ( is_wp_error( $region ) ) {
855
}
856
857
// upload attachment to S3
858
+ $s3_meta = $this->upload_attachment_to_s3( $post_id, $data );
859
860
+ if ( is_wp_error( $s3_meta ) ) {
861
+ return $data;
862
+ }
863
+
864
+ return $s3_meta;
865
}
866
867
/**
993
$args['ContentEncoding'] = 'gzip';
994
}
995
996
+ $image_size = wp_attachment_is_image( $post_id ) ? 'full' : '';
997
+ $args = apply_filters( 'as3cf_object_meta', $args, $post_id, $image_size, false );
998
999
do_action( 'as3cf_upload_attachment_pre_remove', $post_id, $s3object, $prefix, $args );
1000
1001
$files_to_remove = array();
1002
1003
+ try {
1004
+ $s3client->putObject( $args );
1005
+ $files_to_remove[] = $file_path;
1006
+ } catch ( Exception $e ) {
1007
+ $error_msg = sprintf( __( 'Error uploading %s to S3: %s', 'amazon-s3-and-cloudfront' ), $file_path, $e->getMessage() );
1008
1009
+ return $this->return_upload_error( $error_msg, $return_metadata );
1010
}
1011
1012
delete_post_meta( $post_id, 'amazonS3_info' );
1013
1014
add_post_meta( $post_id, 'amazonS3_info', $s3object );
1015
1016
+ $file_paths = AS3CF_Utils::get_attachment_file_paths( $post_id, false, $data );
1017
$additional_images = array();
1018
1019
$filesize_total = 0;
1041
if ( ! in_array( $file_path, $files_to_remove ) ) {
1042
$acl = apply_filters( 'as3cf_upload_acl_sizes', self::DEFAULT_ACL, $size, $post_id, $data );
1043
1044
+ $additional_images[ $size ] = array(
1045
'Key' => $prefix . wp_basename( $file_path ),
1046
'SourceFile' => $file_path,
1047
'ACL' => $acl,
1052
$s3object_sizes[ $size ]['acl'] = $acl;
1053
}
1054
1055
+ if ( $remove_local_files_setting && file_exists( $file_path ) ) {
1056
// Record the file size for the additional image
1057
$bytes = filesize( $file_path );
1058
if ( false !== $bytes ) {
1062
}
1063
}
1064
1065
+ $upload_errors = array();
1066
+
1067
+ foreach ( $additional_images as $size => $image ) {
1068
+ $args = apply_filters( 'as3cf_object_meta', array_merge( $args, $image ), $post_id, $size, false );
1069
+
1070
+ if ( ! file_exists( $args['SourceFile'] ) ) {
1071
+ $upload_errors[] = $this->return_upload_error( sprintf( __( 'File %s does not exist', 'amazon-s3-and-cloudfront' ), $args['SourceFile'] ) );
1072
+ continue;
1073
+ }
1074
+
1075
try {
1076
$s3client->putObject( $args );
1077
$files_to_remove[] = $image['SourceFile'];
1078
} catch ( Exception $e ) {
1079
+ $upload_errors[] = $this->return_upload_error( sprintf( __( 'Error uploading %s to S3: %s', 'amazon-s3-and-cloudfront' ), $args['SourceFile'], $e->getMessage() ) );
1080
}
1081
}
1082
1122
1123
do_action( 'wpos3_post_upload_attachment', $post_id, $s3object );
1124
1125
+ if ( $upload_errors ) {
1126
+ return $this->consolidate_upload_errors( $upload_errors );
1127
+ }
1128
+
1129
if ( ! is_null( $return_metadata ) ) {
1130
// If the attachment metadata is supplied, return it
1131
return $data;
1193
}
1194
1195
/**
1196
+ * Helper to record errors and return meta data on upload error.
1197
*
1198
* @param string $error_msg
1199
* @param array|null $return
1201
* @return array|WP_Error
1202
*/
1203
protected function return_upload_error( $error_msg, $return = null ) {
1204
+
1205
+ AS3CF_Error::log( $error_msg );
1206
+
1207
if ( is_null( $return ) ) {
1208
return new WP_Error( 'exception', $error_msg );
1209
}
1210
1211
return $return;
1212
}
1213
1455
}
1456
1457
$s3client = $this->get_s3client( $region );
1458
+ $prefix = AS3CF_Utils::trailingslash_prefix( $this->get_object_prefix() );
1459
+ $prefix .= AS3CF_Utils::trailingslash_prefix( $this->get_dynamic_prefix( $time ) );
1460
1461
return $s3client->doesObjectExist( $bucket, $prefix . $filename );
1462
}
1490
* @return mixed
1491
*/
1492
public function get_attachment_s3_info( $post_id ) {
1493
+ $s3_object = get_post_meta( $post_id, 'amazonS3_info', true );
1494
+
1495
+ if ( is_array( $s3_object ) ) {
1496
+ $s3_object = array_merge( array(
1497
+ 'region' => null,
1498
+ ), $s3_object );
1499
+ }
1500
+
1501
+ return apply_filters( 'as3cf_get_attachment_s3_info', $s3_object, $post_id );
1502
}
1503
1504
/**
1536
* @param array $headers Header overrides for request
1537
* @param bool $skip_rewrite_check
1538
*
1539
+ * @return mixed|WP_Error
1540
*/
1541
+ public function get_secure_attachment_url( $post_id, $expires = null, $size = null, $headers = array(), $skip_rewrite_check = false ) {
1542
if ( is_null( $expires ) ) {
1543
$expires = self::DEFAULT_EXPIRES;
1544
}
1595
*/
1596
function get_object_prefix( $toggle_setting = 'enable-object-prefix' ) {
1597
if ( $this->get_setting( $toggle_setting ) ) {
1598
+ return trailingslashit( trim( $this->get_setting( 'object-prefix' ) ) );
1599
}
1600
1601
+ return '';
1602
}
1603
1604
/**
1608
*
1609
* @return string
1610
*/
1611
+ public function get_file_prefix( $time = null ) {
1612
+ $prefix = AS3CF_Utils::trailingslash_prefix( $this->get_object_prefix() );
1613
+ $prefix .= AS3CF_Utils::trailingslash_prefix( $this->get_dynamic_prefix( $time ) );
1614
1615
if ( $this->get_setting( 'object-versioning' ) ) {
1616
+ $prefix .= AS3CF_Utils::trailingslash_prefix( $this->get_object_version_string() );
1617
}
1618
1619
return $prefix;
2455
*
2456
* @return Aws\S3\S3Client
2457
*/
2458
+ public function get_s3client( $region = false, $force = false ) {
2459
if ( is_null( $this->s3client ) || $force ) {
2460
2461
$args = array(
2609
}
2610
}
2611
2612
+ // need to set region for buckets in non default region
2613
+ if ( is_null( $region ) ) {
2614
+ $region = $this->get_setting( 'region' );
2615
+
2616
+ if ( is_wp_error( $region ) ) {
2617
+ return $region;
2618
+ }
2619
+ }
2620
+
2621
if ( isset( self::$buckets_check[ $bucket ] ) ) {
2622
return self::$buckets_check[ $bucket ];
2623
}
2624
2625
+ $key = $this->get_file_prefix() . 'as3cf-permission-check.txt';
2626
$file_contents = __( 'This is a test file to check if the user has write permission to S3. Delete me if found.', 'amazon-s3-and-cloudfront' );
2627
2628
try {
2629
// attempt to create the test file
2630
+ $this->get_s3client( $region, true )->putObject( array(
2631
+ 'Bucket' => $bucket,
2632
+ 'Key' => $key,
2633
+ 'Body' => $file_contents,
2634
+ 'ACL' => 'public-read',
2635
+ ) );
2636
// delete it straight away if created
2637
$this->get_s3client()->deleteObject( array(
2638
'Bucket' => $bucket,
2685
wp_register_script( 'as3cf-modal', $src, array( 'jquery' ), $version, true );
2686
}
2687
2688
+ /**
2689
+ * On plugin load.
2690
+ */
2691
+ public function plugin_load() {
2692
+ $this->enqueue_style( 'as3cf-styles', 'assets/css/styles', array( 'as3cf-modal' ) );
2693
+ $this->enqueue_script( 'as3cf-script', 'assets/js/script', array( 'jquery', 'as3cf-modal' ) );
2694
2695
wp_localize_script( 'as3cf-script',
2696
'as3cf',
3054
*
3055
* @return array|bool|WP_Error
3056
*/
3057
+ public function set_attachment_acl_on_s3( $post_id, $s3object, $acl ) {
3058
// Return early if already set to the desired ACL
3059
if ( isset( $s3object['acl'] ) && $acl === $s3object['acl'] ) {
3060
return false;
3714
return $table_prefixes;
3715
}
3716
3717
/**
3718
* Get the access denied bucket error notice message
3719
*
3722
* @return string
3723
*/
3724
function get_access_denied_notice_message( $single = true ) {
3725
+ $url = $this->dbrains_url( '/wp-offload-s3/doc/quick-start-guide/', array(
3726
+ 'utm_campaign' => 'error+messages',
3727
+ ), 'bucket-restrictions' );
3728
+
3729
+ $quick_start = sprintf( '<a class="js-link" href="%s">%s</a>', $url, __( 'Quick Start Guide', 'amazon-s3-and-cloudfront' ) );
3730
3731
$message = sprintf( __( "Looks like we don't have write access to this bucket. It's likely that the user you've provided access keys for hasn't been granted the correct permissions. Please see our %s for instructions on setting up permissions correctly.", 'amazon-s3-and-cloudfront' ), $quick_start );
3732
if ( ! $single ) {
3733
$message = sprintf( __( "Looks like we don't have access to the buckets. It's likely that the user you've provided access keys for hasn't been granted the correct permissions. Please see our %s for instructions on setting up permissions correctly.", 'amazon-s3-and-cloudfront' ), $quick_start );
3734
}
3735
3736
return $message;
3868
's3' => $all_media_s3,
3869
);
3870
3871
+ set_site_transient( 'wpos3_attachment_counts', $attachment_counts, 2 * MINUTE_IN_SECONDS );
3872
}
3873
3874
return $attachment_counts;
3909
}
3910
3911
/**
3912
+ * Get UTM source for plugin.
3913
*
3914
* @return string
3915
*/
3916
+ protected function get_utm_source() {
3917
+ return $this->is_pro() ? 'OS3+Paid' : 'OS3+Free';
3918
}
3919
3920
/**
3921
+ * More info link.
3922
*
3923
+ * @param string $path
3924
+ * @param string $utm_content
3925
+ * @param string $hash
3926
*
3927
* @return string
3928
*/
3929
+ public function more_info_link( $path, $utm_content = '', $hash = '' ) {
3930
+ $args = array(
3931
+ 'utm_campaign' => 'support+docs',
3932
+ );
3933
3934
+ if ( ! empty( $utm_content ) ) {
3935
+ $args['utm_content'] = $utm_content;
3936
}
3937
3938
+ $url = $this->dbrains_url( $path, $args, $hash );
3939
+ $text = __( 'More info', 'amazon-s3-and-cloudfront' );
3940
+ $link = AS3CF_Utils::dbrains_link( $url, $text );
3941
3942
return sprintf( '<span class="more-info">%s &raquo;</span>', $link );
3943
}
3944
3945
/**
3946
+ * Settings more info link.
3947
*
3948
* @param string $hash
3949
+ * @param string $utm_content
3950
*
3951
* @return string
3952
*/
3953
+ public function settings_more_info_link( $hash, $utm_content = '' ) {
3954
+ return $this->more_info_link( '/wp-offload-s3/doc/settings/', $utm_content, $hash );
3955
}
3956
3957
/**
4028
'flash' => false,
4029
);
4030
4031
+ $doc_url = $this->dbrains_url( '/wp-offload-s3/doc/force-http-setting/', array(
4032
+ 'utm_campaign' => 'support+docs'
4033
+ ) );
4034
+ $doc_link = AS3CF_Utils::dbrains_link( $doc_url, __( 'this doc' ) );
4035
4036
$message = sprintf( '<strong>%s</strong> &mdash; ', __( 'WP Offload S3 Feature Removed', 'amazon-s3-and-cloudfront' ) );
4037
$message .= sprintf( __( 'You had the "Always non-SSL" option selected in your settings, but we\'ve removed this option in version 1.3. We\'ll now use HTTPS when the request is HTTPS and regular HTTP when the request is HTTP. This should work fine for your site, but please take a poke around and make sure things are working ok. See %s for more details on why we did this and how you can revert back to the old behavior.', 'amazon-s3-and-cloudfront' ), $doc_link );
4181
* Load media assets.
4182
*/
4183
public function load_media_assets() {
4184
+ $this->enqueue_style( 'as3cf-media-styles', 'assets/css/media', array( 'as3cf-modal' ) );
4185
+ $this->enqueue_script( 'as3cf-media-script', 'assets/js/media', array(
4186
+ 'jquery',
4187
+ 'media-views',
4188
+ 'media-grid',
4189
+ 'wp-util',
4190
+ ) );
4191
4192
+ wp_localize_script( 'as3cf-media-script', 'as3cf_media', array(
4193
'strings' => $this->get_media_action_strings(),
4194
'nonces' => array(
4195
'get_attachment_s3_details' => wp_create_nonce( 'get-attachment-s3-details' ),
4196
),
4197
+ ) );
4198
}
4199
4200
/**
4238
* @param $hook_suffix
4239
*/
4240
public function load_attachment_assets( $hook_suffix ) {
4241
global $post;
4242
+ if ( 'post.php' !== $hook_suffix || 'attachment' !== $post->post_type ) {
4243
return;
4244
}
4245
4246
+ $this->enqueue_style( 'as3cf-pro-attachment-styles', 'assets/css/attachment', array( 'as3cf-modal' ) );
4247
4248
+ do_action( 'as3cf_load_attachment_assets' );
4249
}
4250
4251
/**
4274
return ( '.' === $directory ) ? '' : $directory . '/';
4275
}
4276
4277
/**
4278
* Has the given attachment been uploaded by this instance?
4279
*
4290
}
4291
4292
/**
4293
+ * Filters the audio & video shortcodes output to remove "&_=NN" params from source.src as it breaks signed URLs.
4294
*
4295
+ * @param string $html Shortcode HTML output.
4296
+ * @param array $atts Array of shortcode attributes.
4297
+ * @param string $media Media file.
4298
* @param int $post_id Post ID.
4299
+ * @param string $library Media library used for the shortcode.
4300
*
4301
* @return string
4302
*
4303
* Note: Depends on 30377.4.diff from https://core.trac.wordpress.org/ticket/30377
4304
*/
4305
+ public function wp_media_shortcode( $html, $atts, $media, $post_id, $library ) {
4306
$html = preg_replace( '/&#038;_=[0-9]+/', '', $html );
4307
4308
return $html;
4326
4327
return $url;
4328
}
4329
+
4330
+ /**
4331
+ * Get ACL for intermediate size.
4332
+ *
4333
+ * @param int $attachment_id
4334
+ * @param string $size
4335
+ *
4336
+ * @return string
4337
+ */
4338
+ public function get_acl_for_intermediate_size( $attachment_id, $size ) {
4339
+ $s3_info = $this->get_attachment_s3_info( $attachment_id );
4340
+
4341
+ if ( 'original' === $size || empty( $size ) ) {
4342
+ return isset( $s3_info['acl'] ) ? $s3_info['acl'] : self::DEFAULT_ACL;
4343
+ }
4344
+
4345
+ if ( ! empty( $s3_info['sizes'][ $size ]['acl'] ) ) {
4346
+ return $s3_info['sizes'][ $size ]['acl'];
4347
+ }
4348
+
4349
+ return self::DEFAULT_ACL;
4350
+ }
4351
+
4352
+ /**
4353
+ * Consolidate an array of WP_Errors into a single WP_Error object.
4354
+ *
4355
+ * @param array $upload_errors
4356
+ *
4357
+ * @return WP_Error
4358
+ */
4359
+ protected function consolidate_upload_errors( $upload_errors ) {
4360
+ $errors = new WP_Error;
4361
+
4362
+ foreach ( $upload_errors as $error ) {
4363
+
4364
+ /* @var WP_Error $error */
4365
+ $errors->add( $error->get_error_code(), $error->get_error_message() );
4366
+ }
4367
+
4368
+ return $errors;
4369
+ }
4370
}
classes/as3cf-filter.php CHANGED
@@ -2,6 +2,21 @@
2
3
abstract class AS3CF_Filter {
4
5
/**
6
* @var Amazon_S3_And_CloudFront
7
*/
@@ -12,6 +27,11 @@ abstract class AS3CF_Filter {
12
*/
13
protected $query_cache = array();
14
15
/**
16
* Constructor
17
*
@@ -26,6 +46,13 @@ abstract class AS3CF_Filter {
26
$this->init();
27
}
28
29
/**
30
* Filter EDD download files.
31
*
@@ -118,6 +145,87 @@ abstract class AS3CF_Filter {
118
return $content;
119
}
120
121
/**
122
* Process content.
123
*
@@ -206,6 +314,8 @@ abstract class AS3CF_Filter {
206
continue;
207
}
208
209
if ( ! preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) || ! isset( $class_id[1] ) ) {
210
// Can't determine ID from class, skip
211
continue;
@@ -264,7 +374,7 @@ abstract class AS3CF_Filter {
264
continue;
265
}
266
267
- $parts = parse_url( $url );
268
269
if ( ! isset( $parts['path'] ) ) {
270
// URL doesn't have a path, continue
@@ -277,7 +387,7 @@ abstract class AS3CF_Filter {
277
}
278
279
$attachment_id = null;
280
- $bare_url = $this->as3cf->maybe_remove_query_string( $url );
281
282
if ( isset( $cache[ $bare_url ] ) ) {
283
$attachment_id = $cache[ $bare_url ];
@@ -290,9 +400,9 @@ abstract class AS3CF_Filter {
290
291
if ( is_null( $attachment_id ) || is_array( $attachment_id ) ) {
292
// Attachment ID not cached, need to search by URL.
293
- $urls[] = $url;
294
} else {
295
- $this->push_to_url_pairs( $url_pairs, $attachment_id, $url, $to_cache );
296
}
297
}
298
@@ -351,7 +461,7 @@ abstract class AS3CF_Filter {
351
return false;
352
}
353
354
- $base_url = $this->as3cf->remove_scheme( $this->as3cf->maybe_remove_query_string( $this->get_base_url( $attachment_id ) ) );
355
$basename = wp_basename( $base_url );
356
357
// Add full size URL
@@ -362,7 +472,7 @@ abstract class AS3CF_Filter {
362
$base_urls[] = str_replace( $basename, $size['file'], $base_url );
363
}
364
365
- $url = $this->as3cf->remove_scheme( $this->as3cf->maybe_remove_query_string( $url ) );
366
367
if ( in_array( $url, $base_urls ) ) {
368
// Match found, return true
@@ -381,7 +491,7 @@ abstract class AS3CF_Filter {
381
* @param array $to_cache
382
*/
383
protected function push_to_url_pairs( &$url_pairs, $attachment_id, $find, &$to_cache ) {
384
- $find_full = $this->as3cf->remove_size_from_filename( $find );
385
$find_full = $this->normalize_find_value( $this->as3cf->maybe_remove_query_string( $find_full ) );
386
$find_size = $this->normalize_find_value( $this->as3cf->maybe_remove_query_string( $find ) );
387
@@ -404,8 +514,8 @@ abstract class AS3CF_Filter {
404
$parts = parse_url( $find );
405
406
if ( ! isset( $parts['scheme'] ) ) {
407
- $replace_full = $this->as3cf->remove_scheme( $replace_full );
408
- $replace_size = $this->as3cf->remove_scheme( $replace_size );
409
}
410
411
// Find and replace full version
@@ -458,7 +568,7 @@ abstract class AS3CF_Filter {
458
* @param array $to_cache
459
*/
460
protected function url_cache_failure( $url, &$to_cache ) {
461
- $full = $this->as3cf->remove_size_from_filename( $url );
462
$failure = array(
463
'timestamp' => time(),
464
);
@@ -495,19 +605,22 @@ abstract class AS3CF_Filter {
495
/**
496
* Get post cache
497
*
498
- * @param bool|int $post_id
499
*
500
* @return array
501
*/
502
- protected function get_post_cache( $post_id = false ) {
503
- $post_id = $this->get_post_id( $post_id );
504
505
if ( ! $post_id ) {
506
- // Post ID not found, return empty cache
507
return array();
508
}
509
510
- $cache = get_post_meta( $post_id, 'amazonS3_cache', true );
511
512
if ( empty( $cache ) ) {
513
$cache = array();
@@ -517,42 +630,59 @@ abstract class AS3CF_Filter {
517
}
518
519
/**
520
- * Maybe update post cache
521
*
522
- * @param array $to_cache
523
- * @param bool|int $post_id
524
*/
525
- protected function maybe_update_post_cache( $to_cache, $post_id = false ) {
526
- $post_id = $this->get_post_id( $post_id );
527
528
- if ( ! $post_id || empty( $to_cache ) ) {
529
return;
530
}
531
532
- $urls = array_merge( $this->get_post_cache( $post_id ), $to_cache );
533
534
- update_post_meta( $post_id, 'amazonS3_cache', $urls );
535
}
536
537
/**
538
- * Get post ID.
539
*
540
* @param bool|int $post_id
541
- *
542
- * @return bool|int
543
*/
544
- protected function get_post_id( $post_id ) {
545
- if ( false !== $post_id ) {
546
- return $post_id;
547
}
548
549
- global $post;
550
551
- if ( isset( $post->ID ) ) {
552
- return $post->ID;
553
}
554
-
555
- return false;
556
}
557
558
/**
@@ -561,7 +691,17 @@ abstract class AS3CF_Filter {
561
* @return array
562
*/
563
protected function get_option_cache() {
564
- return get_option( 'amazonS3_cache', array() );
565
}
566
567
/**
@@ -574,9 +714,12 @@ abstract class AS3CF_Filter {
574
return;
575
}
576
577
- $urls = array_merge( $this->get_option_cache(), $to_cache );
578
579
- update_option( 'amazonS3_cache', $urls );
580
}
581
582
/**
@@ -585,11 +728,17 @@ abstract class AS3CF_Filter {
585
* @param int $post_id
586
*/
587
public function purge_cache_on_attachment_delete( $post_id ) {
588
- $this->purge_from_cache( $this->get_url( $post_id ) );
589
}
590
591
/**
592
- * Purge URL from cache
593
*
594
* @param string $url
595
* @param bool|int $blog_id
@@ -606,7 +755,7 @@ abstract class AS3CF_Filter {
606
DELETE FROM {$wpdb->postmeta}
607
WHERE meta_key = %s
608
AND meta_value LIKE %s;
609
- ", 'amazonS3_cache', '%"' . $url . '"%' );
610
611
$wpdb->query( $sql );
612
@@ -615,7 +764,7 @@ abstract class AS3CF_Filter {
615
DELETE FROM {$wpdb->options}
616
WHERE option_name = %s
617
AND option_value LIKE %s;
618
- ", 'amazonS3_cache', '%"' . $url . '"%' );
619
620
$wpdb->query( $sql );
621
@@ -691,6 +840,28 @@ abstract class AS3CF_Filter {
691
return $css;
692
}
693
694
/**
695
* Get custom CSS post ID.
696
*
2
3
abstract class AS3CF_Filter {
4
5
+ /**
6
+ * The key used for storing the URL cache.
7
+ */
8
+ const CACHE_KEY = 'amazonS3_cache';
9
+
10
+ /**
11
+ * The cache group used by an external object cache for posts.
12
+ */
13
+ const POST_CACHE_GROUP = 'post_amazonS3_cache';
14
+
15
+ /**
16
+ * The cache group used by an external object cache for options.
17
+ */
18
+ const OPTION_CACHE_GROUP = 'option_amazonS3_cache';
19
+
20
/**
21
* @var Amazon_S3_And_CloudFront
22
*/
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
*
46
$this->init();
47
}
48
49
+ /**
50
+ * Initialize the filter.
51
+ */
52
+ protected function init() {
53
+ // Optionally override in a sub-class.
54
+ }
55
+
56
/**
57
* Filter EDD download files.
58
*
145
return $content;
146
}
147
148
+ /**
149
+ * Handle widget instances.
150
+ *
151
+ * @param array $instance
152
+ * @param WP_Widget $class
153
+ *
154
+ * @return array
155
+ */
156
+ protected function handle_widget( $instance, $class ) {
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.
164
+ // Therefore cache updating has to wait until render or edit via Appearance menu.
165
+ if ( isset( $_POST['wp_customize'] ) && 'on' === $_POST['wp_customize'] ) {
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
+ return $instance;
178
+ }
179
+
180
+ /**
181
+ * Filter media widget.
182
+ *
183
+ * @param array $instance
184
+ * @param bool $update_cache
185
+ *
186
+ * @return array
187
+ */
188
+ protected function filter_media_widget( $instance, $update_cache ) {
189
+ $cache = $this->get_option_cache();
190
+ $to_cache = array();
191
+
192
+ foreach ( $instance as $key => $value ) {
193
+ if ( empty( $value ) ) {
194
+ continue;
195
+ }
196
+
197
+ if ( AS3CF_Utils::is_url( $value ) ) {
198
+ $instance[ $key ] = $this->process_content( $value, $cache, $to_cache );
199
+ }
200
+ }
201
+
202
+ if ( $update_cache ) {
203
+ $this->maybe_update_option_cache( $to_cache );
204
+ }
205
+
206
+ return $instance;
207
+ }
208
+
209
+ /**
210
+ * Filter text widget.
211
+ *
212
+ * @param array $instance
213
+ * @param bool $update_cache
214
+ *
215
+ * @return array
216
+ */
217
+ protected function filter_text_widget( $instance, $update_cache ) {
218
+ $cache = $this->get_option_cache();
219
+ $to_cache = array();
220
+ $instance['text'] = $this->process_content( $instance['text'], $cache, $to_cache );
221
+
222
+ if ( $update_cache ) {
223
+ $this->maybe_update_option_cache( $to_cache );
224
+ }
225
+
226
+ return $instance;
227
+ }
228
+
229
/**
230
* Process content.
231
*
314
continue;
315
}
316
317
+ $url = AS3CF_Utils::reduce_url( $url );
318
+
319
if ( ! preg_match( '/wp-image-([0-9]+)/i', $image, $class_id ) || ! isset( $class_id[1] ) ) {
320
// Can't determine ID from class, skip
321
continue;
374
continue;
375
}
376
377
+ $parts = AS3CF_Utils::parse_url( $url );
378
379
if ( ! isset( $parts['path'] ) ) {
380
// URL doesn't have a path, continue
387
}
388
389
$attachment_id = null;
390
+ $bare_url = AS3CF_Utils::reduce_url( $url );
391
392
if ( isset( $cache[ $bare_url ] ) ) {
393
$attachment_id = $cache[ $bare_url ];
400
401
if ( is_null( $attachment_id ) || is_array( $attachment_id ) ) {
402
// Attachment ID not cached, need to search by URL.
403
+ $urls[] = $bare_url;
404
} else {
405
+ $this->push_to_url_pairs( $url_pairs, $attachment_id, $bare_url, $to_cache );
406
}
407
}
408
461
return false;
462
}
463
464
+ $base_url = AS3CF_Utils::reduce_url( $this->get_base_url( $attachment_id ) );
465
$basename = wp_basename( $base_url );
466
467
// Add full size URL
472
$base_urls[] = str_replace( $basename, $size['file'], $base_url );
473
}
474
475
+ $url = AS3CF_Utils::reduce_url( $url );
476
477
if ( in_array( $url, $base_urls ) ) {
478
// Match found, return true
491
* @param array $to_cache
492
*/
493
protected function push_to_url_pairs( &$url_pairs, $attachment_id, $find, &$to_cache ) {
494
+ $find_full = AS3CF_Utils::remove_size_from_filename( $find );
495
$find_full = $this->normalize_find_value( $this->as3cf->maybe_remove_query_string( $find_full ) );
496
$find_size = $this->normalize_find_value( $this->as3cf->maybe_remove_query_string( $find ) );
497
514
$parts = parse_url( $find );
515
516
if ( ! isset( $parts['scheme'] ) ) {
517
+ $replace_full = AS3CF_Utils::remove_scheme( $replace_full );
518
+ $replace_size = AS3CF_Utils::remove_scheme( $replace_size );
519
}
520
521
// Find and replace full version
568
* @param array $to_cache
569
*/
570
protected function url_cache_failure( $url, &$to_cache ) {
571
+ $full = AS3CF_Utils::remove_size_from_filename( $url );
572
$failure = array(
573
'timestamp' => time(),
574
);
605
/**
606
* Get post cache
607
*
608
+ * @param null|int|WP_Post $post Optional. Post ID or post object. Defaults to current post.
609
*
610
* @return array
611
*/
612
+ public function get_post_cache( $post = null ) {
613
+ $post_id = AS3CF_Utils::get_post_id( $post );
614
615
if ( ! $post_id ) {
616
return array();
617
}
618
619
+ if ( wp_using_ext_object_cache() ) {
620
+ $cache = wp_cache_get( $post_id, self::POST_CACHE_GROUP );
621
+ } else {
622
+ $cache = get_post_meta( $post_id, self::CACHE_KEY, true );
623
+ }
624
625
if ( empty( $cache ) ) {
626
$cache = array();
630
}
631
632
/**
633
+ * Set the cache for the given post.
634
*
635
+ * @param null|int|WP_Post $post Optional. Post ID or post object. Defaults to current post.
636
+ * @param $data
637
*/
638
+ protected function set_post_cache( $post, $data ) {
639
+ $post_id = AS3CF_Utils::get_post_id( $post );
640
641
+ if ( ! $post_id ) {
642
return;
643
}
644
645
+ if ( wp_using_ext_object_cache() ) {
646
+ $expires = apply_filters( 'as3cf_' . self::POST_CACHE_GROUP . '_expires', DAY_IN_SECONDS, $post_id, $data );
647
+ wp_cache_set( $post_id, $data, self::POST_CACHE_GROUP, $expires );
648
+ } else {
649
+ update_post_meta( $post_id, self::CACHE_KEY, $data );
650
+ }
651
+ }
652
653
+ /**
654
+ * Set the option cache with the given data.
655
+ *
656
+ * @param $data
657
+ */
658
+ protected function set_option_cache( $data ) {
659
+ if ( wp_using_ext_object_cache() ) {
660
+ $expires = apply_filters( 'as3cf_' . self::OPTION_CACHE_GROUP . '_expires', DAY_IN_SECONDS, self::CACHE_KEY, $data );
661
+ wp_cache_set( self::CACHE_KEY, $data, self::OPTION_CACHE_GROUP, $expires );
662
+ } else {
663
+ update_option( self::CACHE_KEY, $data );
664
+ }
665
}
666
667
/**
668
+ * Maybe update post cache
669
*
670
+ * @param array $to_cache
671
* @param bool|int $post_id
672
*/
673
+ protected function maybe_update_post_cache( $to_cache, $post_id = false ) {
674
+ $post_id = AS3CF_Utils::get_post_id( $post_id );
675
+
676
+ if ( ! $post_id || empty( $to_cache ) ) {
677
+ return;
678
}
679
680
+ $cached = $this->get_post_cache( $post_id );
681
+ $urls = static::merge_cache( $cached, $to_cache );
682
683
+ if ( $urls !== $cached ) {
684
+ $this->set_post_cache( $post_id, $urls );
685
}
686
}
687
688
/**
691
* @return array
692
*/
693
protected function get_option_cache() {
694
+ if ( wp_using_ext_object_cache() ) {
695
+ $cache = wp_cache_get( self::CACHE_KEY, self::OPTION_CACHE_GROUP );
696
+ } else {
697
+ $cache = get_option( self::CACHE_KEY, array() );
698
+ }
699
+
700
+ if ( empty( $cache ) ) {
701
+ $cache = array();
702
+ }
703
+
704
+ return $cache;
705
}
706
707
/**
714
return;
715
}
716
717
+ $cached = $this->get_option_cache();
718
+ $urls = static::merge_cache( $cached, $to_cache );
719
720
+ if ( $urls !== $cached ) {
721
+ $this->set_option_cache( $urls );
722
+ }
723
}
724
725
/**
728
* @param int $post_id
729
*/
730
public function purge_cache_on_attachment_delete( $post_id ) {
731
+ if ( ! in_array( $post_id, self::$purged_ids ) ) {
732
+ $this->purge_from_cache( $this->get_url( $post_id ) );
733
+ self::$purged_ids[] = $post_id;
734
+ }
735
}
736
737
/**
738
+ * Purge URL from cache.
739
+ *
740
+ * Currently does nothing for purging from an external object cache.
741
+ * Values are left to expire using the expiration time provided when set.
742
*
743
* @param string $url
744
* @param bool|int $blog_id
755
DELETE FROM {$wpdb->postmeta}
756
WHERE meta_key = %s
757
AND meta_value LIKE %s;
758
+ ", self::CACHE_KEY, '%"' . $url . '"%' );
759
760
$wpdb->query( $sql );
761
764
DELETE FROM {$wpdb->options}
765
WHERE option_name = %s
766
AND option_value LIKE %s;
767
+ ", self::CACHE_KEY, '%"' . $url . '"%' );
768
769
$wpdb->query( $sql );
770
840
return $css;
841
}
842
843
+ /**
844
+ * Merge content filtering cache arrays.
845
+ *
846
+ * @param array $existing_cache
847
+ * @param array $merge_cache
848
+ *
849
+ * @return array
850
+ */
851
+ public static function merge_cache( $existing_cache, $merge_cache ) {
852
+ if ( ! empty( $existing_cache ) ) {
853
+ $post_cache_keys = array_map( 'AS3CF_Utils::reduce_url', array_keys( $existing_cache ) );
854
+ $existing_cache = array_combine( $post_cache_keys, $existing_cache );
855
+ }
856
+
857
+ if ( ! empty( $merge_cache ) ) {
858
+ $add_cache_keys = array_map( 'AS3CF_Utils::reduce_url', array_keys( $merge_cache ) );
859
+ $merge_cache = array_combine( $add_cache_keys, $merge_cache );
860
+ }
861
+
862
+ return array_merge( $existing_cache, $merge_cache );
863
+ }
864
+
865
/**
866
* Get custom CSS post ID.
867
*
classes/as3cf-notices.php CHANGED
@@ -423,15 +423,8 @@ class AS3CF_Notices {
423
* Enqueue notice scripts in the admin
424
*/
425
public function enqueue_notice_scripts() {
426
- $version = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? time() : $GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'];
427
- $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
428
-
429
- // Enqueue notice.css & notice.js globally as some notices can be shown & dismissed on any admin page.
430
- $src = plugins_url( 'assets/css/notice.css', $this->as3cf->get_plugin_file_path() );
431
- wp_enqueue_style( 'as3cf-notice', $src, array(), $version );
432
-
433
- $src = plugins_url( 'assets/js/notice' . $suffix . '.js', $this->as3cf->get_plugin_file_path() );
434
- wp_enqueue_script( 'as3cf-notice', $src, array( 'jquery' ), $version, true );
435
436
wp_localize_script( 'as3cf-notice', 'as3cf_notice', array(
437
'strings' => array(
423
* Enqueue notice scripts in the admin
424
*/
425
public function enqueue_notice_scripts() {
426
+ $this->as3cf->enqueue_style( 'as3cf-notice', 'assets/css/notice' );
427
+ $this->as3cf->enqueue_script( 'as3cf-notice', 'assets/js/notice', array( 'jquery' ) );
428
429
wp_localize_script( 'as3cf-notice', 'as3cf_notice', array(
430
'strings' => array(
classes/as3cf-plugin-compatibility.php CHANGED
@@ -72,9 +72,6 @@ class AS3CF_Plugin_Compatibility {
72
* Register the compatibility hooks as long as the plugin is setup.
73
*/
74
function compatibility_init_if_setup() {
75
- // Add notices about compatibility addons to install
76
- add_action( 'admin_init', array( $this, 'maybe_render_compatibility_addons_notice' ) );
77
-
78
// Turn on stream wrapper S3 file
79
add_filter( 'as3cf_get_attached_file', array( $this, 'get_stream_wrapper_file' ), 20, 4 );
80
@@ -88,7 +85,7 @@ class AS3CF_Plugin_Compatibility {
88
* WP_Image_Editor
89
* /wp-includes/class-wp-image-editor.php
90
*/
91
- add_action( 'as3cf_upload_attachment_pre_remove', array( $this, 'image_editor_remove_files' ), 10, 4 );
92
add_filter( 'as3cf_get_attached_file', array( $this, 'image_editor_download_file' ), 10, 4 );
93
add_filter( 'as3cf_upload_attachment_local_files_to_remove', array( $this, 'image_editor_remove_original_image' ), 10, 3 );
94
add_filter( 'as3cf_get_attached_file', array( $this, 'customizer_crop_download_file' ), 10, 4 );
@@ -100,202 +97,13 @@ class AS3CF_Plugin_Compatibility {
100
* https://wordpress.org/plugins/regenerate-thumbnails/
101
*/
102
add_filter( 'as3cf_get_attached_file', array( $this, 'regenerate_thumbnails_download_file' ), 10, 4 );
103
- }
104
-
105
- /**
106
- * Get the addons for the Pro upgrade
107
- *
108
- * @return array
109
- */
110
- public function get_pro_addons() {
111
- global $amazon_web_services;
112
-
113
- $all_addons = $amazon_web_services->get_addons( true );
114
- if ( ! isset( $all_addons['amazon-s3-and-cloudfront-pro']['addons'] ) ) {
115
- return array();
116
- }
117
-
118
- $addons = $all_addons['amazon-s3-and-cloudfront-pro']['addons'];
119
-
120
- return $addons;
121
- }
122
-
123
- /**
124
- * Get compatibility addons that are required to be installed
125
- *
126
- * @return array
127
- */
128
- public function get_compatibility_addons_to_install() {
129
- if ( isset( $this->compatibility_addons ) ) {
130
- return $this->compatibility_addons;
131
- }
132
-
133
- $addons = $this->get_pro_addons();
134
- $addons_to_install = array();
135
-
136
- if ( empty ( $addons ) ) {
137
- return $addons_to_install;
138
- }
139
-
140
- foreach ( $addons as $addon_slug => $addon ) {
141
- if ( file_exists( WP_PLUGIN_DIR . '/' . $addon_slug . '/' . $addon_slug . '.php' ) ) {
142
- // Addon already installed, ignore.
143
- continue;
144
- }
145
-
146
- if ( ! isset( $addon['parent_plugin_basename'] ) || '' === $addon['parent_plugin_basename'] ) {
147
- // Addon doesn't have a parent plugin, ignore.
148
- continue;
149
- }
150
-
151
- if ( ! file_exists( WP_PLUGIN_DIR . '/' . $addon['parent_plugin_basename'] ) || ! is_plugin_active( $addon['parent_plugin_basename'] ) ) {
152
- // Parent plugin not installed or not activated, ignore.
153
- continue;
154
- }
155
-
156
- $addons_to_install[ $addon_slug ] = array(
157
- 'title' => $addon['title'],
158
- 'url' => $addon['url'],
159
- );
160
- }
161
-
162
- $this->compatibility_addons = $addons_to_install;
163
-
164
- return $addons_to_install;
165
- }
166
-
167
- /**
168
- * Maybe show a notice about installing addons when the site is using the
169
- * plugins they add compatibility for.
170
- */
171
- public function maybe_render_compatibility_addons_notice() {
172
- if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
173
- return;
174
- }
175
-
176
- global $as3cf_compat_check;
177
- if ( ! $as3cf_compat_check->check_capabilities() ) {
178
- // User can't install plugins anyway, bail.
179
- return;
180
- }
181
-
182
- if ( ! $this->should_show_compatibility_notice() ) {
183
- // No addons to install, or addons haven't changed
184
- return;
185
- }
186
-
187
- $notice_id = 'as3cf-compat-addons';
188
- $addons_to_install = $this->get_compatibility_addons_to_install();
189
-
190
- // Remove previous notice to refresh addon list
191
- $this->remove_compatibility_notice();
192
-
193
- $title = __( 'WP Offload S3 Compatibility Addons', 'amazon-s3-and-cloudfront' );
194
- $compat_url = 'https://deliciousbrains.com/wp-offload-s3/doc/compatibility-with-other-plugins/';
195
- $compat_link = sprintf( '<a href="%s">%s</a>', $compat_url, __( 'compatibility addons', 'amazon-s3-and-cloudfront' ) );
196
- $message = sprintf( __( "To get WP Offload S3 to work with certain 3rd party plugins, you might need to install and activate some of our %s. We've detected the following addons might need to be installed. Please click the links for more information about each addon to determine if you need it or not.", 'amazon-s3-and-cloudfront' ), $compat_link );
197
-
198
- $notice_addons_text = $this->render_addon_list( $addons_to_install );
199
- $support_email = 'nom@deliciousbrains.com';
200
- $support_link = sprintf( '<a href="mailto:%1$s">%1$s</a>', $support_email );
201
-
202
- $notice_addons_text .= '<p>' . sprintf( __( "You will need to purchase a license to get access to these addons. If you're having trouble determining whether or not you need the addons, send an email to %s.", 'amazon-s3-and-cloudfront' ), $support_link ) . '</p>';
203
- $notice_addons_text .= sprintf( '<p><a href="%s" class="button button-large">%s</a></p>', 'https://deliciousbrains.com/wp-offload-s3/pricing/', __( 'View Licenses', 'amazon-s3-and-cloudfront' ) );
204
-
205
- $notice_addons_text = apply_filters( 'wpos3_compat_addons_notice', $notice_addons_text, $addons_to_install );
206
-
207
- if ( false === $notice_addons_text ) {
208
- // Allow the notice to be aborted.
209
- return;
210
- }
211
-
212
- $notice = '<p><strong>' . $title . '</strong> &mdash; ' . $message . '</p>' . $notice_addons_text;
213
-
214
- $notice_args = array(
215
- 'type' => 'notice-info',
216
- 'custom_id' => $notice_id,
217
- 'only_show_to_user' => false,
218
- 'flash' => false,
219
- 'auto_p' => false,
220
- );
221
-
222
- $notice_args = apply_filters( 'wpos3_compat_addons_notice_args', $notice_args, $addons_to_install );
223
-
224
- update_site_option( 'as3cf_compat_addons_to_install', $addons_to_install );
225
226
- $this->as3cf->notices->add_notice( $notice, $notice_args );
227
- }
228
-
229
- /**
230
- * Should show compatibility notice
231
- *
232
- * @return bool
233
- */
234
- protected function should_show_compatibility_notice() {
235
- $addons = $this->get_compatibility_addons_to_install();
236
- $previous_addons = get_site_option( 'as3cf_compat_addons_to_install', array() );
237
-
238
- if ( empty( $addons ) && empty( $previous_addons ) ) {
239
- // No addons to install
240
- return false;
241
- }
242
-
243
- if ( empty( $addons ) && ! empty( $previous_addons ) ) {
244
- // No addons to install but previous exist
245
- $this->remove_compatibility_notice( true );
246
-
247
- return false;
248
- }
249
-
250
- if ( $previous_addons === $addons ) {
251
- // Addons have not changed
252
- return false;
253
- }
254
-
255
- return true;
256
- }
257
-
258
- /**
259
- * Remove compatibility notice
260
- *
261
- * @param bool $delete_option
262
- */
263
- protected function remove_compatibility_notice( $delete_option = false ) {
264
- $notice_id = 'as3cf-compat-addons';
265
-
266
- if ( $this->as3cf->notices->find_notice_by_id( $notice_id ) ) {
267
- $this->as3cf->notices->undismiss_notice_for_all( $notice_id );
268
- $this->as3cf->notices->remove_notice_by_id( $notice_id );
269
- }
270
-
271
- if ( $delete_option ) {
272
- delete_site_option( 'as3cf_compat_addons_to_install' );
273
- }
274
- }
275
-
276
- /**
277
- * Render list of addons for a notice
278
- *
279
- * @param array $addons
280
- *
281
- * @return string
282
- */
283
- protected function render_addon_list( $addons ) {
284
- if ( ! is_array( $addons ) || empty( $addons ) ) {
285
- return '';
286
- }
287
-
288
- sort( $addons );
289
-
290
- $html = '<ul style="list-style-type: disc; padding: 0 0 0 30px; margin: 5px 0;">';
291
- foreach ( $addons as $addon ) {
292
- $html .= '<li style="margin: 0;">';
293
- $html .= '<a href="' . $addon['url'] . '">' . $addon['title'] . '</a>';
294
- $html .= '</li>';
295
}
296
- $html .= '</ul>';
297
-
298
- return $html;
299
}
300
301
/**
@@ -325,6 +133,13 @@ class AS3CF_Plugin_Compatibility {
325
return $url;
326
}
327
328
/**
329
* Is this an AJAX process?
330
*
@@ -426,21 +241,49 @@ class AS3CF_Plugin_Compatibility {
426
* Allow the WordPress Image Editor to remove edited version of images
427
* if the original image is being restored and 'IMAGE_EDIT_OVERWRITE' is set
428
*
429
- * @param int $post_id
430
- * @param array $s3object
431
- * @param string $prefix
432
- * @param array $args
433
*/
434
- function image_editor_remove_files( $post_id, $s3object, $prefix, $args ) {
435
if ( ! isset( $_POST['do'] ) || 'restore' !== $_POST['do'] ) {
436
- return;
437
}
438
439
if ( ! defined( 'IMAGE_EDIT_OVERWRITE' ) || ! IMAGE_EDIT_OVERWRITE ) {
440
return;
441
}
442
443
- $this->as3cf->remove_attachment_files_from_s3( $post_id, $s3object, false );
444
}
445
446
/**
@@ -475,19 +318,19 @@ class AS3CF_Plugin_Compatibility {
475
$this->copy_s3_file_to_server( $orig_s3, $orig_file );
476
477
// Copy the edited file back to the server as well, it will be cleaned up later
478
- if ( ( $s3_file = $this->copy_s3_file_to_server( $s3_object, $file ) ) ) {
479
// Return the file if successfully downloaded from S3
480
return $s3_file;
481
};
482
}
483
484
- // must be the image-editor process
485
- if ( isset( $_POST['action'] ) && 'image-editor' == sanitize_key( $_POST['action'] ) ) { // input var okay
486
- $callers = debug_backtrace();
487
- foreach ( $callers as $caller ) {
488
if ( isset( $caller['function'] ) && '_load_image_to_edit_path' == $caller['function'] ) {
489
// check this has been called by '_load_image_to_edit_path' so as only to copy back once
490
- if ( ( $s3_file = $this->copy_s3_file_to_server( $s3_object, $file ) ) ) {
491
// Return the file if successfully downloaded from S3
492
return $s3_file;
493
};
72
* Register the compatibility hooks as long as the plugin is setup.
73
*/
74
function compatibility_init_if_setup() {
75
// Turn on stream wrapper S3 file
76
add_filter( 'as3cf_get_attached_file', array( $this, 'get_stream_wrapper_file' ), 20, 4 );
77
85
* WP_Image_Editor
86
* /wp-includes/class-wp-image-editor.php
87
*/
88
+ add_action( 'as3cf_pre_upload_attachment', array( $this, 'image_editor_remove_files' ), 10, 3 );
89
add_filter( 'as3cf_get_attached_file', array( $this, 'image_editor_download_file' ), 10, 4 );
90
add_filter( 'as3cf_upload_attachment_local_files_to_remove', array( $this, 'image_editor_remove_original_image' ), 10, 3 );
91
add_filter( 'as3cf_get_attached_file', array( $this, 'customizer_crop_download_file' ), 10, 4 );
97
* https://wordpress.org/plugins/regenerate-thumbnails/
98
*/
99
add_filter( 'as3cf_get_attached_file', array( $this, 'regenerate_thumbnails_download_file' ), 10, 4 );
100
101
+ /*
102
+ * WP-CLI Compatibility
103
+ */
104
+ if ( defined( 'WP_CLI' ) && class_exists( 'WP_CLI') ) {
105
+ WP_CLI::add_hook( 'before_invoke:media regenerate', array( $this, 'enable_get_attached_file_copy_back_to_local' ) );
106
}
107
}
108
109
/**
133
return $url;
134
}
135
136
+ /**
137
+ * Enables copying missing local files back to the server when `get_attached_file` filter is called.
138
+ */
139
+ public function enable_get_attached_file_copy_back_to_local() {
140
+ add_filter( 'as3cf_get_attached_file_copy_back_to_local', '__return_true' );
141
+ }
142
+
143
/**
144
* Is this an AJAX process?
145
*
241
* Allow the WordPress Image Editor to remove edited version of images
242
* if the original image is being restored and 'IMAGE_EDIT_OVERWRITE' is set
243
*
244
+ * @param bool $pre
245
+ * @param int $post_id
246
+ * @param array $data
247
+ *
248
+ * @return bool
249
*/
250
+ public function image_editor_remove_files( $pre, $post_id, $data ) {
251
if ( ! isset( $_POST['do'] ) || 'restore' !== $_POST['do'] ) {
252
+ return $pre;
253
}
254
255
if ( ! defined( 'IMAGE_EDIT_OVERWRITE' ) || ! IMAGE_EDIT_OVERWRITE ) {
256
+ return $pre;
257
+ }
258
+
259
+ $s3object = $this->as3cf->get_attachment_s3_info( $post_id );
260
+ $this->remove_edited_image_files( $post_id, $s3object );
261
+
262
+ // Update object key with original filename
263
+ $restored_filename = wp_basename( $data['file'] );
264
+ $old_filename = wp_basename( $s3object['key'] );
265
+ $s3object['key'] = str_replace( $old_filename, $restored_filename, $s3object['key'] );
266
+ update_post_meta( $post_id, 'amazonS3_info', $s3object );
267
+
268
+ return true;
269
+ }
270
+
271
+ /**
272
+ * Remove edited image files from S3.
273
+ *
274
+ * @param int $attachment_id
275
+ * @param array $s3object
276
+ */
277
+ protected function remove_edited_image_files( $attachment_id, $s3object ) {
278
+ $bucket = $s3object['bucket'];
279
+ $region = $this->as3cf->get_s3object_region( $s3object );
280
+ $keys = AS3CF_Utils::get_attachment_edited_keys( $attachment_id, $s3object );
281
+
282
+ if ( empty( $keys ) ) {
283
return;
284
}
285
286
+ $this->as3cf->delete_s3_objects( $region, $bucket, $keys );
287
}
288
289
/**
318
$this->copy_s3_file_to_server( $orig_s3, $orig_file );
319
320
// Copy the edited file back to the server as well, it will be cleaned up later
321
+ if ( $s3_file = $this->copy_s3_file_to_server( $s3_object, $file ) ) {
322
// Return the file if successfully downloaded from S3
323
return $s3_file;
324
};
325
}
326
327
+ $action = filter_input( INPUT_GET, 'action' ) ?: filter_input( INPUT_POST, 'action' );
328
+
329
+ if ( in_array( $action, array( 'image-editor', 'imgedit-preview' ) ) ) { // input var okay
330
+ foreach ( debug_backtrace() as $caller ) {
331
if ( isset( $caller['function'] ) && '_load_image_to_edit_path' == $caller['function'] ) {
332
// check this has been called by '_load_image_to_edit_path' so as only to copy back once
333
+ if ( $s3_file = $this->copy_s3_file_to_server( $s3_object, $file ) ) {
334
// Return the file if successfully downloaded from S3
335
return $s3_file;
336
};
classes/as3cf-upgrade.php DELETED
@@ -1,600 +0,0 @@
1
- <?php
2
- /**
3
- * Upgrade
4
- *
5
- * @package amazon-s3-and-cloudfront
6
- * @subpackage Classes/Upgrade
7
- * @copyright Copyright (c) 2014, Delicious Brains
8
- * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9
- * @since 0.6.2
10
- */
11
-
12
- // Exit if accessed directly
13
- if ( ! defined( 'ABSPATH' ) ) {
14
- exit;
15
- }
16
-
17
- /**
18
- * AS3CF_Upgrade Class
19
- *
20
- * This class handles updates to attachments and attachment meta data
21
- *
22
- * @since 0.6.2
23
- */
24
- abstract class AS3CF_Upgrade {
25
-
26
- /**
27
- * @var Amazon_S3_And_CloudFront
28
- */
29
- protected $as3cf;
30
-
31
- /**
32
- * @var int
33
- */
34
- protected $upgrade_id = 0;
35
-
36
- /**
37
- * @var string
38
- */
39
- protected $upgrade_name = 'base';
40
-
41
- /**
42
- * @var string 'metadata', 'attachment'
43
- */
44
- protected $upgrade_type = 'attachment';
45
-
46
- /**
47
- * @var string
48
- */
49
- protected $running_update_text;
50
-
51
- /**
52
- * @var string
53
- */
54
- protected $settings_key = 'post_meta_version';
55
-
56
- /**
57
- * @var string
58
- */
59
- protected $cron_hook;
60
-
61
- /**
62
- * @var string
63
- */
64
- protected $cron_schedule_key;
65
-
66
- /**
67
- * @var mixed|void
68
- */
69
- protected $cron_interval_in_minutes;
70
-
71
- /**
72
- * @var mixed|void
73
- */
74
- protected $error_threshold;
75
-
76
- /**
77
- * @var int
78
- */
79
- protected $error_count;
80
-
81
- /**
82
- * @var string
83
- */
84
- protected $lock_key = 'as3cf_upgrade_lock';
85
-
86
- const STATUS_RUNNING = 1;
87
- const STATUS_ERROR = 2;
88
- const STATUS_PAUSED = 3;
89
-
90
- /**
91
- * Start it up
92
- *
93
- * @param Amazon_S3_And_CloudFront $as3cf - the instance of the as3cf class
94
- */
95
- public function __construct( $as3cf ) {
96
- $this->as3cf = $as3cf;
97
-
98
- $this->running_update_text = $this->get_running_update_text();
99
- $this->cron_hook = 'as3cf_cron_update_' . $this->upgrade_name;
100
- $this->cron_schedule_key = 'as3cf_update_' . $this->upgrade_name . '_interval';
101
-
102
- $this->cron_interval_in_minutes = apply_filters( 'as3cf_update_' . $this->upgrade_name . '_interval', 2 );
103
- $this->error_threshold = apply_filters( 'as3cf_update_' . $this->upgrade_name . '_error_threshold', 20 );
104
-
105
- add_filter( 'cron_schedules', array( $this, 'cron_schedules' ) );
106
- add_action( $this->cron_hook, array( $this, 'do_upgrade' ) );
107
-
108
- add_action( 'as3cf_pre_settings_render', array( $this, 'maybe_display_notices' ) );
109
- add_action( 'admin_init', array( $this, 'maybe_handle_action' ) );
110
-
111
- // Do default checks if the upgrade can be started
112
- if ( $this->maybe_init() ) {
113
- $this->init();
114
- }
115
- }
116
-
117
- /**
118
- * Can we start the upgrade using default checks
119
- *
120
- * @return bool
121
- */
122
- protected function maybe_init() {
123
- if ( ! is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
124
- return false;
125
- }
126
-
127
- // make sure this only fires inside the network admin for multisites
128
- if ( is_multisite() && ! is_network_admin() ) {
129
- return false;
130
- }
131
-
132
- // Is plugin setup?
133
- if ( ! $this->as3cf->is_plugin_setup() ) {
134
- return false;
135
- }
136
-
137
- // Have we completed the upgrade?
138
- if ( $this->get_saved_upgrade_id() >= $this->upgrade_id ) {
139
- return false;
140
- }
141
-
142
- // Has the previous upgrade completed yet?
143
- if ( ! $this->has_previous_upgrade_completed() ) {
144
- return false;
145
- }
146
-
147
- // Does the upgrade lock exist?
148
- if ( false !== get_site_transient( $this->lock_key ) ) {
149
- return false;
150
- }
151
-
152
- // Do we actually have attachments to process?
153
- if ( 0 === $this->count_items_to_process() ) {
154
- $this->upgrade_finished();
155
-
156
- return false;
157
- }
158
-
159
- // If the upgrade status is already set, then we've already initialized the upgrade
160
- if ( $upgrade_status = $this->get_upgrade_status() ) {
161
- if ( self::STATUS_RUNNING === $upgrade_status ) {
162
- // Make sure cron job is persisted in case it has dropped
163
- $this->schedule();
164
- }
165
-
166
- return false;
167
- }
168
-
169
- return true;
170
- }
171
-
172
- /**
173
- * Count items to process.
174
- *
175
- * @return int
176
- */
177
- abstract protected function count_items_to_process();
178
-
179
- /**
180
- * Get items to process.
181
- *
182
- * @param string $prefix
183
- * @param int $limit
184
- * @param bool|mixed $offset
185
- *
186
- * @return array
187
- */
188
- abstract protected function get_items_to_process( $prefix, $limit, $offset = false );
189
-
190
- /**
191
- * Upgrade attachment.
192
- *
193
- * @param mixed $attachment
194
- *
195
- * @return bool
196
- */
197
- abstract protected function upgrade_item( $attachment );
198
-
199
- /**
200