WP Offload S3 Lite - Version 0.9.7

Version Description

  • 2015-10-26 =
  • Improvement: Improve compatibility with third party plugins when the Remove Files From Server option is enabled
  • Improvement: Fix inconsistent spacing on the WP Offload S3 settings screen
  • Improvement: Validate CloudFront or custom domain input field
  • Improvement: Link to current S3 bucket added to WP Offload S3 settings screen
  • Improvement: Show notice when neither GD or Imagick image libraries are not installed
  • Improvement: Supply Cache-Control header to S3 when the Far Future Expiration Header option is enabled
  • Improvement: Additional information added to Diagnostic Information
  • Improvement: Added warning when Remove Files From Server option is enabled
  • Improvement: Filter added to allow additional image versions to be uploaded to S3
  • Bug fix: File size not stored in wp_attachment_metadata when Remove Files From Server option is enabled
  • Bug fix: Uploads on Multisite installs allowed after surpassing upload limit
  • Bug fix: Site icon in WordPress customizer returns 404
  • Bug fix: Image versions remain locally and on S3 after deletion, when the file name contains characters which require escaping
  • Bug fix: Files with the same file name overwritten when _Remove Files From Server option is enabled
  • Bug fix: Cron tasks incorrectly scheduled due to passing the wrong time to wp_schedule_event
  • Bug fix: Default options not shown in the UI after first install
Download this release

Release Info

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

Code changes from version 0.9.6 to 0.9.7

