Plugin Updates
This commit is contained in:
@@ -44,7 +44,7 @@ class AdminBar {
|
||||
|
||||
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' );
|
||||
esc_html__( 'From $5.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() ) {
|
||||
|
||||
31
wp/wp-content/plugins/imagify/classes/Avif/Apache.php
Normal file
31
wp/wp-content/plugins/imagify/classes/Avif/Apache.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Avif;
|
||||
|
||||
use Imagify\WriteFile\AbstractApacheDirConfFile;
|
||||
|
||||
/**
|
||||
* Add and remove contents to the .htaccess file to display AVIF images on the site.
|
||||
*/
|
||||
class Apache extends AbstractApacheDirConfFile {
|
||||
|
||||
/**
|
||||
* Name of the tag used as block delemiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TAG_NAME = 'Imagify: avif file type';
|
||||
|
||||
/**
|
||||
* Get unfiltered new contents to write into the file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_raw_new_contents() {
|
||||
return trim( '
|
||||
<IfModule mod_mime.c>
|
||||
AddType image/avif .avif
|
||||
</IfModule>' );
|
||||
}
|
||||
}
|
||||
169
wp/wp-content/plugins/imagify/classes/Avif/Display.php
Normal file
169
wp/wp-content/plugins/imagify/classes/Avif/Display.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Avif;
|
||||
|
||||
use Imagify\EventManagement\SubscriberInterface;
|
||||
use Imagify\Notices\Notices;
|
||||
use Imagify\WriteFile\WriteFileInterface;
|
||||
|
||||
/**
|
||||
* Display AVIF images on the site using picture tag.
|
||||
*/
|
||||
class Display implements SubscriberInterface {
|
||||
/**
|
||||
* Server conf object.
|
||||
*
|
||||
* @var WriteFileInterface|null
|
||||
* @since 1.9
|
||||
*/
|
||||
protected $server_conf = null;
|
||||
|
||||
/**
|
||||
* Returns an array of events this subscriber listens to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'imagify_settings_on_save' => [ 'maybe_add_rewrite_rules', 12 ],
|
||||
'imagify_activation' => 'activate',
|
||||
'imagify_deactivation' => 'deactivate',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* If display Next-Gen images, add the AVIF type to the .htaccess/etc file.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $values The option values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function maybe_add_rewrite_rules( $values ) {
|
||||
if ( ! $this->get_server_conf() ) {
|
||||
return $values;
|
||||
}
|
||||
|
||||
$enabled = isset( $values['display_nextgen'] ) ? true : false;
|
||||
$result = false;
|
||||
|
||||
if ( $enabled ) {
|
||||
// Add the AVIF file type.
|
||||
$result = $this->get_server_conf()->add();
|
||||
} elseif ( ! $enabled ) {
|
||||
// Remove the AVIF file type.
|
||||
$result = $this->get_server_conf()->remove();
|
||||
}
|
||||
|
||||
if ( ! is_wp_error( $result ) ) {
|
||||
return $values;
|
||||
}
|
||||
|
||||
// Display an error message.
|
||||
if ( is_multisite() && strpos( wp_get_referer(), network_admin_url( '/' ) ) === 0 ) {
|
||||
Notices::get_instance()->add_network_temporary_notice( $result->get_error_message() );
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
Notices::get_instance()->add_site_temporary_notice( $result->get_error_message() );
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add rules on plugin activation.
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
public function activate() {
|
||||
$conf = $this->get_server_conf();
|
||||
|
||||
if ( ! $conf ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! get_imagify_option( 'display_nextgen' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( is_wp_error( $conf->is_file_writable() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$conf->add();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove rules on plugin deactivation.
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
public function deactivate() {
|
||||
$conf = $this->get_server_conf();
|
||||
|
||||
if ( ! $conf ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$file_path = $conf->get_file_path();
|
||||
$filesystem = \Imagify_Filesystem::get_instance();
|
||||
|
||||
if ( ! $filesystem->exists( $file_path ) ) {
|
||||
return;
|
||||
}
|
||||
if ( ! $filesystem->is_writable( $file_path ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$conf->remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the directory conf file.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @param bool $relative True to get a path relative to the site’s root.
|
||||
* @return string|bool The file path. False on failure.
|
||||
*/
|
||||
public function get_file_path( $relative = false ) {
|
||||
if ( ! $this->get_server_conf() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$file_path = $this->get_server_conf()->get_file_path();
|
||||
|
||||
if ( $relative ) {
|
||||
return \Imagify_Filesystem::get_instance()->make_path_relative( $file_path );
|
||||
}
|
||||
|
||||
return $file_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the server conf instance.
|
||||
* Note: nothing needed for nginx.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @return WriteFileInterface
|
||||
*/
|
||||
protected function get_server_conf() {
|
||||
global $is_apache, $is_iis7;
|
||||
|
||||
if ( isset( $this->server_conf ) ) {
|
||||
return $this->server_conf;
|
||||
}
|
||||
|
||||
if ( $is_apache ) {
|
||||
$this->server_conf = new Apache();
|
||||
} elseif ( $is_iis7 ) {
|
||||
$this->server_conf = new IIS();
|
||||
}
|
||||
|
||||
return $this->server_conf;
|
||||
}
|
||||
}
|
||||
32
wp/wp-content/plugins/imagify/classes/Avif/IIS.php
Normal file
32
wp/wp-content/plugins/imagify/classes/Avif/IIS.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Avif;
|
||||
|
||||
use Imagify\WriteFile\AbstractIISDirConfFile;
|
||||
|
||||
/**
|
||||
* Add and remove contents to the web.config file to display AVIF images on the site.
|
||||
*/
|
||||
class IIS extends AbstractIISDirConfFile {
|
||||
|
||||
/**
|
||||
* Name of the tag used as block delemiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TAG_NAME = 'Imagify: avif file type';
|
||||
|
||||
/**
|
||||
* Get unfiltered new contents to write into the file.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_raw_new_contents() {
|
||||
return trim( '
|
||||
<!-- @parent /configuration/system.webServer -->
|
||||
<staticContent name="' . esc_attr( static::TAG_NAME ) . ' 1">
|
||||
<mimeMap fileExtension=".avif" mimeType="image/avif" />
|
||||
</staticContent>' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Avif\RewriteRules;
|
||||
|
||||
use Imagify\WriteFile\AbstractApacheDirConfFile;
|
||||
|
||||
/**
|
||||
* Add and remove rewrite rules to the .htaccess file to display AVIF images on the site.
|
||||
*/
|
||||
class Apache extends AbstractApacheDirConfFile {
|
||||
|
||||
/**
|
||||
* Name of the tag used as block delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TAG_NAME = 'Imagify: rewrite rules for avif';
|
||||
|
||||
/**
|
||||
* Get unfiltered new contents to write into the file.
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_raw_new_contents() {
|
||||
$extensions = $this->get_extensions_pattern();
|
||||
$extensions = str_replace( '|avif', '', $extensions );
|
||||
$home_root = wp_parse_url( home_url( '/' ) );
|
||||
$home_root = $home_root['path'];
|
||||
|
||||
return trim( '
|
||||
<IfModule mod_setenvif.c>
|
||||
# Vary: Accept for all the requests to jpeg, png, and gif.
|
||||
SetEnvIf Request_URI "\.(' . $extensions . ')$" REQUEST_image
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine On
|
||||
RewriteBase ' . $home_root . '
|
||||
|
||||
# Check if browser supports AVIF images.
|
||||
# Update the MIME type accordingly.
|
||||
RewriteCond %{HTTP_ACCEPT} image/avif
|
||||
|
||||
# Check if AVIF replacement image exists.
|
||||
RewriteCond %{REQUEST_FILENAME}.avif -f
|
||||
|
||||
# Serve AVIF image instead.
|
||||
RewriteRule (.+)\.(' . $extensions . ')$ $1.$2.avif [T=image/avif,NC]
|
||||
</IfModule>
|
||||
|
||||
<IfModule mod_headers.c>
|
||||
# Update the MIME type accordingly.
|
||||
Header append Vary Accept env=REQUEST_image
|
||||
</IfModule>' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Avif\RewriteRules;
|
||||
|
||||
use Imagify\EventManagement\SubscriberInterface;
|
||||
use Imagify\Notices\Notices;
|
||||
use Imagify\WriteFile\WriteFileInterface;
|
||||
|
||||
/**
|
||||
* Display Avif images on the site with rewrite rules.
|
||||
*/
|
||||
class Display implements SubscriberInterface {
|
||||
/**
|
||||
* Configuration file writer.
|
||||
*
|
||||
* @var WriteFileInterface|null
|
||||
*/
|
||||
protected $server_conf = null;
|
||||
|
||||
/**
|
||||
* Option value.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const OPTION_VALUE = 'rewrite';
|
||||
|
||||
/**
|
||||
* Returns an array of events this subscriber listens to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'imagify_settings_on_save' => [ 'maybe_add_rewrite_rules', 11 ],
|
||||
'imagify_settings_webp_info' => 'maybe_add_avif_info',
|
||||
'imagify_activation' => 'activate',
|
||||
'imagify_deactivation' => 'deactivate',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* If display AVIF images via rewrite rules, add the rules to the .htaccess/etc file.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $values The option values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function maybe_add_rewrite_rules( $values ) {
|
||||
$was_enabled = (bool) get_imagify_option( 'display_nextgen' );
|
||||
$is_enabled = ! empty( $values['display_nextgen'] );
|
||||
|
||||
// Which method?
|
||||
$old_value = get_imagify_option( 'display_nextgen_method' );
|
||||
$new_value = ! empty( $values['display_nextgen_method'] ) ? $values['display_nextgen_method'] : '';
|
||||
|
||||
// Decide when to add or remove rules.
|
||||
$is_rewrite = self::OPTION_VALUE === $new_value;
|
||||
$was_rewrite = self::OPTION_VALUE === $old_value;
|
||||
|
||||
if ( ! $this->get_server_conf() ) {
|
||||
return $values;
|
||||
}
|
||||
|
||||
$result = false;
|
||||
|
||||
if ( $is_enabled && $is_rewrite && ( ! $was_enabled || ! $was_rewrite ) ) {
|
||||
// Add the rewrite rules.
|
||||
$result = $this->get_server_conf()->add();
|
||||
} elseif ( $was_enabled && $was_rewrite && ( ! $is_enabled || ! $is_rewrite ) ) {
|
||||
// Remove the rewrite rules.
|
||||
$result = $this->get_server_conf()->remove();
|
||||
}
|
||||
|
||||
if ( ! is_wp_error( $result ) ) {
|
||||
return $values;
|
||||
}
|
||||
|
||||
// Display an error message.
|
||||
if ( is_multisite() && strpos( wp_get_referer(), network_admin_url( '/' ) ) === 0 ) {
|
||||
Notices::get_instance()->add_network_temporary_notice( $result->get_error_message() );
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
Notices::get_instance()->add_site_temporary_notice( $result->get_error_message() );
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the conf file is not writable, add a warning.
|
||||
*/
|
||||
public function maybe_add_avif_info() {
|
||||
$conf = $this->get_server_conf();
|
||||
|
||||
if ( ! $conf ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$writable = $conf->is_file_writable();
|
||||
|
||||
if ( is_wp_error( $writable ) ) {
|
||||
$rules = $conf->get_new_contents();
|
||||
|
||||
if ( ! $rules ) {
|
||||
// Uh?
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
/* translators: %s is a file name. */
|
||||
esc_html__( 'If you choose to use rewrite rules, you will have to add the following lines manually to the %s file:', 'imagify' ),
|
||||
'<code>' . $this->get_file_path( true ) . '</code>'
|
||||
);
|
||||
|
||||
echo '<pre class="code">' . esc_html( $rules ) . '</pre>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add rules on plugin activation.
|
||||
*/
|
||||
public function activate() {
|
||||
$conf = $this->get_server_conf();
|
||||
|
||||
if ( ! $conf ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! get_imagify_option( 'display_nextgen' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( self::OPTION_VALUE !== get_imagify_option( 'display_nextgen_method' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( is_wp_error( $conf->is_file_writable() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$conf->add();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove rules on plugin deactivation.
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
public function deactivate() {
|
||||
$conf = $this->get_server_conf();
|
||||
|
||||
if ( ! $conf ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! get_imagify_option( 'display_nextgen' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( self::OPTION_VALUE !== get_imagify_option( 'display_nextgen_method' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$file_path = $conf->get_file_path();
|
||||
$filesystem = \Imagify_Filesystem::get_instance();
|
||||
|
||||
if ( ! $filesystem->exists( $file_path ) ) {
|
||||
return;
|
||||
}
|
||||
if ( ! $filesystem->is_writable( $file_path ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$conf->remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the directory conf file.
|
||||
*
|
||||
* @param bool $relative True to get a path relative to the site’s root.
|
||||
*
|
||||
* @return string|bool The file path. False on failure.
|
||||
*/
|
||||
public function get_file_path( $relative = false ) {
|
||||
if ( ! $this->get_server_conf() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$file_path = $this->get_server_conf()->get_file_path();
|
||||
|
||||
if ( $relative ) {
|
||||
return \Imagify_Filesystem::get_instance()->make_path_relative( $file_path );
|
||||
}
|
||||
|
||||
return $file_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the server conf instance.
|
||||
*
|
||||
* @return WriteFileInterface
|
||||
*/
|
||||
protected function get_server_conf() {
|
||||
global $is_apache, $is_iis7, $is_nginx;
|
||||
|
||||
if ( isset( $this->server_conf ) ) {
|
||||
return $this->server_conf;
|
||||
}
|
||||
|
||||
if ( $is_apache ) {
|
||||
$this->server_conf = new Apache();
|
||||
} elseif ( $is_iis7 ) {
|
||||
$this->server_conf = new IIS();
|
||||
} elseif ( $is_nginx ) {
|
||||
$this->server_conf = new Nginx();
|
||||
}
|
||||
|
||||
return $this->server_conf;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Avif\RewriteRules;
|
||||
|
||||
use Imagify\WriteFile\AbstractIISDirConfFile;
|
||||
|
||||
/**
|
||||
* Add and remove rewrite rules to the web.config file to display AVIF images on the site.
|
||||
*/
|
||||
class IIS extends AbstractIISDirConfFile {
|
||||
|
||||
/**
|
||||
* Name of the tag used as block delemiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TAG_NAME = 'Imagify: rewrite rules for avif';
|
||||
|
||||
/**
|
||||
* Get unfiltered new contents to write into the file.
|
||||
*
|
||||
* @source https://github.com/igrigorik/webp-detect/blob/master/iis.config
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_raw_new_contents() {
|
||||
$extensions = $this->get_extensions_pattern();
|
||||
$extensions = str_replace( '|avif', '', $extensions );
|
||||
$home_root = wp_parse_url( home_url( '/' ) );
|
||||
$home_root = $home_root['path'];
|
||||
|
||||
return trim( '
|
||||
<!-- @parent /configuration/system.webServer/rewrite/rules -->
|
||||
<rule name="' . esc_attr( static::TAG_NAME ) . ' 2">
|
||||
<match url="^(' . $home_root . '.+)\.(' . $extensions . ')$" ignoreCase="true" />
|
||||
<conditions logicalGrouping="MatchAll">
|
||||
<add input="{HTTP_ACCEPT}" pattern="image/avif" ignoreCase="false" />
|
||||
<add input="{DOCUMENT_ROOT}/{R:1}{R:2}.avif" matchType="IsFile" />
|
||||
</conditions>
|
||||
<action type="Rewrite" url="{R:1}{R:2}.avif" logRewrittenUrl="true" />
|
||||
<serverVariables>
|
||||
<set name="ACCEPTS_AVIF" value="true" />
|
||||
</serverVariables>
|
||||
</rule>
|
||||
|
||||
<!-- @parent /configuration/system.webServer/rewrite/outboundRules -->
|
||||
<rule preCondition="IsAvif" name="' . esc_attr( static::TAG_NAME ) . ' 3">
|
||||
<match serverVariable="RESPONSE_Vary" pattern=".*" />
|
||||
<action type="Rewrite" value="Accept"/>
|
||||
</rule>
|
||||
<preConditions name="' . esc_attr( static::TAG_NAME ) . ' 4">
|
||||
<preCondition name="IsAvif">
|
||||
<add input="{ACCEPTS_AVIF}" pattern="true" ignoreCase="false" />
|
||||
</preCondition>
|
||||
</preConditions>' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Avif\RewriteRules;
|
||||
|
||||
use Imagify\WriteFile\AbstractNginxDirConfFile;
|
||||
|
||||
/**
|
||||
* Add and remove rewrite rules to the imagify.conf file to display AVIF images on the site.
|
||||
*/
|
||||
class Nginx extends AbstractNginxDirConfFile {
|
||||
|
||||
/**
|
||||
* Name of the tag used as block delimiter.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TAG_NAME = 'Imagify: rewrite rules for avif';
|
||||
|
||||
/**
|
||||
* Get unfiltered new contents to write into the file.
|
||||
*
|
||||
* @access protected
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_raw_new_contents() {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Avif;
|
||||
|
||||
use Imagify\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider;
|
||||
use Imagify\Avif\RewriteRules\Display as RewriteRules;
|
||||
|
||||
/**
|
||||
* Service provider for AVIF rewrite rules
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
/**
|
||||
* Services provided by this provider
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'avif_display',
|
||||
'avif_rewrite_rules',
|
||||
];
|
||||
|
||||
/**
|
||||
* Subscribers provided by this provider
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $subscribers = [
|
||||
'avif_display',
|
||||
'avif_rewrite_rules',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the provided classes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$this->getContainer()->share( 'avif_display', Display::class );
|
||||
$this->getContainer()->share( 'avif_rewrite_rules', RewriteRules::class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subscribers array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_subscribers() {
|
||||
return $this->subscribers;
|
||||
}
|
||||
}
|
||||
@@ -105,13 +105,19 @@ abstract class AbstractBulk implements BulkInterface {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if there are optimized media without WebP versions.
|
||||
* Tell if there are optimized media without next-gen versions.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @return int The number of media.
|
||||
*/
|
||||
public function has_optimized_media_without_webp() {
|
||||
return count( $this->get_optimized_media_ids_without_webp()['ids'] );
|
||||
public function has_optimized_media_without_nextgen() {
|
||||
$format = 'webp';
|
||||
|
||||
if ( get_imagify_option( 'convert_to_avif' ) ) {
|
||||
$format = 'avif';
|
||||
}
|
||||
|
||||
return count( $this->get_optimized_media_ids_without_format( $format )['ids'] );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,15 +17,15 @@ class Bulk {
|
||||
*/
|
||||
public function init() {
|
||||
add_action( 'imagify_optimize_media', [ $this, 'optimize_media' ], 10, 3 );
|
||||
add_action( 'imagify_convert_webp', [ $this, 'generate_webp_versions' ], 10, 2 );
|
||||
add_action( 'imagify_convert_webp_finished', [ $this, 'clear_webp_transients' ], 10, 2 );
|
||||
add_action( 'imagify_convert_next_gen', [ $this, 'generate_nextgen_versions' ], 10, 2 );
|
||||
add_action( 'wp_ajax_imagify_bulk_optimize', [ $this, 'bulk_optimize_callback' ] );
|
||||
add_action( 'wp_ajax_imagify_missing_webp_generation', [ $this, 'missing_webp_callback' ] );
|
||||
add_action( 'wp_ajax_imagify_missing_nextgen_generation', [ $this, 'missing_nextgen_callback' ] );
|
||||
add_action( 'wp_ajax_imagify_get_folder_type_data', [ $this, 'get_folder_type_data_callback' ] );
|
||||
add_action( 'wp_ajax_imagify_bulk_info_seen', [ $this, 'bulk_info_seen_callback' ] );
|
||||
add_action( 'wp_ajax_imagify_bulk_get_stats', [ $this, 'bulk_get_stats_callback' ] );
|
||||
add_action( 'imagify_after_optimize', [ $this, 'check_optimization_status' ], 10, 2 );
|
||||
add_action( 'imagify_deactivation', [ $this, 'delete_transients_data' ] );
|
||||
add_action( 'update_option_imagify_settings', [ $this, 'maybe_generate_missing_nextgen' ], 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,7 +37,7 @@ class Bulk {
|
||||
delete_transient( 'imagify_custom-folders_optimize_running' );
|
||||
delete_transient( 'imagify_wp_optimize_running' );
|
||||
delete_transient( 'imagify_bulk_optimization_complete' );
|
||||
delete_transient( 'imagify_missing_webp_total' );
|
||||
delete_transient( 'imagify_missing_next_gen_total' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,17 +173,31 @@ class Bulk {
|
||||
'message' => 'over-quota',
|
||||
];
|
||||
}
|
||||
$formats = imagify_nextgen_images_formats();
|
||||
$media_ids = [
|
||||
'ids' => [],
|
||||
'errors' => [
|
||||
'no_file_path' => [],
|
||||
'no_backup' => [],
|
||||
],
|
||||
];
|
||||
foreach ( $formats as $format ) {
|
||||
$result = $this->get_bulk_instance( $context )->get_optimized_media_ids_without_format( $format );
|
||||
$media_ids['ids'] = array_merge( $media_ids['ids'], $result['ids'] );
|
||||
}
|
||||
$get_unoptimized_media_ids = $this->get_bulk_instance( $context )->get_unoptimized_media_ids( $optimization_level );
|
||||
|
||||
$media_ids = $this->get_bulk_instance( $context )->get_unoptimized_media_ids( $optimization_level );
|
||||
$media_ids['ids'] = array_merge( $media_ids['ids'], $get_unoptimized_media_ids );
|
||||
|
||||
if ( empty( $media_ids ) ) {
|
||||
if ( empty( $media_ids['ids'] ) ) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'no-images',
|
||||
];
|
||||
}
|
||||
$media_ids['ids'] = array_unique( $media_ids['ids'] );
|
||||
|
||||
foreach ( $media_ids as $media_id ) {
|
||||
foreach ( $media_ids['ids'] as $media_id ) {
|
||||
try {
|
||||
as_enqueue_async_action(
|
||||
'imagify_optimize_media',
|
||||
@@ -213,13 +227,14 @@ class Bulk {
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the WebP generation
|
||||
* Runs the next-gen generation
|
||||
*
|
||||
* @param array $contexts An array of contexts (WP/Custom folders).
|
||||
* @param array $formats An array of format to generate.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function run_generate_webp( array $contexts ) {
|
||||
public function run_generate_nextgen( array $contexts, array $formats ) {
|
||||
if ( ! $this->can_optimize() ) {
|
||||
return [
|
||||
'success' => false,
|
||||
@@ -227,28 +242,29 @@ class Bulk {
|
||||
];
|
||||
}
|
||||
|
||||
delete_transient( 'imagify_stat_without_webp' );
|
||||
delete_transient( 'imagify_stat_without_next_gen' );
|
||||
|
||||
$medias = [];
|
||||
|
||||
foreach ( $contexts as $context ) {
|
||||
$media = $this->get_bulk_instance( $context )->get_optimized_media_ids_without_webp();
|
||||
foreach ( $formats as $format ) {
|
||||
$media = $this->get_bulk_instance( $context )->get_optimized_media_ids_without_format( $format );
|
||||
if ( ! $media['ids'] && $media['errors']['no_backup'] ) {
|
||||
// No backup, no next-gen.
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'no-backup',
|
||||
];
|
||||
} elseif ( ! $media['ids'] && $media['errors']['no_file_path'] ) {
|
||||
// Error.
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => __( 'The path to the selected files could not be retrieved.', 'imagify' ),
|
||||
];
|
||||
}
|
||||
|
||||
if ( ! $media['ids'] && $media['errors']['no_backup'] ) {
|
||||
// No backup, no WebP.
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => 'no-backup',
|
||||
];
|
||||
} elseif ( ! $media['ids'] && $media['errors']['no_file_path'] ) {
|
||||
// Error.
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => __( 'The path to the selected files could not be retrieved.', 'imagify' ),
|
||||
];
|
||||
$medias[ $context ] = $media['ids'];
|
||||
}
|
||||
|
||||
$medias[ $context ] = $media['ids'];
|
||||
}
|
||||
|
||||
if ( empty( $medias ) ) {
|
||||
@@ -266,12 +282,12 @@ class Bulk {
|
||||
foreach ( $media_ids as $media_id ) {
|
||||
try {
|
||||
as_enqueue_async_action(
|
||||
'imagify_convert_webp',
|
||||
'imagify_convert_next_gen',
|
||||
[
|
||||
'id' => $media_id,
|
||||
'context' => $context,
|
||||
],
|
||||
"imagify-{$context}-convert-webp"
|
||||
"imagify-{$context}-convert-nextgen"
|
||||
);
|
||||
} catch ( Exception $exception ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
|
||||
// nothing to do.
|
||||
@@ -279,7 +295,7 @@ class Bulk {
|
||||
}
|
||||
}
|
||||
|
||||
set_transient( 'imagify_missing_webp_total', $total, HOUR_IN_SECONDS );
|
||||
set_transient( 'imagify_missing_next_gen_total', $total, HOUR_IN_SECONDS );
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
@@ -310,13 +326,13 @@ class Bulk {
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the name of the class to use for bulk process.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @param int $class_name The class name.
|
||||
* @param string $context The context name.
|
||||
*/
|
||||
* Filter the name of the class to use for bulk process.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @param int $class_name The class name.
|
||||
* @param string $context The context name.
|
||||
*/
|
||||
$class_name = apply_filters( 'imagify_bulk_class_name', $class_name, $context );
|
||||
|
||||
return '\\' . ltrim( $class_name, '\\' );
|
||||
@@ -374,7 +390,7 @@ class Bulk {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate WebP images if they are missing.
|
||||
* Generate next-gen images if they are missing.
|
||||
*
|
||||
* @since 2.1
|
||||
*
|
||||
@@ -383,12 +399,12 @@ class Bulk {
|
||||
*
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
*/
|
||||
public function generate_webp_versions( int $media_id, string $context ) {
|
||||
public function generate_nextgen_versions( int $media_id, string $context ) {
|
||||
if ( ! $this->can_optimize() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return imagify_get_optimization_process( $media_id, $context )->generate_webp_versions();
|
||||
return imagify_get_optimization_process( $media_id, $context )->generate_nextgen_versions();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -451,10 +467,6 @@ class Bulk {
|
||||
return (int) $level;
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** BULK OPTIMIZATION CALLBACKS ============================================================= */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Launch the bulk optimization action
|
||||
*
|
||||
@@ -480,14 +492,14 @@ class Bulk {
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch the missing WebP versions generation
|
||||
* Launch the missing Next-gen versions generation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function missing_webp_callback() {
|
||||
public function missing_nextgen_callback() {
|
||||
imagify_check_nonce( 'imagify-bulk-optimize' );
|
||||
|
||||
$contexts = explode( '_', sanitize_key( wp_unslash( $_GET['context'] ) ) );
|
||||
$contexts = $this->get_contexts();
|
||||
|
||||
foreach ( $contexts as $context ) {
|
||||
if ( ! imagify_get_context( $context )->current_user_can( 'bulk-optimize' ) ) {
|
||||
@@ -495,8 +507,9 @@ class Bulk {
|
||||
}
|
||||
}
|
||||
|
||||
$data = $this->run_generate_webp( $contexts );
|
||||
$formats = imagify_nextgen_images_formats();
|
||||
|
||||
$data = $this->run_generate_nextgen( $contexts, $formats );
|
||||
if ( false === $data['success'] ) {
|
||||
wp_send_json_error( [ 'message' => $data['message'] ] );
|
||||
}
|
||||
@@ -575,4 +588,87 @@ class Bulk {
|
||||
|
||||
wp_send_json_success( imagify_get_bulk_stats( array_flip( $folder_types ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Options callback to start bulk optimization.
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
* @param array $old_value The old option value.
|
||||
* @param array $value The new option value.
|
||||
*
|
||||
* Please note that the convert_to_avif new value is a checkbox,
|
||||
* so it equals 1 when it's set otherwise it's not set.
|
||||
* That's why we need to use empty function when checking its value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_generate_missing_nextgen( $old_value, $value ) {
|
||||
if ( empty( $old_value['convert_to_avif'] ) === empty( $value['convert_to_avif'] ) ) {
|
||||
// Old value = new value so do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( empty( $value['convert_to_avif'] ) ) {
|
||||
// new value is disabled, do nothing.
|
||||
return;
|
||||
}
|
||||
|
||||
$contexts = $this->get_contexts();
|
||||
$formats = imagify_nextgen_images_formats();
|
||||
|
||||
$this->run_generate_nextgen( $contexts, $formats );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the context for the bulk optimization page.
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
* @return array The array of unique contexts ('wp' or 'custom-folders').
|
||||
*/
|
||||
public function get_contexts() {
|
||||
$contexts = [];
|
||||
$types = [];
|
||||
|
||||
// Library: in each site.
|
||||
if ( ! is_network_admin() ) {
|
||||
$types['library|wp'] = 1;
|
||||
}
|
||||
|
||||
// Custom folders: in network admin only if network activated, in each site otherwise.
|
||||
if ( imagify_can_optimize_custom_folders() && ( imagify_is_active_for_network() && is_network_admin() || ! imagify_is_active_for_network() ) ) {
|
||||
$types['custom-folders|custom-folders'] = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the types to display in the bulk optimization page.
|
||||
*
|
||||
* @since 1.7.1
|
||||
*
|
||||
* @param array $types The folder types displayed on the page. If a folder type is "library", the context should be suffixed after a pipe character. They are passed as array keys.
|
||||
*/
|
||||
$types = apply_filters( 'imagify_bulk_page_types', $types );
|
||||
$types = array_filter( (array) $types );
|
||||
|
||||
if ( isset( $types['library|wp'] ) && ! in_array( 'wp', $contexts, true ) ) {
|
||||
$contexts[] = 'wp';
|
||||
}
|
||||
|
||||
if ( isset( $types['custom-folders|custom-folders'] ) ) {
|
||||
$folders_instance = \Imagify_Folders_DB::get_instance();
|
||||
|
||||
if ( ! $folders_instance->has_items() ) {
|
||||
// New Feature!
|
||||
if ( ! in_array( 'wp', $contexts, true ) ) {
|
||||
$contexts[] = 'wp';
|
||||
}
|
||||
} elseif ( $folders_instance->has_active_folders() && ! in_array( 'custom-folders', $contexts, true ) ) {
|
||||
$contexts[] = 'custom-folders';
|
||||
}
|
||||
}
|
||||
|
||||
return $contexts;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,10 +18,11 @@ interface BulkInterface {
|
||||
public function get_unoptimized_media_ids( $optimization_level );
|
||||
|
||||
/**
|
||||
* Get ids of all optimized media without WebP versions.
|
||||
* Get ids of all optimized media without Next gen versions.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 1.9.5 The method doesn't return the IDs directly anymore.
|
||||
* @since 2.2
|
||||
*
|
||||
* @param string $format Format we are looking for. (webp|avif).
|
||||
*
|
||||
* @return array {
|
||||
* @type array $ids A list of media IDs.
|
||||
@@ -31,16 +32,17 @@ interface BulkInterface {
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public function get_optimized_media_ids_without_webp();
|
||||
public function get_optimized_media_ids_without_format( $format );
|
||||
|
||||
|
||||
/**
|
||||
* Tell if there are optimized media without WebP versions.
|
||||
* Tell if there are optimized media without next-gen versions.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 2.2
|
||||
*
|
||||
* @return int The number of media.
|
||||
*/
|
||||
public function has_optimized_media_without_webp();
|
||||
public function has_optimized_media_without_nextgen();
|
||||
|
||||
/**
|
||||
* Get the context data.
|
||||
|
||||
@@ -74,10 +74,11 @@ class CustomFolders extends AbstractBulk {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ids of all optimized media without WebP versions.
|
||||
* Get ids of all optimized media without Next gen versions.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 1.9.5 The method doesn't return the IDs directly anymore.
|
||||
* @since 2.2
|
||||
*
|
||||
* @param string $format Format we are looking for. (webp|avif).
|
||||
*
|
||||
* @return array {
|
||||
* @type array $ids A list of media IDs.
|
||||
@@ -87,7 +88,7 @@ class CustomFolders extends AbstractBulk {
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public function get_optimized_media_ids_without_webp() {
|
||||
public function get_optimized_media_ids_without_format( $format ) {
|
||||
global $wpdb;
|
||||
|
||||
$this->set_no_time_limit();
|
||||
@@ -95,9 +96,22 @@ 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.
|
||||
// Remove single quotes and explode string into array.
|
||||
$mime_types_array = explode( ',', str_replace( "'", '', $mime_types ) );
|
||||
|
||||
// Iterate over array and check if string contains input.
|
||||
foreach ( $mime_types_array as $item ) {
|
||||
if ( strpos( $item, $format ) !== false ) {
|
||||
$mime = $item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ! isset( $mime ) && empty( $mime ) ) {
|
||||
$mime = 'image/webp';
|
||||
}
|
||||
$mime_types = str_replace( ",'" . $mime . "'", '', $mime_types );
|
||||
$nextgen_suffix = constant( imagify_get_optimization_process_class_name( 'custom-folders' ) . '::' . strtoupper( $format ) . '_SUFFIX' );
|
||||
$files = $wpdb->get_results( $wpdb->prepare( // WPCS: unprepared SQL ok.
|
||||
"
|
||||
SELECT fi.file_id, fi.path
|
||||
FROM $files_table as fi
|
||||
@@ -108,11 +122,11 @@ class CustomFolders extends AbstractBulk {
|
||||
AND ( fi.status = 'success' OR fi.status = 'already_optimized' )
|
||||
AND ( fi.data NOT LIKE %s OR fi.data IS NULL )
|
||||
ORDER BY fi.file_id DESC",
|
||||
'%' . $wpdb->esc_like( $webp_suffix . '";a:4:{s:7:"success";b:1;' ) . '%'
|
||||
'%' . $wpdb->esc_like( $nextgen_suffix . '";a:4:{s:7:"success";b:1;' ) . '%'
|
||||
) );
|
||||
|
||||
$wpdb->flush();
|
||||
unset( $mime_types, $files_table, $folders_table, $webp_suffix );
|
||||
unset( $mime_types, $files_table, $folders_table, $nextgen_suffix, $mime );
|
||||
|
||||
$data = [
|
||||
'ids' => [],
|
||||
|
||||
@@ -20,10 +20,11 @@ class Noop extends AbstractBulk {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ids of all optimized media without WebP versions.
|
||||
* * Get ids of all optimized media without Next gen versions.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 1.9.5 The method doesn't return the IDs directly anymore.
|
||||
* @since 2.2
|
||||
*
|
||||
* @param string $format Format we are looking for. (webp|avif).
|
||||
*
|
||||
* @return array {
|
||||
* @type array $ids A list of media IDs.
|
||||
@@ -33,7 +34,7 @@ class Noop extends AbstractBulk {
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public function get_optimized_media_ids_without_webp() {
|
||||
public function get_optimized_media_ids_without_format( $format ) {
|
||||
return [
|
||||
'ids' => [],
|
||||
'errors' => [
|
||||
|
||||
@@ -165,10 +165,11 @@ class WP extends AbstractBulk {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ids of all optimized media without WebP versions.
|
||||
* Get ids of all optimized media without Next gen versions.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 1.9.5 The method doesn't return the IDs directly anymore.
|
||||
* @since 2.2
|
||||
*
|
||||
* @param string $format Format we are looking for. (webp|avif).
|
||||
*
|
||||
* @return array {
|
||||
* @type array $ids A list of media IDs.
|
||||
@@ -178,45 +179,61 @@ class WP extends AbstractBulk {
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
public function get_optimized_media_ids_without_webp() {
|
||||
public function get_optimized_media_ids_without_format( $format ) {
|
||||
global $wpdb;
|
||||
|
||||
$this->set_no_time_limit();
|
||||
|
||||
$mime_types = Imagify_DB::get_mime_types( 'image' );
|
||||
$mime_types = str_replace( ",'image/webp'", '', $mime_types );
|
||||
|
||||
// Remove single quotes and explode string into array.
|
||||
$mime_types_array = explode( ',', str_replace( "'", '', $mime_types ) );
|
||||
|
||||
// Iterate over array and check if string contains input.
|
||||
foreach ( $mime_types_array as $item ) {
|
||||
if ( strpos( $item, $format ) !== false ) {
|
||||
$mime = $item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ! isset( $mime ) && empty( $mime ) ) {
|
||||
$mime = 'image/webp';
|
||||
}
|
||||
$mime_types = str_replace( ",'" . $mime . "'", '', $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( [
|
||||
'prepared' => true,
|
||||
] );
|
||||
$webp_suffix = constant( imagify_get_optimization_process_class_name( 'wp' ) . '::WEBP_SUFFIX' );
|
||||
$nextgen_suffix = constant( imagify_get_optimization_process_class_name( 'wp' ) . '::' . strtoupper( $format ) . '_SUFFIX' );
|
||||
|
||||
$ids = $wpdb->get_col( $wpdb->prepare( // WPCS: unprepared SQL ok.
|
||||
"
|
||||
SELECT p.ID
|
||||
FROM $wpdb->posts AS p
|
||||
$nodata_join
|
||||
LEFT JOIN $wpdb->postmeta AS mt1
|
||||
ON ( p.ID = mt1.post_id AND mt1.meta_key = '_imagify_status' )
|
||||
LEFT JOIN $wpdb->postmeta AS mt2
|
||||
SELECT p.ID
|
||||
FROM $wpdb->posts AS p
|
||||
$nodata_join
|
||||
LEFT JOIN $wpdb->postmeta AS mt1
|
||||
ON ( p.ID = mt1.post_id AND mt1.meta_key = '_imagify_status' )
|
||||
LEFT JOIN $wpdb->postmeta AS mt2
|
||||
ON ( p.ID = mt2.post_id AND mt2.meta_key = '_imagify_data' )
|
||||
WHERE
|
||||
p.post_mime_type IN ( $mime_types )
|
||||
AND ( mt1.meta_value = 'success' OR mt1.meta_value = 'already_optimized' )
|
||||
AND mt2.meta_value NOT LIKE %s
|
||||
AND p.post_type = 'attachment'
|
||||
AND p.post_status IN ( $statuses )
|
||||
$nodata_where
|
||||
ORDER BY p.ID DESC
|
||||
LIMIT 0, %d",
|
||||
'%' . $wpdb->esc_like( $webp_suffix . '";a:4:{s:7:"success";b:1;' ) . '%',
|
||||
WHERE
|
||||
p.post_mime_type IN ( $mime_types )
|
||||
AND (mt1.meta_key IS NULL OR mt1.meta_value = 'success' OR mt1.meta_value = 'already_optimized' )
|
||||
AND mt2.meta_value NOT LIKE %s
|
||||
AND p.post_type = 'attachment'
|
||||
AND p.post_status IN ( $statuses )
|
||||
$nodata_where
|
||||
ORDER BY p.ID DESC
|
||||
LIMIT 0, %d",
|
||||
'%' . $wpdb->esc_like( $nextgen_suffix . '";a:4:{s:7:"success";b:1;' ) . '%',
|
||||
imagify_get_unoptimized_attachment_limit()
|
||||
) );
|
||||
|
||||
$wpdb->flush();
|
||||
unset( $mime_types, $statuses, $webp_suffix );
|
||||
unset( $mime_types, $statuses, $nextgen_suffix, $mime );
|
||||
|
||||
$ids = array_filter( array_map( 'absint', $ids ) );
|
||||
|
||||
$data = [
|
||||
'ids' => [],
|
||||
'errors' => [
|
||||
@@ -243,7 +260,7 @@ class WP extends AbstractBulk {
|
||||
* @param array $metas An array of the data fetched from the database.
|
||||
* @param string $context The context.
|
||||
*/
|
||||
do_action( 'imagify_bulk_generate_webp_before_file_existence_tests', $ids, $metas, 'wp' );
|
||||
do_action( 'imagify_bulk_generate_nextgen_before_file_existence_tests', $ids, $metas, 'wp' );
|
||||
|
||||
foreach ( $ids as $i => $id ) {
|
||||
if ( empty( $metas['filenames'][ $id ] ) ) {
|
||||
|
||||
123
wp/wp-content/plugins/imagify/classes/CDN/CDN.php
Normal file
123
wp/wp-content/plugins/imagify/classes/CDN/CDN.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\CDN;
|
||||
|
||||
use Imagify\EventManagement\SubscriberInterface;
|
||||
|
||||
/**
|
||||
* CDN subscriber
|
||||
*/
|
||||
class CDN implements SubscriberInterface {
|
||||
/**
|
||||
* Array of events this subscriber listens to
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'imagify_cdn_source_url' => 'get_cdn_source',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CDN "source".
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param string $option_url An URL to use instead of the one stored in the option. It is used only if no constant/filter.
|
||||
*
|
||||
* @return array {
|
||||
* @type string $source Where does it come from? Possible values are 'constant', 'filter', or 'option'.
|
||||
* @type string $name Who? Can be a constant name, a plugin name, or an empty string.
|
||||
* @type string $url The CDN URL, with a trailing slash. An empty string if no URL is set.
|
||||
* }
|
||||
*/
|
||||
public function get_cdn_source( $option_url = '' ) {
|
||||
if ( defined( 'IMAGIFY_CDN_URL' ) && IMAGIFY_CDN_URL && is_string( IMAGIFY_CDN_URL ) ) {
|
||||
// Use a constant.
|
||||
$source = [
|
||||
'source' => 'constant',
|
||||
'name' => 'IMAGIFY_CDN_URL',
|
||||
'url' => IMAGIFY_CDN_URL,
|
||||
];
|
||||
} else {
|
||||
// Maybe use a filter.
|
||||
$filter_source = [
|
||||
'name' => null,
|
||||
'url' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* Provide a custom CDN source.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param array $filter_source {
|
||||
* @type $name string The name of which provides the URL (plugin name, etc).
|
||||
* @type $url string The CDN URL.
|
||||
* }
|
||||
*/
|
||||
$filter_source = apply_filters( 'imagify_cdn_source', $filter_source );
|
||||
|
||||
if ( ! empty( $filter_source['url'] ) ) {
|
||||
$source = [
|
||||
'source' => 'filter',
|
||||
'name' => ! empty( $filter_source['name'] ) ? $filter_source['name'] : '',
|
||||
'url' => $filter_source['url'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $source['url'] ) ) {
|
||||
// No constant, no filter: use the option.
|
||||
$source = [
|
||||
'source' => 'option',
|
||||
'name' => '',
|
||||
'url' => $option_url && is_string( $option_url ) ? $option_url : get_imagify_option( 'cdn_url' ),
|
||||
];
|
||||
}
|
||||
|
||||
if ( empty( $source['url'] ) ) {
|
||||
// Nothing set.
|
||||
return [
|
||||
'source' => 'option',
|
||||
'name' => '',
|
||||
'url' => '',
|
||||
];
|
||||
}
|
||||
|
||||
$source['url'] = $this->sanitize_cdn_url( $source['url'] );
|
||||
|
||||
if ( empty( $source['url'] ) ) {
|
||||
// Not an URL.
|
||||
return [
|
||||
'source' => 'option',
|
||||
'name' => '',
|
||||
'url' => '',
|
||||
];
|
||||
}
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the CDN URL value.
|
||||
*
|
||||
* @since 1.9.3
|
||||
*
|
||||
* @param string $url The URL to sanitize.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function sanitize_cdn_url( $url ) {
|
||||
$url = sanitize_text_field( $url );
|
||||
|
||||
if ( ! $url || ! preg_match( '@^https?://.+\.[^.]+@i', $url ) ) {
|
||||
// Not an URL.
|
||||
return '';
|
||||
}
|
||||
|
||||
return trailingslashit( $url );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\CDN;
|
||||
|
||||
use Imagify\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service provider for CDN compatibility
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
/**
|
||||
* Services provided by this provider
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'cdn',
|
||||
];
|
||||
|
||||
/**
|
||||
* Subscribers provided by this provider
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $subscribers = [
|
||||
'cdn',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the provided classes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$this->getContainer()->share( 'cdn', CDN::class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subscribers array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_subscribers() {
|
||||
return $this->subscribers;
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,9 @@ namespace Imagify\CLI;
|
||||
use Imagify\Bulk\Bulk;
|
||||
|
||||
/**
|
||||
* Command class for the missing WebP generation
|
||||
* Command class for the missing Nextgen generation
|
||||
*/
|
||||
class GenerateMissingWebpCommand extends AbstractCommand {
|
||||
class GenerateMissingNextgenCommand extends AbstractCommand {
|
||||
/**
|
||||
* Executes the command.
|
||||
*
|
||||
@@ -16,23 +16,23 @@ class GenerateMissingWebpCommand extends AbstractCommand {
|
||||
* @param array $options Optional arguments.
|
||||
*/
|
||||
public function __invoke( $arguments, $options ) {
|
||||
Bulk::get_instance()->run_generate_webp( $arguments );
|
||||
Bulk::get_instance()->run_generate_nextgen( $arguments );
|
||||
|
||||
\WP_CLI::log( 'Imagify missing WebP generation triggered.' );
|
||||
\WP_CLI::log( 'Imagify missing next-gen images generation triggered.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function get_command_name(): string {
|
||||
return 'generate-missing-webp';
|
||||
return 'generate-missing-nextgen';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_description(): string {
|
||||
return 'Run the generation of the missing WebP versions';
|
||||
return 'Run the generation of the missing next-gen images versions';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +43,7 @@ class GenerateMissingWebpCommand extends AbstractCommand {
|
||||
[
|
||||
'type' => 'positional',
|
||||
'name' => 'contexts',
|
||||
'description' => 'The context(s) to run the missing WebP generation for. Possible values are wp and custom-folders.',
|
||||
'description' => 'The context(s) to run the missing next-gen images generation for. Possible values are wp and custom-folders.',
|
||||
'optional' => false,
|
||||
'repeating' => true,
|
||||
],
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Argument;
|
||||
|
||||
use Imagify\Dependencies\League\Container\ContainerAwareInterface;
|
||||
use ReflectionFunctionAbstract;
|
||||
|
||||
interface ArgumentResolverInterface extends ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Resolve an array of arguments to their concrete implementations.
|
||||
*
|
||||
* @param array $arguments
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function resolveArguments(array $arguments) : array;
|
||||
|
||||
/**
|
||||
* Resolves the correct arguments to be passed to a method.
|
||||
*
|
||||
* @param ReflectionFunctionAbstract $method
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function reflectArguments(ReflectionFunctionAbstract $method, array $args = []) : array;
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Argument;
|
||||
|
||||
use Imagify\Dependencies\League\Container\Container;
|
||||
use Imagify\Dependencies\League\Container\Exception\{ContainerException, NotFoundException};
|
||||
use Imagify\Dependencies\League\Container\ReflectionContainer;
|
||||
use Imagify\Dependencies\Psr\Container\ContainerInterface;
|
||||
use ReflectionFunctionAbstract;
|
||||
use ReflectionParameter;
|
||||
|
||||
trait ArgumentResolverTrait
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolveArguments(array $arguments) : array
|
||||
{
|
||||
return array_map(function ($argument) {
|
||||
$justStringValue = false;
|
||||
|
||||
if ($argument instanceof RawArgumentInterface) {
|
||||
return $argument->getValue();
|
||||
} elseif ($argument instanceof ClassNameInterface) {
|
||||
$id = $argument->getClassName();
|
||||
} elseif (!is_string($argument)) {
|
||||
return $argument;
|
||||
} else {
|
||||
$justStringValue = true;
|
||||
$id = $argument;
|
||||
}
|
||||
|
||||
$container = null;
|
||||
|
||||
try {
|
||||
$container = $this->getLeagueContainer();
|
||||
} catch (ContainerException $e) {
|
||||
if ($this instanceof ReflectionContainer) {
|
||||
$container = $this;
|
||||
}
|
||||
}
|
||||
|
||||
if ($container !== null) {
|
||||
try {
|
||||
return $container->get($id);
|
||||
} catch (NotFoundException $exception) {
|
||||
if ($argument instanceof ClassNameWithOptionalValue) {
|
||||
return $argument->getOptionalValue();
|
||||
}
|
||||
|
||||
if ($justStringValue) {
|
||||
return $id;
|
||||
}
|
||||
|
||||
throw $exception;
|
||||
}
|
||||
}
|
||||
|
||||
if ($argument instanceof ClassNameWithOptionalValue) {
|
||||
return $argument->getOptionalValue();
|
||||
}
|
||||
|
||||
// Just a string value.
|
||||
return $id;
|
||||
}, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function reflectArguments(ReflectionFunctionAbstract $method, array $args = []) : array
|
||||
{
|
||||
$arguments = array_map(function (ReflectionParameter $param) use ($method, $args) {
|
||||
$name = $param->getName();
|
||||
$type = $param->getType();
|
||||
|
||||
if (array_key_exists($name, $args)) {
|
||||
return new RawArgument($args[$name]);
|
||||
}
|
||||
|
||||
if ($type) {
|
||||
if (PHP_VERSION_ID >= 70100) {
|
||||
$typeName = $type->getName();
|
||||
} else {
|
||||
$typeName = (string) $type;
|
||||
}
|
||||
|
||||
$typeName = ltrim($typeName, '?');
|
||||
|
||||
if ($param->isDefaultValueAvailable()) {
|
||||
return new ClassNameWithOptionalValue($typeName, $param->getDefaultValue());
|
||||
}
|
||||
|
||||
return new ClassName($typeName);
|
||||
}
|
||||
|
||||
if ($param->isDefaultValueAvailable()) {
|
||||
return new RawArgument($param->getDefaultValue());
|
||||
}
|
||||
|
||||
throw new NotFoundException(sprintf(
|
||||
'Unable to resolve a value for parameter (%s) in the function/method (%s)',
|
||||
$name,
|
||||
$method->getName()
|
||||
));
|
||||
}, $method->getParameters());
|
||||
|
||||
return $this->resolveArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
abstract public function getContainer() : ContainerInterface;
|
||||
|
||||
/**
|
||||
* @return Container
|
||||
*/
|
||||
abstract public function getLeagueContainer() : Container;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Argument;
|
||||
|
||||
class ClassName implements ClassNameInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
*
|
||||
* @param string $value
|
||||
*/
|
||||
public function __construct(string $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getClassName() : string
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Argument;
|
||||
|
||||
interface ClassNameInterface
|
||||
{
|
||||
/**
|
||||
* Return the class name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClassName() : string;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Argument;
|
||||
|
||||
class ClassNameWithOptionalValue implements ClassNameInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $className;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
private $optionalValue;
|
||||
|
||||
/**
|
||||
* @param string $className
|
||||
* @param mixed $optionalValue
|
||||
*/
|
||||
public function __construct(string $className, $optionalValue)
|
||||
{
|
||||
$this->className = $className;
|
||||
$this->optionalValue = $optionalValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getClassName(): string
|
||||
{
|
||||
return $this->className;
|
||||
}
|
||||
|
||||
public function getOptionalValue()
|
||||
{
|
||||
return $this->optionalValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Argument;
|
||||
|
||||
class RawArgument implements RawArgumentInterface
|
||||
{
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $value;
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
*
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __construct($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Argument;
|
||||
|
||||
interface RawArgumentInterface
|
||||
{
|
||||
/**
|
||||
* Return the value of the raw argument.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue();
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container;
|
||||
|
||||
use Imagify\Dependencies\League\Container\Definition\{DefinitionAggregate, DefinitionInterface, DefinitionAggregateInterface};
|
||||
use Imagify\Dependencies\League\Container\Exception\{NotFoundException, ContainerException};
|
||||
use Imagify\Dependencies\League\Container\Inflector\{InflectorAggregate, InflectorInterface, InflectorAggregateInterface};
|
||||
use Imagify\Dependencies\League\Container\ServiceProvider\{
|
||||
ServiceProviderAggregate,
|
||||
ServiceProviderAggregateInterface,
|
||||
ServiceProviderInterface
|
||||
};
|
||||
use Imagify\Dependencies\Psr\Container\ContainerInterface;
|
||||
|
||||
class Container implements ContainerInterface
|
||||
{
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $defaultToShared = false;
|
||||
|
||||
/**
|
||||
* @var DefinitionAggregateInterface
|
||||
*/
|
||||
protected $definitions;
|
||||
|
||||
/**
|
||||
* @var ServiceProviderAggregateInterface
|
||||
*/
|
||||
protected $providers;
|
||||
|
||||
/**
|
||||
* @var InflectorAggregateInterface
|
||||
*/
|
||||
protected $inflectors;
|
||||
|
||||
/**
|
||||
* @var ContainerInterface[]
|
||||
*/
|
||||
protected $delegates = [];
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
*
|
||||
* @param DefinitionAggregateInterface|null $definitions
|
||||
* @param ServiceProviderAggregateInterface|null $providers
|
||||
* @param InflectorAggregateInterface|null $inflectors
|
||||
*/
|
||||
public function __construct(
|
||||
DefinitionAggregateInterface $definitions = null,
|
||||
ServiceProviderAggregateInterface $providers = null,
|
||||
InflectorAggregateInterface $inflectors = null
|
||||
) {
|
||||
$this->definitions = $definitions ?? new DefinitionAggregate;
|
||||
$this->providers = $providers ?? new ServiceProviderAggregate;
|
||||
$this->inflectors = $inflectors ?? new InflectorAggregate;
|
||||
|
||||
if ($this->definitions instanceof ContainerAwareInterface) {
|
||||
$this->definitions->setLeagueContainer($this);
|
||||
}
|
||||
|
||||
if ($this->providers instanceof ContainerAwareInterface) {
|
||||
$this->providers->setLeagueContainer($this);
|
||||
}
|
||||
|
||||
if ($this->inflectors instanceof ContainerAwareInterface) {
|
||||
$this->inflectors->setLeagueContainer($this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to the container.
|
||||
*
|
||||
* @param string $id
|
||||
* @param mixed $concrete
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return DefinitionInterface
|
||||
*/
|
||||
public function add(string $id, $concrete = null, bool $shared = null) : DefinitionInterface
|
||||
{
|
||||
$concrete = $concrete ?? $id;
|
||||
$shared = $shared ?? $this->defaultToShared;
|
||||
|
||||
return $this->definitions->add($id, $concrete, $shared);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy to add with shared as true.
|
||||
*
|
||||
* @param string $id
|
||||
* @param mixed $concrete
|
||||
*
|
||||
* @return DefinitionInterface
|
||||
*/
|
||||
public function share(string $id, $concrete = null) : DefinitionInterface
|
||||
{
|
||||
return $this->add($id, $concrete, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the container should default to defining shared definitions.
|
||||
*
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function defaultToShared(bool $shared = true) : ContainerInterface
|
||||
{
|
||||
$this->defaultToShared = $shared;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a definition to extend.
|
||||
*
|
||||
* @param string $id [description]
|
||||
*
|
||||
* @return DefinitionInterface
|
||||
*/
|
||||
public function extend(string $id) : DefinitionInterface
|
||||
{
|
||||
if ($this->providers->provides($id)) {
|
||||
$this->providers->register($id);
|
||||
}
|
||||
|
||||
if ($this->definitions->has($id)) {
|
||||
return $this->definitions->getDefinition($id);
|
||||
}
|
||||
|
||||
throw new NotFoundException(
|
||||
sprintf('Unable to extend alias (%s) as it is not being managed as a definition', $id)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a service provider.
|
||||
*
|
||||
* @param ServiceProviderInterface|string $provider
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addServiceProvider($provider) : self
|
||||
{
|
||||
$this->providers->add($provider);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get($id, bool $new = false)
|
||||
{
|
||||
if ($this->definitions->has($id)) {
|
||||
$resolved = $this->definitions->resolve($id, $new);
|
||||
return $this->inflectors->inflect($resolved);
|
||||
}
|
||||
|
||||
if ($this->definitions->hasTag($id)) {
|
||||
$arrayOf = $this->definitions->resolveTagged($id, $new);
|
||||
|
||||
array_walk($arrayOf, function (&$resolved) {
|
||||
$resolved = $this->inflectors->inflect($resolved);
|
||||
});
|
||||
|
||||
return $arrayOf;
|
||||
}
|
||||
|
||||
if ($this->providers->provides($id)) {
|
||||
$this->providers->register($id);
|
||||
|
||||
if (!$this->definitions->has($id) && !$this->definitions->hasTag($id)) {
|
||||
throw new ContainerException(sprintf('Service provider lied about providing (%s) service', $id));
|
||||
}
|
||||
|
||||
return $this->get($id, $new);
|
||||
}
|
||||
|
||||
foreach ($this->delegates as $delegate) {
|
||||
if ($delegate->has($id)) {
|
||||
$resolved = $delegate->get($id);
|
||||
return $this->inflectors->inflect($resolved);
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotFoundException(sprintf('Alias (%s) is not being managed by the container or delegates', $id));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has($id)
|
||||
{
|
||||
if ($this->definitions->has($id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->definitions->hasTag($id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->providers->provides($id)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($this->delegates as $delegate) {
|
||||
if ($delegate->has($id)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows for manipulation of specific types on resolution.
|
||||
*
|
||||
* @param string $type
|
||||
* @param callable|null $callback
|
||||
*
|
||||
* @return InflectorInterface
|
||||
*/
|
||||
public function inflector(string $type, callable $callback = null) : InflectorInterface
|
||||
{
|
||||
return $this->inflectors->add($type, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate a backup container to be checked for services if it
|
||||
* cannot be resolved via this container.
|
||||
*
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function delegate(ContainerInterface $container) : self
|
||||
{
|
||||
$this->delegates[] = $container;
|
||||
|
||||
if ($container instanceof ContainerAwareInterface) {
|
||||
$container->setLeagueContainer($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container;
|
||||
|
||||
use Imagify\Dependencies\Psr\Container\ContainerInterface;
|
||||
|
||||
interface ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Set a container
|
||||
*
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setContainer(ContainerInterface $container) : ContainerAwareInterface;
|
||||
|
||||
/**
|
||||
* Get the container
|
||||
*
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public function getContainer() : ContainerInterface;
|
||||
|
||||
/**
|
||||
* Set a container. This will be removed in favour of setContainer receiving Container in next major release.
|
||||
*
|
||||
* @param Container $container
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setLeagueContainer(Container $container) : self;
|
||||
|
||||
/**
|
||||
* Get the container. This will be removed in favour of getContainer returning Container in next major release.
|
||||
*
|
||||
* @return Container
|
||||
*/
|
||||
public function getLeagueContainer() : Container;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container;
|
||||
|
||||
use Imagify\Dependencies\League\Container\Exception\ContainerException;
|
||||
use Imagify\Dependencies\Psr\Container\ContainerInterface;
|
||||
|
||||
trait ContainerAwareTrait
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* @var Container
|
||||
*/
|
||||
protected $leagueContainer;
|
||||
|
||||
/**
|
||||
* Set a container.
|
||||
*
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return ContainerAwareInterface
|
||||
*/
|
||||
public function setContainer(ContainerInterface $container) : ContainerAwareInterface
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the container.
|
||||
*
|
||||
* @return ContainerInterface
|
||||
*/
|
||||
public function getContainer() : ContainerInterface
|
||||
{
|
||||
if ($this->container instanceof ContainerInterface) {
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
throw new ContainerException('No container implementation has been set.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a container.
|
||||
*
|
||||
* @param Container $container
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setLeagueContainer(Container $container) : ContainerAwareInterface
|
||||
{
|
||||
$this->container = $container;
|
||||
$this->leagueContainer = $container;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the container.
|
||||
*
|
||||
* @return Container
|
||||
*/
|
||||
public function getLeagueContainer() : Container
|
||||
{
|
||||
if ($this->leagueContainer instanceof Container) {
|
||||
return $this->leagueContainer;
|
||||
}
|
||||
|
||||
throw new ContainerException('No container implementation has been set.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Definition;
|
||||
|
||||
use Imagify\Dependencies\League\Container\Argument\{
|
||||
ArgumentResolverInterface, ArgumentResolverTrait, ClassNameInterface, RawArgumentInterface
|
||||
};
|
||||
use Imagify\Dependencies\League\Container\ContainerAwareTrait;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
|
||||
class Definition implements ArgumentResolverInterface, DefinitionInterface
|
||||
{
|
||||
use ArgumentResolverTrait;
|
||||
use ContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $alias;
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $concrete;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $shared = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $tags = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $arguments = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $methods = [];
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected $resolved;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $id
|
||||
* @param mixed $concrete
|
||||
*/
|
||||
public function __construct(string $id, $concrete = null)
|
||||
{
|
||||
$concrete = $concrete ?? $id;
|
||||
|
||||
$this->alias = $id;
|
||||
$this->concrete = $concrete;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addTag(string $tag) : DefinitionInterface
|
||||
{
|
||||
$this->tags[$tag] = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasTag(string $tag) : bool
|
||||
{
|
||||
return isset($this->tags[$tag]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setAlias(string $id) : DefinitionInterface
|
||||
{
|
||||
$this->alias = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getAlias() : string
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setShared(bool $shared = true) : DefinitionInterface
|
||||
{
|
||||
$this->shared = $shared;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isShared() : bool
|
||||
{
|
||||
return $this->shared;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getConcrete()
|
||||
{
|
||||
return $this->concrete;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setConcrete($concrete) : DefinitionInterface
|
||||
{
|
||||
$this->concrete = $concrete;
|
||||
$this->resolved = null;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addArgument($arg) : DefinitionInterface
|
||||
{
|
||||
$this->arguments[] = $arg;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addArguments(array $args) : DefinitionInterface
|
||||
{
|
||||
foreach ($args as $arg) {
|
||||
$this->addArgument($arg);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addMethodCall(string $method, array $args = []) : DefinitionInterface
|
||||
{
|
||||
$this->methods[] = [
|
||||
'method' => $method,
|
||||
'arguments' => $args
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function addMethodCalls(array $methods = []) : DefinitionInterface
|
||||
{
|
||||
foreach ($methods as $method => $args) {
|
||||
$this->addMethodCall($method, $args);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolve(bool $new = false)
|
||||
{
|
||||
$concrete = $this->concrete;
|
||||
|
||||
if ($this->isShared() && $this->resolved !== null && $new === false) {
|
||||
return $this->resolved;
|
||||
}
|
||||
|
||||
if (is_callable($concrete)) {
|
||||
$concrete = $this->resolveCallable($concrete);
|
||||
}
|
||||
|
||||
if ($concrete instanceof RawArgumentInterface) {
|
||||
$this->resolved = $concrete->getValue();
|
||||
|
||||
return $concrete->getValue();
|
||||
}
|
||||
|
||||
if ($concrete instanceof ClassNameInterface) {
|
||||
$concrete = $concrete->getClassName();
|
||||
}
|
||||
|
||||
if (is_string($concrete) && class_exists($concrete)) {
|
||||
$concrete = $this->resolveClass($concrete);
|
||||
}
|
||||
|
||||
if (is_object($concrete)) {
|
||||
$concrete = $this->invokeMethods($concrete);
|
||||
}
|
||||
|
||||
if (is_string($concrete) && $this->getContainer()->has($concrete)) {
|
||||
$concrete = $this->getContainer()->get($concrete);
|
||||
}
|
||||
|
||||
$this->resolved = $concrete;
|
||||
|
||||
return $concrete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a callable.
|
||||
*
|
||||
* @param callable $concrete
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function resolveCallable(callable $concrete)
|
||||
{
|
||||
$resolved = $this->resolveArguments($this->arguments);
|
||||
|
||||
return call_user_func_array($concrete, $resolved);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a class.
|
||||
*
|
||||
* @param string $concrete
|
||||
*
|
||||
* @return object
|
||||
*
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
protected function resolveClass(string $concrete)
|
||||
{
|
||||
$resolved = $this->resolveArguments($this->arguments);
|
||||
$reflection = new ReflectionClass($concrete);
|
||||
|
||||
return $reflection->newInstanceArgs($resolved);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke methods on resolved instance.
|
||||
*
|
||||
* @param object $instance
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
protected function invokeMethods($instance)
|
||||
{
|
||||
foreach ($this->methods as $method) {
|
||||
$args = $this->resolveArguments($method['arguments']);
|
||||
|
||||
/** @var callable $callable */
|
||||
$callable = [$instance, $method['method']];
|
||||
call_user_func_array($callable, $args);
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Definition;
|
||||
|
||||
use Generator;
|
||||
use Imagify\Dependencies\League\Container\ContainerAwareTrait;
|
||||
use Imagify\Dependencies\League\Container\Exception\NotFoundException;
|
||||
|
||||
class DefinitionAggregate implements DefinitionAggregateInterface
|
||||
{
|
||||
use ContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var DefinitionInterface[]
|
||||
*/
|
||||
protected $definitions = [];
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
*
|
||||
* @param DefinitionInterface[] $definitions
|
||||
*/
|
||||
public function __construct(array $definitions = [])
|
||||
{
|
||||
$this->definitions = array_filter($definitions, function ($definition) {
|
||||
return ($definition instanceof DefinitionInterface);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function add(string $id, $definition, bool $shared = false) : DefinitionInterface
|
||||
{
|
||||
if (!$definition instanceof DefinitionInterface) {
|
||||
$definition = new Definition($id, $definition);
|
||||
}
|
||||
|
||||
$this->definitions[] = $definition
|
||||
->setAlias($id)
|
||||
->setShared($shared)
|
||||
;
|
||||
|
||||
return $definition;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has(string $id) : bool
|
||||
{
|
||||
foreach ($this->getIterator() as $definition) {
|
||||
if ($id === $definition->getAlias()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hasTag(string $tag) : bool
|
||||
{
|
||||
foreach ($this->getIterator() as $definition) {
|
||||
if ($definition->hasTag($tag)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDefinition(string $id) : DefinitionInterface
|
||||
{
|
||||
foreach ($this->getIterator() as $definition) {
|
||||
if ($id === $definition->getAlias()) {
|
||||
return $definition->setLeagueContainer($this->getLeagueContainer());
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotFoundException(sprintf('Alias (%s) is not being handled as a definition.', $id));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolve(string $id, bool $new = false)
|
||||
{
|
||||
return $this->getDefinition($id)->resolve($new);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resolveTagged(string $tag, bool $new = false) : array
|
||||
{
|
||||
$arrayOf = [];
|
||||
|
||||
foreach ($this->getIterator() as $definition) {
|
||||
if ($definition->hasTag($tag)) {
|
||||
$arrayOf[] = $definition->setLeagueContainer($this->getLeagueContainer())->resolve($new);
|
||||
}
|
||||
}
|
||||
|
||||
return $arrayOf;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIterator() : Generator
|
||||
{
|
||||
$count = count($this->definitions);
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
yield $this->definitions[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Definition;
|
||||
|
||||
use IteratorAggregate;
|
||||
use Imagify\Dependencies\League\Container\ContainerAwareInterface;
|
||||
|
||||
interface DefinitionAggregateInterface extends ContainerAwareInterface, IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* Add a definition to the aggregate.
|
||||
*
|
||||
* @param string $id
|
||||
* @param mixed $definition
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return DefinitionInterface
|
||||
*/
|
||||
public function add(string $id, $definition, bool $shared = false) : DefinitionInterface;
|
||||
|
||||
/**
|
||||
* Checks whether alias exists as definition.
|
||||
*
|
||||
* @param string $id
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function has(string $id) : bool;
|
||||
|
||||
/**
|
||||
* Checks whether tag exists as definition.
|
||||
*
|
||||
* @param string $tag
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasTag(string $tag) : bool;
|
||||
|
||||
/**
|
||||
* Get the definition to be extended.
|
||||
*
|
||||
* @param string $id
|
||||
*
|
||||
* @return DefinitionInterface
|
||||
*/
|
||||
public function getDefinition(string $id) : DefinitionInterface;
|
||||
|
||||
/**
|
||||
* Resolve and build a concrete value from an id/alias.
|
||||
*
|
||||
* @param string $id
|
||||
* @param boolean $new
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function resolve(string $id, bool $new = false);
|
||||
|
||||
/**
|
||||
* Resolve and build an array of concrete values from a tag.
|
||||
*
|
||||
* @param string $tag
|
||||
* @param boolean $new
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function resolveTagged(string $tag, bool $new = false);
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Definition;
|
||||
|
||||
use Imagify\Dependencies\League\Container\ContainerAwareInterface;
|
||||
|
||||
interface DefinitionInterface extends ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Add a tag to the definition.
|
||||
*
|
||||
* @param string $tag
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addTag(string $tag) : DefinitionInterface;
|
||||
|
||||
/**
|
||||
* Does the definition have a tag?
|
||||
*
|
||||
* @param string $tag
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasTag(string $tag) : bool;
|
||||
|
||||
/**
|
||||
* Set the alias of the definition.
|
||||
*
|
||||
* @param string $id
|
||||
*
|
||||
* @return DefinitionInterface
|
||||
*/
|
||||
public function setAlias(string $id) : DefinitionInterface;
|
||||
|
||||
/**
|
||||
* Get the alias of the definition.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAlias() : string;
|
||||
|
||||
/**
|
||||
* Set whether this is a shared definition.
|
||||
*
|
||||
* @param boolean $shared
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setShared(bool $shared) : DefinitionInterface;
|
||||
|
||||
/**
|
||||
* Is this a shared definition?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isShared() : bool;
|
||||
|
||||
/**
|
||||
* Get the concrete of the definition.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConcrete();
|
||||
|
||||
/**
|
||||
* Set the concrete of the definition.
|
||||
*
|
||||
* @param mixed $concrete
|
||||
*
|
||||
* @return DefinitionInterface
|
||||
*/
|
||||
public function setConcrete($concrete) : DefinitionInterface;
|
||||
|
||||
/**
|
||||
* Add an argument to be injected.
|
||||
*
|
||||
* @param mixed $arg
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addArgument($arg) : DefinitionInterface;
|
||||
|
||||
/**
|
||||
* Add multiple arguments to be injected.
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addArguments(array $args) : DefinitionInterface;
|
||||
|
||||
/**
|
||||
* Add a method to be invoked
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addMethodCall(string $method, array $args = []) : DefinitionInterface;
|
||||
|
||||
/**
|
||||
* Add multiple methods to be invoked
|
||||
*
|
||||
* @param array $methods
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function addMethodCalls(array $methods = []) : DefinitionInterface;
|
||||
|
||||
/**
|
||||
* Handle instantiation and manipulation of value and return.
|
||||
*
|
||||
* @param boolean $new
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function resolve(bool $new = false);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Exception;
|
||||
|
||||
use Imagify\Dependencies\Psr\Container\ContainerExceptionInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class ContainerException extends RuntimeException implements ContainerExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Exception;
|
||||
|
||||
use Imagify\Dependencies\Psr\Container\NotFoundExceptionInterface;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class NotFoundException extends InvalidArgumentException implements NotFoundExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Inflector;
|
||||
|
||||
use Imagify\Dependencies\League\Container\Argument\ArgumentResolverInterface;
|
||||
use Imagify\Dependencies\League\Container\Argument\ArgumentResolverTrait;
|
||||
use Imagify\Dependencies\League\Container\ContainerAwareTrait;
|
||||
|
||||
class Inflector implements ArgumentResolverInterface, InflectorInterface
|
||||
{
|
||||
use ArgumentResolverTrait;
|
||||
use ContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @var callable|null
|
||||
*/
|
||||
protected $callback;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $methods = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $properties = [];
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
*
|
||||
* @param string $type
|
||||
* @param callable|null $callback
|
||||
*/
|
||||
public function __construct(string $type, callable $callback = null)
|
||||
{
|
||||
$this->type = $type;
|
||||
$this->callback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getType() : string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function invokeMethod(string $name, array $args) : InflectorInterface
|
||||
{
|
||||
$this->methods[$name] = $args;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function invokeMethods(array $methods) : InflectorInterface
|
||||
{
|
||||
foreach ($methods as $name => $args) {
|
||||
$this->invokeMethod($name, $args);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setProperty(string $property, $value) : InflectorInterface
|
||||
{
|
||||
$this->properties[$property] = $this->resolveArguments([$value])[0];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setProperties(array $properties) : InflectorInterface
|
||||
{
|
||||
foreach ($properties as $property => $value) {
|
||||
$this->setProperty($property, $value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function inflect($object)
|
||||
{
|
||||
$properties = $this->resolveArguments(array_values($this->properties));
|
||||
$properties = array_combine(array_keys($this->properties), $properties);
|
||||
|
||||
// array_combine() can technically return false
|
||||
foreach ($properties ?: [] as $property => $value) {
|
||||
$object->{$property} = $value;
|
||||
}
|
||||
|
||||
foreach ($this->methods as $method => $args) {
|
||||
$args = $this->resolveArguments($args);
|
||||
|
||||
/** @var callable $callable */
|
||||
$callable = [$object, $method];
|
||||
call_user_func_array($callable, $args);
|
||||
}
|
||||
|
||||
if ($this->callback !== null) {
|
||||
call_user_func($this->callback, $object);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Inflector;
|
||||
|
||||
use Generator;
|
||||
use Imagify\Dependencies\League\Container\ContainerAwareTrait;
|
||||
|
||||
class InflectorAggregate implements InflectorAggregateInterface
|
||||
{
|
||||
use ContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var Inflector[]
|
||||
*/
|
||||
protected $inflectors = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function add(string $type, callable $callback = null) : Inflector
|
||||
{
|
||||
$inflector = new Inflector($type, $callback);
|
||||
$this->inflectors[] = $inflector;
|
||||
|
||||
return $inflector;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIterator() : Generator
|
||||
{
|
||||
$count = count($this->inflectors);
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
yield $this->inflectors[$i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function inflect($object)
|
||||
{
|
||||
foreach ($this->getIterator() as $inflector) {
|
||||
$type = $inflector->getType();
|
||||
|
||||
if (! $object instanceof $type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$inflector->setLeagueContainer($this->getLeagueContainer());
|
||||
$inflector->inflect($object);
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Inflector;
|
||||
|
||||
use IteratorAggregate;
|
||||
use Imagify\Dependencies\League\Container\ContainerAwareInterface;
|
||||
|
||||
interface InflectorAggregateInterface extends ContainerAwareInterface, IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* Add an inflector to the aggregate.
|
||||
*
|
||||
* @param string $type
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return Inflector
|
||||
*/
|
||||
public function add(string $type, callable $callback = null) : Inflector;
|
||||
|
||||
/**
|
||||
* Applies all inflectors to an object.
|
||||
*
|
||||
* @param object $object
|
||||
* @return object
|
||||
*/
|
||||
public function inflect($object);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\Inflector;
|
||||
|
||||
interface InflectorInterface
|
||||
{
|
||||
/**
|
||||
* Get the type.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType() : string;
|
||||
|
||||
/**
|
||||
* Defines a method to be invoked on the subject object.
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $args
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function invokeMethod(string $name, array $args) : InflectorInterface;
|
||||
|
||||
/**
|
||||
* Defines multiple methods to be invoked on the subject object.
|
||||
*
|
||||
* @param array $methods
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function invokeMethods(array $methods) : InflectorInterface;
|
||||
|
||||
/**
|
||||
* Defines a property to be set on the subject object.
|
||||
*
|
||||
* @param string $property
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setProperty(string $property, $value) : InflectorInterface;
|
||||
|
||||
/**
|
||||
* Defines multiple properties to be set on the subject object.
|
||||
*
|
||||
* @param array $properties
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setProperties(array $properties) : InflectorInterface;
|
||||
|
||||
/**
|
||||
* Apply inflections to an object.
|
||||
*
|
||||
* @param object $object
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function inflect($object);
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container;
|
||||
|
||||
use Imagify\Dependencies\League\Container\Argument\{ArgumentResolverInterface, ArgumentResolverTrait};
|
||||
use Imagify\Dependencies\League\Container\Exception\NotFoundException;
|
||||
use Imagify\Dependencies\Psr\Container\ContainerInterface;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
use ReflectionFunction;
|
||||
use ReflectionMethod;
|
||||
|
||||
class ReflectionContainer implements ArgumentResolverInterface, ContainerInterface
|
||||
{
|
||||
use ArgumentResolverTrait;
|
||||
use ContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $cacheResolutions = false;
|
||||
|
||||
/**
|
||||
* Cache of resolutions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $cache = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function get($id, array $args = [])
|
||||
{
|
||||
if ($this->cacheResolutions === true && array_key_exists($id, $this->cache)) {
|
||||
return $this->cache[$id];
|
||||
}
|
||||
|
||||
if (! $this->has($id)) {
|
||||
throw new NotFoundException(
|
||||
sprintf('Alias (%s) is not an existing class and therefore cannot be resolved', $id)
|
||||
);
|
||||
}
|
||||
|
||||
$reflector = new ReflectionClass($id);
|
||||
$construct = $reflector->getConstructor();
|
||||
|
||||
if ($construct && !$construct->isPublic()) {
|
||||
throw new NotFoundException(
|
||||
sprintf('Alias (%s) has a non-public constructor and therefore cannot be instantiated', $id)
|
||||
);
|
||||
}
|
||||
|
||||
$resolution = $construct === null
|
||||
? new $id
|
||||
: $resolution = $reflector->newInstanceArgs($this->reflectArguments($construct, $args))
|
||||
;
|
||||
|
||||
if ($this->cacheResolutions === true) {
|
||||
$this->cache[$id] = $resolution;
|
||||
}
|
||||
|
||||
return $resolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function has($id)
|
||||
{
|
||||
return class_exists($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke a callable via the container.
|
||||
*
|
||||
* @param callable $callable
|
||||
* @param array $args
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function call(callable $callable, array $args = [])
|
||||
{
|
||||
if (is_string($callable) && strpos($callable, '::') !== false) {
|
||||
$callable = explode('::', $callable);
|
||||
}
|
||||
|
||||
if (is_array($callable)) {
|
||||
if (is_string($callable[0])) {
|
||||
$callable[0] = $this->getContainer()->get($callable[0]);
|
||||
}
|
||||
|
||||
$reflection = new ReflectionMethod($callable[0], $callable[1]);
|
||||
|
||||
if ($reflection->isStatic()) {
|
||||
$callable[0] = null;
|
||||
}
|
||||
|
||||
return $reflection->invokeArgs($callable[0], $this->reflectArguments($reflection, $args));
|
||||
}
|
||||
|
||||
if (is_object($callable)) {
|
||||
$reflection = new ReflectionMethod($callable, '__invoke');
|
||||
|
||||
return $reflection->invokeArgs($callable, $this->reflectArguments($reflection, $args));
|
||||
}
|
||||
|
||||
$reflection = new ReflectionFunction(\Closure::fromCallable($callable));
|
||||
|
||||
return $reflection->invokeArgs($this->reflectArguments($reflection, $args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the container should default to caching resolutions and returning
|
||||
* the cache on following calls.
|
||||
*
|
||||
* @param boolean $option
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function cacheResolutions(bool $option = true) : ContainerInterface
|
||||
{
|
||||
$this->cacheResolutions = $option;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\ServiceProvider;
|
||||
|
||||
use Imagify\Dependencies\League\Container\ContainerAwareTrait;
|
||||
|
||||
abstract class AbstractServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
use ContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $identifier;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function provides(string $alias) : bool
|
||||
{
|
||||
return in_array($alias, $this->provides, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setIdentifier(string $id) : ServiceProviderInterface
|
||||
{
|
||||
$this->identifier = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIdentifier() : string
|
||||
{
|
||||
return $this->identifier ?? get_class($this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\ServiceProvider;
|
||||
|
||||
interface BootableServiceProviderInterface extends ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* Method will be invoked on registration of a service provider implementing
|
||||
* this interface. Provides ability for eager loading of Service Providers.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\ServiceProvider;
|
||||
|
||||
use Generator;
|
||||
use Imagify\Dependencies\League\Container\{ContainerAwareInterface, ContainerAwareTrait};
|
||||
use Imagify\Dependencies\League\Container\Exception\ContainerException;
|
||||
|
||||
class ServiceProviderAggregate implements ServiceProviderAggregateInterface
|
||||
{
|
||||
use ContainerAwareTrait;
|
||||
|
||||
/**
|
||||
* @var ServiceProviderInterface[]
|
||||
*/
|
||||
protected $providers = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $registered = [];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function add($provider) : ServiceProviderAggregateInterface
|
||||
{
|
||||
if (is_string($provider) && $this->getContainer()->has($provider)) {
|
||||
$provider = $this->getContainer()->get($provider);
|
||||
} elseif (is_string($provider) && class_exists($provider)) {
|
||||
$provider = new $provider;
|
||||
}
|
||||
|
||||
if (in_array($provider, $this->providers, true)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
if ($provider instanceof ContainerAwareInterface) {
|
||||
$provider->setLeagueContainer($this->getLeagueContainer());
|
||||
}
|
||||
|
||||
if ($provider instanceof BootableServiceProviderInterface) {
|
||||
$provider->boot();
|
||||
}
|
||||
|
||||
if ($provider instanceof ServiceProviderInterface) {
|
||||
$this->providers[] = $provider;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
throw new ContainerException(
|
||||
'A service provider must be a fully qualified class name or instance ' .
|
||||
'of (\Imagify\Dependencies\League\Container\ServiceProvider\ServiceProviderInterface)'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function provides(string $service) : bool
|
||||
{
|
||||
foreach ($this->getIterator() as $provider) {
|
||||
if ($provider->provides($service)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getIterator() : Generator
|
||||
{
|
||||
$count = count($this->providers);
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
yield $this->providers[$i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function register(string $service)
|
||||
{
|
||||
if (false === $this->provides($service)) {
|
||||
throw new ContainerException(
|
||||
sprintf('(%s) is not provided by a service provider', $service)
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($this->getIterator() as $provider) {
|
||||
if (in_array($provider->getIdentifier(), $this->registered, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($provider->provides($service)) {
|
||||
$this->registered[] = $provider->getIdentifier();
|
||||
$provider->register();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\ServiceProvider;
|
||||
|
||||
use IteratorAggregate;
|
||||
use Imagify\Dependencies\League\Container\ContainerAwareInterface;
|
||||
|
||||
interface ServiceProviderAggregateInterface extends ContainerAwareInterface, IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* Add a service provider to the aggregate.
|
||||
*
|
||||
* @param string|ServiceProviderInterface $provider
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function add($provider) : ServiceProviderAggregateInterface;
|
||||
|
||||
/**
|
||||
* Determines whether a service is provided by the aggregate.
|
||||
*
|
||||
* @param string $service
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function provides(string $service) : bool;
|
||||
|
||||
/**
|
||||
* Invokes the register method of a provider that provides a specific service.
|
||||
*
|
||||
* @param string $service
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(string $service);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\League\Container\ServiceProvider;
|
||||
|
||||
use Imagify\Dependencies\League\Container\ContainerAwareInterface;
|
||||
|
||||
interface ServiceProviderInterface extends ContainerAwareInterface
|
||||
{
|
||||
/**
|
||||
* Returns a boolean if checking whether this provider provides a specific
|
||||
* service or returns an array of provided services if no argument passed.
|
||||
*
|
||||
* @param string $service
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function provides(string $service) : bool;
|
||||
|
||||
/**
|
||||
* Use the register method to register items with the container via the
|
||||
* protected $this->leagueContainer property or the `getLeagueContainer` method
|
||||
* from the ContainerAwareTrait.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register();
|
||||
|
||||
/**
|
||||
* Set a custom id for the service provider. This enables
|
||||
* registering the same service provider multiple times.
|
||||
*
|
||||
* @param string $id
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function setIdentifier(string $id) : ServiceProviderInterface;
|
||||
|
||||
/**
|
||||
* The id of the service provider uniquely identifies it, so
|
||||
* that we can quickly determine if it has already been registered.
|
||||
* Defaults to get_class($provider).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getIdentifier() : string;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace Imagify\Dependencies\Psr\Container;
|
||||
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Base interface representing a generic exception in a container.
|
||||
*/
|
||||
interface ContainerExceptionInterface extends Throwable
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Dependencies\Psr\Container;
|
||||
|
||||
/**
|
||||
* Describes the interface of a container that exposes methods to read its entries.
|
||||
*/
|
||||
interface ContainerInterface
|
||||
{
|
||||
/**
|
||||
* Finds an entry of the container by its identifier and returns it.
|
||||
*
|
||||
* @param string $id Identifier of the entry to look for.
|
||||
*
|
||||
* @throws NotFoundExceptionInterface No entry was found for **this** identifier.
|
||||
* @throws ContainerExceptionInterface Error while retrieving the entry.
|
||||
*
|
||||
* @return mixed Entry.
|
||||
*/
|
||||
public function get(string $id);
|
||||
|
||||
/**
|
||||
* Returns true if the container can return an entry for the given identifier.
|
||||
* Returns false otherwise.
|
||||
*
|
||||
* `has($id)` returning true does not mean that `get($id)` will not throw an exception.
|
||||
* It does however mean that `get($id)` will not throw a `NotFoundExceptionInterface`.
|
||||
*
|
||||
* @param string $id Identifier of the entry to look for.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $id);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Imagify\Dependencies\Psr\Container;
|
||||
|
||||
/**
|
||||
* No entry was found in the container.
|
||||
*/
|
||||
interface NotFoundExceptionInterface extends ContainerExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -174,7 +174,7 @@ class Actions {
|
||||
}
|
||||
|
||||
$remaining = 0;
|
||||
$total = get_transient( 'imagify_missing_webp_total' );
|
||||
$total = get_transient( 'imagify_missing_next_gen_total' );
|
||||
|
||||
if ( false === $total ) {
|
||||
return $response;
|
||||
@@ -182,8 +182,14 @@ class Actions {
|
||||
|
||||
$bulk = Bulk::get_instance();
|
||||
|
||||
$format = 'webp';
|
||||
|
||||
if ( get_imagify_option( 'convert_to_avif' ) ) {
|
||||
$format = 'avif';
|
||||
}
|
||||
|
||||
foreach ( $data[ $imagifybeat_id ] as $context ) {
|
||||
$media = $bulk->get_bulk_instance( $context )->get_optimized_media_ids_without_webp();
|
||||
$media = $bulk->get_bulk_instance( $context )->get_optimized_media_ids_without_format( $format );
|
||||
$remaining += count( $media['ids'] );
|
||||
}
|
||||
|
||||
|
||||
@@ -187,8 +187,8 @@ class MediaOptimization extends \Imagify_Abstract_Background_Process {
|
||||
$item['error'] = $data;
|
||||
|
||||
} elseif ( 'already_optimized' === $data['status'] ) {
|
||||
// Status is "already_optimized", try to create WebP versions only.
|
||||
$item['sizes'] = array_filter( $item['sizes'], [ $this->optimization_process, 'is_size_webp' ] );
|
||||
// Status is "already_optimized", try to create next-gen versions only.
|
||||
$item['sizes'] = array_filter( $item['sizes'], [ $this->optimization_process, 'is_size_next_gen' ] );
|
||||
|
||||
} elseif ( 'success' !== $data['status'] ) {
|
||||
// Don't go further if the full size has not the "success" status.
|
||||
|
||||
@@ -113,7 +113,7 @@ class File {
|
||||
return new \WP_Error(
|
||||
'not_exists',
|
||||
sprintf(
|
||||
/* translators: %s is a file path. */
|
||||
/* translators: %s is a file path. */
|
||||
__( 'The file %s does not seem to exist.', 'imagify' ),
|
||||
'<code>' . esc_html( $this->filesystem->make_path_relative( $this->path ) ) . '</code>'
|
||||
)
|
||||
@@ -124,7 +124,7 @@ class File {
|
||||
return new \WP_Error(
|
||||
'not_a_file',
|
||||
sprintf(
|
||||
/* translators: %s is a file path. */
|
||||
/* translators: %s is a file path. */
|
||||
__( 'This does not seem to be a file: %s.', 'imagify' ),
|
||||
'<code>' . esc_html( $this->filesystem->make_path_relative( $this->path ) ) . '</code>'
|
||||
)
|
||||
@@ -135,7 +135,7 @@ class File {
|
||||
return new \WP_Error(
|
||||
'not_writable',
|
||||
sprintf(
|
||||
/* translators: %s is a file path. */
|
||||
/* translators: %s is a file path. */
|
||||
__( 'The file %s does not seem to be writable.', 'imagify' ),
|
||||
'<code>' . esc_html( $this->filesystem->make_path_relative( $this->path ) ) . '</code>'
|
||||
)
|
||||
@@ -148,7 +148,7 @@ class File {
|
||||
return new \WP_Error(
|
||||
'folder_not_writable',
|
||||
sprintf(
|
||||
/* translators: %s is a file path. */
|
||||
/* translators: %s is a file path. */
|
||||
__( 'The folder %s does not seem to be writable.', 'imagify' ),
|
||||
'<code>' . esc_html( $this->filesystem->make_path_relative( $parent_folder ) ) . '</code>'
|
||||
)
|
||||
@@ -197,7 +197,7 @@ class File {
|
||||
return new \WP_Error(
|
||||
'not_an_image',
|
||||
sprintf(
|
||||
/* translators: %s is a file path. */
|
||||
/* translators: %s is a file path. */
|
||||
__( 'The file %s does not seem to be an image, and cannot be resized.', 'imagify' ),
|
||||
'<code>' . esc_html( $this->filesystem->make_path_relative( $this->path ) ) . '</code>'
|
||||
)
|
||||
@@ -321,7 +321,7 @@ class File {
|
||||
return new \WP_Error(
|
||||
'not_an_image',
|
||||
sprintf(
|
||||
/* translators: %s is a file path. */
|
||||
/* translators: %s is a file path. */
|
||||
__( 'The file %s does not seem to be an image, and cannot be resized.', 'imagify' ),
|
||||
'<code>' . esc_html( $this->filesystem->make_path_relative( $this->path ) ) . '</code>'
|
||||
)
|
||||
@@ -423,6 +423,22 @@ class File {
|
||||
) );
|
||||
}
|
||||
|
||||
// Check if a '-scaled' version of the image exists.
|
||||
$scaled_path = preg_replace( '/(\.)([^\.]+)$/', '-scaled.$2', $backup_source );
|
||||
if ( $this->filesystem->exists( $scaled_path ) ) {
|
||||
// Create a backup path for the scaled image.
|
||||
$scaled_backup_path = preg_replace( '/(\.)([^\.]+)$/', '-scaled.$2', $backup_path );
|
||||
// Copy the '-scaled' version to the backup.
|
||||
$this->filesystem->copy( $scaled_path, $scaled_backup_path, $overwrite, FS_CHMOD_FILE );
|
||||
|
||||
if ( ! $this->filesystem->exists( $scaled_backup_path ) ) {
|
||||
return new \WP_Error( 'backup_doesnt_exist', __( 'The file could not be saved.', 'imagify' ), array(
|
||||
'file_path' => $this->filesystem->make_path_relative( $scaled_path ),
|
||||
'backup_path' => $this->filesystem->make_path_relative( $scaled_backup_path ),
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -438,7 +454,7 @@ class File {
|
||||
* @type bool $backup False to prevent backup. True to follow the user's setting. A backup can't be forced.
|
||||
* @type string $backup_path If a backup must be done, this is the path to use. Default is the backup path used for the WP Media Library.
|
||||
* @type int $optimization_level The optimization level (2=ultra, 1=aggressive, 0=normal).
|
||||
* @type string $convert Set to 'webp' to convert the image to WebP.
|
||||
* @type string $convert Set to 'webp' to convert the image to WebP, 'avif' to convert image to AVIF.
|
||||
* @type string $context The context.
|
||||
* @type int $original_size The file size, sent to the API.
|
||||
* }
|
||||
@@ -474,7 +490,7 @@ class File {
|
||||
*
|
||||
* @param string $path Absolute path to the media file.
|
||||
* @param array $args Arguments passed to the method.
|
||||
*/
|
||||
*/
|
||||
do_action( 'imagify_before_optimize_file', $this->path, $args );
|
||||
|
||||
/**
|
||||
@@ -485,7 +501,7 @@ class File {
|
||||
*
|
||||
* @param string $path Absolute path to the image file.
|
||||
* @param bool $backup True if a backup will be make.
|
||||
*/
|
||||
*/
|
||||
do_action_deprecated( 'before_do_imagify', [ $this->path, $args['backup'] ], '1.9', 'imagify_before_optimize_file' );
|
||||
|
||||
if ( $args['backup'] ) {
|
||||
@@ -509,6 +525,7 @@ class File {
|
||||
|
||||
if ( $args['convert'] ) {
|
||||
$data['convert'] = $args['convert'];
|
||||
$format = $args['convert'];
|
||||
}
|
||||
|
||||
$response = upload_imagify_image( [
|
||||
@@ -534,8 +551,12 @@ class File {
|
||||
$args['convert'] = '';
|
||||
}
|
||||
|
||||
if ( 'webp' === $args['convert'] ) {
|
||||
$destination_path = $this->get_path_to_webp();
|
||||
$formats = [
|
||||
'webp',
|
||||
'avif',
|
||||
];
|
||||
if ( in_array( $args['convert'], $formats, true ) ) {
|
||||
$destination_path = $this->get_path_to_nextgen( $args['convert'] );
|
||||
$this->path = $destination_path;
|
||||
$this->file_type = null;
|
||||
$this->editor = null;
|
||||
@@ -557,7 +578,7 @@ class File {
|
||||
*
|
||||
* @param string $path Absolute path to the image file.
|
||||
* @param bool $backup True if a backup has been made.
|
||||
*/
|
||||
*/
|
||||
do_action_deprecated( 'after_do_imagify', [ $this->path, $args['backup'] ], '1.9', 'imagify_before_optimize_file' );
|
||||
|
||||
/**
|
||||
@@ -568,7 +589,7 @@ class File {
|
||||
*
|
||||
* @param string $path Absolute path to the media file.
|
||||
* @param array $args Arguments passed to the method.
|
||||
*/
|
||||
*/
|
||||
do_action( 'imagify_after_optimize_file', $this->path, $args );
|
||||
|
||||
return $response;
|
||||
@@ -603,7 +624,7 @@ class File {
|
||||
$this->editor = new \WP_Error(
|
||||
'image_editor',
|
||||
sprintf(
|
||||
/* translators: %1$s is an error message, %2$s is a "More info?" link. */
|
||||
/* translators: %1$s is an error message, %2$s is a "More info?" link. */
|
||||
__( 'No php extensions are available to edit images on the server. ImageMagick or GD is required. The internal error is: %1$s. %2$s', 'imagify' ),
|
||||
$this->editor->get_error_message(),
|
||||
'<a href="' . esc_url( imagify_get_external_url( 'documentation-imagick-gd' ) ) . '" target="_blank">' . __( 'More info?', 'imagify' ) . '</a>'
|
||||
@@ -765,6 +786,26 @@ class File {
|
||||
return imagify_path_to_webp( $this->path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the file extension by its next-gen format extension.
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
* @param string $format the format we are targeting.
|
||||
* @return string|bool The file path on success. False if not an image or on failure.
|
||||
*/
|
||||
public function get_path_to_nextgen( string $format ) {
|
||||
if ( ! $this->is_image() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( $this->is_webp() || $this->is_avif() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return imagify_path_to_nextgen( $this->path, $format );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the file is a WebP image.
|
||||
* Rejects "path/to/.webp" files.
|
||||
@@ -778,6 +819,18 @@ class File {
|
||||
return preg_match( '@(?!^|/|\\\)\.webp$@i', $this->path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if the file is an AVIF image.
|
||||
* Rejects "path/to/.avif" files.
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_avif() {
|
||||
return preg_match( '@(?!^|/|\\\)\.avif$@i', $this->path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file mime type + file extension.
|
||||
*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,31 +1,35 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Optimization\Process;
|
||||
|
||||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Fallback class to optimize medias.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
class Noop implements ProcessInterface {
|
||||
|
||||
/**
|
||||
* The suffix used in the thumbnail size name.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @var string
|
||||
* @since 1.9
|
||||
*/
|
||||
const WEBP_SUFFIX = '@imagify-webp';
|
||||
|
||||
/**
|
||||
* The suffix used in the thumbnail size name.
|
||||
*
|
||||
* @var string
|
||||
* @since 2.2
|
||||
*/
|
||||
const AVIF_SUFFIX = '@imagify-avif';
|
||||
|
||||
/**
|
||||
* The suffix used in file name to create a temporary copy of the full size.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @var string
|
||||
* @since 1.9
|
||||
*/
|
||||
const TMP_SUFFIX = '@imagify-tmp';
|
||||
|
||||
@@ -33,9 +37,8 @@ class Noop implements ProcessInterface {
|
||||
* Used for the name of the transient telling if a media is locked.
|
||||
* %1$s is the context, %2$s is the media ID.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @var string
|
||||
* @since 1.9
|
||||
*/
|
||||
const LOCK_NAME = 'imagify_%1$s_%2$s_process_locked';
|
||||
|
||||
@@ -43,11 +46,10 @@ class Noop implements ProcessInterface {
|
||||
* Tell if the given entry can be accepted in the constructor.
|
||||
* For example it can include `is_numeric( $id )` if the constructor accepts integers.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param mixed $id Whatever.
|
||||
*
|
||||
* @param mixed $id Whatever.
|
||||
* @return bool
|
||||
*/
|
||||
public static function constructor_accepts( $id ) {
|
||||
@@ -57,9 +59,7 @@ class Noop implements ProcessInterface {
|
||||
/**
|
||||
* Get the data instance.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return DataInterface|false
|
||||
*/
|
||||
@@ -70,9 +70,7 @@ class Noop implements ProcessInterface {
|
||||
/**
|
||||
* Get the media instance.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return MediaInterface|false
|
||||
*/
|
||||
@@ -83,9 +81,7 @@ class Noop implements ProcessInterface {
|
||||
/**
|
||||
* Get the File instance.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return File|false
|
||||
*/
|
||||
@@ -96,9 +92,7 @@ class Noop implements ProcessInterface {
|
||||
/**
|
||||
* Tell if the current media is valid.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -109,106 +103,87 @@ class Noop implements ProcessInterface {
|
||||
/**
|
||||
* Tell if the current user is allowed to operate Imagify in this context.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $describer Capacity describer. See \Imagify\Context\ContextInterface->get_capacity() for possible values. Can also be a "real" user capacity.
|
||||
*
|
||||
* @param string $describer Capacity describer. See \Imagify\Context\ContextInterface->get_capacity() for possible values. Can also be a "real" user capacity.
|
||||
* @return bool
|
||||
*/
|
||||
public function current_user_can( $describer ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** OPTIMIZATION ============================================================================ */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Optimize a media files by pushing tasks into the queue.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
*
|
||||
* @return bool|WP_Error True if successfully launched. A WP_Error instance on failure.
|
||||
*/
|
||||
public function optimize( $optimization_level = null ) {
|
||||
return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
return new WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-optimize a media files with a different level.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
*
|
||||
* @return bool|WP_Error True if successfully launched. A WP_Error instance on failure.
|
||||
*/
|
||||
public function reoptimize( $optimization_level = null ) {
|
||||
return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
return new WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize several file sizes by pushing tasks into the queue.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $sizes An array of media sizes (strings). Use "full" for the size of the main file.
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
* @param array $sizes An array of media sizes (strings). Use "full" for the size of the main file.
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
*
|
||||
* @return bool|WP_Error True if successfully launched. A WP_Error instance on failure.
|
||||
*/
|
||||
public function optimize_sizes( $sizes, $optimization_level = null ) {
|
||||
return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
return new WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize one file with Imagify directly.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $size The media size.
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
* @return array|WP_Error The optimization data. A \WP_Error instance on failure.
|
||||
* @param string $size The media size.
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
*
|
||||
* @return array|WP_Error The optimization data. A WP_Error instance on failure.
|
||||
*/
|
||||
public function optimize_size( $size, $optimization_level = null ) {
|
||||
return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
return new WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the media files from the backup file.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return bool|WP_Error True on success. A \WP_Error instance on failure.
|
||||
* @return bool|WP_Error True on success. A WP_Error instance on failure.
|
||||
*/
|
||||
public function restore() {
|
||||
return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
return new WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
}
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** MISSING THUMBNAILS ====================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the sizes for this media that have not get through optimization.
|
||||
* No sizes are returned if the file is not optimized, has no backup, or is not an image.
|
||||
* The 'full' size os never returned.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return array|WP_Error {
|
||||
* A WP_Error object on failure.
|
||||
@@ -229,45 +204,30 @@ class Noop implements ProcessInterface {
|
||||
/**
|
||||
* Optimize missing thumbnail sizes.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
* @return bool|WP_Error True if successfully launched. A WP_Error instance on failure.
|
||||
*/
|
||||
public function optimize_missing_thumbnails() {
|
||||
return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
return new WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
}
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** BACKUP FILE ============================================================================= */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Delete the backup file.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
public function delete_backup() {}
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** RESIZE FILE ============================================================================= */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Maybe resize an image.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $size The size name.
|
||||
* @param File $file A File instance.
|
||||
* @return array|WP_Error A \WP_Error instance on failure, an array on success as follow: {
|
||||
* @param string $size The size name.
|
||||
* @param File $file A File instance.
|
||||
*
|
||||
* @return array|WP_Error A WP_Error instance on failure, an array on success as follow: {
|
||||
* @type bool $resized True when the image has been resized.
|
||||
* @type bool $backuped True when the image has been backuped.
|
||||
* @type int $file_size The file size in bytes.
|
||||
@@ -281,58 +241,47 @@ class Noop implements ProcessInterface {
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** WEBP ==================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Generate WebP images if they are missing.
|
||||
* Generate Nextgen images if they are missing.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
* @return bool|WP_Error True if successfully launched. A WP_Error instance on failure.
|
||||
*/
|
||||
public function generate_webp_versions() {
|
||||
return new \WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
public function generate_nextgen_versions() {
|
||||
return new WP_Error( 'invalid_media', __( 'This media is not valid.', 'imagify' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the WebP images.
|
||||
* Delete the next gen format images.
|
||||
* This doesn't delete the related optimization data.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 2.2
|
||||
*
|
||||
* @param bool $keep_full Set to true to keep the full size.
|
||||
* @return bool|WP_Error True on success. A WP_Error object on failure.
|
||||
*/
|
||||
public function delete_webp_files() {}
|
||||
|
||||
/**
|
||||
* Tell if a thumbnail size is an "Imagify WebP" size.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $size_name The size name.
|
||||
* @return string|bool The unsuffixed name of the size if WebP. False if not WebP.
|
||||
*/
|
||||
public function is_size_webp( $size_name ) {
|
||||
public function delete_nextgen_files( $keep_full = false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** PROCESS STATUS ========================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* Tell if a thumbnail size is an "Imagify Next-Gen" size.
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
* @param string $size_name The size name.
|
||||
*
|
||||
* @return string|bool The unsuffixed name of the size if Next-Gen. False if not a Next-Gen.
|
||||
*/
|
||||
public function is_size_next_gen( $size_name ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if a process is running for this media.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -343,34 +292,24 @@ class Noop implements ProcessInterface {
|
||||
/**
|
||||
* Set the running status to "running" for a period of time.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
public function lock() {}
|
||||
|
||||
/**
|
||||
* Delete the running status.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
public function unlock() {}
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** DATA ==================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Tell if a size already has optimization data.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $size The size name.
|
||||
*
|
||||
* @param string $size The size name.
|
||||
* @return bool
|
||||
*/
|
||||
public function size_has_optimization_data( $size ) {
|
||||
@@ -380,13 +319,12 @@ class Noop implements ProcessInterface {
|
||||
/**
|
||||
* Update the optimization data for a size.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param object $response The API response.
|
||||
* @param string $size The size name.
|
||||
* @param int $level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
*
|
||||
* @param object $response The API response.
|
||||
* @param string $size The size name.
|
||||
* @param int $level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
* @return array {
|
||||
* The optimization data.
|
||||
*
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<?php
|
||||
namespace Imagify\Optimization\Process;
|
||||
declare(strict_types=1);
|
||||
|
||||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||||
namespace Imagify\Optimization\Process;
|
||||
|
||||
/**
|
||||
* Interface to use to optimize medias.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
interface ProcessInterface {
|
||||
|
||||
@@ -15,11 +14,10 @@ interface ProcessInterface {
|
||||
* Tell if the given entry can be accepted in the constructor.
|
||||
* For example it can include `is_numeric( $id )` if the constructor accepts integers.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param mixed $id Whatever.
|
||||
*
|
||||
* @param mixed $id Whatever.
|
||||
* @return bool
|
||||
*/
|
||||
public static function constructor_accepts( $id );
|
||||
@@ -27,9 +25,7 @@ interface ProcessInterface {
|
||||
/**
|
||||
* Get the data instance.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return DataInterface|false
|
||||
*/
|
||||
@@ -38,9 +34,7 @@ interface ProcessInterface {
|
||||
/**
|
||||
* Get the media instance.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return MediaInterface|false
|
||||
*/
|
||||
@@ -49,9 +43,7 @@ interface ProcessInterface {
|
||||
/**
|
||||
* Get the File instance of the original file.
|
||||
*
|
||||
* @since 1.9.8
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9.8
|
||||
*
|
||||
* @return File|false
|
||||
*/
|
||||
@@ -60,9 +52,7 @@ interface ProcessInterface {
|
||||
/**
|
||||
* Get the File instance of the full size file.
|
||||
*
|
||||
* @since 1.9.8
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9.8
|
||||
*
|
||||
* @return File|false
|
||||
*/
|
||||
@@ -71,9 +61,7 @@ interface ProcessInterface {
|
||||
/**
|
||||
* Tell if the current media is valid.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -82,94 +70,75 @@ interface ProcessInterface {
|
||||
/**
|
||||
* Tell if the current user is allowed to operate Imagify in this context.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $describer Capacity describer. See \Imagify\Context\ContextInterface->get_capacity() for possible values. Can also be a "real" user capacity.
|
||||
*
|
||||
* @param string $describer Capacity describer. See \Imagify\Context\ContextInterface->get_capacity() for possible values. Can also be a "real" user capacity.
|
||||
* @return bool
|
||||
*/
|
||||
public function current_user_can( $describer );
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** OPTIMIZATION ============================================================================ */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Optimize a media files by pushing tasks into the queue.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
*
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
*/
|
||||
public function optimize( $optimization_level = null );
|
||||
|
||||
/**
|
||||
* Re-optimize a media files with a different level.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
*
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
*/
|
||||
public function reoptimize( $optimization_level = null );
|
||||
|
||||
/**
|
||||
* Optimize several file sizes by pushing tasks into the queue.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $sizes An array of media sizes (strings). Use "full" for the size of the main file.
|
||||
* @param array $sizes An array of media sizes (strings). Use "full" for the size of the main file.
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
*
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
*/
|
||||
public function optimize_sizes( $sizes, $optimization_level = null );
|
||||
|
||||
/**
|
||||
* Optimize one file with Imagify directly.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $size The media size.
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
* @return array|WP_Error The optimization data. A \WP_Error instance on failure.
|
||||
* @param string $size The media size.
|
||||
* @param int $optimization_level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
*
|
||||
* @return array|WP_Error The optimization data. A \WP_Error instance on failure.
|
||||
*/
|
||||
public function optimize_size( $size, $optimization_level = null );
|
||||
|
||||
/**
|
||||
* Restore the media files from the backup file.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return bool|WP_Error True on success. A \WP_Error instance on failure.
|
||||
*/
|
||||
public function restore();
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** MISSING THUMBNAILS ====================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the sizes for this media that have not get through optimization.
|
||||
* No sizes are returned if the file is not optimized, has no backup, or is not an image.
|
||||
* The 'full' size os never returned.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return array|WP_Error {
|
||||
* A WP_Error object on failure.
|
||||
@@ -188,42 +157,27 @@ interface ProcessInterface {
|
||||
/**
|
||||
* Optimize missing thumbnail sizes.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
*/
|
||||
public function optimize_missing_thumbnails();
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** BACKUP FILE ============================================================================= */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Delete the backup file.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
public function delete_backup();
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** RESIZE FILE ============================================================================= */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Maybe resize an image.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $size The size name.
|
||||
* @param File $file A File instance.
|
||||
*
|
||||
* @param string $size The size name.
|
||||
* @param File $file A File instance.
|
||||
* @return array|WP_Error A \WP_Error instance on failure, an array on success as follow: {
|
||||
* @type bool $resized True when the image has been resized.
|
||||
* @type bool $backuped True when the image has been backuped.
|
||||
@@ -232,77 +186,58 @@ interface ProcessInterface {
|
||||
*/
|
||||
public function maybe_resize( $size, $file );
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** WEBP ==================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Generate WebP images if they are missing.
|
||||
* Generate next-gen images if they are missing.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return bool|WP_Error True if successfully launched. A \WP_Error instance on failure.
|
||||
*/
|
||||
public function generate_webp_versions();
|
||||
public function generate_nextgen_versions();
|
||||
|
||||
/**
|
||||
* Delete the WebP images.
|
||||
* Delete the next gen format images.
|
||||
* This doesn't delete the related optimization data.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 1.9.6 Return WP_Error or true.
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 2.2
|
||||
*
|
||||
* @param bool $keep_full Set to true to keep the full size.
|
||||
* @return bool|\WP_Error True on success. A \WP_Error object on failure.
|
||||
* @param bool $keep_full Set to true to keep the full size.
|
||||
*
|
||||
* @return bool|WP_Error True on success. A \WP_Error object on failure.
|
||||
*/
|
||||
public function delete_webp_files( $keep_full = false );
|
||||
public function delete_nextgen_files( $keep_full = false );
|
||||
|
||||
/**
|
||||
* Tell if a thumbnail size is an "Imagify WebP" size.
|
||||
* Tell if a thumbnail size is an "Imagify Next-Gen" size.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 2.2
|
||||
*
|
||||
* @param string $size_name The size name.
|
||||
* @return string|bool The unsuffixed name of the size if WebP. False if not WebP.
|
||||
* @param string $size_name The size name.
|
||||
*
|
||||
* @return string|bool The unsuffixed name of the size if next-gen. False if not next-gen.
|
||||
*/
|
||||
public function is_size_webp( $size_name );
|
||||
public function is_size_next_gen( $size_name );
|
||||
|
||||
/**
|
||||
* Tell if the media has all WebP versions.
|
||||
* Tell if the media has all next-gen versions.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_full_webp();
|
||||
public function is_full_next_gen();
|
||||
|
||||
/**
|
||||
* Tell if the media has WebP versions.
|
||||
* Tell if the media has a next-gen format.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 2.2
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_webp();
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** PROCESS STATUS ========================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
public function has_next_gen();
|
||||
|
||||
/**
|
||||
* Tell if a process is running for this media.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -311,34 +246,24 @@ interface ProcessInterface {
|
||||
/**
|
||||
* Set the running status to "running" for a period of time.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
public function lock();
|
||||
|
||||
/**
|
||||
* Delete the running status.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
public function unlock();
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** DATA ==================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Tell if a size already has optimization data.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $size The size name.
|
||||
*
|
||||
* @param string $size The size name.
|
||||
* @return bool
|
||||
*/
|
||||
public function size_has_optimization_data( $size );
|
||||
@@ -346,13 +271,12 @@ interface ProcessInterface {
|
||||
/**
|
||||
* Update the optimization data for a size.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param object $response The API response.
|
||||
* @param string $size The size name.
|
||||
* @param int $level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
*
|
||||
* @param object $response The API response.
|
||||
* @param string $size The size name.
|
||||
* @param int $level The optimization level (0=normal, 1=aggressive, 2=ultra).
|
||||
* @return array {
|
||||
* The optimization data.
|
||||
*
|
||||
|
||||
@@ -1,57 +1,50 @@
|
||||
<?php
|
||||
namespace Imagify\Webp\Picture;
|
||||
declare(strict_types=1);
|
||||
|
||||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||||
namespace Imagify\Picture;
|
||||
|
||||
use Imagify\EventManagement\SubscriberInterface;
|
||||
use Imagify_Filesystem;
|
||||
|
||||
/**
|
||||
* Display WebP images on the site with <picture> tags.
|
||||
* Display Next-gen images on the site with <picture> tags.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
*/
|
||||
class Display {
|
||||
use \Imagify\Traits\InstanceGetterTrait;
|
||||
|
||||
class Display implements SubscriberInterface {
|
||||
/**
|
||||
* Option value.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @var string
|
||||
*/
|
||||
const OPTION_VALUE = 'picture';
|
||||
|
||||
/**
|
||||
* Filesystem object.
|
||||
*
|
||||
* @var \Imagify_Filesystem
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @var Imagify_Filesystem
|
||||
*/
|
||||
protected $filesystem;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @param Imagify_Filesystem $filesystem Filesystem instance.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->filesystem = \Imagify_Filesystem::get_instance();
|
||||
public function __construct( Imagify_Filesystem $filesystem ) {
|
||||
$this->filesystem = $filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init.
|
||||
* Array of events this subscriber listens to
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @return array
|
||||
*/
|
||||
public function init() {
|
||||
add_action( 'template_redirect', [ $this, 'start_content_process' ], -1000 );
|
||||
add_filter( 'imagify_process_webp_content', [ $this, 'process_content' ] );
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'template_redirect' => [ 'start_content_process', -1000 ],
|
||||
'imagify_process_webp_content' => 'process_content',
|
||||
];
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
@@ -61,28 +54,29 @@ class Display {
|
||||
/**
|
||||
* Start buffering the page content.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function start_content_process() {
|
||||
if ( ! get_imagify_option( 'display_webp' ) ) {
|
||||
if ( ! get_imagify_option( 'display_nextgen' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( self::OPTION_VALUE !== get_imagify_option( 'display_webp_method' ) ) {
|
||||
if ( self::OPTION_VALUE !== get_imagify_option( 'display_nextgen_method' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$allow = apply_filters_deprecated( 'imagify_allow_picture_tags_for_webp', [ true ], '2.2', 'imagify_allow_picture_tags_for_nextgen' );
|
||||
|
||||
/**
|
||||
* Prevent the replacement of <img> tags into <picture> tags.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param bool $allow True to allow the use of <picture> tags (default). False to prevent their use.
|
||||
*/
|
||||
$allow = apply_filters( 'imagify_allow_picture_tags_for_webp', true );
|
||||
$allow = apply_filters( 'imagify_allow_picture_tags_for_nextgen', true );
|
||||
|
||||
if ( ! $allow ) {
|
||||
return;
|
||||
@@ -94,11 +88,10 @@ class Display {
|
||||
/**
|
||||
* Maybe process the page content.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $buffer The buffer content.
|
||||
*
|
||||
* @param string $buffer The buffer content.
|
||||
* @return string
|
||||
*/
|
||||
public function maybe_process_buffer( $buffer ) {
|
||||
@@ -116,8 +109,7 @@ class Display {
|
||||
/**
|
||||
* Filter the page content after Imagify.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $buffer The page content.
|
||||
*/
|
||||
@@ -129,11 +121,10 @@ class Display {
|
||||
/**
|
||||
* Process the content.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $content The content.
|
||||
*
|
||||
* @param string $content The content.
|
||||
* @return string
|
||||
*/
|
||||
public function process_content( $content ) {
|
||||
@@ -181,13 +172,12 @@ class Display {
|
||||
/**
|
||||
* Build the <picture> tag to insert.
|
||||
*
|
||||
* @since 1.9
|
||||
* @see $this->process_image()
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
* @see $this->process_image()
|
||||
*
|
||||
* @param array $image An array of data.
|
||||
* @return string A <picture> tag.
|
||||
* @param array $image An array of data.
|
||||
*
|
||||
* @return string A <picture> tag.
|
||||
*/
|
||||
protected function build_picture_tag( $image ) {
|
||||
$to_remove = [
|
||||
@@ -210,8 +200,7 @@ class Display {
|
||||
/**
|
||||
* Filter the attributes to be added to the <picture> tag.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $attributes A list of attributes to be added to the <picture> tag.
|
||||
* @param array $data Data built from the originale <img> tag. See $this->process_image().
|
||||
@@ -233,8 +222,7 @@ class Display {
|
||||
/**
|
||||
* Allow to add more <source> tags to the <picture> tag.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $more_source_tags Additional <source> tags.
|
||||
* @param array $data Data built from the originale <img> tag. See $this->process_image().
|
||||
@@ -250,33 +238,74 @@ class Display {
|
||||
/**
|
||||
* Build the <source> tag to insert in the <picture>.
|
||||
*
|
||||
* @since 1.9
|
||||
* @see $this->process_image()
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
* @see $this->process_image()
|
||||
*
|
||||
* @param array $image An array of data.
|
||||
* @return string A <source> tag.
|
||||
* @param array $image An array of data.
|
||||
*
|
||||
* @return string A <source> tag.
|
||||
*/
|
||||
protected function build_source_tag( $image ) {
|
||||
$source = '';
|
||||
|
||||
foreach ( [ 'avif', 'webp' ] as $image_type ) {
|
||||
$attributes = $this->build_source_attributes( $image, $image_type );
|
||||
|
||||
if ( empty( $attributes ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$source .= '<source' . $this->build_attributes( $attributes ) . "/>\n";
|
||||
}
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the attribute for the source tag.
|
||||
*
|
||||
* @param array $image An array of data.
|
||||
* @param string $image_type Type of image.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function build_source_attributes( array $image, string $image_type ): array {
|
||||
$mime_type = '';
|
||||
$url = '';
|
||||
|
||||
switch ( $image_type ) {
|
||||
case 'webp':
|
||||
$mime_type = 'image/webp';
|
||||
$url = 'webp_url';
|
||||
break;
|
||||
case 'avif':
|
||||
$mime_type = 'image/avif';
|
||||
$url = 'avif_url';
|
||||
break;
|
||||
}
|
||||
|
||||
$srcset_source = ! empty( $image['srcset_attribute'] ) ? $image['srcset_attribute'] : $image['src_attribute'] . 'set';
|
||||
$attributes = [
|
||||
'type' => 'image/webp',
|
||||
'type' => $mime_type,
|
||||
$srcset_source => [],
|
||||
];
|
||||
|
||||
if ( ! empty( $image['srcset'] ) ) {
|
||||
foreach ( $image['srcset'] as $srcset ) {
|
||||
if ( empty( $srcset['webp_url'] ) ) {
|
||||
if ( empty( $srcset[ $url ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributes[ $srcset_source ][] = $srcset['webp_url'] . ' ' . $srcset['descriptor'];
|
||||
$attributes[ $srcset_source ][] = $srcset[ $url ] . ' ' . $srcset['descriptor'];
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $attributes[ $srcset_source ] ) && empty( $image['src'][ $url ] ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ( empty( $attributes[ $srcset_source ] ) ) {
|
||||
$attributes[ $srcset_source ][] = $image['src']['webp_url'];
|
||||
$attributes[ $srcset_source ][] = $image['src'][ $url ];
|
||||
}
|
||||
|
||||
$attributes[ $srcset_source ] = implode( ', ', $attributes[ $srcset_source ] );
|
||||
@@ -301,27 +330,25 @@ class Display {
|
||||
/**
|
||||
* Filter the attributes to be added to the <source> tag.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $attributes A list of attributes to be added to the <source> tag.
|
||||
* @param array $data Data built from the original <img> tag. See $this->process_image().
|
||||
*/
|
||||
$attributes = apply_filters( 'imagify_picture_source_attributes', $attributes, $image );
|
||||
|
||||
return '<source' . $this->build_attributes( $attributes ) . "/>\n";
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the <img> tag to insert in the <picture>.
|
||||
*
|
||||
* @since 1.9
|
||||
* @see $this->process_image()
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
* @see $this->process_image()
|
||||
*
|
||||
* @param array $image An array of data.
|
||||
* @return string A <img> tag.
|
||||
* @param array $image An array of data.
|
||||
*
|
||||
* @return string A <img> tag.
|
||||
*/
|
||||
protected function build_img_tag( $image ) {
|
||||
/**
|
||||
@@ -349,8 +376,7 @@ class Display {
|
||||
/**
|
||||
* Filter the attributes to be added to the <img> tag.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $attributes A list of attributes to be added to the <img> tag.
|
||||
* @param array $data Data built from the originale <img> tag. See $this->process_image().
|
||||
@@ -363,12 +389,11 @@ class Display {
|
||||
/**
|
||||
* Create HTML attributes from an array.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $attributes A list of attribute pairs.
|
||||
* @return string HTML attributes.
|
||||
* @param array $attributes A list of attribute pairs.
|
||||
*
|
||||
* @return string HTML attributes.
|
||||
*/
|
||||
protected function build_attributes( $attributes ) {
|
||||
if ( ! $attributes || ! is_array( $attributes ) ) {
|
||||
@@ -391,11 +416,10 @@ class Display {
|
||||
/**
|
||||
* Get a list of images in a content.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $content The content.
|
||||
*
|
||||
* @param string $content The content.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_images( $content ) {
|
||||
@@ -412,9 +436,8 @@ class Display {
|
||||
/**
|
||||
* Filter the images to display with a <picture> tag.
|
||||
*
|
||||
* @since 1.9
|
||||
* @see $this->process_image()
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
* @see $this->process_image()
|
||||
*
|
||||
* @param array $images A list of arrays.
|
||||
* @param string $content The page content.
|
||||
@@ -426,12 +449,23 @@ class Display {
|
||||
}
|
||||
|
||||
foreach ( $images as $i => $image ) {
|
||||
if ( empty( $image['src']['webp_exists'] ) || empty( $image['src']['webp_url'] ) ) {
|
||||
if ( ( empty( $image['src']['webp_exists'] ) || empty( $image['src']['webp_url'] ) ) &&
|
||||
( empty( $image['src']['avif_exists'] ) || empty( $image['src']['avif_url'] ) ) ) {
|
||||
|
||||
unset( $images[ $i ] );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( empty( $image['src']['webp_exists'] ) || empty( $image['src']['webp_url'] ) ) {
|
||||
unset( $images[ $i ]['src']['webp_url'] );
|
||||
}
|
||||
|
||||
if ( empty( $image['src']['avif_exists'] ) || empty( $image['src']['avif_url'] ) ) {
|
||||
unset( $images[ $i ]['src']['avif_url'] );
|
||||
}
|
||||
|
||||
unset( $images[ $i ]['src']['webp_path'], $images[ $i ]['src']['webp_exists'] );
|
||||
unset( $images[ $i ]['src']['avif_path'], $images[ $i ]['src']['avif_exists'] );
|
||||
|
||||
if ( empty( $image['srcset'] ) || ! is_array( $image['srcset'] ) ) {
|
||||
unset( $images[ $i ]['srcset'] );
|
||||
@@ -443,11 +477,22 @@ class Display {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ( empty( $srcset['webp_exists'] ) || empty( $srcset['webp_url'] ) ) &&
|
||||
( empty( $srcset['avif_exists'] ) || empty( $srcset['avif_url'] ) ) ) {
|
||||
unset( $images[ $i ]['srcset'][ $j ]['webp_url'] );
|
||||
unset( $images[ $i ]['srcset'][ $j ]['avif_url'] );
|
||||
}
|
||||
|
||||
if ( empty( $srcset['webp_exists'] ) || empty( $srcset['webp_url'] ) ) {
|
||||
unset( $images[ $i ]['srcset'][ $j ]['webp_url'] );
|
||||
}
|
||||
|
||||
if ( empty( $srcset['avif_exists'] ) || empty( $srcset['avif_url'] ) ) {
|
||||
unset( $images[ $i ]['srcset'][ $j ]['avif_url'] );
|
||||
}
|
||||
|
||||
unset( $images[ $i ]['srcset'][ $j ]['webp_path'], $images[ $i ]['srcset'][ $j ]['webp_exists'] );
|
||||
unset( $images[ $i ]['srcset'][ $j ]['avif_path'], $images[ $i ]['srcset'][ $j ]['avif_exists'] );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,9 +502,7 @@ class Display {
|
||||
/**
|
||||
* Process an image tag and get an array containing some data.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $image An image html tag.
|
||||
* @return array|false {
|
||||
@@ -527,24 +570,21 @@ class Display {
|
||||
return false;
|
||||
}
|
||||
|
||||
$webp_url = imagify_path_to_webp( $src['src'] );
|
||||
$webp_path = $this->url_to_path( $webp_url );
|
||||
$webp_url .= ! empty( $src['query'] ) ? $src['query'] : '';
|
||||
|
||||
$data = [
|
||||
'tag' => $image,
|
||||
'attributes' => $attributes,
|
||||
'src_attribute' => $src_source,
|
||||
'src' => [
|
||||
'url' => $attributes[ $src_source ],
|
||||
'webp_url' => $webp_url,
|
||||
'webp_path' => $webp_path,
|
||||
'webp_exists' => $webp_path && $this->filesystem->exists( $webp_path ),
|
||||
],
|
||||
'srcset_attribute' => false,
|
||||
'srcset' => [],
|
||||
];
|
||||
|
||||
foreach ( $this->get_nextgen_image_data_set( $src ) as $key => $value ) {
|
||||
$data['src'][ $key ] = $value;
|
||||
}
|
||||
|
||||
// Deal with the srcset attribute.
|
||||
$srcset_source = false;
|
||||
|
||||
@@ -556,6 +596,8 @@ class Display {
|
||||
}
|
||||
|
||||
if ( $srcset_source ) {
|
||||
$srcset_data = [];
|
||||
|
||||
$data['srcset_attribute'] = $srcset_source;
|
||||
|
||||
$srcset = explode( ',', $attributes[ $srcset_source ] );
|
||||
@@ -582,25 +624,23 @@ class Display {
|
||||
continue;
|
||||
}
|
||||
|
||||
$webp_url = imagify_path_to_webp( $src['src'] );
|
||||
$webp_path = $this->url_to_path( $webp_url );
|
||||
$webp_url .= ! empty( $src['query'] ) ? $src['query'] : '';
|
||||
|
||||
$data['srcset'][] = [
|
||||
$srcset_data = [
|
||||
'url' => $srcs[0],
|
||||
'descriptor' => $srcs[1],
|
||||
'webp_url' => $webp_url,
|
||||
'webp_path' => $webp_path,
|
||||
'webp_exists' => $webp_path && $this->filesystem->exists( $webp_path ),
|
||||
];
|
||||
|
||||
foreach ( $this->get_nextgen_image_data_set( $src ) as $key => $value ) {
|
||||
$srcset_data[ $key ] = $value;
|
||||
}
|
||||
|
||||
$data['srcset'][] = $srcset_data;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a processed image tag.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $data An array of data for this image.
|
||||
* @param string $image An image html tag.
|
||||
@@ -618,14 +658,41 @@ class Display {
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next-gen image(webp & avif) data set.
|
||||
*
|
||||
* @param array $src Array of url/path segments.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_nextgen_image_data_set( array $src ): array {
|
||||
$webp_url = imagify_path_to_nextgen( $src['src'], 'webp' );
|
||||
$webp_path = $this->url_to_path( $webp_url );
|
||||
|
||||
$avif_url = imagify_path_to_nextgen( $src['src'], 'avif' );
|
||||
$avif_path = $this->url_to_path( $avif_url );
|
||||
$query_string = ! empty( $src['query'] ) ? $src['query'] : '';
|
||||
|
||||
return [
|
||||
// WebP data set.
|
||||
'webp_url' => $webp_url . $query_string,
|
||||
'webp_path' => $webp_path,
|
||||
'webp_exists' => $webp_path && $this->filesystem->exists( $webp_path ),
|
||||
|
||||
// Avif data set.
|
||||
'avif_url' => $avif_url . $query_string,
|
||||
'avif_path' => $avif_path,
|
||||
'avif_exists' => $avif_path && $this->filesystem->exists( $avif_path ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell if a content is HTML.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $content The content.
|
||||
*
|
||||
* @param string $content The content.
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_html( $content ) {
|
||||
@@ -635,11 +702,10 @@ class Display {
|
||||
/**
|
||||
* Convert a file URL to an absolute path.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @param string $url A file URL.
|
||||
*
|
||||
* @param string $url A file URL.
|
||||
* @return string|bool The file path. False on failure.
|
||||
*/
|
||||
protected function url_to_path( $url ) {
|
||||
@@ -658,7 +724,7 @@ class Display {
|
||||
$uploads_dir = $this->filesystem->get_upload_basedir( true );
|
||||
$root_url = set_url_scheme( $this->filesystem->get_site_root_url() );
|
||||
$root_dir = $this->filesystem->get_site_root();
|
||||
$cdn_url = $this->get_cdn_source();
|
||||
$cdn_url = apply_filters( 'imagify_cdn_source_url', '' );
|
||||
$cdn_url = $cdn_url['url'] ? set_url_scheme( $cdn_url['url'] ) : false;
|
||||
$domain_url = wp_parse_url( $root_url );
|
||||
|
||||
@@ -693,108 +759,4 @@ class Display {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the CDN "source".
|
||||
*
|
||||
* @since 1.9.3
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $option_url An URL to use instead of the one stored in the option. It is used only if no constant/filter.
|
||||
* @return array {
|
||||
* @type string $source Where does it come from? Possible values are 'constant', 'filter', or 'option'.
|
||||
* @type string $name Who? Can be a constant name, a plugin name, or an empty string.
|
||||
* @type string $url The CDN URL, with a trailing slash. An empty string if no URL is set.
|
||||
* }
|
||||
*/
|
||||
public function get_cdn_source( $option_url = '' ) {
|
||||
if ( defined( 'IMAGIFY_CDN_URL' ) && IMAGIFY_CDN_URL && is_string( IMAGIFY_CDN_URL ) ) {
|
||||
// Use a constant.
|
||||
$source = [
|
||||
'source' => 'constant',
|
||||
'name' => 'IMAGIFY_CDN_URL',
|
||||
'url' => IMAGIFY_CDN_URL,
|
||||
];
|
||||
} else {
|
||||
// Maybe use a filter.
|
||||
$filter_source = [
|
||||
'name' => null,
|
||||
'url' => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* Provide a custom CDN source.
|
||||
*
|
||||
* @since 1.9.3
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param array $filter_source {
|
||||
* @type $name string The name of which provides the URL (plugin name, etc).
|
||||
* @type $url string The CDN URL.
|
||||
* }
|
||||
*/
|
||||
$filter_source = apply_filters( 'imagify_cdn_source', $filter_source );
|
||||
|
||||
if ( ! empty( $filter_source['url'] ) ) {
|
||||
$source = [
|
||||
'source' => 'filter',
|
||||
'name' => ! empty( $filter_source['name'] ) ? $filter_source['name'] : '',
|
||||
'url' => $filter_source['url'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $source['url'] ) ) {
|
||||
// No constant, no filter: use the option.
|
||||
$source = [
|
||||
'source' => 'option',
|
||||
'name' => '',
|
||||
'url' => $option_url && is_string( $option_url ) ? $option_url : get_imagify_option( 'cdn_url' ),
|
||||
];
|
||||
}
|
||||
|
||||
if ( empty( $source['url'] ) ) {
|
||||
// Nothing set.
|
||||
return [
|
||||
'source' => 'option',
|
||||
'name' => '',
|
||||
'url' => '',
|
||||
];
|
||||
}
|
||||
|
||||
$source['url'] = $this->sanitize_cdn_url( $source['url'] );
|
||||
|
||||
if ( empty( $source['url'] ) ) {
|
||||
// Not an URL.
|
||||
return [
|
||||
'source' => 'option',
|
||||
'name' => '',
|
||||
'url' => '',
|
||||
];
|
||||
}
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the CDN URL value.
|
||||
*
|
||||
* @since 1.9.3
|
||||
* @access public
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @param string $url The URL to sanitize.
|
||||
* @return string
|
||||
*/
|
||||
public function sanitize_cdn_url( $url ) {
|
||||
$url = sanitize_text_field( $url );
|
||||
|
||||
if ( ! $url || ! preg_match( '@^https?://.+\.[^.]+@i', $url ) ) {
|
||||
// Not an URL.
|
||||
return '';
|
||||
}
|
||||
|
||||
return trailingslashit( $url );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Picture;
|
||||
|
||||
use Imagify\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service provider for Picture display
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
/**
|
||||
* Services provided by this provider
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'picture_display',
|
||||
];
|
||||
|
||||
/**
|
||||
* Subscribers provided by this provider
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $subscribers = [
|
||||
'picture_display',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the provided classes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$this->getContainer()->share( 'picture_display', Display::class )
|
||||
->addArgument( $this->getContainer()->get( 'filesystem' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subscribers array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_subscribers() {
|
||||
return $this->subscribers;
|
||||
}
|
||||
}
|
||||
@@ -3,16 +3,33 @@ declare(strict_types=1);
|
||||
|
||||
namespace Imagify;
|
||||
|
||||
use Imagify\Bulk\Bulk;
|
||||
use Imagify\CLI\BulkOptimizeCommand;
|
||||
use Imagify\CLI\GenerateMissingWebpCommand;
|
||||
use Imagify\Notices\Notices;
|
||||
use Imagify\Admin\AdminBar;
|
||||
use Imagify\Bulk\Bulk;
|
||||
use Imagify\CLI\{BulkOptimizeCommand, GenerateMissingNextgenCommand};
|
||||
use Imagify\Dependencies\League\Container\Container;
|
||||
use Imagify\Dependencies\League\Container\ServiceProvider\ServiceProviderInterface;
|
||||
use Imagify\EventManagement\{EventManager, SubscriberInterface};
|
||||
use Imagify\Notices\Notices;
|
||||
use Imagify_Filesystem;
|
||||
|
||||
/**
|
||||
* Main plugin class.
|
||||
*/
|
||||
class Plugin {
|
||||
/**
|
||||
* Container instance.
|
||||
*
|
||||
* @var Container
|
||||
*/
|
||||
private $container;
|
||||
|
||||
/**
|
||||
* Is the plugin loaded
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $loaded = false;
|
||||
|
||||
/**
|
||||
* Absolute path to the plugin (with trailing slash).
|
||||
*
|
||||
@@ -25,22 +42,64 @@ class Plugin {
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $plugin_args {
|
||||
* @param Container $container Instance of the container.
|
||||
* @param array $plugin_args {
|
||||
* An array of arguments.
|
||||
*
|
||||
* @type string $plugin_path Absolute path to the plugin (with trailing slash).
|
||||
* }
|
||||
*/
|
||||
public function __construct( $plugin_args ) {
|
||||
public function __construct( Container $container, $plugin_args ) {
|
||||
$this->container = $container;
|
||||
$this->plugin_path = $plugin_args['plugin_path'];
|
||||
|
||||
add_filter( 'imagify_container', [ $this, 'get_container' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the container instance.
|
||||
*
|
||||
* @return Container
|
||||
*/
|
||||
public function get_container() {
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the plugin is loaded
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
private function is_loaded(): bool {
|
||||
return $this->loaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin init.
|
||||
*
|
||||
* @param array $providers Array of service providers.
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
public function init() {
|
||||
public function init( $providers ) {
|
||||
if ( $this->is_loaded() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->container->share(
|
||||
'event_manager',
|
||||
function () {
|
||||
return new EventManager();
|
||||
}
|
||||
);
|
||||
|
||||
$this->container->share(
|
||||
'filesystem',
|
||||
function() {
|
||||
return new Imagify_Filesystem();
|
||||
}
|
||||
);
|
||||
|
||||
$this->include_files();
|
||||
|
||||
class_alias( '\\Imagify\\Traits\\InstanceGetterTrait', '\\Imagify\\Traits\\FakeSingletonTrait' );
|
||||
@@ -55,7 +114,6 @@ class Plugin {
|
||||
\Imagify_Cron_Sync_Files::get_instance()->init();
|
||||
\Imagify\Auth\Basic::get_instance()->init();
|
||||
\Imagify\Job\MediaOptimization::get_instance()->init();
|
||||
\Imagify\Stats\OptimizedMediaWithoutWebp::get_instance()->init();
|
||||
Bulk::get_instance()->init();
|
||||
AdminBar::get_instance()->init();
|
||||
|
||||
@@ -72,15 +130,21 @@ class Plugin {
|
||||
\Imagify_Assets::get_instance()->init();
|
||||
}
|
||||
|
||||
\Imagify\Webp\Display::get_instance()->init();
|
||||
|
||||
add_action( 'init', [ $this, 'maybe_activate' ] );
|
||||
|
||||
// Load plugin translations.
|
||||
imagify_load_translations();
|
||||
|
||||
imagify_add_command( new BulkOptimizeCommand() );
|
||||
imagify_add_command( new GenerateMissingWebpCommand() );
|
||||
imagify_add_command( new GenerateMissingNextgenCommand() );
|
||||
|
||||
foreach ( $providers as $service_provider ) {
|
||||
$provider_instance = new $service_provider();
|
||||
$this->container->addServiceProvider( $provider_instance );
|
||||
|
||||
// Load each service provider's subscribers if found.
|
||||
$this->load_subscribers( $provider_instance );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when Imagify is fully loaded.
|
||||
@@ -91,6 +155,8 @@ class Plugin {
|
||||
* @param \Imagify_Plugin $plugin Instance of this class.
|
||||
*/
|
||||
do_action( 'imagify_loaded', $this );
|
||||
|
||||
$this->loaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,4 +237,25 @@ class Plugin {
|
||||
*/
|
||||
do_action( 'imagify_activation', (int) $user_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Load list of event subscribers from service provider.
|
||||
*
|
||||
* @param ServiceProviderInterface $service_provider Instance of service provider.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function load_subscribers( ServiceProviderInterface $service_provider ) {
|
||||
if ( empty( $service_provider->get_subscribers() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $service_provider->get_subscribers() as $subscriber ) {
|
||||
$subscriber_object = $this->container->get( $subscriber );
|
||||
|
||||
if ( $subscriber_object instanceof SubscriberInterface ) {
|
||||
$this->container->get( 'event_manager' )->add_subscriber( $subscriber_object );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Stats;
|
||||
|
||||
use Imagify\Bulk\Bulk;
|
||||
use Imagify\EventManagement\SubscriberInterface;
|
||||
use Imagify\Traits\InstanceGetterTrait;
|
||||
|
||||
/**
|
||||
* Class to get and cache the number of optimized media without WebP versions.
|
||||
*
|
||||
* @since 1.9
|
||||
* Class to get and cache the number of optimized media without next-gen versions.
|
||||
*/
|
||||
class OptimizedMediaWithoutWebp implements StatInterface {
|
||||
class OptimizedMediaWithoutNextGen implements StatInterface, SubscriberInterface {
|
||||
use InstanceGetterTrait;
|
||||
|
||||
/**
|
||||
@@ -17,28 +18,26 @@ class OptimizedMediaWithoutWebp implements StatInterface {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const NAME = 'imagify_stat_without_webp';
|
||||
const NAME = 'imagify_stat_without_next_gen';
|
||||
|
||||
/**
|
||||
* Launch hooks.
|
||||
* Array of events this subscriber listens to
|
||||
*
|
||||
* @since 1.9
|
||||
* @return array
|
||||
*/
|
||||
public function init() {
|
||||
add_action( 'imagify_after_optimize', [ $this, 'maybe_clear_cache_after_optimization' ], 10, 2 );
|
||||
add_action( 'imagify_after_restore_media', [ $this, 'maybe_clear_cache_after_restoration' ], 10, 4 );
|
||||
add_action( 'imagify_delete_media', [ $this, 'maybe_clear_cache_on_deletion' ] );
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'imagify_after_optimize' => [ 'maybe_clear_cache_after_optimization', 10, 2 ],
|
||||
'imagify_after_restore_media' => [ 'maybe_clear_cache_after_restoration', 10, 4 ],
|
||||
'imagify_delete_media' => 'maybe_clear_cache_on_deletion',
|
||||
'update_option_imagify_settings' => [ 'maybe_clear_stat_cache', 9, 2 ],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** GET/CACHE THE STAT ====================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the number of optimized media without WebP versions.
|
||||
* Get the number of optimized media without next-gen versions.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 2.2
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
@@ -48,16 +47,16 @@ class OptimizedMediaWithoutWebp implements StatInterface {
|
||||
|
||||
// Sum the counts of each context.
|
||||
foreach ( imagify_get_context_names() as $context ) {
|
||||
$stat += $bulk->get_bulk_instance( $context )->has_optimized_media_without_webp();
|
||||
$stat += $bulk->get_bulk_instance( $context )->has_optimized_media_without_nextgen();
|
||||
}
|
||||
|
||||
return $stat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get and cache the number of optimized media without WebP versions.
|
||||
* Get and cache the number of optimized media without next-gen versions.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 2.2
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
@@ -83,21 +82,16 @@ class OptimizedMediaWithoutWebp implements StatInterface {
|
||||
/**
|
||||
* Clear the stat cache.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 2.2
|
||||
*/
|
||||
public function clear_cache() {
|
||||
delete_transient( static::NAME );
|
||||
}
|
||||
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** HOOKS =================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Clear cache after optimizing a media.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 2.2
|
||||
*
|
||||
* @param ProcessInterface $process The optimization process.
|
||||
* @param array $item The item being processed.
|
||||
@@ -113,11 +107,15 @@ class OptimizedMediaWithoutWebp implements StatInterface {
|
||||
$new_sizes = array_intersect_key( $sizes, $new_sizes );
|
||||
$size_name = 'full' . $process::WEBP_SUFFIX;
|
||||
|
||||
if ( get_imagify_option( 'convert_to_avif' ) ) {
|
||||
$size_name = 'full' . $process::AVIF_SUFFIX;
|
||||
}
|
||||
|
||||
if ( ! isset( $new_sizes['full'] ) && ! empty( $new_sizes[ $size_name ]['success'] ) ) {
|
||||
/**
|
||||
* We just successfully generated the WebP version of the full size.
|
||||
* We just successfully generated the next-gen version of the full size.
|
||||
* The full size was not optimized at the same time, that means it was optimized previously.
|
||||
* Meaning: we just added a WebP version to a media that was previously optimized, so there is one less optimized media without WebP.
|
||||
* Meaning: we just added a next-gen version to a media that was previously optimized, so there is one less optimized media without next-gen.
|
||||
*/
|
||||
$this->clear_cache();
|
||||
return;
|
||||
@@ -125,7 +123,7 @@ class OptimizedMediaWithoutWebp implements StatInterface {
|
||||
|
||||
if ( ! empty( $new_sizes['full']['success'] ) && empty( $new_sizes[ $size_name ]['success'] ) ) {
|
||||
/**
|
||||
* We now have a new optimized media without WebP.
|
||||
* We now have a new optimized media without next-gen.
|
||||
*/
|
||||
$this->clear_cache();
|
||||
}
|
||||
@@ -134,7 +132,7 @@ class OptimizedMediaWithoutWebp implements StatInterface {
|
||||
/**
|
||||
* Clear cache after restoring a media.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 2.2
|
||||
*
|
||||
* @param ProcessInterface $process The optimization process.
|
||||
* @param bool|WP_Error $response The result of the operation: true on success, a WP_Error object on failure.
|
||||
@@ -149,9 +147,13 @@ class OptimizedMediaWithoutWebp implements StatInterface {
|
||||
$sizes = isset( $data['sizes'] ) ? (array) $data['sizes'] : [];
|
||||
$size_name = 'full' . $process::WEBP_SUFFIX;
|
||||
|
||||
if ( get_imagify_option( 'convert_to_avif' ) ) {
|
||||
$size_name = 'full' . $process::AVIF_SUFFIX;
|
||||
}
|
||||
|
||||
if ( ! empty( $sizes['full']['success'] ) && empty( $sizes[ $size_name ]['success'] ) ) {
|
||||
/**
|
||||
* This media had no WebP versions.
|
||||
* This media had no next-gen versions.
|
||||
*/
|
||||
$this->clear_cache();
|
||||
}
|
||||
@@ -160,7 +162,7 @@ class OptimizedMediaWithoutWebp implements StatInterface {
|
||||
/**
|
||||
* Clear cache on media deletion.
|
||||
*
|
||||
* @since 1.9
|
||||
* @since 2.2
|
||||
*
|
||||
* @param ProcessInterface $process An optimization process.
|
||||
*/
|
||||
@@ -173,11 +175,37 @@ class OptimizedMediaWithoutWebp implements StatInterface {
|
||||
$sizes = isset( $data['sizes'] ) ? (array) $data['sizes'] : [];
|
||||
$size_name = 'full' . $process::WEBP_SUFFIX;
|
||||
|
||||
if ( get_imagify_option( 'convert_to_avif' ) ) {
|
||||
$size_name = 'full' . $process::AVIF_SUFFIX;
|
||||
}
|
||||
|
||||
if ( ! empty( $sizes['full']['success'] ) && empty( $sizes[ $size_name ]['success'] ) ) {
|
||||
/**
|
||||
* This media had no WebP versions.
|
||||
* This media had no next-gen versions.
|
||||
*/
|
||||
$this->clear_cache();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe clear the stat cache on option change
|
||||
*
|
||||
* @since 2.2
|
||||
*
|
||||
* @param array $old_value The old option value.
|
||||
* @param array $value The new option value.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function maybe_clear_stat_cache( $old_value, $value ) {
|
||||
if ( isset( $old_value['convert_to_avif'] ) && isset( $value['convert_to_avif'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! isset( $old_value['convert_to_avif'] ) && ! isset( $value['convert_to_avif'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->clear_cache();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Stats;
|
||||
|
||||
use Imagify\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider;
|
||||
|
||||
/**
|
||||
* Service provider for Stats
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
/**
|
||||
* Services provided by this provider
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'optimized_media_without_next_gen',
|
||||
];
|
||||
|
||||
/**
|
||||
* Subscribers provided by this provider
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $subscribers = [
|
||||
'optimized_media_without_next_gen',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the provided classes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$this->getContainer()->share( 'optimized_media_without_next_gen', OptimizedMediaWithoutNextGen::class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subscribers array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_subscribers() {
|
||||
return $this->subscribers;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,29 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Webp;
|
||||
|
||||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||||
use Imagify\WriteFile\AbstractApacheDirConfFile;
|
||||
|
||||
/**
|
||||
* Add and remove contents to the .htaccess file to display WebP images on the site.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
class Apache extends \Imagify\WriteFile\AbstractApacheDirConfFile {
|
||||
class Apache extends AbstractApacheDirConfFile {
|
||||
|
||||
/**
|
||||
* Name of the tag used as block delemiter.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @var string
|
||||
* @since 1.9
|
||||
*/
|
||||
const TAG_NAME = 'Imagify: webp file type';
|
||||
|
||||
/**
|
||||
* Get unfiltered new contents to write into the file.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
||||
@@ -1,70 +1,64 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Webp;
|
||||
|
||||
use Imagify\EventManagement\SubscriberInterface;
|
||||
use Imagify\Notices\Notices;
|
||||
use Imagify\Traits\InstanceGetterTrait;
|
||||
use Imagify\WriteFile\WriteFileInterface;
|
||||
|
||||
/**
|
||||
* Display WebP images on the site.
|
||||
* Display WebP images on the site using picture tag.
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
class Display {
|
||||
class Display implements SubscriberInterface {
|
||||
use InstanceGetterTrait;
|
||||
|
||||
/**
|
||||
* Server conf object.
|
||||
*
|
||||
* @var \Imagify\WriteFile\WriteFileInterface
|
||||
* @var WriteFileInterface|null
|
||||
* @since 1.9
|
||||
*/
|
||||
protected $server_conf;
|
||||
protected $server_conf = null;
|
||||
|
||||
/**
|
||||
* Init.
|
||||
* Returns an array of events this subscriber listens to
|
||||
*
|
||||
* @since 1.9
|
||||
* @return array
|
||||
*/
|
||||
public function init() {
|
||||
add_filter( 'imagify_settings_on_save', [ $this, 'maybe_add_rewrite_rules' ] );
|
||||
add_action( 'imagify_settings_webp_info', [ $this, 'maybe_add_webp_info' ] );
|
||||
add_action( 'imagify_activation', [ $this, 'activate' ] );
|
||||
add_action( 'imagify_deactivation', [ $this, 'deactivate' ] );
|
||||
|
||||
Picture\Display::get_instance()->init();
|
||||
RewriteRules\Display::get_instance()->init();
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'imagify_settings_on_save' => [ 'maybe_add_rewrite_rules', 13 ],
|
||||
'imagify_settings_webp_info' => 'maybe_add_webp_info',
|
||||
'imagify_activation' => 'activate',
|
||||
'imagify_deactivation' => 'deactivate',
|
||||
];
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** HOOKS =================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* If display WebP images, add the WebP type to the .htaccess/etc file.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $values The option values.
|
||||
* @param array $values The option values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function maybe_add_rewrite_rules( $values ) {
|
||||
$old_value = (bool) get_imagify_option( 'display_webp' );
|
||||
// See \Imagify_Options->validate_values_on_update() for why we use 'convert_to_webp' here.
|
||||
$new_value = ! empty( $values['display_webp'] ) && ! empty( $values['convert_to_webp'] );
|
||||
|
||||
if ( $old_value === $new_value ) {
|
||||
// No changes.
|
||||
return $values;
|
||||
}
|
||||
|
||||
if ( ! $this->get_server_conf() ) {
|
||||
return $values;
|
||||
}
|
||||
|
||||
if ( $new_value ) {
|
||||
$enabled = isset( $values['display_nextgen'] ) ? true : false;
|
||||
$result = false;
|
||||
|
||||
if ( $enabled ) {
|
||||
// Add the WebP file type.
|
||||
$result = $this->get_server_conf()->add();
|
||||
} else {
|
||||
} elseif ( ! $enabled ) {
|
||||
// Remove the WebP file type.
|
||||
$result = $this->get_server_conf()->remove();
|
||||
}
|
||||
@@ -76,10 +70,12 @@ class Display {
|
||||
// Display an error message.
|
||||
if ( is_multisite() && strpos( wp_get_referer(), network_admin_url( '/' ) ) === 0 ) {
|
||||
Notices::get_instance()->add_network_temporary_notice( $result->get_error_message() );
|
||||
} else {
|
||||
Notices::get_instance()->add_site_temporary_notice( $result->get_error_message() );
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
Notices::get_instance()->add_site_temporary_notice( $result->get_error_message() );
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
@@ -130,9 +126,11 @@ class Display {
|
||||
if ( ! $conf ) {
|
||||
return;
|
||||
}
|
||||
if ( ! get_imagify_option( 'display_webp' ) ) {
|
||||
|
||||
if ( ! get_imagify_option( 'display_nextgen' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( is_wp_error( $conf->is_file_writable() ) ) {
|
||||
return;
|
||||
}
|
||||
@@ -151,9 +149,6 @@ class Display {
|
||||
if ( ! $conf ) {
|
||||
return;
|
||||
}
|
||||
if ( ! get_imagify_option( 'display_webp' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$file_path = $conf->get_file_path();
|
||||
$filesystem = \Imagify_Filesystem::get_instance();
|
||||
@@ -168,10 +163,6 @@ class Display {
|
||||
$conf->remove();
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** TOOLS =================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the path to the directory conf file.
|
||||
*
|
||||
@@ -194,30 +185,13 @@ class Display {
|
||||
return $file_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WebP display method by validating the given value.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $values The option values.
|
||||
* @return string 'picture' or 'rewrite'.
|
||||
*/
|
||||
public function get_display_webp_method( $values ) {
|
||||
$options = \Imagify_Options::get_instance();
|
||||
$default = $options->get_default_values();
|
||||
$default = $default['display_webp_method'];
|
||||
$method = ! empty( $values['display_webp_method'] ) ? $values['display_webp_method'] : '';
|
||||
|
||||
return $options->sanitize_and_validate( 'display_webp_method', $method, $default );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the server conf instance.
|
||||
* Note: nothing needed for nginx.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @return \Imagify\WriteFile\WriteFileInterface
|
||||
* @return WriteFileInterface
|
||||
*/
|
||||
protected function get_server_conf() {
|
||||
global $is_apache, $is_iis7;
|
||||
@@ -230,8 +204,6 @@ class Display {
|
||||
$this->server_conf = new Apache();
|
||||
} elseif ( $is_iis7 ) {
|
||||
$this->server_conf = new IIS();
|
||||
} else {
|
||||
$this->server_conf = false;
|
||||
}
|
||||
|
||||
return $this->server_conf;
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Webp;
|
||||
|
||||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||||
use Imagify\WriteFile\AbstractIISDirConfFile;
|
||||
|
||||
/**
|
||||
* Add and remove contents to the web.config file to display WebP images on the site.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
class IIS extends \Imagify\WriteFile\AbstractIISDirConfFile {
|
||||
class IIS extends AbstractIISDirConfFile {
|
||||
|
||||
/**
|
||||
* Name of the tag used as block delemiter.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @var string
|
||||
* @since 1.9
|
||||
*/
|
||||
const TAG_NAME = 'Imagify: webp file type';
|
||||
|
||||
/**
|
||||
* Get unfiltered new contents to write into the file.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Webp\RewriteRules;
|
||||
|
||||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||||
use Imagify\WriteFile\AbstractApacheDirConfFile;
|
||||
|
||||
/**
|
||||
* Add and remove rewrite rules to the .htaccess file to display WebP images on the site.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
class Apache extends \Imagify\WriteFile\AbstractApacheDirConfFile {
|
||||
class Apache extends AbstractApacheDirConfFile {
|
||||
|
||||
/**
|
||||
* Name of the tag used as block delemiter.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @var string
|
||||
* @since 1.9
|
||||
*/
|
||||
const TAG_NAME = 'Imagify: rewrite rules for webp';
|
||||
|
||||
@@ -24,14 +24,13 @@ class Apache extends \Imagify\WriteFile\AbstractApacheDirConfFile {
|
||||
* Get unfiltered new contents to write into the file.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @source https://github.com/vincentorback/WebP-images-with-htaccess
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_raw_new_contents() {
|
||||
$extensions = $this->get_extensions_pattern();
|
||||
$extensions = str_replace( '|webp', '', $extensions );
|
||||
$home_root = wp_parse_url( home_url( '/' ) );
|
||||
$home_root = $home_root['path'];
|
||||
|
||||
|
||||
@@ -1,100 +1,80 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Webp\RewriteRules;
|
||||
|
||||
use Imagify\EventManagement\SubscriberInterface;
|
||||
use Imagify\Notices\Notices;
|
||||
use Imagify\Traits\InstanceGetterTrait;
|
||||
use Imagify\WriteFile\AbstractWriteDirConfFile;
|
||||
use Imagify\WriteFile\WriteFileInterface;
|
||||
|
||||
/**
|
||||
* Display WebP images on the site with rewrite rules.
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
class Display {
|
||||
use InstanceGetterTrait;
|
||||
|
||||
class Display implements SubscriberInterface {
|
||||
/**
|
||||
* Configuration file writer.
|
||||
*
|
||||
* @var AbstractWriteDirConfFile
|
||||
* @var WriteFileInterface|null
|
||||
*/
|
||||
protected $server_conf;
|
||||
protected $server_conf = null;
|
||||
|
||||
/**
|
||||
* Option value.
|
||||
*
|
||||
* @var string
|
||||
* @var string
|
||||
* @since 1.9
|
||||
*/
|
||||
const OPTION_VALUE = 'rewrite';
|
||||
|
||||
/**
|
||||
* Init.
|
||||
* Returns an array of events this subscriber listens to
|
||||
*
|
||||
* @since 1.9
|
||||
* @return array
|
||||
*/
|
||||
public function init() {
|
||||
add_filter( 'imagify_settings_on_save', [ $this, 'maybe_add_rewrite_rules' ] );
|
||||
add_action( 'imagify_settings_webp_info', [ $this, 'maybe_add_webp_info' ] );
|
||||
add_action( 'imagify_activation', [ $this, 'activate' ] );
|
||||
add_action( 'imagify_deactivation', [ $this, 'deactivate' ] );
|
||||
public static function get_subscribed_events() {
|
||||
return [
|
||||
'imagify_settings_on_save' => [ 'maybe_add_rewrite_rules', 10 ],
|
||||
'imagify_settings_webp_info' => 'maybe_add_webp_info',
|
||||
'imagify_activation' => 'activate',
|
||||
'imagify_deactivation' => 'deactivate',
|
||||
];
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** HOOKS =================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* If display WebP images via rewrite rules, add the rules to the .htaccess/etc file.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @param array $values The option values.
|
||||
* @param array $values The option values.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function maybe_add_rewrite_rules( $values ) {
|
||||
global $is_apache, $is_iis7, $is_nginx;
|
||||
|
||||
// Display WebP?
|
||||
$was_enabled = (bool) get_imagify_option( 'display_webp' );
|
||||
// See \Imagify_Options->validate_values_on_update() for why we use 'convert_to_webp' here.
|
||||
$is_enabled = ! empty( $values['display_webp'] ) && ! empty( $values['convert_to_webp'] );
|
||||
$was_enabled = (bool) get_imagify_option( 'display_nextgen' );
|
||||
$is_enabled = ! empty( $values['display_nextgen'] );
|
||||
|
||||
// Which method?
|
||||
$old_value = get_imagify_option( 'display_webp_method' );
|
||||
$new_value = ! empty( $values['display_webp_method'] ) ? $values['display_webp_method'] : '';
|
||||
$old_value = get_imagify_option( 'display_nextgen_method' );
|
||||
$new_value = ! empty( $values['display_nextgen_method'] ) ? $values['display_nextgen_method'] : '';
|
||||
|
||||
// Decide when to add or remove rules.
|
||||
$is_rewrite = self::OPTION_VALUE === $new_value;
|
||||
$was_rewrite = self::OPTION_VALUE === $old_value;
|
||||
$add_or_remove = false;
|
||||
$is_rewrite = self::OPTION_VALUE === $new_value;
|
||||
$was_rewrite = self::OPTION_VALUE === $old_value;
|
||||
|
||||
if ( ! $this->get_server_conf() ) {
|
||||
return $values;
|
||||
}
|
||||
|
||||
$result = false;
|
||||
|
||||
if ( $is_enabled && $is_rewrite && ( ! $was_enabled || ! $was_rewrite ) ) {
|
||||
// Display WebP & use rewrite method, but only if one of the values changed: add rules.
|
||||
$add_or_remove = 'add';
|
||||
} elseif ( $was_enabled && $was_rewrite && ( ! $is_enabled || ! $is_rewrite ) ) {
|
||||
// Was displaying WebP & was using rewrite method, but only if one of the values changed: remove rules.
|
||||
$add_or_remove = 'remove';
|
||||
} else {
|
||||
return $values;
|
||||
}
|
||||
|
||||
if ( $is_apache ) {
|
||||
$rules = new Apache();
|
||||
} elseif ( $is_iis7 ) {
|
||||
$rules = new IIS();
|
||||
} elseif ( $is_nginx ) {
|
||||
$rules = new Nginx();
|
||||
} else {
|
||||
return $values;
|
||||
}
|
||||
|
||||
if ( 'add' === $add_or_remove ) {
|
||||
// Add the rewrite rules.
|
||||
$result = $rules->add();
|
||||
} else {
|
||||
$result = $this->get_server_conf()->add();
|
||||
} elseif ( $was_enabled && $was_rewrite && ( ! $is_enabled || ! $is_rewrite ) ) {
|
||||
// Remove the rewrite rules.
|
||||
$result = $rules->remove();
|
||||
$result = $this->get_server_conf()->remove();
|
||||
}
|
||||
|
||||
if ( ! is_wp_error( $result ) ) {
|
||||
@@ -104,10 +84,12 @@ class Display {
|
||||
// Display an error message.
|
||||
if ( is_multisite() && strpos( wp_get_referer(), network_admin_url( '/' ) ) === 0 ) {
|
||||
Notices::get_instance()->add_network_temporary_notice( $result->get_error_message() );
|
||||
} else {
|
||||
Notices::get_instance()->add_site_temporary_notice( $result->get_error_message() );
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
Notices::get_instance()->add_site_temporary_notice( $result->get_error_message() );
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
@@ -162,10 +144,11 @@ class Display {
|
||||
if ( ! $conf ) {
|
||||
return;
|
||||
}
|
||||
if ( ! get_imagify_option( 'display_webp' ) ) {
|
||||
|
||||
if ( ! get_imagify_option( 'display_nextgen' ) ) {
|
||||
return;
|
||||
}
|
||||
if ( self::OPTION_VALUE !== get_imagify_option( 'display_webp_method' ) ) {
|
||||
if ( self::OPTION_VALUE !== get_imagify_option( 'display_nextgen_method' ) ) {
|
||||
return;
|
||||
}
|
||||
if ( is_wp_error( $conf->is_file_writable() ) ) {
|
||||
@@ -186,10 +169,10 @@ class Display {
|
||||
if ( ! $conf ) {
|
||||
return;
|
||||
}
|
||||
if ( ! get_imagify_option( 'display_webp' ) ) {
|
||||
if ( ! get_imagify_option( 'display_nextgen' ) ) {
|
||||
return;
|
||||
}
|
||||
if ( self::OPTION_VALUE !== get_imagify_option( 'display_webp_method' ) ) {
|
||||
if ( self::OPTION_VALUE !== get_imagify_option( 'display_nextgen_method' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,17 +189,14 @@ class Display {
|
||||
$conf->remove();
|
||||
}
|
||||
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
/** TOOLS =================================================================================== */
|
||||
/** ----------------------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the path to the directory conf file.
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @param bool $relative True to get a path relative to the site’s root.
|
||||
* @return string|bool The file path. False on failure.
|
||||
*
|
||||
* @return string|bool The file path. False on failure.
|
||||
*/
|
||||
public function get_file_path( $relative = false ) {
|
||||
if ( ! $this->get_server_conf() ) {
|
||||
@@ -237,7 +217,7 @@ class Display {
|
||||
*
|
||||
* @since 1.9
|
||||
*
|
||||
* @return \Imagify\WriteFile\WriteFileInterface
|
||||
* @return WriteFileInterface
|
||||
*/
|
||||
protected function get_server_conf() {
|
||||
global $is_apache, $is_iis7, $is_nginx;
|
||||
@@ -252,8 +232,6 @@ class Display {
|
||||
$this->server_conf = new IIS();
|
||||
} elseif ( $is_nginx ) {
|
||||
$this->server_conf = new Nginx();
|
||||
} else {
|
||||
$this->server_conf = false;
|
||||
}
|
||||
|
||||
return $this->server_conf;
|
||||
|
||||
@@ -1,37 +1,36 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Webp\RewriteRules;
|
||||
|
||||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||||
use Imagify\WriteFile\AbstractIISDirConfFile;
|
||||
|
||||
/**
|
||||
* Add and remove rewrite rules to the web.config file to display WebP images on the site.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
class IIS extends \Imagify\WriteFile\AbstractIISDirConfFile {
|
||||
class IIS extends AbstractIISDirConfFile {
|
||||
|
||||
/**
|
||||
* Name of the tag used as block delemiter.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @var string
|
||||
* @since 1.9
|
||||
*/
|
||||
const TAG_NAME = 'Imagify: rewrite rules for webp';
|
||||
|
||||
/**
|
||||
* Get unfiltered new contents to write into the file.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @since 1.9
|
||||
* @source https://github.com/igrigorik/webp-detect/blob/master/iis.config
|
||||
* @author Grégory Viguier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_raw_new_contents() {
|
||||
$extensions = $this->get_extensions_pattern();
|
||||
$extensions = str_replace( '|webp', '', $extensions );
|
||||
$home_root = wp_parse_url( home_url( '/' ) );
|
||||
$home_root = $home_root['path'];
|
||||
|
||||
|
||||
@@ -1,52 +1,70 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Webp\RewriteRules;
|
||||
|
||||
defined( 'ABSPATH' ) || die( 'Cheatin’ uh?' );
|
||||
use Imagify\WriteFile\AbstractNginxDirConfFile;
|
||||
|
||||
/**
|
||||
* Add and remove rewrite rules to the imagify.conf file to display WebP images on the site.
|
||||
*
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*/
|
||||
class Nginx extends \Imagify\WriteFile\AbstractNginxDirConfFile {
|
||||
class Nginx extends AbstractNginxDirConfFile {
|
||||
|
||||
/**
|
||||
* Name of the tag used as block delemiter.
|
||||
*
|
||||
* @var string
|
||||
* @since 1.9
|
||||
* @author Grégory Viguier
|
||||
* @var string
|
||||
* @since 1.9
|
||||
*/
|
||||
const TAG_NAME = 'Imagify: rewrite rules for webp';
|
||||
|
||||
/**
|
||||
* Get unfiltered new contents to write into the file.
|
||||
*
|
||||
* @since 1.9
|
||||
* @access protected
|
||||
* @author Grégory Viguier
|
||||
* @since 1.9
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_raw_new_contents() {
|
||||
$extensions = $this->get_extensions_pattern();
|
||||
$extensions = $this->get_extensions_pattern() . '|avif';
|
||||
$home_root = wp_parse_url( home_url( '/' ) );
|
||||
$home_root = $home_root['path'];
|
||||
|
||||
return trim( '
|
||||
location ~* ^(' . $home_root . '.+)\.(' . $extensions . ')$ {
|
||||
add_header Vary Accept;
|
||||
add_header Vary Accept;
|
||||
|
||||
if ($http_accept ~* "webp"){
|
||||
set $imwebp A;
|
||||
}
|
||||
if (-f $request_filename.webp) {
|
||||
set $imwebp "${imwebp}B";
|
||||
}
|
||||
if ($imwebp = AB) {
|
||||
rewrite ^(.*) $1.webp;
|
||||
}
|
||||
set $canavif 1;
|
||||
|
||||
if ($http_accept !~* "avif"){
|
||||
set $canavif 0;
|
||||
}
|
||||
|
||||
if (!-f $request_filename.avif) {
|
||||
set $canavif 0;
|
||||
|
||||
}
|
||||
if ($canavif = 1){
|
||||
rewrite ^(.*) $1.avif;
|
||||
break;
|
||||
}
|
||||
|
||||
set $canwebp 1;
|
||||
|
||||
if ($http_accept !~* "webp"){
|
||||
set $canwebp 0;
|
||||
}
|
||||
|
||||
if (!-f $request_filename.webp) {
|
||||
set $canwebp 0;
|
||||
|
||||
}
|
||||
if ($canwebp = 1){
|
||||
rewrite ^(.*) $1.webp;
|
||||
break;
|
||||
}
|
||||
}' );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Imagify\Webp;
|
||||
|
||||
use Imagify\Dependencies\League\Container\ServiceProvider\AbstractServiceProvider;
|
||||
use Imagify\Webp\RewriteRules\Display as RewriteRules;
|
||||
|
||||
/**
|
||||
* Service provider for WebP rewrite rules
|
||||
*/
|
||||
class ServiceProvider extends AbstractServiceProvider {
|
||||
/**
|
||||
* Services provided by this provider
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $provides = [
|
||||
'webp_display',
|
||||
'webp_rewrite_rules',
|
||||
];
|
||||
|
||||
/**
|
||||
* Subscribers provided by this provider
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $subscribers = [
|
||||
'webp_display',
|
||||
'webp_rewrite_rules',
|
||||
];
|
||||
|
||||
/**
|
||||
* Registers the provided classes
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
$this->getContainer()->share( 'webp_display', Display::class );
|
||||
$this->getContainer()->share( 'webp_rewrite_rules', RewriteRules::class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subscribers array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_subscribers() {
|
||||
return $this->subscribers;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user