Merged in feature/MAW-855-import-code-into-aws (pull request #2)

code import from pantheon

* code import from pantheon
This commit is contained in:
Tony Volpe
2023-12-04 23:08:14 +00:00
parent 8c9b1312bc
commit 8f4b5efda6
4766 changed files with 185592 additions and 239967 deletions

View File

@@ -0,0 +1,81 @@
<?php
namespace Imagify\Admin;
use Imagify\Traits\InstanceGetterTrait;
use Imagify\User\User;
use Imagify_Views;
/**
* Admin bar handler
*/
class AdminBar {
use InstanceGetterTrait;
/**
* Launch the hooks.
*
* @return void
*/
public function init() {
if ( wp_doing_ajax() ) {
add_action( 'wp_ajax_imagify_get_admin_bar_profile', array( $this, 'get_admin_bar_profile_callback' ) );
}
}
/**
* Get admin bar profile output.
*
* @return void
*/
public function get_admin_bar_profile_callback() {
imagify_check_nonce( 'imagify-get-admin-bar-profile', 'imagifygetadminbarprofilenonce' );
if ( ! imagify_get_context( 'wp' )->current_user_can( 'manage' ) ) {
imagify_die();
}
$user = new User();
$views = Imagify_Views::get_instance();
$unconsumed_quota = $views->get_quota_percent();
$text = '';
$button_text = '';
$upgrade_link = '';
if ( $user->is_free() ) {
$text = esc_html__( 'Upgrade your plan now for more!', 'rocket' ) . '<br>' .
esc_html__( 'From $4.99/month only, keep going with image optimization!', 'rocket' );
$button_text = esc_html__( 'Upgrade My Plan', 'rocket' );
$upgrade_link = IMAGIFY_APP_DOMAIN . '/subscription/?utm_source=plugin&utm_medium=notification';
} elseif ( $user->is_growth() ) {
$text = esc_html__( 'Switch to Infinite plan for unlimited optimization:', 'rocket' ) . '<br>';
if ( $user->is_monthly ) {
$text .= esc_html__( 'For $9.99/month, optimize as many images as you like!', 'rocket' );
$upgrade_link = IMAGIFY_APP_DOMAIN . '/subscription/plan_switch/?label=infinite&payment_plan=1&utm_source=plugin&utm_medium=notification ';
} else {
$text .= esc_html__( 'For $99.9/year, optimize as many images as you like!', 'rocket' );
$upgrade_link = IMAGIFY_APP_DOMAIN . '/subscription/plan_switch/?label=infinite&payment_plan=2&utm_source=plugin&utm_medium=notification ';
}
$button_text = esc_html__( 'Switch To Infinite Plan', 'rocket' );
}
$data = [
'quota_icon' => $views->get_quota_icon(),
'quota_class' => $views->get_quota_class(),
'plan_label' => $user->plan_label,
'plan_with_quota' => $user->is_free() || $user->is_growth(),
'unconsumed_quota' => $unconsumed_quota,
'user_quota' => $user->quota,
'next_update' => $user->next_date_update,
'text' => $text,
'button_text' => $button_text,
'upgrade_link' => $upgrade_link,
];
$template = $views->get_template( 'admin/admin-bar-status', $data );
wp_send_json_success( $template );
}
}

View File

@@ -413,13 +413,14 @@ class Bulk {
*
* @since 1.9
*
* @param string $method The method used: 'GET' (default), or 'POST'.
* @param string $parameter The name of the parameter to look for.
* @param string $method The method used: 'GET' (default), or 'POST'.
* @param string $parameter The name of the parameter to look for.
*
* @return string
*/
public function get_context( $method = 'GET', $parameter = 'context' ) {
$method = 'POST' === $method ? INPUT_POST : INPUT_GET;
$context = filter_input( $method, $parameter, FILTER_SANITIZE_STRING );
$context = 'POST' === $method ? wp_unslash( $_POST[ $parameter ] ) : wp_unslash( $_GET[ $parameter ] ); //phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended
$context = htmlspecialchars( $context );
return imagify_sanitize_context( $context );
}
@@ -557,7 +558,7 @@ class Bulk {
public function bulk_get_stats_callback() {
imagify_check_nonce( 'imagify-bulk-optimize' );
$folder_types = filter_input( INPUT_GET, 'types', FILTER_SANITIZE_STRING, FILTER_REQUIRE_ARRAY );
$folder_types = filter_input( INPUT_GET, 'types', FILTER_REQUIRE_ARRAY );
$folder_types = is_array( $folder_types ) ? array_filter( $folder_types, 'is_string' ) : [];
if ( ! $folder_types ) {

View File

@@ -95,6 +95,7 @@ class CustomFolders extends AbstractBulk {
$files_table = Imagify_Files_DB::get_instance()->get_table_name();
$folders_table = Imagify_Folders_DB::get_instance()->get_table_name();
$mime_types = Imagify_DB::get_mime_types( 'image' );
$mime_types = str_replace( ",'image/webp'", '', $mime_types );
$webp_suffix = constant( imagify_get_optimization_process_class_name( 'custom-folders' ) . '::WEBP_SUFFIX' );
$files = $wpdb->get_results( $wpdb->prepare( // WPCS: unprepared SQL ok.
"

View File

@@ -184,6 +184,7 @@ class WP extends AbstractBulk {
$this->set_no_time_limit();
$mime_types = Imagify_DB::get_mime_types( 'image' );
$mime_types = str_replace( ",'image/webp'", '', $mime_types );
$statuses = Imagify_DB::get_post_statuses();
$nodata_join = Imagify_DB::get_required_wp_metadata_join_clause();
$nodata_where = Imagify_DB::get_required_wp_metadata_where_clause( [

View File

@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Imagify\Notices;
use Imagify\Traits\InstanceGetterTrait;
use Imagify\User\User;
/**
* Class that handles the admin notices.
@@ -66,8 +67,6 @@ class Notices {
'http-block-external',
// This warning is displayed when the grid view is active on the library. Dismissible.
'grid-view',
// This warning is displayed to warn the user that the quota is almost consumed for the current month. Dismissible.
'almost-over-quota',
// This warning is displayed if the backup folder is not writable. NOT dismissible.
'backup-folder-not-writable',
// This notice is displayed to rate the plugin after 100 optimizations & 7 days after the first installation. Dismissible.
@@ -76,6 +75,8 @@ class Notices {
'wp-rocket',
'bulk-optimization-complete',
'bulk-optimization-running',
'upsell-banner',
'upsell-admin-bar',
];
/**
@@ -250,7 +251,7 @@ class Notices {
public function renew_almost_over_quota_notice() {
global $wpdb;
$results = $wpdb->get_results( $wpdb->prepare( "SELECT umeta_id, user_id FROM $wpdb->usermeta WHERE meta_key = %s AND meta_value LIKE %s", self::DISMISS_META_NAME, '%almost-over-quota%' ) );
$results = $wpdb->get_results( $wpdb->prepare( "SELECT umeta_id, user_id FROM $wpdb->usermeta WHERE meta_key = %s AND meta_value LIKE %s", self::DISMISS_META_NAME, '%upsell%' ) );
if ( ! $results ) {
return;
@@ -271,7 +272,8 @@ class Notices {
// Renew the notice for all users.
foreach ( $results as $result ) {
self::renew_notice( 'almost-over-quota', $result->user_id );
self::renew_notice( 'upsell-banner', $result->user_id );
self::renew_notice( 'upsell-admin-bar', $result->user_id );
}
}
@@ -439,45 +441,6 @@ class Notices {
return $display;
}
/**
* Tell if the 'almost-over-quota' notice should be displayed.
*
* @since 1.7.0
*
* @return bool|object An Imagify user object. False otherwise.
*/
public function display_almost_over_quota() {
static $display;
if ( isset( $display ) ) {
return $display;
}
$display = false;
if ( ! $this->user_can( 'almost-over-quota' ) ) {
return $display;
}
if ( ! imagify_is_screen( 'imagify-settings' ) && ! imagify_is_screen( 'bulk' ) ) {
return $display;
}
if ( self::notice_is_dismissed( 'almost-over-quota' ) ) {
return $display;
}
$user = new \Imagify_User();
// Don't display the notice if the user's unconsumed quota is superior to 20%.
if ( $user->get_percent_unconsumed_quota() > 20 ) {
return $display;
}
$display = $user;
return $display;
}
/**
* Tell if the 'backup-folder-not-writable' notice should be displayed.
*

View File

@@ -25,6 +25,7 @@ abstract class AbstractData implements DataInterface {
*/
protected $default_optimization_data = [
'status' => '',
'message' => '',
'level' => false,
'sizes' => [],
'stats' => [

View File

@@ -159,6 +159,10 @@ class CustomFolders extends AbstractData {
$old_data['hash'] = md5_file( $file_path );
}
if ( key_exists( 'message', $data ) ) {
$old_data['message'] = $data['message'];
}
if ( ! $data['success'] ) {
/**
* Error.

View File

@@ -93,8 +93,13 @@ class WP extends AbstractData {
'original_size' => 0,
'optimized_size' => 0,
'percent' => 0,
'message' => '',
], $old_data['stats'] );
if ( key_exists( 'message', $data ) ) {
$old_data['message'] = $data['message'];
}
if ( ! $data['success'] ) {
/**
* Error.

View File

@@ -530,6 +530,10 @@ class File {
return new \WP_Error( 'temp_file_not_found', $temp_file->get_error_message() );
}
if ( property_exists( $response, 'message' ) ) {
$args['convert'] = '';
}
if ( 'webp' === $args['convert'] ) {
$destination_path = $this->get_path_to_webp();
$this->path = $destination_path;

View File

@@ -656,6 +656,14 @@ abstract class AbstractProcess implements ProcessInterface {
'non_webp_file_path' => $sizes[ $thumb_size ]['path'], // Don't use $path nor $file->get_path(), it may return the path to a temporary file.
'optimization_level' => $optimization_level,
] );
if ( property_exists( $response, 'message' ) ) {
$path_is_temp = false;
if ( $path !== $sizes[ $thumb_size ]['path'] ) {
$this->filesystem->delete( $path );
}
$path = $sizes[ $thumb_size ]['path'];
}
}
}
}
@@ -731,7 +739,7 @@ abstract class AbstractProcess implements ProcessInterface {
}
// Optimization succeeded.
if ( $args['is_webp'] ) {
if ( ! property_exists( $args['response'], 'message' ) && $args['is_webp'] ) {
/**
* We just created a WebP version:
* Check if it is lighter than the (maybe optimized) non-WebP file.
@@ -776,7 +784,7 @@ abstract class AbstractProcess implements ProcessInterface {
$webp_size = $args['non_webp_thumb_size'] . static::WEBP_SUFFIX;
$webp_file_size = $this->get_data()->get_size_data( $webp_size, 'optimized_size' );
if ( ! $webp_file_size || $webp_file_size < $args['response']->new_size ) {
if ( property_exists( $args['response'], 'message' ) || ! $webp_file_size || $webp_file_size < $args['response']->new_size ) {
// The WebP file is lighter than this one.
return $args['response'];
}
@@ -1531,6 +1539,38 @@ abstract class AbstractProcess implements ProcessInterface {
return is_string( $data ) && strpos( $data, $needle );
}
/**
* Tell if the media has all WebP versions.
*
* @return bool
*/
public function is_full_webp() {
if ( ! $this->is_valid() ) {
return false;
}
if ( ! $this->get_media()->is_image() ) {
return false;
}
$data = $this->get_data()->get_optimization_data();
$sizes = $data['sizes'];
if ( empty( $sizes ) ) {
return false;
}
$keys = array_keys( $sizes );
$non_webp_keys = array_values(array_filter($keys, function ( $key ) {
return strpos( $key, static::WEBP_SUFFIX ) === false;
}));
return array_reduce($non_webp_keys, function ( $is_fully, $key ) use ( $sizes ) {
return key_exists( $key . self::WEBP_SUFFIX, $sizes ) && $is_fully;
}, true);
}
/**
* Tell if a WebP version can be created for the given file.
* Make sure the file is an image before using this method.
@@ -1757,6 +1797,9 @@ abstract class AbstractProcess implements ProcessInterface {
// Size data.
$data['success'] = true;
if ( property_exists( $response, 'message' ) ) {
$data['message'] = imagify_translate_api_message( $response->message );
}
$data['original_size'] = $response->original_size;
$data['optimized_size'] = $response->new_size;
}
@@ -1785,6 +1828,9 @@ abstract class AbstractProcess implements ProcessInterface {
*/
$data = (array) apply_filters( "imagify{$_unauthorized}_file_optimization_data", $data, $response, $size, $level, $this->get_data() );
if ( property_exists( $response, 'message' ) ) {
$size = str_replace( '@imagify-webp', '', $size );
}
// Store.
$this->get_data()->update_size_optimization_data( $size, $data );

View File

@@ -274,6 +274,13 @@ interface ProcessInterface {
*/
public function is_size_webp( $size_name );
/**
* Tell if the media has all WebP versions.
*
* @return bool
*/
public function is_full_webp();
/**
* Tell if the media has WebP versions.
*

View File

@@ -7,6 +7,7 @@ use Imagify\Bulk\Bulk;
use Imagify\CLI\BulkOptimizeCommand;
use Imagify\CLI\GenerateMissingWebpCommand;
use Imagify\Notices\Notices;
use Imagify\Admin\AdminBar;
/**
* Main plugin class.
@@ -56,6 +57,7 @@ class Plugin {
\Imagify\Job\MediaOptimization::get_instance()->init();
\Imagify\Stats\OptimizedMediaWithoutWebp::get_instance()->init();
Bulk::get_instance()->init();
AdminBar::get_instance()->init();
if ( is_admin() ) {
Notices::get_instance()->init();

View File

@@ -0,0 +1,292 @@
<?php
namespace Imagify\User;
use Date;
use Imagify_Data;
use WP_Error;
/**
* Imagify User class.
*
* @since 1.0
*/
class User {
/**
* The Imagify user ID.
*
* @since 1.0
*
* @var string
*/
public $id;
/**
* The user email.
*
* @since 1.0
*
* @var string
*/
public $email;
/**
* The plan ID.
*
* @since 1.0
*
* @var int
*/
public $plan_id;
/**
* The plan label.
*
* @since 1.2
*
* @var string
*/
public $plan_label;
/**
* The total quota.
*
* @since 1.0
*
* @var int
*/
public $quota;
/**
* The total extra quota (Imagify Pack).
*
* @since 1.0
*
* @var int
*/
public $extra_quota;
/**
* The extra quota consumed.
*
* @since 1.0
*
* @var int
*/
public $extra_quota_consumed;
/**
* The current month consumed quota.
*
* @since 1.0
*
* @var int
*/
public $consumed_current_month_quota;
/**
* The next month date to credit the account.
*
* @since 1.1.1
*
* @var Date
*/
public $next_date_update;
/**
* If the account is activate or not.
*
* @since 1.0.1
*
* @var bool
*/
public $is_active;
/**
* If the account is monthly or yearly.
*
* @var bool
*/
public $is_monthly;
/**
* Store a \WP_Error object if the request to fetch the user data failed.
* False overwise.
*
* @var bool|WP_Error
* @since 1.9.9
*/
private $error;
/**
* The constructor.
*
* @since 1.0
*
* @return void
*/
public function __construct() {
$user = get_imagify_user();
if ( is_wp_error( $user ) ) {
$this->error = $user;
return;
}
$this->id = $user->id;
$this->email = $user->email;
$this->plan_id = (int) $user->plan_id;
$this->plan_label = ucfirst( $user->plan_label );
$this->quota = $user->quota;
$this->extra_quota = $user->extra_quota;
$this->extra_quota_consumed = $user->extra_quota_consumed;
$this->consumed_current_month_quota = $user->consumed_current_month_quota;
$this->next_date_update = $user->next_date_update;
$this->is_active = $user->is_active;
$this->is_monthly = $user->is_monthly;
$this->error = false;
}
/**
* Get the possible error returned when fetching user data.
*
* @return bool|WP_Error A \WP_Error object if the request to fetch the user data failed. False overwise.
* @since 1.9.9
*/
public function get_error() {
return $this->error;
}
/**
* Percentage of consumed quota, including extra quota.
*
* @since 1.0
*
* @return float|int
*/
public function get_percent_consumed_quota() {
static $done = false;
if ( $this->get_error() ) {
return 0;
}
$quota = $this->quota;
$consumed_quota = $this->consumed_current_month_quota;
if ( imagify_round_half_five( $this->extra_quota_consumed ) < $this->extra_quota ) {
$quota += $this->extra_quota;
$consumed_quota += $this->extra_quota_consumed;
}
if ( ! $quota || ! $consumed_quota ) {
$percent = 0;
} else {
$percent = 100 * $consumed_quota / $quota;
$percent = round( $percent, 1 );
$percent = min( max( 0, $percent ), 100 );
}
$percent = (float) $percent;
if ( $done ) {
return $percent;
}
$previous_percent = Imagify_Data::get_instance()->get( 'previous_quota_percent' );
// Percent is not 100% anymore.
if ( 100.0 === (float) $previous_percent && $percent < 100 ) {
/**
* Triggered when the consumed quota percent decreases below 100%.
*
* @since 1.7
* @author Grégory Viguier
*
* @param float|int $percent The current percentage of consumed quota.
*/
do_action( 'imagify_not_over_quota_anymore', $percent );
}
// Percent is not >= 80% anymore.
if ( ( (float) $previous_percent >= 80.0 && $percent < 80 ) ) {
/**
* Triggered when the consumed quota percent decreases below 80%.
*
* @since 1.7
* @author Grégory Viguier
*
* @param float|int $percent The current percentage of consumed quota.
* @param float|int $previous_percent The previous percentage of consumed quota.
*/
do_action( 'imagify_not_almost_over_quota_anymore', $percent, $previous_percent );
}
if ( (float) $previous_percent !== (float) $percent ) {
Imagify_Data::get_instance()->set( 'previous_quota_percent', $percent );
}
$done = true;
return $percent;
}
/**
* Count percent of unconsumed quota.
*
* @since 1.0
*
* @return float|int
*/
public function get_percent_unconsumed_quota() {
return 100 - $this->get_percent_consumed_quota();
}
/**
* Check if the user has a free account.
*
* @since 1.1.1
*
* @return bool
*/
public function is_free() {
return 1 === $this->plan_id;
}
/**
* Check if the user is a growth account
*
* @return bool
*/
public function is_growth() {
return ( 16 === $this->plan_id || 18 === $this->plan_id );
}
/**
* Check if the user is an infinite account
*
* @return bool
*/
public function is_infinite() {
return ( 15 === $this->plan_id || 17 === $this->plan_id );
}
/**
* Check if the user has consumed all his/her quota.
*
* @since 1.1.1
* @since 1.9.9 Return false if the request to fetch the user data failed.
*
* @return bool
*/
public function is_over_quota() {
if ( $this->get_error() ) {
return false;
}
return (
$this->is_free()
&&
floatval( 100 ) === round( $this->get_percent_consumed_quota() )
);
}
}

View File

@@ -3,6 +3,7 @@ namespace Imagify\Webp\RewriteRules;
use Imagify\Notices\Notices;
use Imagify\Traits\InstanceGetterTrait;
use Imagify\WriteFile\AbstractWriteDirConfFile;
/**
* Display WebP images on the site with rewrite rules.
@@ -12,6 +13,13 @@ use Imagify\Traits\InstanceGetterTrait;
class Display {
use InstanceGetterTrait;
/**
* Configuration file writer.
*
* @var AbstractWriteDirConfFile
*/
protected $server_conf;
/**
* Option value.
*