README.md CHANGED
@@ -3,7 +3,7 @@
3
**Tags:** uploads, amazon, s3, mirror, admin, media, cdn, cloudfront
4
**Requires at least:** 3.7
5
**Tested up to:** 4.3
6
- **Stable tag:** 0.9.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.
@@ -67,8 +67,25 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin
67
68
## Changelog ##
69
70
- ### 0.9.6 - 2015-10-01 ###
71
72
* Improvement: Update text domains for translate.wordpress.org integration
73
74
### 0.9.5 - 2015-09-01 ###
3
**Tags:** uploads, amazon, s3, mirror, admin, media, cdn, cloudfront
4
**Requires at least:** 3.7
5
**Tested up to:** 4.3
6
+ **Stable tag:** 0.9.7
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.
67
68
## Changelog ##
69
70
+ ### 0.9.7 - 2015-10-26 ###
71
+ * Improvement: Improve compatibility with third party plugins when the _Remove Files From Server_ option is enabled
72
+ * Improvement: Fix inconsistent spacing on the WP Offload S3 settings screen
73
+ * Improvement: Validate _CloudFront or custom domain_ input field
74
+ * Improvement: Link to current S3 bucket added to WP Offload S3 settings screen
75
+ * Improvement: Show notice when neither GD or Imagick image libraries are not installed
76
+ * Improvement: Supply Cache-Control header to S3 when the _Far Future Expiration Header_ option is enabled
77
+ * Improvement: Additional information added to _Diagnostic Information_
78
+ * Improvement: Added warning when _Remove Files From Server_ option is enabled
79
+ * Improvement: Filter added to allow additional image versions to be uploaded to S3
80
+ * Bug fix: File size not stored in _wp_attachment_metadata_ when _Remove Files From Server_ option is enabled
81
+ * Bug fix: Uploads on Multisite installs allowed after surpassing upload limit
82
+ * Bug fix: Site icon in WordPress customizer returns 404
83
+ * Bug fix: Image versions remain locally and on S3 after deletion, when the file name contains characters which require escaping
84
+ * Bug fix: Files with the same file name overwritten when __Remove Files From Server_ option is enabled
85
+ * Bug fix: Cron tasks incorrectly scheduled due to passing the wrong time to `wp_schedule_event`
86
+ * Bug fix: Default options not shown in the UI after first install
87
88
+ ### 0.9.6 - 2015-10-01 ###
89
* Improvement: Update text domains for translate.wordpress.org integration
90
91
### 0.9.5 - 2015-09-01 ###
assets/css/styles.css CHANGED
@@ -1 +1 @@
1
- .aws-main.wrap>h2{float:left}.aws-main.wrap .as3cf-notice,.aws-main.wrap .as3cf-updated,.aws-main.wrap .as3cf-error{margin-bottom:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.aws-main.wrap .as3cf-error.fatal{clear:both;float:left}.aws-main.wrap h2.nav-tab-wrapper{float:none;margin-bottom:0;width:650px;margin-top:10px;padding-left:5px;padding-right:0}.aws-main.wrap h2.nav-tab-wrapper a.nav-tab-active{color:#464646;cursor:default}.aws-main.wrap h2.nav-tab-wrapper a:focus{-webkit-box-shadow:none;box-shadow:none}.aws-main.wrap .error pre{background:#eaeaea;background:rgba(0,0,0,0.07);display:block;padding:10px 15px}.aws-main.wrap .error pre code{padding:0;background:none}.aws-main.wrap[data-tab="support"] .as3cf-notice,.aws-main.wrap[data-tab="support"] .error,.aws-main.wrap[data-tab="support"] .updated,.aws-main.wrap[data-tab="support"] .updated.show{display:none}.aws-main.wrap[data-tab="support"] .fatal .error,.aws-main.wrap[data-tab="support"] .as3cf-notice.important,.aws-main.wrap[data-tab="support"] .dbrains-api-down{display:block}.aws-main.wrap .as3cf-notice,.aws-main.wrap .error,.aws-main.wrap .updated{max-width:650px;margin-top:15px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.aws-main.wrap .as3cf-updated{display:none}.aws-main.wrap .as3cf-updated.as3cf-notice,.aws-main.wrap .as3cf-updated.show{display:block}.as3cf-tab .as3cf-main-settings{display:none}.as3cf-tab .as3cf-bucket-container{display:block}.as3cf-tab.as3cf-has-bucket .as3cf-main-settings{display:block}.as3cf-tab.as3cf-has-bucket .as3cf-bucket-container{display:none}.as3cf-tab{display:none;position:relative;width:650px}.as3cf-tab .as3cf-main-settings p{font-size:13px}.as3cf-tab .as3cf-main-settings p a{color:#444}.as3cf-tab .object-prefix-desc em{white-space:nowrap}.as3cf-tab .as3cf-url-preview-wrap{background:#fff;text-align:center;padding:20px 0 0;max-width:650px;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.as3cf-tab .as3cf-url-preview-wrap .as3cf-url-preview{margin-top:10px;padding:0 20px 10px;overflow-x:scroll}.as3cf-tab .as3cf-url-preview-wrap span{color:#aaa;text-transform:uppercase;font-weight:bold}.as3cf-tab .as3cf-ssl p.info{margin-top:10px;padding:0}.as3cf-tab .as3cf-radio-group label{display:block;margin-bottom:10px}.as3cf-tab .as3cf-radio-group label.disabled,.as3cf-tab .as3cf-radio-group label.disabled p{color:#bbbbbb;cursor:default}.as3cf-tab .as3cf-radio-group p{padding-left:25px;color:#6b6b6b;margin:0;font-size:12px}.as3cf-tab .as3cf-radio-group p.as3cf-setting{margin-top:5px}.as3cf-tab .as3cf-switch{position:relative;display:inline-block;padding:2px;overflow:hidden;border-radius:2px;-webkit-border-radius:2px;background-color:#d4d3d3;cursor:pointer}.as3cf-tab .as3cf-switch.on{background-color:#ade7b5}.as3cf-tab .as3cf-switch span{visibility:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;display:inline-block;height:100%;font-size:12px;line-height:20px;border-radius:2px;-webkit-border-radius:2px;font-weight:bold;padding:4px 8px;background:#fff;color:#8d8d8d;z-index:1}.as3cf-tab .as3cf-switch span.on{color:#82d78b}.as3cf-tab .as3cf-switch span.checked{visibility:visible}.as3cf-tab .as3cf-switch.disabled{cursor:default;background:#e6e6e6}.as3cf-tab .as3cf-switch.disabled span{background:#f1f1f1;color:#d6d6d6}.as3cf-tab .as3cf-switch input[type="checkbox"]{position:absolute !important;top:0;left:0;opacity:0;filter:alpha(opacity=0);z-index:-1}.as3cf-tab .as3cf-setting.hide{display:none}.as3cf-tab h3{font-weight:normal;text-transform:uppercase;margin:15px 0}.as3cf-tab .form-table{margin:0}.as3cf-tab .form-table tr.as3cf-border-bottom td{border-bottom:1px solid #ddd;padding:20px 0px}.as3cf-tab .form-table tr.as3cf-setting-title td{padding-bottom:0}.as3cf-tab .form-table tr.as3cf-setting-title:first-child td{padding-top:20px}.as3cf-tab .form-table tr td{padding:15px 0}.as3cf-tab .form-table tr td:first-child{vertical-align:top;min-width:120px}.as3cf-tab .form-table h3{padding:0;margin:0}.as3cf-tab .form-table h4{margin:0}.as3cf-tab .as3cf-active-bucket{font-weight:bold;margin-right:10px}.as3cf-tab .tooltip{position:relative;z-index:2;cursor:pointer}.as3cf-tab .tooltip:before,.as3cf-tab .tooltip:after{visibility:hidden;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=0);opacity:0;pointer-events:none}.as3cf-tab .tooltip:before{position:absolute;bottom:150%;left:50%;margin-bottom:5px;margin-left:-250px;padding:10px;width:500px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#000;background-color:rgba(51,51,51,0.9);color:#fff;content:attr(data-tooltip);text-align:center;font-size:14px;line-height:1.3}.as3cf-tab .tooltip:after{position:absolute;bottom:150%;left:50%;margin-left:-5px;width:0;border-top:5px solid #000;border-top:5px solid rgba(51,51,51,0.9);border-right:5px solid transparent;border-left:5px solid transparent;content:" ";font-size:0;line-height:0}.as3cf-tab .tooltip:hover:before,.as3cf-tab .tooltip:hover:after{visibility:visible;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);opacity:1}#tab-media{display:block}#tab-media .as3cf-main-settings{display:none}#tab-media .as3cf-bucket-container{display:block}#tab-media.as3cf-has-bucket .as3cf-main-settings{display:block}#tab-media.as3cf-has-bucket .as3cf-bucket-container{display:none}.as3cf-bucket-container h3{line-height:1.3;text-transform:none}.as3cf-bucket-container a:focus{-webkit-box-shadow:none;box-shadow:none;outline:none}.as3cf-bucket-container input[type=text]{box-sizing:border-box;width:100%}.as3cf-bucket-container select{box-sizing:border-box;width:50%}.as3cf-bucket-container .form-table td{padding:5px 0}.as3cf-bucket-container .form-table td:first-child{width:100px;line-height:30px;vertical-align:top}.as3cf-bucket-container .as3cf-invalid-bucket-name{font-size:12px;color:#a00}.as3cf-bucket-container .bucket-actions{margin:15px 0;border-top:1px solid #ccc;padding-top:15px;overflow:hidden}.as3cf-bucket-container .bucket-actions button,.as3cf-bucket-container .bucket-actions .right{float:right;margin-right:0}.as3cf-bucket-container .bucket-actions span{display:inline-block;margin-right:20px;line-height:28px}.as3cf-bucket-container .bucket-actions .bucket-action-cancel{color:#a00;text-decoration:none}.as3cf-bucket-container .bucket-actions .bucket-action-cancel:hover{color:red}.as3cf-bucket-container .as3cf-bucket-list{padding:15px;max-height:200px;overflow-x:hidden;overflow-y:auto;background-color:#fff;font-size:14px}.as3cf-bucket-container .as3cf-bucket-list li:last-of-type{margin-bottom:0}.as3cf-bucket-container .as3cf-bucket-list a{color:#444;text-decoration:none}.as3cf-bucket-container .as3cf-bucket-list a:hover{color:#0074A2}.as3cf-bucket-container .as3cf-bucket-list a.selected{font-weight:bold;color:#0074A2}.as3cf-bucket-container .as3cf-bucket-list a .dashicons{margin-right:5px}.as3cf-bucket-container .as3cf-bucket-select,.as3cf-bucket-container .as3cf-bucket-create{display:none}.as3cf-bucket-container .bucket-actions.select{display:none}.as3cf-tab{display:none}#tab-media{display:block}#tab-support{min-height:900px}#tab-support .as3cf-sidebar{top:11px}#tab-support .support-section{border-bottom:1px solid #ccc;padding-bottom:20px;margin-bottom:20px}#tab-support .debug textarea{width:100%;min-height:200px;font-family:Consolas, Monaco, monospace;margin-bottom:5px}.as3cf-sidebar{position:absolute;top:25px;left:670px;width:292px}.as3cf-sidebar .block{padding:20px;border:1px solid #ccc}.as3cf-sidebar .subscribe{border-top:none}.as3cf-sidebar .subscribe h2{padding:0;margin:0;margin-bottom:0.5em;color:#666;font-size:20px;line-height:1.2em;float:none}.as3cf-sidebar .subscribe h3{font-size:16px;margin:0}.as3cf-sidebar .subscribe p{margin:0}.as3cf-sidebar .subscribe .intro{margin-bottom:1em;line-height:1.4}.as3cf-sidebar .subscribe li{line-height:1.4}.as3cf-sidebar .subscribe .links{margin-bottom:2em}.as3cf-sidebar .subscribe .links a{text-decoration:none}.as3cf-sidebar .subscribe .promise{color:#999;font-size:12px;line-height:1.4em}.as3cf-sidebar .subscribe .field{margin-bottom:0.5em}.as3cf-sidebar .subscribe .field p{margin-bottom:0.3em}.as3cf-sidebar .subscribe .field input[type=text],.as3cf-sidebar .subscribe .field input[type=email]{width:100%}.as3cf-sidebar .subscribe .field.submit-button{margin-bottom:1em}.as3cf-sidebar .credits{border-top:0}.as3cf-sidebar .credits h4{font-size:16px;margin-top:0;margin-bottom:10px}.as3cf-sidebar .credits ul{margin:0}.as3cf-sidebar .credits li{overflow:hidden}.as3cf-sidebar .credits li:last-child{margin-bottom:0}.as3cf-sidebar .credits img{float:left;margin-right:10px}.as3cf-sidebar .credits span{float:left;display:block;line-height:32px}.as3cf-sidebar .credits a{display:block;text-decoration:none;color:#444;font-size:16px;text-align:center}.as3cf-sidebar .credits a:hover{color:#888}@media (min--moz-device-pixel-ratio: 1.3), (-o-min-device-pixel-ratio: 2.6 / 2), (-webkit-min-device-pixel-ratio: 1.3), (min-device-pixel-ratio: 1.3), (min-resolution: 1.3dppx){.as3cf-sidebar .as3cf-banner{background-image:url(../img/snail-banner@2x.jpg);background-size:292px 156px}}@media screen and (max-width: 1052px){.as3cf-sidebar{position:relative;top:auto;right:auto;margin-top:50px}}.as3cf-banner{margin-top:28px;width:292px;height:156px;display:block;background-image:url(../img/snail-banner.jpg);position:relative}.as3cf-banner h1{font-size:28px;color:#fff;font-weight:200;margin:0;position:absolute;bottom:25px;left:20px;text-decoration:none}.as3cf-upgrade-details{background-color:#73833b;padding:20px;color:#fff;font-size:13px;margin:0;display:block;text-decoration:none}.as3cf-upgrade-details p{margin:0}.as3cf-upgrade-details a{color:#fff;font-weight:bold;text-decoration:none;font-size:16px}.as3cf-upgrade-details a:hover{color:#fff;opacity:0.9}.as3cf-upgrade-details ul{margin-top:0;margin-left:16px;list-style-type:disc}.aws-compatibility-notice.error{clear:both;margin:5px 20px 5px 0}.as3cf-bucket-error span.title{font-weight:bold}
1
+ .aws-main.wrap>h1{float:left}.aws-main.wrap .as3cf-notice,.aws-main.wrap .as3cf-updated,.aws-main.wrap .as3cf-error{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.aws-main.wrap .as3cf-error.fatal{clear:both;float:left}.aws-main.wrap h2.nav-tab-wrapper{float:none;margin-bottom:15px;width:650px;margin-top:10px;padding:9px 0 0 5px}.aws-main.wrap h2.nav-tab-wrapper a.nav-tab-active{color:#464646;cursor:default}.aws-main.wrap h2.nav-tab-wrapper a:focus{-webkit-box-shadow:none;box-shadow:none}.aws-main.wrap .error pre{background:#eaeaea;background:rgba(0,0,0,0.07);display:block;padding:10px 15px}.aws-main.wrap .error pre code{padding:0;background:none}.aws-main.wrap[data-tab="support"] .as3cf-notice,.aws-main.wrap[data-tab="support"] .error,.aws-main.wrap[data-tab="support"] .updated,.aws-main.wrap[data-tab="support"] .updated.show{display:none}.aws-main.wrap[data-tab="support"] .fatal .error,.aws-main.wrap[data-tab="support"] .as3cf-notice.important,.aws-main.wrap[data-tab="support"] .dbrains-api-down{display:block}.aws-main.wrap .as3cf-notice,.aws-main.wrap .error,.aws-main.wrap .updated{max-width:650px;margin-top:15px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.aws-main.wrap .as3cf-updated{display:none}.aws-main.wrap .as3cf-updated.as3cf-notice,.aws-main.wrap .as3cf-updated.show{display:block}.as3cf-tab .as3cf-main-settings{display:none}.as3cf-tab .as3cf-bucket-container{display:block}.as3cf-tab.as3cf-has-bucket .as3cf-main-settings{display:block}.as3cf-tab.as3cf-has-bucket .as3cf-bucket-container{display:none}.as3cf-tab{display:none;position:relative;width:650px}.as3cf-tab .as3cf-main-settings p{font-size:13px}.as3cf-tab .as3cf-main-settings p a{color:#444}.as3cf-tab .object-prefix-desc em{white-space:nowrap}.as3cf-tab .as3cf-url-preview-wrap{background:#fff;text-align:center;padding:20px 0 0;max-width:650px;width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.as3cf-tab .as3cf-url-preview-wrap .as3cf-url-preview{margin-top:10px;padding:0 20px 10px;overflow-x:scroll}.as3cf-tab .as3cf-url-preview-wrap span{color:#aaa;text-transform:uppercase;font-weight:bold}.as3cf-tab .as3cf-ssl p.info{margin-top:10px;padding:0}.as3cf-tab .as3cf-radio-group label{display:block;margin-bottom:10px}.as3cf-tab .as3cf-radio-group label.disabled,.as3cf-tab .as3cf-radio-group label.disabled p{color:#bbbbbb;cursor:default}.as3cf-tab .as3cf-radio-group p{padding-left:25px;color:#6b6b6b;margin:0;font-size:12px}.as3cf-tab .as3cf-radio-group p.as3cf-setting{margin-top:5px}.as3cf-tab .as3cf-switch{position:relative;display:inline-block;padding:2px;overflow:hidden;border-radius:2px;-webkit-border-radius:2px;background-color:#d4d3d3;cursor:pointer}.as3cf-tab .as3cf-switch.on{background-color:#ade7b5}.as3cf-tab .as3cf-switch span{visibility:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;display:inline-block;height:100%;font-size:12px;line-height:20px;border-radius:2px;-webkit-border-radius:2px;font-weight:bold;padding:4px 8px;background:#fff;color:#8d8d8d;z-index:1}.as3cf-tab .as3cf-switch span.on{color:#82d78b}.as3cf-tab .as3cf-switch span.checked{visibility:visible}.as3cf-tab .as3cf-switch.disabled{cursor:default;background:#e6e6e6}.as3cf-tab .as3cf-switch.disabled span{background:#f1f1f1;color:#d6d6d6}.as3cf-tab .as3cf-switch input[type="checkbox"]{position:absolute !important;top:0;left:0;opacity:0;filter:alpha(opacity=0);z-index:-1}.as3cf-tab .as3cf-setting.hide{display:none}.as3cf-tab h3{font-weight:normal;text-transform:uppercase;margin:15px 0}.as3cf-tab .form-table{margin:0}.as3cf-tab .form-table tr.as3cf-border-bottom td{border-bottom:1px solid #ddd;padding:20px 0px}.as3cf-tab .form-table tr.as3cf-setting-title td{padding-bottom:0}.as3cf-tab .form-table tr.as3cf-setting-title:first-child td{padding-top:20px}.as3cf-tab .form-table tr td{padding:15px 0}.as3cf-tab .form-table tr td:first-child{vertical-align:top;min-width:120px}.as3cf-tab .form-table tr td .as3cf-notice:last-child{margin-bottom:0}.as3cf-tab .form-table tr:first-of-type td{padding-top:5px}.as3cf-tab .form-table h3{padding:0;margin:0}.as3cf-tab .form-table h4{margin:0}.as3cf-tab .as3cf-active-bucket{font-weight:bold;margin-right:10px}.as3cf-tab .as3cf-view-bucket{color:#444;text-decoration:none;margin-right:10px}.as3cf-tab .as3cf-view-bucket:hover,.as3cf-tab .as3cf-view-bucket:active{color:#00a0d2}.as3cf-tab .as3cf-view-bucket .dashicons-external{margin-top:-2px}.as3cf-tab .tooltip{position:relative;z-index:2;cursor:pointer}.as3cf-tab .tooltip:before,.as3cf-tab .tooltip:after{visibility:hidden;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=0);opacity:0;pointer-events:none}.as3cf-tab .tooltip:before{position:absolute;bottom:150%;left:50%;margin-bottom:5px;margin-left:-250px;padding:10px;width:500px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;background-color:#000;background-color:rgba(51,51,51,0.9);color:#fff;content:attr(data-tooltip);text-align:center;font-size:14px;line-height:1.3}.as3cf-tab .tooltip:after{position:absolute;bottom:150%;left:50%;margin-left:-5px;width:0;border-top:5px solid #000;border-top:5px solid rgba(51,51,51,0.9);border-right:5px solid transparent;border-left:5px solid transparent;content:" ";font-size:0;line-height:0}.as3cf-tab .tooltip:hover:before,.as3cf-tab .tooltip:hover:after{visibility:visible;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);opacity:1}#tab-media{display:block}#tab-media .as3cf-main-settings{display:none}#tab-media .as3cf-bucket-container{display:block}#tab-media.as3cf-has-bucket .as3cf-main-settings{display:block}#tab-media.as3cf-has-bucket .as3cf-bucket-container{display:none}.as3cf-bucket-container h3{line-height:1.3;text-transform:none}.as3cf-bucket-container a:focus{-webkit-box-shadow:none;box-shadow:none;outline:none}.as3cf-bucket-container input[type=text]{box-sizing:border-box;width:100%}.as3cf-bucket-container select{box-sizing:border-box;width:50%}.as3cf-bucket-container .form-table td{padding:5px 0}.as3cf-bucket-container .form-table td:first-child{width:100px;line-height:30px;vertical-align:top}.as3cf-bucket-container .bucket-actions{margin:15px 0;border-top:1px solid #ccc;padding-top:15px;overflow:hidden}.as3cf-bucket-container .bucket-actions button,.as3cf-bucket-container .bucket-actions .right{float:right;margin-right:0}.as3cf-bucket-container .bucket-actions span{display:inline-block;margin-right:20px;line-height:28px}.as3cf-bucket-container .bucket-actions .bucket-action-cancel{color:#a00;text-decoration:none}.as3cf-bucket-container .bucket-actions .bucket-action-cancel:hover{color:red}.as3cf-bucket-container .as3cf-bucket-list{padding:15px;max-height:200px;overflow-x:hidden;overflow-y:auto;background-color:#fff;font-size:14px}.as3cf-bucket-container .as3cf-bucket-list li:last-of-type{margin-bottom:0}.as3cf-bucket-container .as3cf-bucket-list a{color:#444;text-decoration:none}.as3cf-bucket-container .as3cf-bucket-list a:hover{color:#0074A2}.as3cf-bucket-container .as3cf-bucket-list a.selected{font-weight:bold;color:#0074A2}.as3cf-bucket-container .as3cf-bucket-list a .dashicons{margin-right:5px}.as3cf-bucket-container .as3cf-bucket-select,.as3cf-bucket-container .as3cf-bucket-create{display:none}.as3cf-bucket-container .bucket-actions.select{display:none}.as3cf-tab{display:none}#tab-media{display:block}#tab-support{min-height:900px}#tab-support .as3cf-sidebar{top:11px}#tab-support .support-section{border-bottom:1px solid #ccc;padding-bottom:20px;margin-bottom:20px}#tab-support .debug textarea{width:100%;min-height:200px;font-family:Consolas, Monaco, monospace;margin-bottom:5px}.as3cf-sidebar{position:absolute;top:25px;left:670px;width:292px}.as3cf-sidebar .block{padding:20px;border:1px solid #ccc}.as3cf-sidebar .subscribe{border-top:none}.as3cf-sidebar .subscribe h2{padding:0;margin:0;margin-bottom:0.5em;color:#666;font-size:20px;line-height:1.2em;float:none}.as3cf-sidebar .subscribe h3{font-size:16px;margin:0}.as3cf-sidebar .subscribe p{margin:0}.as3cf-sidebar .subscribe .intro{margin-bottom:1em;line-height:1.4}.as3cf-sidebar .subscribe li{line-height:1.4}.as3cf-sidebar .subscribe .links{margin-bottom:2em}.as3cf-sidebar .subscribe .links a{text-decoration:none}.as3cf-sidebar .subscribe .promise{color:#999;font-size:12px;line-height:1.4em}.as3cf-sidebar .subscribe .field{margin-bottom:0.5em}.as3cf-sidebar .subscribe .field p{margin-bottom:0.3em}.as3cf-sidebar .subscribe .field input[type=text],.as3cf-sidebar .subscribe .field input[type=email]{width:100%}.as3cf-sidebar .subscribe .field.submit-button{margin-bottom:1em}.as3cf-sidebar .credits{border-top:0}.as3cf-sidebar .credits h4{font-size:16px;margin-top:0;margin-bottom:10px}.as3cf-sidebar .credits ul{margin:0}.as3cf-sidebar .credits li{overflow:hidden}.as3cf-sidebar .credits li:last-child{margin-bottom:0}.as3cf-sidebar .credits img{float:left;margin-right:10px}.as3cf-sidebar .credits span{float:left;display:block;line-height:32px}.as3cf-sidebar .credits a{display:block;text-decoration:none;color:#444;font-size:16px;text-align:center}.as3cf-sidebar .credits a:hover{color:#888}@media (min--moz-device-pixel-ratio: 1.3), (-o-min-device-pixel-ratio: 2.6 / 2), (-webkit-min-device-pixel-ratio: 1.3), (min-device-pixel-ratio: 1.3), (min-resolution: 1.3dppx){.as3cf-sidebar .as3cf-banner{background-image:url(../img/snail-banner@2x.jpg);background-size:292px 156px}}@media screen and (max-width: 1052px){.as3cf-sidebar{position:relative;top:auto;right:auto;margin-top:50px}}.as3cf-banner{margin-top:28px;width:292px;height:156px;display:block;background-image:url(../img/snail-banner.jpg);position:relative}.as3cf-banner h1{font-size:28px;color:#fff;font-weight:200;margin:0;position:absolute;bottom:25px;left:20px;text-decoration:none}.as3cf-upgrade-details{background-color:#73833b;padding:20px;color:#fff;font-size:13px;margin:0;display:block;text-decoration:none}.as3cf-upgrade-details p{margin:0}.as3cf-upgrade-details a{color:#fff;font-weight:bold;text-decoration:none;font-size:16px}.as3cf-upgrade-details a:hover{color:#fff;opacity:0.9}.as3cf-upgrade-details ul{margin-top:0;margin-left:16px;list-style-type:disc}.aws-compatibility-notice.error{clear:both;margin:5px 20px 5px 0}.as3cf-bucket-error span.title{font-weight:bold}.as3cf-invalid-bucket-name,.as3cf-validation-error{display:block;margin-top:2px;font-size:12px;color:#a00}
assets/js/notice.js ADDED
@@ -0,0 +1,24 @@
1
+ (function( $ ) {
2
+
3
+ $( 'body' ).on( 'click', '.as3cf-notice .notice-dismiss', function( e ) {
4
+ var id = $( this ).parents( '.as3cf-notice' ).attr( 'id' );
5
+ if ( id ) {
6
+ var data = {
7
+ action : 'as3cf-dismiss-notice',
8
+ notice_id: id,
9
+ _nonce : as3cf_notice.nonces.dismiss_notice
10
+ };
11
+
12
+ $.ajax( {
13
+ url : ajaxurl,
14
+ type : 'POST',
15
+ dataType: 'JSON',
16
+ data : data,
17
+ error : function( jqXHR, textStatus, errorThrown ) {
18
+ alert( as3cf_notice.strings.dismiss_notice_error + errorThrown );
19
+ }
20
+ } );
21
+ }
22
+ } );
23
+
24
+ })( jQuery );
assets/js/script.js CHANGED
@@ -32,6 +32,25 @@
32
$checkbox.attr( 'checked', switchOn ).trigger( 'change' );
33
}
34
35
as3cf.tabs = {
36
defaultTab: 'media',
37
/**
@@ -348,7 +367,7 @@
348
var $manualBucketForm = $( '.as3cf-bucket-container.' + as3cfModal.prefix + ' .as3cf-manual-save-bucket-form' );
349
var $activeBucket = $( '#' + as3cfModal.prefix + '-active-bucket' );
350
351
- if ( 'as3cf' === as3cfModal.prefix && '' === $activeBucket.text() ) {
352
// first time bucket select - enable main options by default
353
setCheckbox( 'copy-to-s3-wrap' );
354
setCheckbox( 'serve-from-s3-wrap' );
@@ -376,6 +395,8 @@
376
generateUrlPreview();
377
}
378
379
as3cfModal.close( unlockBucketSelect );
380
},
381
@@ -479,6 +500,25 @@
479
480
};
481
482
/**
483
* Generate URL preview
484
*/
@@ -525,6 +565,28 @@
525
as3cf.buckets.bucketSelectLock = false;
526
}
527
528
$( document ).ready( function() {
529
530
// Tabs
@@ -630,6 +692,16 @@
630
generateUrlPreview();
631
} );
632
633
// Don't allow 'enter' key to submit form on text input settings
634
$( '.as3cf-setting input[type="text"]' ).keypress( function( event ) {
635
if ( 13 === event.which ) {
@@ -640,6 +712,28 @@
640
641
} );
642
643
// Bucket select
644
// --------------------
645
32
$checkbox.attr( 'checked', switchOn ).trigger( 'change' );
33
}
34
35
+ /**
36
+ * Validate custom domain
37
+ *
38
+ * @param {object} $input
39
+ */
40
+ function validateCustomDomain( $input ) {
41
+ var $error = $input.next( '.as3cf-validation-error' );
42
+ var $submit = $( '#' + $activeTab.attr( 'id' ) + ' form button[type="submit"]' );
43
+ var pattern = /[^a-zA-Z0-9\.\-]/;
44
+
45
+ if ( pattern.test( $input.val() ) ) {
46
+ $error.show();
47
+ $submit.attr( 'disabled', true );
48
+ } else {
49
+ $error.hide();
50
+ $submit.attr( 'disabled', false );
51
+ }
52
+ }
53
+
54
as3cf.tabs = {
55
defaultTab: 'media',
56
/**
367
var $manualBucketForm = $( '.as3cf-bucket-container.' + as3cfModal.prefix + ' .as3cf-manual-save-bucket-form' );
368
var $activeBucket = $( '#' + as3cfModal.prefix + '-active-bucket' );
369
370
+ if ( 'as3cf' === as3cfModal.prefix && 0 === $activeBucket.text().trim().length ) {
371
// first time bucket select - enable main options by default
372
setCheckbox( 'copy-to-s3-wrap' );
373
setCheckbox( 'serve-from-s3-wrap' );
395
generateUrlPreview();
396
}
397
398
+ setBucketLink();
399
+
400
as3cfModal.close( unlockBucketSelect );
401
},
402
500
501
};
502
503
+ /**
504
+ * Get the link to the bucket on the AWS Console and update the DOM
505
+ *
506
+ * @returns {string}
507
+ */
508
+ function setBucketLink() {
509
+ var bucket = $( '#' + as3cfModal.prefix + '-bucket' ).val();
510
+ var $objectPrefix = $activeTab.find( 'input[name="object-prefix"]' );
511
+ var prefix = $objectPrefix.val();
512
+
513
+ if ( '' !== prefix ) {
514
+ prefix = '&prefix=' + encodeURIComponent( prefix );
515
+ }
516
+
517
+ var url = as3cf.aws_bucket_link + bucket + prefix;
518
+
519
+ $( '#' + as3cfModal.prefix + '-view-bucket' ).attr( 'href', url );
520
+ }
521
+
522
/**
523
* Generate URL preview
524
*/
565
as3cf.buckets.bucketSelectLock = false;
566
}
567
568
+ /*
569
+ * Toggle the lost files notice
570
+ */
571
+ function toggleLostFilesNotice() {
572
+ if ( $( '#remove-local-file' ).is( ':checked' ) && $( '#serve-from-s3' ).is( ':not(:checked)' ) ) {
573
+ $( '#as3cf-lost-files-notice' ).show();
574
+ } else {
575
+ $( '#as3cf-lost-files-notice' ).hide();
576
+ }
577
+ }
578
+
579
+ /*
580
+ * Toggle the remove local files notice
581
+ */
582
+ function toggleRemoveLocalNotice() {
583
+ if ( $( '#remove-local-file' ).is( ':checked' ) ) {
584
+ $( '#as3cf-remove-local-notice' ).show();
585
+ } else {
586
+ $( '#as3cf-remove-local-notice' ).hide();
587
+ }
588
+ }
589
+
590
$( document ).ready( function() {
591
592
// Tabs
692
generateUrlPreview();
693
} );
694
695
+ toggleLostFilesNotice();
696
+ $( '#serve-from-s3,#remove-local-file' ).on( 'change', function( e ) {
697
+ toggleLostFilesNotice();
698
+ } );
699
+
700
+ toggleRemoveLocalNotice();
701
+ $( '#remove-local-file' ).on( 'change', function( e ) {
702
+ toggleRemoveLocalNotice();
703
+ } );
704
+
705
// Don't allow 'enter' key to submit form on text input settings
706
$( '.as3cf-setting input[type="text"]' ).keypress( function( event ) {
707
if ( 13 === event.which ) {
712
713
} );
714
715
+ // Validate custom domain
716
+ $( 'input[name="cloudfront"]' ).on( 'keyup', function( e ) {
717
+ validateCustomDomain( $( this ) );
718
+ } );
719
+
720
+ // Re-enable submit button on domain change
721
+ $( 'input[name="domain"]' ).on( 'change', function( e ) {
722
+ var $input = $( this );
723
+ var $submit = $( '#' + $activeTab.attr( 'id' ) + ' form button[type="submit"]' );
724
+
725
+ if ( 'cloudfront' !== $input.val() ) {
726
+ $submit.attr( 'disabled', false );
727
+ } else {
728
+ validateCustomDomain( $input.next( '.as3cf-setting' ).find( 'input[name="cloudfront"]' ) );
729
+ }
730
+ } );
731
+
732
+ // Change bucket link when custom path changes
733
+ $( 'input[name="object-prefix"]' ).on( 'change', function( e ) {
734
+ setBucketLink();
735
+ } );
736
+
737
// Bucket select
738
// --------------------
739
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(b){var c=a("#"+b),d=c.find("input[type=checkbox]");c.toggleClass("on").find("span").toggleClass("checked");var e=c.find("span.on").hasClass("checked");d.attr("checked",e).trigger("change")}function e(){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 f(a){as3cf.buckets.bucketSelectLock=!1}var g,h={},i=/[^a-z0-9.-]/,j=a(".as3cf-tab");as3cf.tabs={defaultTab:"media",toggle:function(c,d){j.hide(),g=a("#tab-"+c),g.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),g.attr("data-prefix")&&(b.prefix=g.attr("data-prefix")),d||a(".as3cf-updated").removeClass("show")}},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===g.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()),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(),h=e.first().text();if(f===a("#"+b.prefix+"-active-bucket").text())return a(".as3cf-bucket-error").hide(),g.addClass("as3cf-has-bucket"),void b.close();a(".as3cf-bucket-error").hide(),e.text(e.attr("data-working")),e.prop("disabled",!0);var i={action:b.prefix+"-manual-save-bucket",bucket_name:f,_nonce:window[b.prefix.replace(/-/g,"_")].nonces.manual_bucket},j=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:i,error:function(a,b,c){e.text(h),j.showError(as3cf.strings.save_bucket_error,c,"as3cf-bucket-manual")},success:function(c,d,g){e.text(h),e.prop("disabled",!1),"undefined"!=typeof c.success?(j.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")):j.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 g.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"),h={action:b.prefix+"-save-bucket",bucket_name:f,_nonce:window[b.prefix.replace(/-/g,"_")].nonces.save_bucket},i=this;a.ajax({url:ajaxurl,type:"POST",dataType:"JSON",data:h,error:function(b,c,f){d.removeClass("saving"),i.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,h,j){c.find(".spinner").hide().css("visibility","hidden"),d.removeClass("saving"),"undefined"!=typeof g.success?(i.set(f,g.region,g.can_write),a("#"+b.prefix+"-bucket-select").val("")):(i.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(i,j,k){var l=a(".as3cf-bucket-container."+b.prefix+" .as3cf-manual-save-bucket-form"),m=a("#"+b.prefix+"-active-bucket");if("as3cf"===b.prefix&&""===m.text()){d("copy-to-s3-wrap"),d("serve-from-s3-wrap");var n=g.attr("id");h[n]=c(n)}a(".as3cf-error.fatal").hide(),m.text(i),l.find(".as3cf-bucket-name").val(i),a("#"+b.prefix+"-bucket").val(i),a("#"+b.prefix+"-region").val(j),a(".updated").not(".as3cf-notice").show(),g.addClass("as3cf-has-bucket"),g.find(".as3cf-can-write-error").toggle(!k),g.find(".as3cf-bucket-error").hide(),"as3cf"===b.prefix&&e(),b.close(f)},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)):j.showError(as3cf.strings.create_bucket_error,b.error,"as3cf-bucket-create")}})},isValidName:function(a){return a.length<3||a.length>63?!1:!0===i.test(a)?!1:!0},updateNameNotice:function(b){var c=null;!0===i.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 f=a(".wrap.aws-main .nav-tab-wrapper");if(a(".aws-compatibility-notice, div.updated, div.error, div.notice").not(".below-h2, .inline").insertAfter(f),window.location.hash){var i=window.location.hash.substring(1);as3cf.tabs.toggle(i,!0)}else g=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}}),j.length&&j.each(function(a,b){h[b.id]=c(b.id)}),a(window).on("beforeunload.as3cf-settings",function(){if(!a.isEmptyObject(h)){var b=g.attr("id");return c(b)!==h[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"))}),j.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(".as3cf-ssl").on("change",'input[type="radio"]',function(b){var c=a('input:radio[name="ssl"]:checked').val();if("https"===c){var d=a('input:radio[name="domain"]:checked').val();"subdomain"===d&&a('input[name="domain"][value="path"]').attr("checked",!0),a(".subdomain-wrap input").attr("disabled",!0),a(".subdomain-wrap").addClass("disabled")}else a(".subdomain-wrap input").removeAttr("disabled"),a(".subdomain-wrap").removeClass("disabled")}),a(".url-preview").on("change","input",function(a){e()}),a('.as3cf-setting input[type="text"]').keypress(function(a){return 13===a.which?(a.preventDefault(),!1):void 0}),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()}),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(b){var c=a("#"+b),d=c.find("input[type=checkbox]");c.toggleClass("on").find("span").toggleClass("checked");var e=c.find("span.on").hasClass("checked");d.attr("checked",e).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("#remove-local-file").is(":checked")&&a("#serve-from-s3").is(":not(:checked)")?a("#as3cf-lost-files-notice").show():a("#as3cf-lost-files-notice").hide()}function j(){a("#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=a(".as3cf-tab");as3cf.tabs={defaultTab:"media",toggle:function(c,d){n.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")}},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()),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")):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("copy-to-s3-wrap"),d("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)):j.showError(as3cf.strings.create_bucket_error,b.error,"as3cf-bucket-create")}})},isValidName:function(a){return a.length<3||a.length>63?!1:!0===m.test(a)?!1:!0},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}}),n.length&&n.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"))}),n.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(".as3cf-ssl").on("change",'input[type="radio"]',function(b){var c=a('input:radio[name="ssl"]:checked').val();if("https"===c){var d=a('input:radio[name="domain"]:checked').val();"subdomain"===d&&a('input[name="domain"][value="path"]').attr("checked",!0),a(".subdomain-wrap input").attr("disabled",!0),a(".subdomain-wrap").addClass("disabled")}else a(".subdomain-wrap input").removeAttr("disabled"),a(".subdomain-wrap").removeClass("disabled")}),a(".url-preview").on("change","input",function(a){g()}),i(),a("#serve-from-s3,#remove-local-file").on("change",function(a){i()}),j(),a("#remove-local-file").on("change",function(a){j()}),a('.as3cf-setting input[type="text"]').keypress(function(a){return 13===a.which?(a.preventDefault(),!1):void 0}),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()}),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);
assets/sass/styles.scss CHANGED
@@ -3,12 +3,11 @@
3
* AWS wrap
4
*/
5
.aws-main.wrap {
6
- &> h2 {
7
float: left;
8
}
9
10
.as3cf-notice, .as3cf-updated, .as3cf-error {
11
- margin-bottom: 0;
12
-webkit-box-sizing: border-box;
13
-moz-box-sizing: border-box;
14
box-sizing: border-box;
@@ -21,11 +20,10 @@
21
22
h2.nav-tab-wrapper {
23
float: none;
24
- margin-bottom: 0;
25
width: 650px;
26
margin-top: 10px;
27
- padding-left: 5px;
28
- padding-right: 0;
29
30
a.nav-tab-active {
31
color: #464646;
@@ -247,6 +245,7 @@
247
248
.form-table {
249
margin: 0;
250
tr {
251
&.as3cf-border-bottom td {
252
border-bottom: 1px solid #ddd;
@@ -264,6 +263,16 @@
264
vertical-align: top;
265
min-width: 120px;
266
}
267
}
268
}
269
h3 {
@@ -275,10 +284,21 @@
275
}
276
}
277
278
- .as3cf-active-bucket {
279
- font-weight: bold;
280
- margin-right: 10px;
281
- }
282
283
.tooltip {
284
position: relative;
@@ -405,11 +425,6 @@
405
}
406
}
407
408
- .as3cf-invalid-bucket-name {
409
- font-size: 12px;
410
- color: #a00;
411
- }
412
-
413
.bucket-actions {
414
margin: 15px 0;
415
border-top: 1px solid #ccc;
@@ -714,4 +729,12 @@
714
span.title {
715
font-weight: bold;
716
}
717
}
3
* AWS wrap
4
*/
5
.aws-main.wrap {
6
+ & > h1 {
7
float: left;
8
}
9
10
.as3cf-notice, .as3cf-updated, .as3cf-error {
11
-webkit-box-sizing: border-box;
12
-moz-box-sizing: border-box;
13
box-sizing: border-box;
20
21
h2.nav-tab-wrapper {
22
float: none;
23
+ margin-bottom: 15px;
24
width: 650px;
25
margin-top: 10px;
26
+ padding: 9px 0 0 5px;
27
28
a.nav-tab-active {
29
color: #464646;
245
246
.form-table {
247
margin: 0;
248
+
249
tr {
250
&.as3cf-border-bottom td {
251
border-bottom: 1px solid #ddd;
263
vertical-align: top;
264
min-width: 120px;
265
}
266
+
267
+ .as3cf-notice:last-child {
268
+ margin-bottom: 0;
269
+ }
270
+ }
271
+
272
+ &:first-of-type {
273
+ td {
274
+ padding-top: 5px;
275
+ }
276
}
277
}
278
h3 {
284
}
285
}
286
287
+ .as3cf-active-bucket {
288
+ font-weight: bold;
289
+ margin-right: 10px;
290
+ }
291
+ .as3cf-view-bucket {
292
+ color: #444;
293
+ text-decoration: none;
294
+ margin-right: 10px;
295
+ &:hover, &:active {
296
+ color: #00a0d2;
297
+ }
298
+ .dashicons-external {
299
+ margin-top: -2px;
300
+ }
301
+ }
302
303
.tooltip {
304
position: relative;
425
}
426
}
427
428
.bucket-actions {
429
margin: 15px 0;
430
border-top: 1px solid #ccc;
729
span.title {
730
font-weight: bold;
731
}
732
+ }
733
+
734
+ .as3cf-invalid-bucket-name,
735
+ .as3cf-validation-error {
736
+ display: block;
737
+ margin-top: 2px;
738
+ font-size: 12px;
739
+ color: #a00;
740
}
classes/amazon-s3-and-cloudfront.php CHANGED
@@ -42,6 +42,11 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
42
*/
43
protected $default_tab = '';
44
45
/**
46
* @var string
47
*/
@@ -52,6 +57,16 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
52
*/
53
protected static $buckets_check = array();
54
55
const DEFAULT_ACL = 'public-read';
56
const PRIVATE_ACL = 'private';
57
const DEFAULT_EXPIRES = 900;
@@ -70,6 +85,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
70
parent::__construct( $plugin_file_path );
71
72
$this->aws = $aws;
73
74
$this->init( $plugin_file_path );
75
}
@@ -95,15 +111,12 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
95
add_action( 'wp_ajax_as3cf-manual-save-bucket', array( $this, 'ajax_save_bucket' ) );
96
add_action( 'wp_ajax_as3cf-get-url-preview', array( $this, 'ajax_get_url_preview' ) );
97
98
- // Admin notices
99
- add_action( 'admin_notices', array( $this, 'maybe_show_admin_notices' ) );
100
- add_action( 'network_admin_notices', array( $this, 'maybe_show_admin_notices' ) );
101
- add_action( 'shutdown', array( $this, 'save_admin_notices' ) );
102
-
103
add_filter( 'wp_get_attachment_url', array( $this, 'wp_get_attachment_url' ), 99, 2 );
104
add_filter( 'wp_handle_upload_prefilter', array( $this, 'wp_handle_upload_prefilter' ), 1 );
105
add_filter( 'wp_update_attachment_metadata', array( $this, 'wp_update_attachment_metadata' ), 110, 2 );
106
- add_filter( 'wp_get_attachment_metadata', array( $this, 'wp_get_attachment_metadata' ), 10, 2 );
107
add_filter( 'delete_attachment', array( $this, 'delete_attachment' ), 20 );
108
add_filter( 'update_attached_file', array( $this, 'update_attached_file' ), 100, 2 );
109
add_filter( 'get_attached_file', array( $this, 'get_attached_file' ), 10, 2 );
@@ -111,7 +124,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
111
add_filter( 'pre_get_space_used', array( $this, 'multisite_get_spaced_used' ) );
112
113
// include compatibility code for other plugins
114
- new AS3CF_Plugin_Compatibility( $this );
115
116
load_plugin_textdomain( 'amazon-s3-and-cloudfront', false, dirname( plugin_basename( $plugin_file_path ) ) . '/languages/' );
117
@@ -282,9 +295,28 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
282
283
$value = apply_filters( 'as3cf_set_setting_' . $key, $value );
284
285
parent::set_setting( $key, $value );
286
}
287
288
/**
289
* Return the default object prefix
290
*
@@ -323,7 +355,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
323
$interval = $hook;
324
}
325
if ( ! wp_next_scheduled( $hook ) ) {
326
- wp_schedule_event( current_time( 'timestamp' ), $interval, $hook, $args );
327
}
328
}
329
@@ -355,7 +387,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
355
if ( is_wp_error( $region ) ) {
356
$region = '';
357
}
358
- $domain = $this->get_s3_url_domain( $bucket, $region );
359
360
$url = $scheme . '://' . $domain . '/' . $path . $suffix;
361
@@ -490,7 +522,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
490
}
491
492
// upload attachment to S3
493
- $this->upload_attachment_to_s3( $post_id, $data );
494
495
return $data;
496
}
@@ -508,8 +540,25 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
508
* @return array|WP_Error $s3object|$meta If meta is supplied, return it. Else return S3 meta
509
*/
510
function upload_attachment_to_s3( $post_id, $data = null, $file_path = null, $force_new_s3_client = false, $remove_local_files = true ) {
511
if ( is_null( $data ) ) {
512
$data = wp_get_attachment_metadata( $post_id, true );
513
}
514
515
if ( is_null( $file_path ) ) {
@@ -518,7 +567,9 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
518
519
// Check file exists locally before attempting upload
520
if ( ! file_exists( $file_path ) ) {
521
- return new WP_Error( 'exception', sprintf( __( 'File %s does not exist', 'amazon-s3-and-cloudfront' ), $file_path ) );
522
}
523
524
$file_name = basename( $file_path );
@@ -527,7 +578,9 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
527
528
// check mime type of file is in allowed S3 mime types
529
if ( ! in_array( $type, $allowed_types ) ) {
530
- return new WP_Error( 'exception', sprintf( __( 'Mime type %s is not allowed', 'amazon-s3-and-cloudfront' ), $type ) );
531
}
532
533
$acl = self::DEFAULT_ACL;
@@ -590,7 +643,8 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
590
591
// If far future expiration checked (10 years)
592
if ( $this->get_setting( 'expires' ) ) {
593
- $args['Expires'] = date( 'D, d M Y H:i:s O', time() + 315360000 );
594
}
595
$args = apply_filters( 'as3cf_object_meta', $args, $post_id );
596
@@ -605,9 +659,8 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
605
}
606
catch ( Exception $e ) {
607
$error_msg = sprintf( __( 'Error uploading %s to S3: %s', 'amazon-s3-and-cloudfront' ), $file_path, $e->getMessage() );
608
- error_log( $error_msg );
609
610
- return new WP_Error( 'exception', $error_msg );
611
}
612
}
613
@@ -627,8 +680,10 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
627
// Store in the attachment meta data for use by WP
628
$data['filesize'] = $bytes;
629
630
- // Update metadata with filesize
631
- update_post_meta( $post_id, '_wp_attachment_metadata', $data );
632
633
// Add to the file size total
634
$filesize_total += $bytes;
@@ -688,16 +743,43 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
688
// Make sure we don't have a cached file sizes in the meta
689
unset( $data['filesize'] );
690
691
- // Remove the filesize from the metadata
692
- update_post_meta( $post_id, '_wp_attachment_metadata', $data );
693
694
delete_post_meta( $post_id, 'wpos3_filesize_total' );
695
}
696
}
697
698
return $s3object;
699
}
700
701
/**
702
* Remove files from the local site
703
*
@@ -711,11 +793,31 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
711
}
712
}
713
714
function get_hidpi_file_path( $orig_path ) {
715
$hidpi_suffix = apply_filters( 'as3cf_hidpi_suffix', '@2x' );
716
- $pathinfo = pathinfo( $orig_path );
717
718
- return $pathinfo['dirname'] . '/' . $pathinfo['filename'] . $hidpi_suffix . '.' . $pathinfo['extension'];
719
}
720
721
/**
@@ -801,11 +903,6 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
801
return $file;
802
}
803
804
- // only do this when we are removing local versions of files
805
- if ( ! $this->get_setting( 'remove-local-file' ) ) {
806
- return $file;
807
- }
808
-
809
$filename = $file['name'];
810
811
// sanitize the file name before we begin processing
@@ -824,37 +921,146 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
824
// rebuild filename with lowercase extension as S3 will have converted extension on upload
825
$ext = strtolower( $ext );
826
$filename = $info['filename'] . $ext;
827
828
- $time = current_time( 'timestamp' );
829
- $time = date( 'Y/m', $time );
830
831
- $prefix = ltrim( trailingslashit( $this->get_object_prefix() ), '/' );
832
- $prefix .= ltrim( trailingslashit( $this->get_dynamic_prefix( $time ) ), '/' );
833
834
$bucket = $this->get_setting( 'bucket' );
835
$region = $this->get_setting( 'region' );
836
if ( is_wp_error( $region ) ) {
837
- return $file;
838
}
839
840
$s3client = $this->get_s3client( $region );
841
842
- $number = '';
843
- while ( $s3client->doesObjectExist( $bucket, $prefix . $filename ) !== false ) {
844
- $previous = $number;
845
- ++$number;
846
- if ( '' == $previous ) {
847
- $filename = $name . $number . $ext;
848
- } else {
849
- $filename = str_replace( "$previous$ext", $number . $ext, $filename );
850
- }
851
- }
852
853
- $file['name'] = $filename;
854
855
- return $file;
856
}
857
858
function wp_get_attachment_url( $url, $post_id ) {
859
$new_url = $this->get_attachment_url( $post_id );
860
if ( false === $new_url ) {
@@ -867,6 +1073,13 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
867
return $new_url;
868
}
869
870
function get_attachment_s3_info( $post_id ) {
871
return get_post_meta( $post_id, 'amazonS3_info', true );
872
}
@@ -958,10 +1171,12 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
958
/**
959
* Get the custom object prefix if enabled
960
*
961
* @return string
962
*/
963
- function get_object_prefix() {
964
- if ( $this->get_setting( 'enable-object-prefix' ) ) {
965
$prefix = trim( $this->get_setting( 'object-prefix' ) );
966
} else {
967
$prefix = '';
@@ -1121,50 +1336,100 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1121
}
1122
1123
/**
1124
- * Override the attachment metadata
1125
*
1126
- * @param unknown $data
1127
- * @param unknown $post_id
1128
*
1129
- * @return mixed
1130
*/
1131
- function wp_get_attachment_metadata( $data, $post_id ) {
1132
- return $this->maybe_encoded_file_of_resized_images( $data, $post_id );
1133
}
1134
1135
/**
1136
- * Encodes the file names for resized image files for an attachment where necessary
1137
*
1138
- * @param array $data
1139
- * @param int $post_id
1140
*
1141
- * @return mixed Attachment meta data
1142
*/
1143
- function maybe_encoded_file_of_resized_images( $data, $post_id ) {
1144
if ( ! $this->get_setting( 'serve-from-s3' ) ) {
1145
- return $data;
1146
}
1147
1148
- if ( ! ( $s3object = $this->get_attachment_s3_info( $post_id ) ) ) {
1149
- return $data;
1150
}
1151
1152
- // we only need to encode the file name if url encoding is needed
1153
- $filename = basename( $s3object['key'] );
1154
- if ( $filename == rawurlencode( $filename ) ) {
1155
- return $data;
1156
}
1157
1158
- // we only need to encode resized image files
1159
- if ( ! isset( $data['sizes'] ) ) {
1160
- return $data;
1161
}
1162
1163
- foreach ( $data['sizes'] as $key => $size ) {
1164
- $data['sizes'][ $key ]['file'] = $this->encode_filename_in_path( $data['sizes'][ $key ]['file'] );
1165
}
1166
1167
- return $data;
1168
}
1169
1170
/**
@@ -1176,11 +1441,40 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1176
* @return string Encoded filename with path prefix untouched
1177
*/
1178
function encode_filename_in_path( $file ) {
1179
- $file_path = dirname( $file );
1180
- $file_path = ( '.' != $file_path ) ? trailingslashit( $file_path ) : '';
1181
- $file_name = rawurlencode( basename( $file ) );
1182
1183
- return $file_path . $file_name;
1184
}
1185
1186
/**
@@ -1498,7 +1792,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1498
* @param bool|string $region specify region to client for signature
1499
* @param bool $force force return of new S3 client when swapping regions
1500
*
1501
- * @return mixed
1502
*/
1503
function get_s3client( $region = false, $force = false ) {
1504
if ( is_null( $this->s3client ) || $force ) {
@@ -1739,7 +2033,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1739
wp_localize_script( 'as3cf-script',
1740
'as3cf',
1741
array(
1742
- 'strings' => array(
1743
'create_bucket_error' => __( 'Error creating bucket', 'amazon-s3-and-cloudfront' ),
1744
'create_bucket_name_short' => __( 'Bucket name too short.', 'amazon-s3-and-cloudfront' ),
1745
'create_bucket_name_long' => __( 'Bucket name too long.', 'amazon-s3-and-cloudfront' ),
@@ -1749,19 +2043,21 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1749
'get_url_preview_error' => __( 'Error getting URL preview: ', 'amazon-s3-and-cloudfront' ),
1750
'save_alert' => __( 'The changes you made will be lost if you navigate away from this page', 'amazon-s3-and-cloudfront' )
1751
),
1752
- 'nonces' => array(
1753
'create_bucket' => wp_create_nonce( 'as3cf-create-bucket' ),
1754
'manual_bucket' => wp_create_nonce( 'as3cf-manual-save-bucket' ),
1755
'get_buckets' => wp_create_nonce( 'as3cf-get-buckets' ),
1756
'save_bucket' => wp_create_nonce( 'as3cf-save-bucket' ),
1757
'get_url_preview' => wp_create_nonce( 'as3cf-get-url-preview' ),
1758
),
1759
- 'is_pro' => $this->is_pro(),
1760
)
1761
);
1762
1763
$this->handle_post_request();
1764
$this->http_prepare_download_log();
1765
1766
do_action( 'as3cf_plugin_load' );
1767
}
@@ -1998,6 +2294,22 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
1998
return true;
1999
}
2000
2001
/**
2002
* Apply ACL to an attachment and associated files
2003
*
@@ -2022,7 +2334,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2022
2023
// Add attachment to ACL update notice
2024
$message = $this->make_acl_admin_notice_text( $s3object );
2025
- $this->set_admin_notice( $message );
2026
2027
// update S3 meta data
2028
if ( $acl == self::DEFAULT_ACL ) {
@@ -2049,52 +2361,17 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2049
}
2050
2051
/**
2052
- * Set admin notice
2053
- *
2054
- * @param string $message
2055
- * @param string $type info, updated, error
2056
- * @param bool $dismissible
2057
- * @param bool $inline
2058
- */
2059
- function set_admin_notice( $message, $type = 'info', $dismissible = true, $inline = false ) {
2060
- self::$admin_notices[] = array(
2061
- 'message' => $message,
2062
- 'type' => $type,
2063
- 'dismissible' => $dismissible,
2064
- 'inline' => $inline,
2065
- );
2066
- }
2067
-
2068
- /**
2069
- * Save admin notices to transients before shutdown
2070
- */
2071
- function save_admin_notices() {
2072
- if ( ! empty( self::$admin_notices ) ) {
2073
- set_site_transient( 'as3cf_notices', self::$admin_notices );
2074
- }
2075
- }
2076
-
2077
- /**
2078
- * Maybe show notices on admin page
2079
*/
2080
- function maybe_show_admin_notices() {
2081
- if ( $notices = get_site_transient( 'as3cf_notices' ) ) {
2082
- foreach ( $notices as $notice ) {
2083
- if ( 'info' === $notice['type'] ) {
2084
- $notice['type'] = 'notice-info';
2085
- }
2086
-
2087
- $args = array(
2088
- 'message' => $notice['message'],
2089
- 'type' => $notice['type'],
2090
- 'dismissible' => $notice['dismissible'],
2091
- 'inline' => $notice['inline'],
2092
- );
2093
-
2094
- $this->render_view( 'notice', $args );
2095
- }
2096
2097
- delete_site_transient( 'as3cf_notices' );
2098
}
2099
}
2100
@@ -2148,6 +2425,12 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2148
echo empty( $wpdb->use_mysqli ) ? 'no' : 'yes';
2149
echo "\r\n";
2150
2151
echo 'WP Memory Limit: ';
2152
echo esc_html( WP_MEMORY_LIMIT );
2153
echo "\r\n";
@@ -2190,6 +2473,10 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2190
}
2191
echo "\r\n";
2192
2193
echo 'fsockopen: ';
2194
if ( function_exists( 'fsockopen' ) ) {
2195
echo 'Enabled';
@@ -2220,6 +2507,23 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2220
} else {
2221
echo 'Disabled';
2222
}
2223
echo "\r\n\r\n";
2224
2225
$media_counts = $this->diagnostic_media_counts();
@@ -2294,6 +2598,7 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2294
2295
echo "Active Plugins:\r\n";
2296
$active_plugins = (array) get_option( 'active_plugins', array() );
2297
2298
if ( is_multisite() ) {
2299
$network_active_plugins = wp_get_active_network_plugins();
@@ -2301,7 +2606,24 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2301
}
2302
2303
foreach ( $active_plugins as $plugin ) {
2304
- $this->print_plugin_details( WP_PLUGIN_DIR . '/' . $plugin );
2305
}
2306
}
2307
@@ -2323,14 +2645,16 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2323
*
2324
* @param string $plugin_path
2325
* @param string $suffix
2326
*/
2327
- function print_plugin_details( $plugin_path, $suffix = '' ) {
2328
$plugin_data = get_plugin_data( $plugin_path );
2329
if ( empty( $plugin_data['Name'] ) ) {
2330
- return;
2331
}
2332
2333
- printf( "%s%s (v%s) by %s\r\n", $plugin_data['Name'], $suffix, $plugin_data['Version'], strip_tags( $plugin_data['AuthorName'] ) );
2334
}
2335
2336
/**
@@ -2393,6 +2717,32 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2393
}
2394
}
2395
2396
/**
2397
* Is the current blog ID that specified in wp-config.php
2398
*
@@ -2523,6 +2873,9 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2523
}
2524
}
2525
2526
// Remove duplicates
2527
$paths = array_unique( $paths );
2528
@@ -2566,26 +2919,22 @@ class Amazon_S3_And_CloudFront extends AWS_Plugin_Base {
2566
* @return float|int
2567
*/
2568
function multisite_get_spaced_used( $space_used ) {
2569
- if ( false === ( $space_used = get_transient( 'wpos3_site_space_used' ) ) ) {
2570
- global $wpdb;
2571
2572
- // Sum the total file size (including image sizes) for all S3 attachments
2573
- $sql = "SELECT SUM( meta_value ) AS bytes_total
2574
FROM {$wpdb->postmeta}
2575
WHERE meta_key = 'wpos3_filesize_total'";
2576
2577
- $space_used = $wpdb->get_var( $sql );
2578
2579
- // Get local upload sizes
2580
- $upload_dir = wp_upload_dir();
2581
- $space_used += get_dirsize( $upload_dir['basedir'] );
2582
-
2583
- if ( $space_used > 0 ) {
2584
- // Convert to bytes to MB
2585
- $space_used = $space_used / 1024 / 1024;
2586
- }
2587
2588
- set_transient( 'wpos3_site_space_used', $space_used, HOUR_IN_SECONDS );
2589
}
2590
2591
return $space_used;
42
*/
43
protected $default_tab = '';
44
45
+ /**
46
+ * @var AS3CF_Notices
47
+ */
48
+ public $notices;
49
+
50
/**
51
* @var string
52
*/
57
*/
58
protected static $buckets_check = array();
59
60
+ /**
61
+ * @var array
62
+ */
63
+ protected $encode_files = array();
64
+
65
+ /**
66
+ * @var AS3CF_Plugin_Compatibility
67
+ */
68
+ public $plugin_compat;
69
+
70
const DEFAULT_ACL = 'public-read';
71
const PRIVATE_ACL = 'private';
72
const DEFAULT_EXPIRES = 900;
85
parent::__construct( $plugin_file_path );
86
87
$this->aws = $aws;
88
+ $this->notices = AS3CF_Notices::get_instance( $this, $plugin_file_path );
89
90
$this->init( $plugin_file_path );
91
}
111
add_action( 'wp_ajax_as3cf-manual-save-bucket', array( $this, 'ajax_save_bucket' ) );
112
add_action( 'wp_ajax_as3cf-get-url-preview', array( $this, 'ajax_get_url_preview' ) );
113
114
add_filter( 'wp_get_attachment_url', array( $this, 'wp_get_attachment_url' ), 99, 2 );
115
add_filter( 'wp_handle_upload_prefilter', array( $this, 'wp_handle_upload_prefilter' ), 1 );
116
add_filter( 'wp_update_attachment_metadata', array( $this, 'wp_update_attachment_metadata' ), 110, 2 );
117
+ add_filter( 'get_image_tag', array( $this, 'maybe_encode_get_image_tag' ), 10, 6 );
118
+ add_filter( 'wp_get_attachment_image_src', array( $this, 'maybe_encode_wp_get_attachment_image_src' ), 10, 4 );
119
+ add_filter( 'wp_prepare_attachment_for_js', array( $this, 'maybe_encode_wp_prepare_attachment_for_js' ), 10, 3 );
120
add_filter( 'delete_attachment', array( $this, 'delete_attachment' ), 20 );
121
add_filter( 'update_attached_file', array( $this, 'update_attached_file' ), 100, 2 );
122
add_filter( 'get_attached_file', array( $this, 'get_attached_file' ), 10, 2 );
124
add_filter( 'pre_get_space_used', array( $this, 'multisite_get_spaced_used' ) );
125
126
// include compatibility code for other plugins
127
+ $this->plugin_compat = new AS3CF_Plugin_Compatibility( $this );
128
129
load_plugin_textdomain( 'amazon-s3-and-cloudfront', false, dirname( plugin_basename( $plugin_file_path ) ) . '/languages/' );
130
295
296
$value = apply_filters( 'as3cf_set_setting_' . $key, $value );
297
298
+ // Remove disallowed characters from custom domain
299
+ if ( 'cloudfront' === $key ) {
300
+ $value = $this->sanitize_custom_domain( $value );
301
+ }
302
+
303
parent::set_setting( $key, $value );
304
}
305
306
+ /**
307
+ * Sanitize custom domain
308
+ *
309
+ * @param string $domain
310
+ *
311
+ * @return string
312
+ */
313
+ function sanitize_custom_domain( $domain ) {
314
+ $domain = preg_replace( '@^[a-zA-Z]*:\/\/@', '', $domain );
315
+ $domain = preg_replace( '@[^a-zA-Z0-9\.\-]@', '', $domain );
316
+
317
+ return $domain;
318
+ }
319
+
320
/**
321
* Return the default object prefix
322
*
355
$interval = $hook;
356
}
357
if ( ! wp_next_scheduled( $hook ) ) {
358
+ wp_schedule_event( time(), $interval, $hook, $args );
359
}
360
}
361
387
if ( is_wp_error( $region ) ) {
388
$region = '';
389
}
390
+ $domain = $this->sanitize_custom_domain( $this->get_s3_url_domain( $bucket, $region ) );
391
392
$url = $scheme . '://' . $domain . '/' . $path . $suffix;
393
522
}
523
524
// upload attachment to S3
525
+ $data = $this->upload_attachment_to_s3( $post_id, $data );
526
527
return $data;
528
}
540
* @return array|WP_Error $s3object|$meta If meta is supplied, return it. Else return S3 meta
541
*/
542
function upload_attachment_to_s3( $post_id, $data = null, $file_path = null, $force_new_s3_client = false, $remove_local_files = true ) {
543
+ $return_metadata = null;
544
if ( is_null( $data ) ) {
545
$data = wp_get_attachment_metadata( $post_id, true );
546
+ } else {
547
+ // As we have passed in the meta, return it later
548
+ $return_metadata = $data;
549
+ }
550
+
551
+ // Allow S3 upload to be hijacked / cancelled for any reason
552
+ $pre = apply_filters( 'as3cf_pre_upload_attachment', false, $post_id, $data );
553
+ if ( false !== $pre ) {
554
+ if ( ! is_null( $return_metadata ) ) {
555
+ // If the attachment metadata is supplied, return it
556
+ return $data;
557
+ }
558
+
559
+ $error_msg = is_string( $pre ) ? $pre : __( 'Upload aborted by filter \'as3cf_pre_upload_attachment\'', 'amazon-s3-and-cloudfront' );
560
+
561
+ return $this->return_upload_error( $error_msg );
562
}
563
564
if ( is_null( $file_path ) ) {
567
568
// Check file exists locally before attempting upload
569
if ( ! file_exists( $file_path ) ) {
570
+ $error_msg = sprintf( __( 'File %s does not exist', 'amazon-s3-and-cloudfront' ), $file_path );
571
+
572
+ return $this->return_upload_error( $error_msg, $return_metadata );
573
}
574
575
$file_name = basename( $file_path );
578
579
// check mime type of file is in allowed S3 mime types
580
if ( ! in_array( $type, $allowed_types ) ) {
581
+ $error_msg = sprintf( __( 'Mime type %s is not allowed', 'amazon-s3-and-cloudfront' ), $type );
582
+
583
+ return $this->return_upload_error( $error_msg, $return_metadata );
584
}
585
586
$acl = self::DEFAULT_ACL;
643
644
// If far future expiration checked (10 years)
645
if ( $this->get_setting( 'expires' ) ) {
646
+ $args['CacheControl'] = 'max-age=315360000';
647
+ $args['Expires'] = date( 'D, d M Y H:i:s O', time() + 315360000 );
648
}
649
$args = apply_filters( 'as3cf_object_meta', $args, $post_id );
650
659
}
660
catch ( Exception $e ) {
661
$error_msg = sprintf( __( 'Error uploading %s to S3: %s', 'amazon-s3-and-cloudfront' ), $file_path, $e->getMessage() );
662
663
+ return $this->return_upload_error( $error_msg, $return_metadata );
664
}
665
}
666
680
// Store in the attachment meta data for use by WP
681
$data['filesize'] = $bytes;
682
683
+ if ( is_null( $return_metadata ) ) {
684
+ // Update metadata with filesize
685
+ update_post_meta( $post_id, '_wp_attachment_metadata', $data );
686
+ }
687
688
// Add to the file size total
689
$filesize_total += $bytes;
743
// Make sure we don't have a cached file sizes in the meta
744
unset( $data['filesize'] );
745
746
+ if ( is_null( $return_metadata ) ) {
747
+ // Remove the filesize from the metadata
748
+ update_post_meta( $post_id, '_wp_attachment_metadata', $data );
749
+ }
750
751
delete_post_meta( $post_id, 'wpos3_filesize_total' );
752
}
753
}
754
755
+ do_action( 'wpos3_post_upload_attachment', $post_id, $s3object );
756
+
757
+ if ( ! is_null( $return_metadata ) ) {
758
+ // If the attachment metadata is supplied, return it
759
+ return $data;
760
+ }
761
+
762
return $s3object;
763
}
764
765
+ /**
766
+ * Helper to return meta data on upload error
767
+ *
768
+ * @param string $error_msg
769
+ * @param array|null $return
770
+ *
771
+ * @return array|WP_Error
772
+ */
773
+ protected function return_upload_error( $error_msg, $return = null ) {
774
+ if ( is_null( $return ) ) {
775
+ return new WP_Error( 'exception', $error_msg );
776
+ }
777
+
778
+ error_log( $error_msg );
779
+
780
+ return $return;
781
+ }
782
+
783
/**
784
* Remove files from the local site
785
*
793
}
794
}
795
796
+ /**
797
+ * Add HiDPi suffix to a file path
798
+ *
799
+ * @param string $orig_path
800
+ *
801
+ * @return string
802
+ */
803
function get_hidpi_file_path( $orig_path ) {
804
$hidpi_suffix = apply_filters( 'as3cf_hidpi_suffix', '@2x' );
805
806
+ return $this->apply_file_suffix( $orig_path, $hidpi_suffix );
807
+ }
808
+
809
+ /**
810
+ * Helper to apply a suffix to a file path
811
+ *
812
+ * @param string $file
813
+ * @param string $suffix
814
+ *
815
+ * @return string
816
+ */
817
+ function apply_file_suffix( $file, $suffix ) {
818
+ $pathinfo = pathinfo( $file );
819
+
820
+ return $pathinfo['dirname'] . '/' . $pathinfo['filename'] . $suffix . '.' . $pathinfo['extension'];
821
}
822
823
/**
903
return $file;
904
}
905
906
$filename = $file['name'];
907
908
// sanitize the file name before we begin processing
921
// rebuild filename with lowercase extension as S3 will have converted extension on upload
922
$ext = strtolower( $ext );
923
$filename = $info['filename'] . $ext;
924
+ $time = current_time( 'mysql' );
925
926
+ // Get time if uploaded in post screen
927
+ $post_id = filter_input( INPUT_POST, 'post_id', FILTER_VALIDATE_INT );
928
+ if ( isset( $post_id ) ) {
929
+ $time = $this->get_post_time( $post_id );
930
+ }
931
932
+ if ( ! $this->does_file_exist( $filename, $time ) ) {
933
+ // File doesn't exist locally or on S3, return it
934
+ return $file;
935
+ }
936
+
937
+ $file['name'] = $this->generate_unique_filename( $name, $ext, $time );
938
939
+ return $file;
940
+ }
941
+
942
+ /**
943
+ * Get post time
944
+ *
945
+ * @param int $post_id
946
+ *
947
+ * @return string
948
+ */
949
+ function get_post_time( $post_id ) {
950
+ $time = current_time( 'mysql' );
951
+
952
+ if ( ! $post = get_post( $post_id ) ) {
953
+ return $time;
954
+ }
955
+
956
+ if ( substr( $post->post_date, 0, 4 ) > 0 ) {
957
+ $time = $post->post_date;
958
+ }
959
+
960
+ return $time;
961
+ }
962
+
963
+ /**
964
+ * Does file exist
965
+ *
966
+ * @param string $filename
967
+ * @param string $time
968
+ *
969
+ * @return bool
970
+ */
971
+ function does_file_exist( $filename, $time ) {
972
+ if ( $this->does_file_exist_local( $filename, $time ) ) {
973
+ return true;
974
+ }
975
+
976
+ if ( ! $this->get_setting( 'object-versioning' ) && $this->does_file_exist_s3( $filename, $time ) ) {
977
+ return true;
978
+ }
979
+
980
+ return false;
981
+ }
982
+
983
+ /**
984
+ * Does file exist local
985
+ *
986
+ * @param string $filename
987
+ * @param string $time
988
+ *
989
+ * @return bool
990
+ */
991
+ function does_file_exist_local( $filename, $time ) {
992
+ global $wpdb;
993
+
994
+ $path = wp_upload_dir( $time );
995
+ $path = ltrim( $path['subdir'], '/' );
996
+
997
+ if ( '' !== $path ) {
998
+ $path = trailingslashit( $path );
999
+ }
1000
+ $file = $path . $filename;
1001
+
1002
+ $sql = $wpdb->prepare( "
1003
+ SELECT COUNT(*)
1004
+ FROM $wpdb->postmeta
1005
+ WHERE meta_key = %s
1006
+ AND meta_value = %s
1007
+ ", '_wp_attached_file', $file );
1008
+
1009
+ return (bool) $wpdb->get_var( $sql );
1010
+ }
1011
+
1012
+ /**
1013
+ * Does file exist s3
1014
+ *
1015
+ * @param string $filename
1016
+ * @param string $time
1017
+ *
1018
+ * @return bool
1019
+ */
1020
+ function does_file_exist_s3( $filename, $time ) {
1021
$bucket = $this->get_setting( 'bucket' );
1022
$region = $this->get_setting( 'region' );
1023
+
1024
if ( is_wp_error( $region ) ) {
1025
+ return false;
1026
}
1027
1028
$s3client = $this->get_s3client( $region );
1029
+ $prefix = ltrim( trailingslashit( $this->get_object_prefix() ), '/' );
1030
+ $prefix .= ltrim( trailingslashit( $this->get_dynamic_prefix( $time ) ), '/' );
1031
1032
+ return $s3client->doesObjectExist( $bucket, $prefix . $filename );
1033
+ }
1034
+
1035
+ /**
1036
+ * Generate unique filename
1037
+ *
1038
+ * @param string $name
1039
+ * @param string $ext
1040
+ * @param string $time
1041
+ *
1042
+ * @return string
1043
+ */
1044
+ function generate_unique_filename( $name, $ext, $time ) {
1045
+ $count = 1;
1046
+ $filename = $name . $count . $ext;
1047
1048
+ while ( $this->does_file_exist( $filename, $time ) ) {
1049
+ $count++;
1050
+ $filename = $name . $count . $ext;
1051
+ }
1052
1053
+ return $filename;
1054
}
1055
1056
+ /**
1057
+ * Get attachment url
1058
+ *
1059
+ * @param string $url
1060
+ * @param int $post_id
1061
+ *
1062
+ * @return bool|mixed|void|WP_Error
1063
+ */
1064
function wp_get_attachment_url( $url, $post_id ) {
1065
$new_url = $this->get_attachment_url( $post_id );
1066
if ( false === $new_url ) {
1073
return $new_url;
1074
}
1075
1076
+ /**
1077
+ * Get attachment s3 info
1078
+ *
1079
+ * @param int $post_id
1080
+ *
1081
+ * @return mixed
1082
+ */
1083
function get_attachment_s3_info( $post_id ) {
1084
return get_post_meta( $post_id, 'amazonS3_info', true );
1085
}
1171
/**
1172
* Get the custom object prefix if enabled
1173
*
1174
+ * @param string $toggle_setting
1175
+ *
1176
* @return string
1177
*/
1178
+ function get_object_prefix( $toggle_setting = 'enable-object-prefix' ) {
1179
+ if ( $this->get_setting( $toggle_setting ) ) {
1180
$prefix = trim( $this->get_setting( 'object-prefix' ) );
1181
} else {
1182
$prefix = '';
1336
}
1337
1338
/**
1339
+ * Maybe encode attachment URLs when retrieving the image tag
1340
*
1341
+ * @param string $html
1342
+ * @param int $id
1343
+ * @param string $alt
1344
+ * @param string $title
1345
+ * @param string $align
1346
+ * @param string $size
1347
*
1348
+ * @return string
1349
*/
1350
+ function maybe_encode_get_image_tag( $html, $id, $alt, $title, $align, $size ) {
1351
+ if ( ! $this->get_setting( 'serve-from-s3' ) ) {
1352
+ // Not serving S3 URLs
1353
+ return $html;
1354
+ }
1355
+
1356
+ if ( ! $this->get_attachment_s3_info( $id ) ) {
1357
+ // File not uploaded to S3
1358
+ return $html;
1359
+ }
1360
+
1361
+ preg_match( '@\ssrc=[\'\"]([^\'\"]*)[\'\"]@', $html, $matches );
1362
+
1363
+ if ( ! isset( $matches[1] ) ) {
1364
+ // Can't establish img src
1365
+ return $html;
1366
+ }
1367
+
1368
+ $img_src = $matches[1];
1369
+ $encoded_src = $this->encode_filename_in_path( $img_src );
1370
+
1371
+ return str_replace( $img_src, $encoded_src, $html );
1372
}
1373
1374
/**
1375
+ * Maybe encode URLs for images that represent an attachment
1376
*
1377
+ * @param array|bool $image
1378
+ * @param int $attachment_id
1379
+ * @param string|array $size
1380
+ * @param bool $icon
1381
*
1382
+ * @return array
1383
*/
1384
+ function maybe_encode_wp_get_attachment_image_src( $image, $attachment_id, $size, $icon ) {
1385
if ( ! $this->get_setting( 'serve-from-s3' ) ) {
1386
+ // Not serving S3 URLs
1387
+ return $image;
1388
}
1389
1390
+ if ( ! $this->get_attachment_s3_info( $attachment_id ) ) {
1391
+ // File not uploaded to S3
1392
+ return $image;
1393
}
1394
1395
+ if ( isset( $image[0] ) ) {
1396
+ $image[0] = $this->encode_filename_in_path( $image[0] );
1397
}
1398
1399
+ return $image;
1400
+ }
1401
+
1402
+ /**
1403
+ * Maybe encode URLs when outputting attachments in the media grid
1404
+ *
1405
+ * @param array $response
1406
+ * @param int|object $attachment
1407
+ * @param array $meta
1408
+ *
1409
+ * @return array
1410
+ */
1411
+ function maybe_encode_wp_prepare_attachment_for_js( $response, $attachment, $meta ) {
1412
+ if ( ! $this->get_setting( 'serve-from-s3' ) ) {
1413
+ // Not serving S3 URLs
1414
+ return $response;
1415
}
1416
1417
+ if ( ! $this->get_attachment_s3_info( $attachment->ID ) ) {
1418
+ // File not uploaded to S3
1419
+ return $response;
1420
}
1421
1422
+ if ( isset( $response['url'] ) ) {
1423
+ $response['url'] = $this->encode_filename_in_path( $response['url'] );
1424
+ }
1425
+
1426
+ if ( isset( $response['sizes'] ) && is_array( $response['sizes'] ) ) {
1427
+ foreach ( $response['sizes'] as $key => $value ) {
1428
+ $response['sizes'][ $key ]['url'] = $this->encode_filename_in_path( $value['url'] );
1429
+ }
1430
+ }
1431
+
1432
+ return $response;
1433
}
1434
1435
/**
1441
* @return string Encoded filename with path prefix untouched
1442
*/
1443
function encode_filename_in_path( $file ) {
1444
+ $url = parse_url( $file );
1445
+
1446
+ if ( ! isset( $url['path'] ) ) {
1447
+ return $file;
1448
+ }
1449
+
1450
+ if ( in_array( $this->leading_slash_it( $url['path'] ), $this->encode_files ) ) {
1451
+ // Already encoded return original file
1452
+ return $file;
1453
+ }
1454
+
1455
+ $file_path = dirname( $file );
1456
+ $file_path = ( '.' !== $file_path ) ? trailingslashit( $file_path ) : '';
1457
+ $file_name = basename( $file );
1458
+ $encoded_file_name = rawurlencode( $file_name );
1459
+ $encoded_file_path = $file_path . $encoded_file_name;
1460
+
1461
+ if ( $file_name !== $encoded_file_name ) {
1462
+ $encoded_url = parse_url( $encoded_file_path );
1463
+ $this->encode_files[] = $this->leading_slash_it( $encoded_url['path'] );
1464
+ }
1465
+
1466
+ return $file_path . $encoded_file_name;
1467
+ }
1468
1469
+ /**
1470
+ * Leading slash it
1471
+ *
1472
+ * @param string $path
1473
+ *
1474
+ * @return string
1475
+ */
1476
+ function leading_slash_it( $path ) {
1477
+ return '/' . ltrim( $path, '/\\' );
1478
}
1479
1480
/**
1792
* @param bool|string $region specify region to client for signature
1793
* @param bool $force force return of new S3 client when swapping regions
1794
*
1795
+ * @return Aws\S3\S3Client
1796
*/
1797
function get_s3client( $region = false, $force = false ) {
1798
if ( is_null( $this->s3client ) || $force ) {
2033
wp_localize_script( 'as3cf-script',
2034
'as3cf',
2035
array(
2036
+ 'strings' => array(
2037
'create_bucket_error' => __( 'Error creating bucket', 'amazon-s3-and-cloudfront' ),
2038
'create_bucket_name_short' => __( 'Bucket name too short.', 'amazon-s3-and-cloudfront' ),
2039
'create_bucket_name_long' => __( 'Bucket name too long.', 'amazon-s3-and-cloudfront' ),
2043
'get_url_preview_error' => __( 'Error getting URL preview: ', 'amazon-s3-and-cloudfront' ),
2044
'save_alert' => __( 'The changes you made will be lost if you navigate away from this page', 'amazon-s3-and-cloudfront' )
2045
),
2046
+ 'nonces' => array(
2047
'create_bucket' => wp_create_nonce( 'as3cf-create-bucket' ),
2048
'manual_bucket' => wp_create_nonce( 'as3cf-manual-save-bucket' ),
2049
'get_buckets' => wp_create_nonce( 'as3cf-get-buckets' ),
2050
'save_bucket' => wp_create_nonce( 'as3cf-save-bucket' ),
2051
'get_url_preview' => wp_create_nonce( 'as3cf-get-url-preview' ),
2052
),
2053
+ 'is_pro' => $this->is_pro(),
2054
+ 'aws_bucket_link' => $this->get_aws_bucket_link(),
2055
)
2056
);
2057
2058
$this->handle_post_request();
2059
$this->http_prepare_download_log();
2060
+ $this->check_for_gd_imagick();
2061
2062
do_action( 'as3cf_plugin_load' );
2063
}
2294
return true;
2295
}
2296
2297
+ /**
2298
+ * Get the link to the bucket on the AWS console
2299
+ *
2300
+ * @param string $bucket
2301
+ * @param string $prefix
2302
+ *
2303
+ * @return string
2304
+ */
2305
+ function get_aws_bucket_link( $bucket = '', $prefix = '' ) {
2306
+ if ( '' !== $prefix ) {
2307
+ $prefix = '&prefix=' . urlencode( $prefix );
2308
+ }
2309
+
2310
+ return 'https://console.aws.amazon.com/s3/home?bucket=' . $bucket . $prefix;
2311
+ }
2312
+
2313
/**
2314
* Apply ACL to an attachment and associated files
2315
*
2334
2335
// Add attachment to ACL update notice
2336
$message = $this->make_acl_admin_notice_text( $s3object );
2337
+ $this->notices->add_notice( $message );
2338
2339
// update S3 meta data
2340
if ( $acl == self::DEFAULT_ACL ) {
2361
}
2362
2363
/**
2364
+ * Check if PHP GD and Imagick is installed
2365
*/
2366
+ function check_for_gd_imagick() {
2367
+ $gd_enabled = $this->gd_enabled();
2368
+ $imagick_enabled = $this->imagick_enabled();
2369
2370
+ if( ! $gd_enabled && ! $imagick_enabled ) {
2371
+ $this->notices->add_notice(
2372
+ __( '<strong>Image Manipulation Library Missing</strong> &mdash; Looks like you don\'t have an image manipulation library installed on this server and configured with PHP. You may run into trouble if you try to edit images. Please setup GD or ImageMagick.', 'amazon-s3-and-cloudfront' ),
2373
+ array( 'flash' => false, 'only_show_to_user' => false, 'only_show_in_settings' => true )
2374
+ );
2375
}
2376
}
2377
2425
echo empty( $wpdb->use_mysqli ) ? 'no' : 'yes';
2426
echo "\r\n";
2427
2428
+ echo 'PHP Memory Limit: ';
2429
+ if ( function_exists( 'ini_get' ) ) {
2430
+ echo esc_html( ini_get( 'memory_limit' ) );
2431
+ }
2432
+ echo "\r\n";
2433
+
2434
echo 'WP Memory Limit: ';
2435
echo esc_html( WP_MEMORY_LIMIT );
2436
echo "\r\n";
2473
}
2474
echo "\r\n";
2475
2476
+ echo 'WP Cron: ';
2477
+ echo esc_html( ( defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON ) ? 'Disabled' : 'Enabled' );
2478
+ echo "\r\n";
2479
+
2480
echo 'fsockopen: ';
2481
if ( function_exists( 'fsockopen' ) ) {
2482
echo 'Enabled';
2507
} else {
2508
echo 'Disabled';
2509
}
2510
+ echo "\r\n";
2511
+
2512
+ echo 'PHP GD: ';
2513
+ if ( $this->gd_enabled() ) {
2514
+ $gd_info = gd_info();
2515
+ echo isset( $gd_info['GD Version'] ) ? esc_html( $gd_info['GD Version'] ) : 'Enabled';
2516
+ } else {
2517
+ echo 'Disabled';
2518
+ }
2519
+ echo "\r\n";
2520
+
2521
+ echo 'Imagick: ';
2522
+ if ( $this->imagick_enabled() ) {
2523
+ echo 'Enabled';
2524
+ } else {
2525
+ echo 'Disabled';
2526
+ }
2527
echo "\r\n\r\n";
2528
2529
$media_counts = $this->diagnostic_media_counts();
2598
2599
echo "Active Plugins:\r\n";
2600
$active_plugins = (array) get_option( 'active_plugins', array() );
2601
+ $plugin_details = array();
2602
2603
if ( is_multisite() ) {
2604
$network_active_plugins = wp_get_active_network_plugins();
2606
}
2607
2608
foreach ( $active_plugins as $plugin ) {
2609
+ $plugin_details[] = $this->get_plugin_details( WP_PLUGIN_DIR . '/' . $plugin );
2610
+ }
2611
+
2612
+ asort( $plugin_details );
2613
+ echo implode( '', $plugin_details );
2614
+
2615
+ $mu_plugins = wp_get_mu_plugins();
2616
+ if ( $mu_plugins ) {
2617
+ $mu_plugin_details = array();
2618
+ echo "\r\n";
2619
+ echo "Must-use Plugins:\r\n";
2620
+
2621
+ foreach ( $mu_plugins as $mu_plugin ) {
2622
+ $mu_plugin_details[] = $this->get_plugin_details( $mu_plugin );
2623
+ }
2624
+
2625
+ asort( $mu_plugin_details );
2626
+ echo implode( '', $mu_plugin_details );
2627
}
2628
}
2629
2645
*
2646
* @param string $plugin_path
2647
* @param string $suffix
2648
+ *
2649
+ * @return string
2650
*/
2651
+ function get_plugin_details( $plugin_path, $suffix = '' ) {
2652
$plugin_data = get_plugin_data( $plugin_path );
2653
if ( empty( $plugin_data['Name'] ) ) {
2654
+ return basename( $plugin_path );
2655
}
2656
2657
+ return sprintf( "%s%s (v%s) by %s\r\n", $plugin_data['Name'], $suffix, $plugin_data['Version'], strip_tags( $plugin_data['AuthorName'] ) );
2658
}
2659
2660
/**
2717
}
2718
}
2719
2720
+ /**
2721
+ * Detect if PHP GD is enabled
2722
+ *
2723
+ * @return bool
2724
+ */
2725
+ function gd_enabled() {
2726
+ if ( extension_loaded( 'gd' ) && function_exists( 'gd_info' ) ) {
2727
+ return true;
2728
+ } else {
2729
+ return false;
2730
+ }
2731
+ }
2732
+
2733
+ /**
2734
+ * Detect is Imagick is enabled
2735
+ *
2736
+ * @return bool
2737
+ */
2738
+ function imagick_enabled() {
2739
+ if ( extension_loaded( 'imagick' ) && class_exists( 'Imagick' ) && class_exists( 'ImagickPixel' ) ) {
2740
+ return true;
2741
+ } else {
2742
+ return false;
2743
+ }
2744
+ }
2745
+
2746
/**
2747
* Is the current blog ID that specified in wp-config.php
2748
*
2873
}
2874
}
2875
2876
+ // Allow other processes to add files to be uploaded
2877
+ $paths = apply_filters( 'as3cf_attachment_file_paths', $paths, $attachment_id, $meta );
2878
+
2879
// Remove duplicates
2880
$paths = array_unique( $paths );
2881
2919
* @return float|int
2920
*/
2921
function multisite_get_spaced_used( $space_used ) {
2922
+ global $wpdb;
2923
2924
+ // Sum the total file size (including image sizes) for all S3 attachments
2925
+ $sql = "SELECT SUM( meta_value ) AS bytes_total
2926
FROM {$wpdb->postmeta}
2927
WHERE meta_key = 'wpos3_filesize_total'";
2928
2929
+ $space_used = $wpdb->get_var( $sql );
2930
2931
+ // Get local upload sizes
2932
+ $upload_dir = wp_upload_dir();
2933
+ $space_used += get_dirsize( $upload_dir['basedir'] );
2934
2935
+ if ( $space_used > 0 ) {
2936
+ // Convert to bytes to MB
2937
+ $space_used = $space_used / 1024 / 1024;
2938
}
2939
2940
return $space_used;
classes/as3cf-notices.php ADDED
@@ -0,0 +1,324 @@
1
+ <?php
2
+
3
+ class AS3CF_Notices {
4
+
5
+ /**
6
+ * @var AS3CF_Notices
7
+ */
8
+ protected static $instance = null;
9
+
10
+ /**
11
+ * @var Amazon_S3_And_CloudFront
12
+ */
13
+ private $as3cf;
14
+
15
+ /**
16
+ * @var string
17
+ */
18
+ private $plugin_file_path;
19
+
20
+ /**
21
+ * Make this class a singleton
22
+ *
23
+ * Use this instead of __construct()
24
+ *
25
+ * @param Amazon_S3_And_CloudFront $as3cf
26
+ * @param string $plugin_file_path
27
+ *
28
+ * @return AS3CF_Notices
29
+ */
30
+ public static function get_instance( $as3cf, $plugin_file_path ) {
31
+ if ( ! isset( static::$instance ) ) {
32
+ static::$instance = new static( $as3cf, $plugin_file_path );
33
+ }
34
+
35
+ return static::$instance;
36
+ }
37
+
38
+ /**
39
+ * Constructor
40
+ *
41
+ * @param Amazon_S3_And_CloudFront $as3cf
42
+ * @param string $plugin_file_path
43
+ */
44
+ protected function __construct( $as3cf, $plugin_file_path ) {
45
+ $this->as3cf = $as3cf;
46
+ $this->plugin_file_path = $plugin_file_path;
47
+
48
+ add_action( 'admin_notices', array( $this, 'admin_notices' ) );
49
+ add_action( 'network_admin_notices', array( $this, 'admin_notices' ) );
50
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_notice_scripts' ) );
51
+ add_action( 'wp_ajax_as3cf-dismiss-notice', array( $this, 'ajax_dismiss_notice' ) );
52
+ }
53
+
54
+ /**
55
+ * As this class is a singelton it should not be clone-able
56
+ */
57
+ protected function __clone() {
58
+ // Singleton
59
+ }
60
+
61
+ /**
62
+ * Create a notice
63
+ *
64
+ * @param string $message
65
+ * @param array $args
66
+ *
67
+ * @return string notice ID
68
+ */
69
+ public function add_notice( $message, $args = array() ) {
70
+ $defaults = array(
71
+ 'type' => 'info',
72
+ 'dismissible' => true,
73
+ 'inline' => false,
74
+ 'flash' => true,
75
+ 'only_show_to_user' => true,
76
+ 'only_show_in_settings' => false,
77
+ 'custom_id' => '',
78
+ );
79
+
80
+ $notice = array_intersect_key( array_merge( $defaults, $args ), $defaults );
81
+ $notice['message'] = $message;
82
+ $notice['triggered_by'] = get_current_user_id();
83
+ $notice['created_at'] = time();
84
+
85
+ if ( $notice['custom_id'] ) {
86
+ $notice['id'] = $notice['custom_id'];
87
+ } else {
88
+ $notice['id'] = apply_filters( 'as3cf_notice_id_prefix', 'as3cf-notice-' ) . sha1( $notice['message'] );
89
+ }
90
+
91
+ $this->save_notice( $notice );
92
+
93
+ return $notice['id'];
94
+ }
95
+
96
+ /**
97
+ * Save a notice
98
+ *
99
+ * @param array $notice
100
+ */
101
+ protected function save_notice( $notice ) {
102
+ $user_id = get_current_user_id();
103
+
104
+ if ( $notice['only_show_to_user'] ) {
105
+ $notices = get_user_meta( $user_id, 'as3cf_notices', true );
106
+ } else {
107
+ $notices = get_site_transient( 'as3cf_notices' );
108
+ }
109
+
110
+ if ( ! is_array( $notices ) ) {
111
+ $notices = array();
112
+ }
113
+
114
+ if ( ! array_key_exists( $notice['id'], $notices ) ) {
115
+ $notices[ $notice['id'] ] = $notice;
116
+
117
+ if ( $notice['only_show_to_user'] ) {
118
+ update_user_meta( $user_id, 'as3cf_notices', $notices );
119
+ } else {
120
+ set_site_transient( 'as3cf_notices', $notices );
121
+ }
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Remove a notice
127
+ *
128
+ * @param array $notice
129
+ */
130
+ protected function remove_notice( $notice ) {
131
+ $user_id = get_current_user_id();
132
+
133
+ if ( $notice['only_show_to_user'] ) {
134
+ $notices = get_user_meta( $user_id, 'as3cf_notices', true );
135
+ } else {
136
+ $notices = get_site_transient( 'as3cf_notices' );
137
+ }
138
+
139
+ if ( ! is_array( $notices ) ) {
140
+ $notices = array();
141
+ }
142
+
143
+ if ( array_key_exists( $notice['id'], $notices ) ) {
144
+ unset( $notices[ $notice['id'] ] );
145
+
146
+ if ( $notice['only_show_to_user'] ) {
147
+ if ( ! empty( $notices ) ) {
148
+ update_user_meta( $user_id, 'as3cf_notices', $notices );
149
+ } else {
150
+ delete_user_meta( $user_id, 'as3cf_notices' );
151
+ }
152
+ } else {
153
+ if ( ! empty( $notices ) ) {
154
+ set_site_transient( 'as3cf_notices', $notices );
155
+ } else {
156
+ delete_site_transient( 'as3cf_notices' );
157
+ }
158
+ }
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Remove a notice by it's ID
164
+ *
165
+ * @param string $notice_id
166
+ */
167
+ public function remove_notice_by_id( $notice_id ) {
168
+ $notice = $this->find_notice_by_id( $notice_id );
169
+ if ( $notice ) {
170
+ $this->remove_notice( $notice );
171
+ }
172
+ }
173
+
174
+ /**
175
+ * Dismiss a notice
176
+ *
177
+ * @param string $notice_id
178
+ */
179
+ protected function dismiss_notice( $notice_id ) {
180
+ $user_id = get_current_user_id();
181
+
182
+ $notice = $this->find_notice_by_id( $notice_id );
183
+ if ( $notice ) {
184
+ if ( $notice['only_show_to_user'] ) {
185
+ if ( ! empty( $notices ) ) {
186
+ unset( $notices[ $notice['id'] ] );
187
+ update_user_meta( $user_id, 'as3cf_notices', $notices );
188
+ } else {
189
+ delete_user_meta( $user_id, 'as3cf_notices' );
190
+ }
191
+ } else {
192
+ $dismissed_notices = get_user_meta( $user_id, 'as3cf_dismissed_notices', true );
193
+ if ( ! is_array( $dismissed_notices ) ) {
194
+ $dismissed_notices = array();
195
+ }
196
+
197
+ if ( ! in_array( $notice['id'], $dismissed_notices ) ) {
198
+ $dismissed_notices[] = $notice['id'];
199
+ update_user_meta( $user_id, 'as3cf_dismissed_notices', $dismissed_notices );
200
+ }
201
+ }
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Find a notice by it's ID
207
+ *
208
+ * @param string $notice_id
209
+ *
210
+ * @return mixed
211
+ */
212
+ protected function find_notice_by_id( $notice_id ) {
213
+ $user_id = get_current_user_id();
214
+
215
+ $user_notices = get_user_meta( $user_id, 'as3cf_notices', true );
216
+ if ( ! is_array( $user_notices ) ) {
217
+ $user_notices = array();
218
+ }
219
+
220
+ $global_notices = get_site_transient( 'as3cf_notices' );
221
+ if ( ! is_array( $global_notices ) ) {
222
+ $global_notices = array();
223
+ }
224
+ $notices = array_merge( $user_notices, $global_notices );
225
+
226
+ if ( array_key_exists( $notice_id, $notices ) ) {
227
+ return $notices[ $notice_id ];
228
+ }
229
+
230
+ return null;
231
+ }
232
+
233
+ /**
234
+ * Show the notices
235
+ */
236
+ public function admin_notices() {
237
+ $user_id = get_current_user_id();
238
+ $dismissed_notices = get_user_meta( $user_id, 'as3cf_dismissed_notices', true );
239
+ if ( ! is_array( $dismissed_notices ) ) {
240
+ $dismissed_notices = array();
241
+ }
242
+
243
+ $user_notices = get_user_meta( $user_id, 'as3cf_notices', true );
244
+ if ( is_array( $user_notices ) && ! empty( $user_notices ) ) {
245
+ foreach ( $user_notices as $notice ) {
246
+ $this->maybe_show_notice( $notice, $dismissed_notices );
247
+ }
248
+ }
249
+
250
+ $global_notices = get_site_transient( 'as3cf_notices' );
251
+ if ( is_array( $global_notices ) && ! empty( $global_notices ) ) {
252
+ foreach ( $global_notices as $notice ) {
253
+ $this->maybe_show_notice( $notice, $dismissed_notices );
254
+ }
255
+ }
256
+ }
257
+
258
+ /**
259
+ * If it should be shown, display an individual notice
260
+ *
261
+ * @param array $notice
262
+ */
263
+ protected function maybe_show_notice( $notice, $dismissed_notices ) {
264
+ $screen = get_current_screen();
265
+ if ( $notice['only_show_in_settings'] && false === strpos( $screen->id, $this->as3cf->hook_suffix ) ) {
266
+ return;
267
+ }
268
+
269
+ if ( ! $notice['only_show_to_user'] && in_array( $notice['id'], $dismissed_notices ) ) {
270
+ return;
271
+ }
272
+
273
+ if ( 'info' === $notice['type'] ) {
274
+ $notice['type'] = 'notice-info';
275
+ }
276
+
277
+ $this->as3cf->render_view( 'notice', $notice );
278
+
279
+ if ( $notice['flash'] ) {
280
+ $this->remove_notice( $notice );
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Enqueue notice scripts in the admin
286
+ */
287
+ public function enqueue_notice_scripts() {
288
+ $version = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? time() : $GLOBALS['aws_meta']['amazon-s3-and-cloudfront']['version'];
289
+ $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
290
+
291
+ // Enqueue notice.js globally as notices can be dismissed on any admin page
292
+ $src = plugins_url( 'assets/js/notice' . $suffix . '.js', $this->plugin_file_path );
293
+ wp_enqueue_script( 'as3cf-notice', $src, array( 'jquery' ), $version, true );
294
+
295
+ wp_localize_script( 'as3cf-notice', 'as3cf_notice', array(
296
+ 'strings' => array(
297
+ 'dismiss_notice_error' => __( 'Error dismissing notice.', 'amazon-s3-and-cloudfront' ),
298
+ ),
299
+ 'nonces' => array(
300
+ 'dismiss_notice' => wp_create_nonce( 'as3cf-dismiss-notice' ),
301
+ ),
302
+ ) );
303
+ }
304
+
305
+ /**
306
+ * Handler for AJAX request to dismiss a notice
307
+ */
308
+ public function ajax_dismiss_notice() {
309
+ $this->as3cf->verify_ajax_request();
310
+
311
+ if ( ! isset( $_POST['notice_id'] ) || ! ( $notice_id = sanitize_text_field( $_POST['notice_id'] ) ) ) {
312
+ $out = array( 'error' => __( 'Invalid notice ID.', 'amazon-s3-and-cloudfront' ) );
313
+ $this->as3cf->end_ajax( $out );
314
+ }
315
+
316
+ $this->dismiss_notice( $notice_id );
317
+
318
+ $out = array(
319
+ 'success' => '1',
320
+ );
321
+ $this->as3cf->end_ajax( $out );
322
+ }
323
+
324
+ }
classes/as3cf-plugin-compatibility.php CHANGED
@@ -28,6 +28,14 @@ class AS3CF_Plugin_Compatibility {
28
*/
29
protected $as3cf;
30
31
function __construct( $as3cf ) {
32
$this->as3cf = $as3cf;
33
@@ -38,6 +46,9 @@ class AS3CF_Plugin_Compatibility {
38
* Register the compatibility hooks
39
*/
40
function compatibility_init() {
41
/*
42
* Legacy filter
43
* 'as3cf_get_attached_file_copy_back_to_local'
@@ -51,14 +62,15 @@ class AS3CF_Plugin_Compatibility {
51
add_action( 'as3cf_upload_attachment_pre_remove', array( $this, 'image_editor_remove_files' ), 10, 4 );
52
add_filter( 'as3cf_get_attached_file', array( $this, 'image_editor_download_file' ), 10, 4 );
53
add_filter( 'as3cf_upload_attachment_local_files_to_remove', array( $this, 'image_editor_remove_original_image' ), 10, 3 );
54
- add_filter( 'as3cf_get_attached_file', array( $this, 'customizer_header_crop_download_file' ), 10, 4 );
55
- add_filter( 'as3cf_upload_attachment_local_files_to_remove', array( $this, 'customizer_header_crop_remove_original_image' ), 10, 3 );
56
57
/*
58
* WP_Customize_Control
59
* /wp-includes/class-wp-customize_control.php
60
*/
61
add_filter( 'attachment_url_to_postid', array( $this, 'customizer_background_image' ), 10, 2 );
62
/*
63
* Regenerate Thumbnails
64
* https://wordpress.org/plugins/regenerate-thumbnails/
@@ -93,6 +105,79 @@ class AS3CF_Plugin_Compatibility {
93
return $url;
94
}
95
96
/**
97
* Get the file path of the original image file before an update
98
*
@@ -145,7 +230,7 @@ class AS3CF_Plugin_Compatibility {
145
* @return string
146
*/
147
function image_editor_download_file( $url, $file, $attachment_id, $s3_object ) {
148
- if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
149
return $url;
150
}
151
@@ -199,7 +284,7 @@ class AS3CF_Plugin_Compatibility {
199
* @return array
200
*/
201
function image_editor_remove_original_image( $files, $post_id, $file_path ) {
202
- if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
203
return $files;
204
}
205
@@ -213,6 +298,23 @@ class AS3CF_Plugin_Compatibility {
213
return $files;
214
}
215
216
/**
217
* Allow the WordPress Customizer to crop images that have been copied to S3
218
* but removed from the local server, by copying them back temporarily
@@ -224,17 +326,15 @@ class AS3CF_Plugin_Compatibility {
224
*
225
* @return string
226
*/
227
- function customizer_header_crop_download_file( $url, $file, $attachment_id, $s3_object ) {
228
- if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
229
return $url;
230
}
231
232
- if ( isset( $_POST['action'] ) && 'custom-header-crop' === sanitize_key( $_POST['action'] ) ) { // input var okay
233
- if ( ( $file = $this->copy_s3_file_to_server( $s3_object, $file ) ) ) {
234
- // Return the file if successfully downloaded from S3
235
- return $file;
236
- };
237
- }
238
239
return $url;
240
}
@@ -249,16 +349,14 @@ class AS3CF_Plugin_Compatibility {
249
*
250
* @return array
251
*/
252
- function customizer_header_crop_remove_original_image( $files, $post_id, $file_path ) {
253
- if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
254
return $files;
255
}
256
257
- if ( isset( $_POST['action'] ) && 'custom-header-crop' === sanitize_key( $_POST['action'] ) ) { // input var okay
258
- // remove original main image after edit
259
- if ( ( $original_file = $this->get_original_image_file( $_POST['id'], $file_path ) ) ) {
260
- $files[] = $original_file;
261
- }
262
}
263
264
return $files;
@@ -321,18 +419,7 @@ class AS3CF_Plugin_Compatibility {
321
* @return string
322
*/
323
function regenerate_thumbnails_download_file( $url, $file, $attachment_id, $s3_object ) {
324
- if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
325
- return $url;
326
- }
327
-
328
- if ( isset( $_POST['action'] ) && 'regeneratethumbnail' == sanitize_key( $_POST['action'] ) ) { // input var okay
329
- if ( ( $file = $this->copy_s3_file_to_server( $s3_object, $file ) ) ) {
330
- // Return the file if successfully downloaded from S3
331
- return $file;
332
- };
333
- }
334
-
335
- return $url;
336
}
337
338
/**
@@ -361,4 +448,79 @@ class AS3CF_Plugin_Compatibility {
361
362
return $file;
363
}
364
}
28
*/
29
protected $as3cf;
30
31
+ /**
32
+ * @var array
33
+ */
34
+ protected static $stream_wrappers = array();
35
+
36
+ /**
37
+ * @param Amazon_S3_And_CloudFront $as3cf
38
+ */
39
function __construct( $as3cf ) {
40
$this->as3cf = $as3cf;
41
46
* Register the compatibility hooks
47
*/
48
function compatibility_init() {
49
+ // Turn on stream wrapper S3 file
50
+ add_filter( 'as3cf_get_attached_file', array( $this, 'get_stream_wrapper_file' ), 20, 4 );
51
+
52
/*
53
* Legacy filter
54
* 'as3cf_get_attached_file_copy_back_to_local'
62
add_action( 'as3cf_upload_attachment_pre_remove', array( $this, 'image_editor_remove_files' ), 10, 4 );
63
add_filter( 'as3cf_get_attached_file', array( $this, 'image_editor_download_file' ), 10, 4 );
64
add_filter( 'as3cf_upload_attachment_local_files_to_remove', array( $this, 'image_editor_remove_original_image' ), 10, 3 );
65
+ add_filter( 'as3cf_get_attached_file', array( $this, 'customizer_crop_download_file' ), 10, 4 );
66
+ add_filter( 'as3cf_upload_attachment_local_files_to_remove', array( $this, 'customizer_crop_remove_original_image' ), 10, 3 );
67
68
/*
69
* WP_Customize_Control
70
* /wp-includes/class-wp-customize_control.php
71
*/
72
add_filter( 'attachment_url_to_postid', array( $this, 'customizer_background_image' ), 10, 2 );
73
+
74
/*
75
* Regenerate Thumbnails
76
* https://wordpress.org/plugins/regenerate-thumbnails/
105
return $url;
106
}
107
108
+ /**
109
+ * Is this an AJAX process?
110
+ *
111
+ * @return bool
112
+ */
113
+ function is_ajax() {
114
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
115
+ return true;
116
+ }
117
+
118
+ return false;
119
+ }
120
+
121
+ /**
122
+ * Check the current request is a specific one based on action and
123
+ * optional context
124
+ *
125
+ * @param string $action_key
126
+ * @param bool $ajax
127
+ * @param null|string $context_key
128
+ *
129
+ * @return bool
130
+ */
131
+ function maybe_process_on_action( $action_key, $ajax, $context_key = null ) {
132
+ if ( $ajax !== $this->is_ajax() ) {
133
+ return false;
134
+ }
135
+
136
+ $var_type = 'GET';
137
+
138
+ if ( isset( $_GET['action'] ) ) {
139
+ $action = $_GET['action'];
140
+ } else if ( isset( $_POST['action'] ) ) {
141
+ $var_type = 'POST';
142
+ $action = $_POST['action'];
143
+ } else {
144
+ return false;
145
+ }
146
+
147
+ $context_check = true;
148
+ if ( ! is_null( $context_key ) ) {
149
+ $global = constant( 'INPUT_' . $var_type );
150
+ $context = filter_input( $global, 'context' );
151
+ $context_check = ( $context_key === $context );
152
+ }
153
+
154
+ return ( $action_key === sanitize_key( $action ) && $context_check );
155
+ }
156
+
157
+ /**
158
+ * Generic method for copying back an S3 file to the server on a specific AJAX action
159
+ *
160
+ * @param string $action_key Action that must be in process
161
+ * @param bool $ajax Must the process be an AJAX one?
162
+ * @param string $url S3 URL
163
+ * @param string $file Local file path of image
164
+ * @param array $s3_object S3 meta data
165
+ *
166
+ * @return string
167
+ */
168
+ function copy_image_to_server_on_action( $action_key, $ajax, $url, $file, $s3_object ) {
169
+ if ( false === $this->maybe_process_on_action( $action_key, $ajax ) ) {
170
+ return $url;
171
+ }
172
+
173
+ if ( ( $file = $this->copy_s3_file_to_server( $s3_object, $file ) ) ) {
174
+ // Return the file if successfully downloaded from S3
175
+ return $file;
176
+ };
177
+
178
+ return $url;
179
+ }
180
+
181
/**
182
* Get the file path of the original image file before an update
183
*
230
* @return string
231
*/
232
function image_editor_download_file( $url, $file, $attachment_id, $s3_object ) {
233
+ if ( ! $this->is_ajax() ) {
234
return $url;
235
}
236
284
* @return array
285
*/
286
function image_editor_remove_original_image( $files, $post_id, $file_path ) {
287
+ if ( ! $this->is_ajax() ) {
288
return $files;
289
}
290
298
return $files;
299
}
300
301
+ /**
302
+ * Generic check for Customizer crop actions
303
+ *
304
+ * @return bool
305
+ */
306
+ protected function is_customizer_crop_action() {
307
+ $header_crop = $this->maybe_process_on_action( 'custom-header-crop', true );
308
+ $identity_crop = $this->maybe_process_on_action( 'crop-image', true, 'site-icon' );
309
+
310
+ if ( ! $header_crop && ! $identity_crop ) {
311
+ // Not doing a Customizer action
312
+ return false;
313
+ }
314
+
315
+ return true;
316
+ }
317
+
318
/**
319
* Allow the WordPress Customizer to crop images that have been copied to S3
320
* but removed from the local server, by copying them back temporarily
326
*
327