diff --git a/README.md b/README.md index bd91519e..88a3ad31 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ **Tags:** uploads, amazon, s3, mirror, admin, media, cdn, cloudfront **Requires at least:** 3.7 **Tested up to:** 4.3 -**Stable tag:** 0.9.8 +**Stable tag:** 0.9.9 **License:** GPLv3 Copies files to Amazon S3 as they are uploaded to the Media Library. Optionally configure Amazon CloudFront for faster delivery. @@ -67,6 +67,14 @@ This version requires PHP 5.3.3+ and the Amazon Web Services plugin ## Changelog ## +### 0.9.9 - 2015-11-12 ### +* Improvement: Improve wording of compatibility notices +* Improvement: Compatibility with Easy Digital Downloads 1.0.1 and WooCommerce 1.0.3 addons +* Improvement: Better determine available memory for background processes +* Bug fix: URL previews incorrect due to stripping `/` characters +* Bug fix: PHP Warning: stream_wrapper_register(): Protocol s3:// is already defined +* Bug fix: PHP Fatal error: Call to undefined method WP_Error::get() + ### 0.9.8 - 2015-11-02 ### * Bug fix: Attachment URLs containing query string parameters incorrectly encoded diff --git a/classes/amazon-s3-and-cloudfront.php b/classes/amazon-s3-and-cloudfront.php index e59d115e..134b1271 100644 --- a/classes/amazon-s3-and-cloudfront.php +++ b/classes/amazon-s3-and-cloudfront.php @@ -104,24 +104,30 @@ function init( $plugin_file_path ) { new AS3CF_Upgrade_File_Sizes( $this ); new AS3CF_Upgrade_Meta_WP_Error( $this ); + // Plugin setup add_action( 'aws_admin_menu', array( $this, 'admin_menu' ) ); + add_filter( 'plugin_action_links', array( $this, 'plugin_actions_settings_link' ), 10, 2 ); + add_filter( 'pre_get_space_used', array( $this, 'multisite_get_spaced_used' ) ); + + // UI AJAX add_action( 'wp_ajax_as3cf-get-buckets', array( $this, 'ajax_get_buckets' ) ); add_action( 'wp_ajax_as3cf-save-bucket', array( $this, 'ajax_save_bucket' ) ); add_action( 'wp_ajax_as3cf-create-bucket', array( $this, 'ajax_create_bucket' ) ); add_action( 'wp_ajax_as3cf-manual-save-bucket', array( $this, 'ajax_save_bucket' ) ); add_action( 'wp_ajax_as3cf-get-url-preview', array( $this, 'ajax_get_url_preview' ) ); + // Rewriting URLs, doesn't depend on plugin being setup add_filter( 'wp_get_attachment_url', array( $this, 'wp_get_attachment_url' ), 99, 2 ); - add_filter( 'wp_handle_upload_prefilter', array( $this, 'wp_handle_upload_prefilter' ), 1 ); - add_filter( 'wp_update_attachment_metadata', array( $this, 'wp_update_attachment_metadata' ), 110, 2 ); add_filter( 'get_image_tag', array( $this, 'maybe_encode_get_image_tag' ), 99, 6 ); add_filter( 'wp_get_attachment_image_src', array( $this, 'maybe_encode_wp_get_attachment_image_src' ), 99, 4 ); add_filter( 'wp_prepare_attachment_for_js', array( $this, 'maybe_encode_wp_prepare_attachment_for_js' ), 99, 3 ); + add_filter( 'get_attached_file', array( $this, 'get_attached_file' ), 10, 2 ); + + // Communication with S3, plugin needs to be setup + add_filter( 'wp_handle_upload_prefilter', array( $this, 'wp_handle_upload_prefilter' ), 1 ); + add_filter( 'wp_update_attachment_metadata', array( $this, 'wp_update_attachment_metadata' ), 110, 2 ); add_filter( 'delete_attachment', array( $this, 'delete_attachment' ), 20 ); add_filter( 'update_attached_file', array( $this, 'update_attached_file' ), 100, 2 ); - add_filter( 'get_attached_file', array( $this, 'get_attached_file' ), 10, 2 ); - add_filter( 'plugin_action_links', array( $this, 'plugin_actions_settings_link' ), 10, 2 ); - add_filter( 'pre_get_space_used', array( $this, 'multisite_get_spaced_used' ) ); // include compatibility code for other plugins $this->plugin_compat = new AS3CF_Plugin_Compatibility( $this ); @@ -387,7 +393,8 @@ function get_url_preview( $escape = true, $suffix = 'photo.jpg' ) { if ( is_wp_error( $region ) ) { $region = ''; } - $domain = $this->sanitize_custom_domain( $this->get_s3_url_domain( $bucket, $region ) ); + + $domain = $this->get_s3_url_domain( $bucket, $region, null, array(), true ); $url = $scheme . '://' . $domain . '/' . $path . $suffix; @@ -1117,14 +1124,15 @@ function is_plugin_setup() { * @param int|null $expires Seconds for the link to live * @param string|null $size Size of the image to get * @param array $headers Header overrides for request + * @param bool $skip_rewrite_check * * @return mixed|void|WP_Error */ - function get_secure_attachment_url( $post_id, $expires = null, $size = null, $headers = array() ) { + function get_secure_attachment_url( $post_id, $expires = null, $size = null, $headers = array(), $skip_rewrite_check = false ) { if ( is_null( $expires ) ) { $expires = self::DEFAULT_EXPIRES; } - return $this->get_attachment_url( $post_id, $expires, $size, null, $headers ); + return $this->get_attachment_url( $post_id, $expires, $size, null, $headers, $skip_rewrite_check ); } /** @@ -1236,10 +1244,11 @@ function get_s3_url_prefix( $region = '', $expires = null ) { * @param string $region * @param int $expires * @param array $args Allows you to specify custom URL settings + * @param bool $preview When generating the URL preview sanitize certain output * * @return mixed|string|void */ - function get_s3_url_domain( $bucket, $region = '', $expires = null, $args = array() ) { + function get_s3_url_domain( $bucket, $region = '', $expires = null, $args = array(), $preview = false ) { if ( ! isset( $args['cloudfront'] ) ) { $args['cloudfront'] = $this->get_setting( 'cloudfront' ); } @@ -1255,7 +1264,12 @@ function get_s3_url_domain( $bucket, $region = '', $expires = null, $args = arra $prefix = $this->get_s3_url_prefix( $region, $expires ); if ( 'cloudfront' === $args['domain'] && is_null( $expires ) && $args['cloudfront'] ) { - $s3_domain = $args['cloudfront']; + $cloudfront = $args['cloudfront']; + if ( $preview ) { + $cloudfront = $this->sanitize_custom_domain( $cloudfront ); + } + + $s3_domain = $cloudfront; } elseif ( 'virtual-host' === $args['domain'] ) { $s3_domain = $bucket; @@ -1273,16 +1287,19 @@ function get_s3_url_domain( $bucket, $region = '', $expires = null, $args = arra /** * Get the url of the file from Amazon S3 * - * @param int $post_id Post ID of the attachment - * @param int|null $expires Seconds for the link to live - * @param string|null $size Size of the image to get - * @param array|null $meta Pre retrieved _wp_attachment_metadata for the attachment - * @param array $headers Header overrides for request + * @param int $post_id Post ID of the attachment + * @param int|null $expires Seconds for the link to live + * @param string|null $size Size of the image to get + * @param array|null $meta Pre retrieved _wp_attachment_metadata for the attachment + * @param array $headers Header overrides for request + * @param bool $skip_rewrite_check Always return the URL regardless of the 'Rewrite File URLs' setting. + * Useful for the EDD and Woo addons to not break download URLs when the + * option is disabled. * * @return bool|mixed|void|WP_Error */ - function get_attachment_url( $post_id, $expires = null, $size = null, $meta = null, $headers = array() ) { - if ( ! $this->get_setting( 'serve-from-s3' ) ) { + function get_attachment_url( $post_id, $expires = null, $size = null, $meta = null, $headers = array(), $skip_rewrite_check = false ) { + if ( ! $skip_rewrite_check && ! $this->get_setting( 'serve-from-s3' ) ) { return false; } @@ -1317,7 +1334,7 @@ function get_attachment_url( $post_id, $expires = null, $size = null, $meta = nu } } - if ( ! is_null( $expires ) ) { + if ( ! is_null( $expires ) && $this->is_plugin_setup() ) { try { $expires = time() + $expires; $secure_url = $this->get_s3client( $region )->getObjectUrl( $s3object['bucket'], $s3object['key'], $expires, $headers ); @@ -2021,8 +2038,7 @@ function render_bucket_permission_errors() { /** * Register modal scripts and styles so they can be enqueued later */ - function register_modal_assets() - { + function register_modal_assets() { $version = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? time() : $this->plugin_version; $suffix = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min'; @@ -2963,8 +2979,8 @@ function multisite_get_spaced_used( $space_used ) { * @return bool */ public function memory_exceeded( $filter_name = null ) { + $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory $current_memory = memory_get_usage( true ); - $memory_limit = ( intval( WP_MEMORY_LIMIT ) * 1024 * 1024 ) * 0.9; // 90% of max memory $return = false; if ( $current_memory >= $memory_limit ) { @@ -2978,6 +2994,27 @@ public function memory_exceeded( $filter_name = null ) { return apply_filters( $filter_name, $return ); } + /** + * Get memory limit + * + * @return int + */ + public function get_memory_limit() { + if ( function_exists( 'ini_get' ) ) { + $memory_limit = ini_get( 'memory_limit' ); + } else { + // Sensible default + $memory_limit = '128M'; + } + + if ( ! $memory_limit || -1 == $memory_limit ) { + // Unlimited, set to 32GB + $memory_limit = '32000M'; + } + + return intval( $memory_limit ) * 1024 * 1024; + } + /** * Count attachments on a site * diff --git a/classes/as3cf-notices.php b/classes/as3cf-notices.php index fbcf4515..a32ff78d 100644 --- a/classes/as3cf-notices.php +++ b/classes/as3cf-notices.php @@ -176,7 +176,7 @@ protected function dismiss_notice( $notice_id ) { $notice = $this->find_notice_by_id( $notice_id ); if ( $notice ) { if ( $notice['only_show_to_user'] ) { - $notices = get_user_meta( $user_id, 'as3cf_notices' ); + $notices = get_user_meta( $user_id, 'as3cf_notices', true ); unset( $notices[ $notice['id'] ] ); $this->update_user_meta( $user_id, 'as3cf_notices', $notices ); @@ -291,6 +291,7 @@ public function admin_notices() { } $user_notices = get_user_meta( $user_id, 'as3cf_notices', true ); + $user_notices = $this->cleanup_corrupt_user_notices( $user_id, $user_notices ); if ( is_array( $user_notices ) && ! empty( $user_notices ) ) { foreach ( $user_notices as $notice ) { $this->maybe_show_notice( $notice, $dismissed_notices ); @@ -305,6 +306,32 @@ public function admin_notices() { } } + /** + * Cleanup corrupt user notices. Corrupt notices start with a + * numerically indexed array, opposed to string ID + * + * @param int $user_id + * @param array $notices + * + * @return array + */ + protected function cleanup_corrupt_user_notices( $user_id, $notices ) { + if ( ! is_array( $notices ) || empty( $notices ) ) { + return $notices; + } + + foreach ( $notices as $key => $notice ) { + if ( is_int( $key ) ) { + // Corrupt, remove + unset( $notices[ $key ] ); + + $this->update_user_meta( $user_id, 'as3cf_notices', $notices ); + } + } + + return $notices; + } + /** * If it should be shown, display an individual notice * diff --git a/classes/as3cf-plugin-compatibility.php b/classes/as3cf-plugin-compatibility.php index 49c4ef00..95776806 100644 --- a/classes/as3cf-plugin-compatibility.php +++ b/classes/as3cf-plugin-compatibility.php @@ -43,9 +43,24 @@ function __construct( $as3cf ) { } /** - * Register the compatibility hooks + * Register the compatibility hooks for the plugin. */ function compatibility_init() { + /* + * WP_Customize_Control + * /wp-includes/class-wp-customize_control.php + */ + add_filter( 'attachment_url_to_postid', array( $this, 'customizer_background_image' ), 10, 2 ); + + if ( $this->as3cf->is_plugin_setup() ) { + $this->compatibility_init_if_setup(); + } + } + + /** + * Register the compatibility hooks as long as the plugin is setup. + */ + function compatibility_init_if_setup() { // Add notices about compatibility addons to install add_action( 'admin_init', array( $this, 'maybe_render_compatibility_addons_notice' ) ); @@ -68,12 +83,6 @@ function compatibility_init() { add_filter( 'as3cf_get_attached_file', array( $this, 'customizer_crop_download_file' ), 10, 4 ); add_filter( 'as3cf_upload_attachment_local_files_to_remove', array( $this, 'customizer_crop_remove_original_image' ), 10, 3 ); - /* - * WP_Customize_Control - * /wp-includes/class-wp-customize_control.php - */ - add_filter( 'attachment_url_to_postid', array( $this, 'customizer_background_image' ), 10, 2 ); - /* * Regenerate Thumbnails * https://wordpress.org/plugins/regenerate-thumbnails/ @@ -129,7 +138,10 @@ public function get_compatibility_addons_to_install() { continue; } - $addons_to_install[ $addon_slug ] = $addon['title']; + $addons_to_install[ $addon_slug ] = array( + 'title' => $addon['title'], + 'url' => $addon['url'], + ); } return $addons_to_install; @@ -163,11 +175,14 @@ public function maybe_render_compatibility_addons_notice() { $title = __( 'WP Offload S3 Compatibility Addons', 'amazon-s3-and-cloudfront' ); $compat_url = 'https://deliciousbrains.com/wp-offload-s3/doc/compatibility-with-other-plugins/'; $compat_link = sprintf( '%s', $compat_url, __( 'compatibility addons', 'amazon-s3-and-cloudfront' ) ); - $message = sprintf( __( "To get WP Offload S3 to work with certain 3rd party plugins, you must install and activate some of our %s. We've detected the following addons need to be installed.", 'amazon-s3-and-cloudfront' ), $compat_link ); + $message = sprintf( __( "To get WP Offload S3 to work with certain 3rd party plugins, you might need to install and activate some of our %s. We've detected the following addons might need to be installed. Please click the links for more information about each addon to determine if you need it or not.", 'amazon-s3-and-cloudfront' ), $compat_link ); $notice_addons_text = $this->render_addon_list( $addons_to_install ); - $notice_addons_text .= '
' . __( 'You will need to purchase a license to get access to these addons.', 'amazon-s3-and-cloudfront' ) . '
'; - $notice_addons_text .= sprintf( '', 'https://deliciousbrains.com/wp-offload-s3/pricing/', __( 'View Licenses', 'amazon-s3-and-cloudfront' ) ); + $support_email = 'nom@deliciousbrains.com'; + $support_link = sprintf( '%1$s', $support_email ); + + $notice_addons_text .= '' . sprintf( __( "You will need to purchase a license to get access to these addons. If you're having trouble determining whether or not you need the addons, send an email to %s.", 'amazon-s3-and-cloudfront' ), $support_link ). '
'; + $notice_addons_text .= sprintf( '', 'https://deliciousbrains.com/wp-offload-s3/pricing/', __( 'View Licenses', 'amazon-s3-and-cloudfront' ) ); $notice_addons_text = apply_filters( 'wpos3_compat_addons_notice', $notice_addons_text, $addons_to_install ); @@ -179,7 +194,7 @@ public function maybe_render_compatibility_addons_notice() { $notice = '' . $title . ' — ' . $message . '
' . $notice_addons_text; $notice_args = array( - 'type' => 'notice-warning', + 'type' => 'notice-info', 'custom_id' => $notice_id, 'only_show_to_user' => false, 'flash' => false, @@ -234,7 +249,9 @@ protected function render_addon_list( $addons ) { $html = '