first commit

This commit is contained in:
2024-11-10 21:08:49 +01:00
commit 0d932ce5ee
14455 changed files with 2567501 additions and 0 deletions

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,292 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
/**
* All cache commands that are intended to be available for calling from any sort of control interface (e.g. wp-admin, UpdraftCentral) go in here. All public methods should either return the data to be returned, or a WP_Error with associated error code, message and error data.
*/
class WP_Optimize_Cache_Commands {
private $optimizer;
private $options;
/**
* WP_Optimize_Cache_Commands constructor.
*/
public function __construct() {
$this->optimizer = WP_Optimize()->get_optimizer();
$this->options = WP_Optimize()->get_options();
}
/**
* Save cache settings
*
* @param array $data
*
* @return array
*/
public function save_cache_settings($data) {
if (!class_exists('WPO_Cache_Config')) return array(
'result' => false,
'message' => "WPO_Cache_Config class doesn't exist",
);
// filter for validate cache settings before save it.
$validation = apply_filters('wpo_save_cache_settings_validation', $data['cache-settings']);
if (!empty($validation) && isset($validation['result']) && false === $validation['result']) {
return $validation;
}
$enabled = false;
$disabled = false;
$return = !empty($validation) ? $validation : array();
$previous_settings = WPO_Cache_Config::instance()->get();
// Attempt to change current status if required
if (isset($previous_settings['enable_page_caching']) && $previous_settings['enable_page_caching'] != $data['cache-settings']['enable_page_caching']) {
// Disable cache.
if (empty($data['cache-settings']['enable_page_caching'])) {
$disabled = WPO_Page_Cache::instance()->disable();
// Disabling failed
if ($disabled && is_wp_error($disabled)) {
// If disabling failed, we re-enable whatever was disabled, to make sure nothing breaks.
if ($previous_settings['enable_page_caching']) WPO_Page_Cache::instance()->enable(true);
$return['error'] = array(
'code' => $disabled->get_error_code(),
'message' => $disabled->get_error_message()
);
} elseif (WPO_Page_Cache::instance()->has_warnings()) {
$return['warnings_label'] = __('Page caching was disabled, but with some warnings:', 'wp-optimize');
$return['warnings'] = WPO_Page_Cache::instance()->get_errors('warning');
}
} else {
// we need to rebuild advanced-cache.php and add WP_CACHE to wp-config.
$enabled = WPO_Page_Cache::instance()->enable(true);
// Enabling failed
if (is_wp_error($enabled)) {
// disable everything, to avoid half enabled things
WPO_Page_Cache::instance()->disable();
$return['error'] = array(
'code' => $enabled->get_error_code(),
'message' => $enabled->get_error_message()
);
if (WPO_Page_Cache::instance()->advanced_cache_file_writing_error) {
$return['advanced_cache_file_writing_error'] = true;
$return['advanced_cache_file_content'] = WPO_Page_Cache::instance()->advanced_cache_file_content;
}
} elseif (WPO_Page_Cache::instance()->has_warnings()) {
$return['warnings_label'] = __('Page caching was enabled, but with some warnings:', 'wp-optimize');
$return['warnings'] = WPO_Page_Cache::instance()->get_errors('warning');
}
}
// Override enabled setting value
$data['cache-settings']['enable_page_caching'] = ($enabled && !is_wp_error($enabled)) || ($previous_settings['enable_page_caching'] && is_wp_error($disabled));
} else {
$data['cache-settings']['enable_page_caching'] = $previous_settings['enable_page_caching'];
$enabled = $previous_settings['enable_page_caching'];
}
$skip_if_no_file_yet = !$enabled || is_wp_error($enabled);
$save_settings_result = WPO_Cache_Config::instance()->update($data['cache-settings'], $skip_if_no_file_yet);
if ($save_settings_result && !is_wp_error($save_settings_result)) {
WP_Optimize_Page_Cache_Preloader::instance()->cache_settings_updated($data['cache-settings'], $previous_settings);
$return['result'] = $save_settings_result;
} else {
// Saving the settings returned an error
if (is_wp_error($save_settings_result)) {
if (isset($return['error'])) {
$return['error']['message'] .= "\n\n".$save_settings_result->get_error_message();
} else {
$return['error'] = array(
'code' => $save_settings_result->get_error_code(),
'message' => $save_settings_result->get_error_message()
);
}
}
$return['result'] = false;
}
$return['enabled'] = ($enabled && !is_wp_error($enabled)) || ($previous_settings['enable_page_caching'] && is_wp_error($disabled));
return $return;
}
/**
* Get information about current cache status. Used in cli commands.
*
* @return array
*/
public function get_status_info() {
$status = array();
$status[] = WPO_Page_Cache::instance()->is_enabled() ? __('Caching is enabled', 'wp-optimize') : __('Caching is disabled', 'wp-optimize');
$preloader_status = WP_Optimize_Page_Cache_Preloader::instance()->get_status_info();
$status[] = sprintf(__('Current cache size: %s', 'wp-optimize'), $preloader_status['size']);
$status[] = sprintf(__('Number of files: %s', 'wp-optimize'), $preloader_status['file_count']);
if (array_key_exists('message', $preloader_status)) $status[] = $preloader_status['message'];
$status['message'] = join(PHP_EOL, $status);
return $status;
}
/**
* Enable cache.
*/
public function enable() {
$settings = WPO_Cache_Config::instance()->get();
$settings['enable_page_caching'] = true;
return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings)));
}
/**
* Disable cache.
*/
public function disable() {
$settings = WPO_Cache_Config::instance()->get();
$settings['enable_page_caching'] = false;
return $this->format_save_cache_settings_response($this->save_cache_settings(array('cache-settings' => $settings)));
}
/**
* Purge WP-Optimize page cache.
*
* @return array
*/
public function purge_page_cache() {
if (!WP_Optimize()->get_page_cache()->can_purge_cache()) {
return array(
'success' => false,
'message' => __('You do not have permission to purge the cache', 'wp-optimize'),
);
}
$purged = WP_Optimize()->get_page_cache()->purge();
$cache_size = WP_Optimize()->get_page_cache()->get_cache_size();
$wpo_page_cache_preloader = WP_Optimize_Page_Cache_Preloader::instance();
$response = array(
'success' => $purged,
'size' => WP_Optimize()->format_size($cache_size['size']),
'file_count' => $cache_size['file_count'],
);
// if scheduled preload enabled then reschedule and run preloader.
if ($wpo_page_cache_preloader->is_scheduled_preload_enabled()) {
// cancel preload and reschedule preload action.
$wpo_page_cache_preloader->cancel_preload();
$wpo_page_cache_preloader->reschedule_preload();
// run preloader.
$wpo_page_cache_preloader->run('scheduled', $response);
}
if ($response['success']) {
$response['message'] = __('Page cache purged successfully', 'wp-optimize');
}
return $response;
}
/**
* Run cache preload (for wp-cli).
*
* @return array|bool
*/
public function run_cache_preload_cli() {
if (!(defined('WP_CLI') && WP_CLI)) return false;
// define WPO_ADVANCED_CACHE constant as WP-CLI doesn't load advanced-cache.php file
// but we check this constant value wen detecting status of cache
if (!defined('WPO_ADVANCED_CACHE')) define('WPO_ADVANCED_CACHE', true);
// don't interrupt queue processing
add_filter('updraft_interrupt_tasks_queue_load-url-task', '__return_false', 99);
// if preloading is running then exit.
if (WP_Optimize_Page_Cache_Preloader::instance()->is_busy()) {
return array(
'success' => false,
'error' => __('Preloading is currently running in another process.', 'wp-optimize'),
);
}
// set default response.
$response = array(
'success' => true,
'message' => __('All URLs were preloaded into cache successfully', 'wp-optimize'),
);
WP_CLI::log(__('Preloading URLs into cache...', 'wp-optimize'));
return WP_Optimize_Page_Cache_Preloader::instance()->run('manual', $response);
}
/**
* Run cache preload action.
*
* @return void|array - Doesn't return anything if run() is successfull (Run() prints a JSON object and closed browser connection) or an array if failed.
*/
public function run_cache_preload() {
return WP_Optimize_Page_Cache_Preloader::instance()->run('manual');
}
/**
* Cancel cache preload action.
*
* @return array
*/
public function cancel_cache_preload() {
WP_Optimize_Page_Cache_Preloader::instance()->cancel_preload();
return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info();
}
/**
* Get status of cache preload.
*
* @return array
*/
public function get_cache_preload_status() {
return WP_Optimize_Page_Cache_Preloader::instance()->get_status_info();
}
/**
* Enable or disable browser cache.
*
* @param array $params - ['browser_cache_expire' => '1 month 15 days 2 hours' || '' - for disable cache]
* @return array
*/
public function enable_browser_cache($params) {
return WP_Optimize()->get_browser_cache()->enable_browser_cache_command_handler($params);
}
/**
* Format save_cache_settings() result for displaying in WP-CLI console
*
* @param array $response
* @return array
*/
private function format_save_cache_settings_response($response) {
$result = array(
'success' => $response['result'],
);
if (isset($response['error'])) {
$result['success'] = false;
$result['error'] = $response['error']['message'];
}
if ($result['success']) {
$result['message'] = __('Page cache settings updated successfully.', 'wp-optimize');
}
return $result;
}
}

View File

@@ -0,0 +1,106 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
class WP_Optimize_Detect_Cache_Plugins {
private static $instance;
/**
* WP_Optimize_Detect_Cache_Plugins constructor.
*/
protected function __construct() {
}
/**
* Detect list of active most popular WordPress cache plugins.
*
* @return array
*/
public function get_active_cache_plugins() {
// The index is the plugin's slug
$active_cache_plugins = array();
foreach ($this->get_plugins() as $plugin_slug => $plugin_title) {
$function_name = 'is_'.str_replace('-', '_', $plugin_slug).'_plugin_active';
if (is_callable(array($this, $function_name))) {
if (call_user_func(array($this, $function_name))) {
$active_cache_plugins[$plugin_slug] = $plugin_title;
}
} else {
if ($this->is_plugin_active($plugin_slug)) {
$active_cache_plugins[$plugin_slug] = $plugin_title;
}
}
}
return $active_cache_plugins;
}
/**
* Get the plugins list
*
* @return array
*/
protected function get_plugins() {
return array(
'w3-total-cache' => 'W3 Total Cache',
'wp-super-cache' => 'WP Super Cache',
'wp-rocket' => 'WP Rocket',
'wp-fastest-cache' => 'WP Fastest Cache',
'litespeed-cache' => 'LiteSpeed Cache',
'cache-enabler' => 'Cache Enabler',
'comet-cache' => 'Comet Cache',
'hummingbird-performance' => 'Hummingbird',
'hyper-cache' => 'Hyper Cache',
);
}
/**
* Check if W3 Total Cache active.
*
* @return bool
*/
public function is_w3_total_cache_plugin_active() {
return defined('W3TC_VERSION') || $this->is_plugin_active('w3-total-cache');
}
/**
* Check if WP Rocket active.
*
* @return bool
*/
public function is_wp_rocket_plugin_active() {
return defined('WP_ROCKET_VERSION') || $this->is_plugin_active('wp-rocket');
}
/**
* Check if $plugin is active.
*
* @param string $plugin - plugin slug
*
* @return bool
*/
private function is_plugin_active($plugin) {
$status = WP_Optimize()->get_db_info()->get_plugin_status($plugin);
return $status['active'];
}
/**
* Instance of WP_Optimize_Detect_Cache_Plugins.
*
* @return WP_Optimize_Detect_Cache_Plugins
*/
static public function instance() {
static $instance;
if (empty($instance)) {
$instance = new self();
}
return $instance;
}
}

View File

@@ -0,0 +1,671 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
if (!class_exists('WP_Optimize_Load_Url_Task')) {
require_once(WPO_PLUGIN_MAIN_PATH . 'cache/class-wpo-load-url-task.php');
}
class WP_Optimize_Page_Cache_Preloader extends WP_Optimize_Preloader {
protected $preload_type = 'page_cache';
protected $task_type = 'load-url-task';
static protected $_instance = null;
/**
* WP_Optimize_Page_Cache_Preloader constructor.
*/
public function __construct() {
parent::__construct();
add_action('wpo_page_cache_schedule_preload', array($this, 'run_scheduled_cache_preload'));
add_filter('wpo_preload_headers', array($this, 'preload_headers'));
}
/**
* Check if cache is active.
*
* @return bool
*/
public function is_option_active() {
return WP_Optimize()->get_page_cache()->is_enabled();
}
/**
* Schedule or delete automatic preload action on cache settings update.
*
* @param array $new_settings The new settings
* @param array $previous_settings Settings before saving
*/
public function cache_settings_updated($new_settings, $previous_settings) {
if (!$new_settings['enable_page_caching']) {
wp_clear_scheduled_hook('wpo_page_cache_schedule_preload');
$this->delete_preload_continue_action();
return;
}
if (!empty($new_settings['enable_schedule_preload'])) {
$last_schedule_type = $previous_settings['preload_schedule_type'];
if (wp_next_scheduled('wpo_page_cache_schedule_preload')) {
// if already scheduled this schedule type
if ($new_settings['preload_schedule_type'] == $last_schedule_type) {
// If the schedule type is cache lifespan, check if the cache lifespan changed.
if ('wpo_use_cache_lifespan' == $new_settings['preload_schedule_type']) {
// Else, if the settings cache lifespan settings haven't changed, returns
if ($new_settings['page_cache_length_value'] == $previous_settings['page_cache_length_value'] && $new_settings['page_cache_length_unit'] == $previous_settings['page_cache_length_unit']) {
return;
}
} else {
return;
}
}
// clear currently scheduled preload action.
wp_clear_scheduled_hook('wpo_page_cache_schedule_preload');
}
// schedule preload action.
wp_schedule_event((time() + $this->get_schedule_interval($new_settings['preload_schedule_type'])), $new_settings['preload_schedule_type'], 'wpo_page_cache_schedule_preload');
} else {
wp_clear_scheduled_hook('wpo_page_cache_schedule_preload');
}
}
/**
* Clear active preload tasks, reschedule preload action.
*/
public function reschedule_preload() {
// clear scheduled action.
if (wp_next_scheduled('wpo_page_cache_schedule_preload')) {
wp_clear_scheduled_hook('wpo_page_cache_schedule_preload');
}
// schedule preload action if need.
if ($this->is_scheduled_preload_enabled()) {
$preload_schedule_type = $this->get_cache_config('preload_schedule_type');
wp_schedule_event(time() + $this->get_schedule_interval($preload_schedule_type), $preload_schedule_type, 'wpo_page_cache_schedule_preload');
}
}
/**
* Check if scheduled preload enabled.
*
* @return bool
*/
public function is_scheduled_preload_enabled() {
$enable_schedule_preload = $this->get_cache_config('enable_schedule_preload');
return !empty($enable_schedule_preload);
}
/**
* Check if we need run cache preload and run it.
*/
public function run_scheduled_cache_preload() {
$schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type');
if (!$schedule_type) return;
// Don't run preload if cache lifespan option enabled and cache not expired yet.
if ('wpo_use_cache_lifespan' == $schedule_type) {
/**
* Filters the allowed time difference between the cache exiry and the current time, in seconds.
* If the cache expires in less than $allowed_time_difference, preload. Otherwise leave it.
*
* @param integer $allowed_time_difference The time difference, in seconds (default is same as changed time limit)
*/
$time_limit = (defined('WP_OPTIMIZE_SET_TIME_LIMIT') && WP_OPTIMIZE_SET_TIME_LIMIT > 15) ? WP_OPTIMIZE_SET_TIME_LIMIT : 1800;
$allowed_time_difference = apply_filters('wpo_preload_allowed_time_difference', $time_limit);
$page_cache_lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length', 0);
$last_preload_time = $this->options->get_option('wpo_last_page_cache_preload', 0);
$time_since_last_preload = time() - $last_preload_time;
$minimum_time_to_next_schedule_preload = $page_cache_lifespan - $allowed_time_difference;
// Skip this if the last preload is not as old as the cache lifespan minus $allowed_time_difference
if ($page_cache_lifespan > 0 && $time_since_last_preload < $minimum_time_to_next_schedule_preload) return;
}
$this->run();
}
/**
* Get cache config option value.
*
* @return mixed
*/
public function get_cache_config($option) {
static $config = null;
if (null === $config) $config = WPO_Page_Cache::instance()->config->get();
if (is_array($config) && array_key_exists($option, $config)) {
return $config[$option];
}
return false;
}
/**
* Create tasks (WP_Optimize_Load_Url_Task) for preload all urls from site.
*
* @param string $type The preload type (currently: scheduled, manual)
* @return void
*/
public function create_tasks_for_preload_site_urls($type) {
$urls = $this->get_site_urls();
if (!empty($urls)) {
$this->log(__('Creating tasks for preload site urls.', 'wp-optimize'));
foreach ($urls as $url) {
if (wpo_url_in_exceptions($url)) continue;
if ($this->url_is_already_cached($url, $type)) {
continue;
}
// this description is being used for internal purposes.
$description = 'Preload - '.$url;
$options = array('url' => $url, 'preload_type' => $type, 'anonymous_user_allowed' => (defined('DOING_CRON') && DOING_CRON) || (defined('WP_CLI') && WP_CLI));
if (!class_exists('WP_Optimize_Load_Url_Task')) {
require_once WPO_PLUGIN_MAIN_PATH . 'cache/class-wpo-load-url-task.php';
}
WP_Optimize_Load_Url_Task::create_task($this->task_type, $description, $options, 'WP_Optimize_Load_Url_Task');
}
$this->log(__('Tasks for preload site urls created.', 'wp-optimize'));
}
}
/**
* Preload mobile version from $url.
*
* @param string $url
*
* @return void
*/
public function preload_mobile($url) {
static $is_mobile_caching_enabled;
if (!isset($is_mobile_caching_enabled)) {
$is_mobile_caching_enabled = $this->get_cache_config('enable_mobile_caching');
}
// Only run if option is active
if (!$is_mobile_caching_enabled) return;
$mobile_args = array(
'httpversion' => '1.1',
'user-agent' => 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
'timeout' => 10,
'headers' => apply_filters('wpo_preload_headers', array()),
);
$mobile_args = apply_filters('wpo_page_cache_preloader_mobile_args', $mobile_args, $url);
$this->log('preload_mobile - ' . $url);
wp_remote_get($url, $mobile_args);
}
/**
* Preload amp version from $url.
*
* @param string $url
*
* @return void
*/
public function preload_amp($url) {
if (!apply_filters('wpo_should_preload_amp', false, $url)) return;
$amp_args = array(
'httpversion' => '1.1',
'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
'timeout' => 10,
'headers' => array(
'X-WP-Optimize-Cache-Preload' => 'Yes',
),
);
$url = untrailingslashit($url) . '/amp/';
$amp_args = apply_filters('wpo_page_cache_preloader_amp_args', $amp_args, $url);
$this->log('preload_amp - ' . $url);
wp_remote_get($url, $amp_args);
}
/**
* Check if sitemap exists then returns list of urls from sitemap file otherwise returns all posts urls.
*
* @return array
*/
public function get_site_urls() {
$urls = $this->get_sitemap_urls();
if (!empty($urls)) {
$this->options->update_option('wpo_last_page_cache_preload_type', 'sitemap');
} else {
$urls = $this->get_post_urls();
$this->options->update_option('wpo_last_page_cache_preload_type', 'posts');
}
$this->log(sprintf(_n('%d url found.', '%d urls found.', count($urls), 'wp-optimize'), count($urls)));
/**
* Filter the URLs which will be preloaded
*
* @param array $urls
* @return array
*/
return apply_filters('wpo_preload_get_site_urls', $urls);
}
/**
* Loads sitemap file and returns list of urls.
*
* @param string $sitemap_url
*
* @return array|bool
*/
public function get_sitemap_urls($sitemap_url = '') {
$urls = array();
// if sitemap url is empty then use main sitemap file name.
$sitemap_url = ('' === $sitemap_url) ? site_url('/'.$this->get_sitemap_filename()) : $sitemap_url;
// if simplexml_load_string not available then we don't load sitemap.
if (!function_exists('simplexml_load_string')) {
return $urls;
}
// load sitemap file.
$response = wp_remote_get($sitemap_url, array('timeout' => 30));
// if we get error then
if (is_wp_error($response)) {
$response = file_get_contents($sitemap_url);
// if response is empty then try load from file.
if (empty($response) && '' == $sitemap_url) {
$sitemap_file = $this->get_local_sitemap_file();
$response = file_get_contents($sitemap_file);
}
if (empty($response)) return $urls;
$xml = @simplexml_load_string($response); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
} else {
// parse xml answer.
$xml = @simplexml_load_string(wp_remote_retrieve_body($response)); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
}
// xml file has not valid xml content then return false.
if (false === $xml) return false;
// if exists urls then return them.
if (isset($xml->url)) {
foreach ($xml->url as $element) {
if (!isset($element->loc)) continue;
$urls[] = (string) $element->loc;
}
} elseif (isset($xml->sitemap)) {
// if has links to other sitemap files then get urls from them.
foreach ($xml->sitemap as $element) {
if (!isset($element->loc)) continue;
$sitemap_urls = $this->get_sitemap_urls($element->loc);
if (is_array($sitemap_urls)) {
$urls = array_merge($urls, $sitemap_urls);
}
}
}
return $urls;
}
/**
* Get all posts of any post type and returns urls for them.
*
* @return array
*/
public function get_post_urls() {
global $post;
$offset = 0;
$posts_per_page = 1000;
$urls = array();
$urls[] = site_url('/');
do {
$query = new WP_Query(array(
'post_type' => 'any',
'post_status' => 'publish',
'posts_per_page' => $posts_per_page,
'offset' => $offset,
'orderby' => 'ID',
'order' => 'ASC',
'cache_results' => false, // disable cache to avoid memory error.
));
$posts_loaded = $query->post_count;
while ($query->have_posts()) {
$query->the_post();
$permalink = get_permalink();
$urls[] = $permalink;
// check page separators in the post content
preg_match_all('/\<\!--nextpage--\>/', $post->post_content, $matches);
// if there any separators add urls for each page
if (count($matches[0])) {
$prefix = strpos($permalink, '?') ? '&page=' : '';
for ($page = 0; $page < count($matches[0]); $page++) {
if ('' != $prefix) {
$urls[] = $permalink . $prefix . ($page+2);
} else {
$urls[] = trailingslashit($permalink) . ($page+2);
}
}
}
}
$offset += $posts_loaded;
} while ($posts_loaded > 0);
/**
* If domain mapping enabled then replace domains in urls.
*/
if ($this->is_domain_mapping_enabled()) {
$blog_id = get_current_blog_id();
$mapped_domain = $this->get_mapped_domain($blog_id);
$blog_details = get_blog_details($blog_id);
if ($mapped_domain) {
foreach ($urls as $i => $url) {
$urls[$i] = preg_replace('/'.$blog_details->domain.'/i', $mapped_domain, $url, 1);
}
}
}
wp_reset_postdata();
return $urls;
}
/**
* Check if domain mapping enabled.
*
* @return bool
*/
public function is_domain_mapping_enabled() {
// SUNRISE constant is defined with installation WordPress MU Domain Mapping plugin.
$enabled = is_multisite() && defined('SUNRISE') && 'on' == strtolower(SUNRISE);
/**
* Filters if Multisite Domain mapping is enabled.
* Currently, we can only detect if the WordPress MU Domain Mapping plugin is in use.
* Using the WP Core functionality should not require this, unless if the domain name is set somewhere else but in the site url option.
*/
return apply_filters('wpo_is_domain_mapping_enabled', $enabled);
}
/**
* Return mapped domain by $blog_id.
*
* @param int $blog_id
*
* @return string
*/
public function get_mapped_domain($blog_id) {
global $wpdb;
$domain = '';
$multisite_plugin_table_name = $wpdb->base_prefix.'domain_mapping';
// Check if table exists
if ($wpdb->get_var("SHOW TABLES LIKE '$multisite_plugin_table_name'") != $multisite_plugin_table_name) {
// This table created in WordPress MU Domain Mapping plugin.
$row = $wpdb->get_row("SELECT `domain` FROM {$multisite_plugin_table_name} WHERE `blog_id` = {$blog_id} AND `active` = 1", ARRAY_A);
if (!empty($row)) {
$domain = $row['domain'];
}
} else {
// When using the WP Core method, the site url option contains the mapped domain.
$domain = get_site_url($blog_id);
}
/**
* Filters the mapped domain name
*
* @param string $domain The domain name
* @param integer $blog_id The blog ID
*/
return apply_filters('wpo_get_mapped_domain', $domain, $blog_id);
}
/**
* Captures and logs any interesting messages
*
* @param String $message - the error message
* @param String $error_type - the error type
*/
public function log($message, $error_type = 'info') {
if (isset($this->loggers)) {
foreach ($this->loggers as $logger) {
$logger->log($message, $error_type);
}
}
}
/**
* Instance of WP_Optimize_Page_Cache_Preloader.
*
* @return WP_Optimize_Page_Cache_Preloader
*/
public static function instance() {
if (empty(self::$_instance)) {
self::$_instance = new WP_Optimize_Page_Cache_Preloader();
}
return self::$_instance;
}
/**
* Check if the URL is already cached, or needs to be preloaded
*
* @param string $url The preloaded url
* @param string $preload_type The preload type (manual | scheduled)
* @return boolean
*/
private function url_is_already_cached($url, $preload_type) {
static $files = array();
$regenerate_count = 0;
$folder = trailingslashit(WPO_CACHE_FILES_DIR) . wpo_get_url_path($url);
// If the folder does not exist, consider the URL as cleared
if (!is_dir($folder)) return false;
if (empty($files)) {
// Check only the base files
$files[] = 'index.html';
if (WPO_Cache_Config::instance()->get_option('enable_mobile_caching')) {
$files[] = 'mobile.index.html';
}
$files = apply_filters('wpo_maybe_clear_files_list', $files);
}
foreach ($files as $file) {
$file_path = trailingslashit($folder).$file;
if (!file_exists($file_path)) {
// The file does not exist, count it as "deleted"
$regenerate_count++;
continue;
}
if ($this->should_regenerate_file($file_path, $preload_type)) {
// delefe the expired cache file
unlink($file_path);
$regenerate_count++;
}
}
// if 0 == $regenerate_count, nothing all the expected files exist, and none were deleted.
return 0 == $regenerate_count;
}
/**
* Determine if a file should be regenerated
*
* @param string $path The file to check
* @param string $preload_type The preload type (manual | scheduled)
*
* @return boolean
*/
private function should_regenerate_file($path, $preload_type) {
// Store the variables, as they'll be used for each file and each file
static $is_preloader_scheduled = null;
static $lifespan = null;
static $schedule_type = null;
static $schedule_interval = null;
static $lifespan_expiry_threshold = null;
static $always_regenerate_file_if_preload_is_manual = null;
static $always_regenerate_file_if_preload_is_scheduled = null;
static $regenerate_file_when_no_expiry_date = null;
// Sets the variables once per request:
if (null === $is_preloader_scheduled) {
$is_preloader_scheduled = WPO_Cache_Config::instance()->get_option('enable_schedule_preload');
$schedule_type = WPO_Cache_Config::instance()->get_option('preload_schedule_type');
$lifespan = WPO_Cache_Config::instance()->get_option('page_cache_length');
$schedule_interval = $this->get_schedule_interval($schedule_type);
/**
* Expiry threshold: the current file will be considered stale if within the threshold. Default: 600s (10min)
*/
$lifespan_expiry_threshold = apply_filters('wpo_lifespan_expiry_threshold', 600);
/**
* Filters if a cache should systematically be regenerated when running a manual preload. Default: false
*/
$always_regenerate_file_if_preload_is_manual = apply_filters('wpo_always_regenerate_file_if_preload_is_manual', false);
/**
* Filters if a cache should systematically be regenerated when running a scheduled preload. Default: false
*/
$always_regenerate_file_if_preload_is_scheduled = apply_filters('wpo_always_regenerate_file_if_preload_is_scheduled', false);
/**
* Filters if a cache should systematically be regenerated when running a preload and no schedule is set, and cache does not expire. Default: true
*/
$regenerate_file_when_no_expiry_date = apply_filters('wpo_regenerate_file_when_no_expiry_date', true);
}
if (($always_regenerate_file_if_preload_is_manual && 'manual' == $preload_type) || ($always_regenerate_file_if_preload_is_scheduled && 'scheduled' == $preload_type)) {
$result = true;
} else {
$modified_time = (int) filemtime($path);
// cache lifespan is set.
if (0 != $lifespan) {
$expiry_time = $modified_time + $lifespan - $lifespan_expiry_threshold;
$result = time() > $expiry_time;
} elseif ($is_preloader_scheduled) {
$expiry_time = $modified_time + $schedule_interval - $lifespan_expiry_threshold;
$result = time() > $expiry_time;
} else {
$result = $regenerate_file_when_no_expiry_date;
}
}
return apply_filters('wpo_preloader_should_regenerate_file', $result, $path, $preload_type);
}
/**
* Add preloader headers
*/
public function preload_headers($headers) {
$headers['X-WP-Optimize-Cache-Preload'] = 'Yes';
return $headers;
}
/**
* Option disabled error message
*
* @return array
*/
protected function get_option_disabled_error() {
return array(
'success' => false,
'error' => __('Page cache is disabled.', 'wp-optimize')
);
}
/**
* Get preload already running error message
*
* @return array
*/
protected function get_preload_already_running_error() {
return array(
'success' => false,
'error' => __('Probably page cache preload is running already.', 'wp-optimize')
);
}
protected function get_preload_data() {
return WP_Optimize()->get_page_cache()->get_cache_size();
}
protected function get_preloading_message($cache_size) {
return array(
'done' => false,
'message' => __('Loading URLs...', 'wp-optimize'),
'size' => WP_Optimize()->format_size($cache_size['size']),
'file_count' => $cache_size['file_count']
);
}
protected function get_last_preload_message($cache_size, $last_preload_time_str) {
return array(
'done' => true,
'message' => sprintf(__('Last preload finished at %s', 'wp-optimize'), $last_preload_time_str),
'size' => WP_Optimize()->format_size($cache_size['size']),
'file_count' => $cache_size['file_count']
);
}
protected function get_preload_success_message($cache_size) {
return array(
'done' => true,
'size' => WP_Optimize()->format_size($cache_size['size']),
'file_count' => $cache_size['file_count']
);
}
protected function get_preload_progress_message($cache_size, $preloaded_message, $preload_resuming_in) {
return array(
'done' => false,
'message' => $preloaded_message,
'size' => WP_Optimize()->format_size($cache_size['size']),
'file_count' => $cache_size['file_count'],
'resume_in' => $preload_resuming_in
);
}
}
WP_Optimize_Page_Cache_Preloader::instance();

View File

@@ -0,0 +1,289 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
/**
* Handles cache configuration and related I/O
*/
if (!class_exists('WPO_Cache_Config')) :
class WPO_Cache_Config {
/**
* Defaults
*
* @var array
*/
public $defaults;
/**
* Instance of this class
*
* @var mixed
*/
public static $instance;
/**
* @var array
*/
public $config;
/**
* Set config defaults
*/
public function __construct() {
$this->defaults = $this->get_defaults();
}
/**
* Get config from file or cache
*
* @return array
*/
public function get() {
if (is_multisite()) {
$config = get_site_option('wpo_cache_config', $this->get_defaults());
} else {
$config = get_option('wpo_cache_config', $this->get_defaults());
}
return wp_parse_args($config, $this->get_defaults());
}
/**
* Get a specific configuration option
*
* @param string $option_key The option identifier
* @param boolean $default Default value if the option doesn't exist (Default to false)
* @return mixed
*/
public function get_option($option_key, $default = false) {
$options = $this->get();
return apply_filters("wpo_option_key_{$option_key}", (isset($options[$option_key]) ? $options[$option_key] : $default));
}
/**
* Updates the given config object in file and DB
*
* @param array $config - the cache configuration
* @param boolean $skip_disk_if_not_yet_present - only write the configuration file to disk if it already exists. This presents PHP notices if the cache has never been on, and settings are saved.
*
* @return bool
*/
public function update($config, $skip_disk_if_not_yet_present = false) {
$config = wp_parse_args($config, $this->get_defaults());
$config['page_cache_length_value'] = intval($config['page_cache_length_value']);
$config['page_cache_length'] = $this->calculate_page_cache_length($config['page_cache_length_value'], $config['page_cache_length_unit']);
/**
* Filters the cookies used to set cache file names
*
* @param array $cookies - The cookies
* @param array $config - The new config
*/
$wpo_cache_cookies = apply_filters('wpo_cache_cookies', array(), $config);
sort($wpo_cache_cookies);
/**
* Filters the query variables used to set cache file names
*
* @param array $wpo_query_variables - The variables
* @param array $config - The new config
*/
$wpo_query_variables = apply_filters('wpo_cache_query_variables', array(), $config);
sort($wpo_query_variables);
$config['wpo_cache_cookies'] = $wpo_cache_cookies;
$config['wpo_cache_query_variables'] = $wpo_query_variables;
$config = apply_filters('wpo_cache_update_config', $config);
if (is_multisite()) {
update_site_option('wpo_cache_config', $config);
} else {
update_option('wpo_cache_config', $config);
}
do_action('wpo_cache_config_updated', $config);
return $this->write($config, $skip_disk_if_not_yet_present);
}
/**
* Calculate cache expiration value in seconds.
*
* @param int $value
* @param string $unit ( hours | days | months )
*
* @return int
*/
private function calculate_page_cache_length($value, $unit) {
$cache_length_units = array(
'hours' => 3600,
'days' => 86400,
'months' => 2629800, // 365.25 * 86400 / 12
);
return $value * $cache_length_units[$unit];
}
/**
* Deletes config files and options
*
* @return bool
*/
public function delete() {
if (is_multisite()) {
delete_site_option('wpo_cache_config');
} else {
delete_option('wpo_cache_config');
}
if (!WPO_Page_Cache::delete(WPO_CACHE_CONFIG_DIR)) {
return false;
}
return true;
}
/**
* Writes config to file
*
* @param array $config - Configuration array.
* @param boolean $only_if_present - only writes to the disk if the configuration file already exists
*
* @return boolean - returns false if an attempt to write failed
*/
public function write($config, $only_if_present = false) {
$config_file = WPO_CACHE_CONFIG_DIR.'/'.$this->get_cache_config_filename();
$this->config = wp_parse_args($config, $this->get_defaults());
// from 3.0.17 we use more secure way to store cache config files.
$advanced_cache_version = WPO_Page_Cache::instance()->get_advanced_cache_version();
// if advanced-cache.php exists and has at least 3.0.17 version or
// advanced-cache.php doesn't exist then
// we write the cache config in a new format.
if (($advanced_cache_version && (version_compare($advanced_cache_version, '3.0.17', '>='))) || !$advanced_cache_version) {
$config_content = '<?php' . "\n"
. 'if (!defined(\'ABSPATH\')) die(\'No direct access allowed\');' . "\n\n"
. '$GLOBALS[\'wpo_cache_config\'] = json_decode(\'' . json_encode($this->config) . '\', true);' . "\n";
} else {
$config_content = json_encode($this->config);
}
if ((!$only_if_present || file_exists($config_file)) && !file_put_contents($config_file, $config_content)) {
return new WP_Error('write_cache_config', sprintf(__('The cache configuration file could not be saved to the disk; please check the file/folder permissions of %s .', 'wp-optimize'), $config_file));
}
return true;
}
/**
* Verify we can write to the file system
*
* @since 1.0
* @return boolean
*/
public function verify_file_access() {
if (function_exists('clearstatcache')) {
clearstatcache();
}
// First check wp-config.php.
if (!is_writable(ABSPATH . 'wp-config.php') && !is_writable(ABSPATH . '../wp-config.php')) {
return false;
}
// Now check wp-content. We need to be able to create files of the same user as this file.
if (!$this->_is_dir_writable(untrailingslashit(WP_CONTENT_DIR))) {
return false;
}
// If the cache and config directories exist, make sure they're writeable
if (file_exists(untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache')) {
if (file_exists(WPO_CACHE_DIR)) {
if (!$this->_is_dir_writable(WPO_CACHE_DIR)) {
return false;
}
}
if (file_exists(WPO_CACHE_CONFIG_DIR)) {
if (!$this->_is_dir_writable(WPO_CACHE_CONFIG_DIR)) {
return false;
}
}
}
return true;
}
/**
* Return defaults
*
* @return array
*/
public function get_defaults() {
$defaults = array(
'enable_page_caching' => false,
'page_cache_length_value' => 24,
'page_cache_length_unit' => 'hours',
'page_cache_length' => 86400,
'cache_exception_conditional_tags' => array(),
'cache_exception_urls' => array(),
'cache_exception_cookies' => array(),
'cache_exception_browser_agents' => array(),
'enable_sitemap_preload' => false,
'enable_schedule_preload' => false,
'preload_schedule_type' => '',
'enable_mobile_caching' => false,
'enable_user_caching' => false,
'site_url' => network_home_url('/'),
'enable_cache_per_country' => false,
'permalink_structure' => get_option('permalink_structure'),
'uploads' => wp_normalize_path(wp_upload_dir()['basedir']),
'gmt_offset' => get_option('gmt_offset'),
);
return apply_filters('wpo_cache_defaults', $defaults);
}
/**
* Get advanced-cache.php file name with full path.
*
* @return string
*/
public function get_cache_config_filename() {
$url = parse_url(network_site_url());
if (isset($url['port']) && '' != $url['port'] && 80 != $url['port']) {
return 'config-'.strtolower($url['host']).'-port'.$url['port'].'.php';
} else {
return 'config-'.strtolower($url['host']).'.php';
}
}
/**
* Return an instance of the current class, create one if it doesn't exist
*
* @since 1.0
* @return WPO_Cache_Config
*/
public static function instance() {
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
endif;

View File

@@ -0,0 +1,373 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
/**
* Page caching rules and exceptions
*/
require_once dirname(__FILE__) . '/file-based-page-cache-functions.php';
if (!class_exists('WPO_Cache_Rules')) :
class WPO_Cache_Rules {
/**
* Cache config object
*
* @var mixed
*/
public $config;
/**
* Instance of this class
*
* @var mixed
*/
public static $instance;
public function __construct() {
$this->config = WPO_Cache_Config::instance()->get();
$this->setup_hooks();
}
/**
* Setup hooks/filters
*/
public function setup_hooks() {
add_action('save_post', array($this, 'purge_post_on_update'), 10, 1);
add_action('save_post', array($this, 'purge_archive_pages_on_post_update'), 10, 1);
add_action('wp_trash_post', array($this, 'purge_post_on_update'), 10, 1);
add_action('comment_post', array($this, 'purge_post_on_comment'), 10, 3);
add_action('wp_set_comment_status', array($this, 'purge_post_on_comment_status_change'), 10, 1);
add_action('edit_terms', array($this, 'purge_related_elements_on_term_updated'), 10, 2);
add_action('set_object_terms', array($this, 'purge_related_elements_on_post_terms_change'), 10, 6);
add_action('wpo_cache_config_updated', array($this, 'cache_config_updated'), 10, 1);
add_action('wp_insert_comment', array($this, 'comment_inserted'), 10, 2);
add_action('import_start', array($this, 'remove_wp_insert_comment'));
add_action('woocommerce_variation_set_stock', array($this, 'purge_product_page'), 10, 1);
add_action('woocommerce_product_set_stock', array($this, 'purge_product_page'), 10, 1);
/**
* List of hooks for which when executed, the cache will be purged
*
* @param array $actions The actions
*/
$actions = array(
'after_switch_theme',
'wp_update_nav_menu',
'customize_save_after',
array('wp_ajax_save-widget', 0),
array('wp_ajax_update-widget', 0),
'autoptimize_action_cachepurged',
'upgrader_overwrote_package',
'wpo_active_plugin_or_theme_updated',
'fusion_cache_reset_after',
'update_option_permalink_structure',
'wpml_st_add_string_translation',
);
$purge_on_action = apply_filters('wpo_purge_cache_hooks', $actions);
foreach ($purge_on_action as $action) {
if (is_array($action)) {
add_action($action[0], array($this, 'purge_cache'), $action[1]);
} else {
add_action($action, array($this, 'purge_cache'));
}
}
}
/**
* Purge post cache when there is a new approved comment
*
* @param int $comment_id Comment ID.
* @param int|string $approved Comment approved status. can be 0, 1 or 'spam'.
* @param array $commentdata Comment data array. Always sent be WP core, but a plugin was found that does not send it - https://wordpress.org/support/topic/critical-problems-with-version-3-0-10/
*/
public function purge_post_on_comment($comment_id, $approved, $commentdata = array()) {
if (1 !== $approved) {
return;
}
if (!empty($this->config['enable_page_caching']) && !empty($commentdata['comment_post_ID'])) {
$post_id = $commentdata['comment_post_ID'];
WPO_Page_Cache::delete_single_post_cache($post_id);
WPO_Page_Cache::delete_comments_feed();
}
}
/**
* Every time a comment's status changes, purge it's parent posts cache
*
* @param int $comment_id Comment ID.
*/
public function purge_post_on_comment_status_change($comment_id) {
if (!empty($this->config['enable_page_caching'])) {
$comment = get_comment($comment_id);
if (is_object($comment) && !empty($comment->comment_post_ID)) {
WPO_Page_Cache::delete_single_post_cache($comment->comment_post_ID);
WPO_Page_Cache::delete_comments_feed();
}
}
}
/**
* Action when a comment is inserted
*
* @param integer $comment_id - The comment ID
* @param boolean|WP_Comment $comment - The comment object (from WP 4.4)
* @return void
*/
public function comment_inserted($comment_id, $comment = false) {
if ($comment && is_a($comment, 'WP_Comment')) {
/**
* Filters whether to add a cookie when a comment is posted, in order to exclude the page from caching.
* Regular comments have the property comment_type set to '' or 'comment'. So by default, only add the cookie in those cases.
*
* @param boolean $add_cookie
* @param WP_Comment $comment
* @return boolean
*/
$add_cookie = apply_filters('wpo_add_commented_post_cookie', '' == $comment->comment_type || 'comment' == $comment->comment_type, $comment);
if (!$add_cookie) return;
$url = get_permalink($comment->comment_post_ID);
$url_info = parse_url($url);
setcookie('wpo_commented_post', 1, time() + WEEK_IN_SECONDS, isset($url_info['path']) ? $url_info['path'] : '/');
}
}
/**
* Comment posted cookie is not needed for imports. So remove the action
*/
public function remove_wp_insert_comment() {
remove_action('wp_insert_comment', array($this, 'comment_inserted'), 10);
}
/**
* Automatically purge all file based page cache on post changes
* We want the whole cache purged here as different parts
* of the site could potentially change on post updates
*
* @param Integer $post_id - WP post id
*/
public function purge_post_on_update($post_id) {
$post_type = get_post_type($post_id);
$post_type_object = get_post_type_object($post_type);
if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || null === $post_type_object || !$post_type_object->public) {
return;
}
/**
* Purge the whole cache if set to true, only the edited post otherwise. Default is false.
*
* @param boolean $purge_all_cache The default filter value
* @param integer $post_id The saved post ID
*/
if (apply_filters('wpo_purge_all_cache_on_update', false, $post_id)) {
$this->purge_cache();
return;
} else {
if (apply_filters('wpo_delete_cached_homepage_on_post_update', true, $post_id)) WPO_Page_Cache::delete_homepage_cache();
WPO_Page_Cache::delete_feed_cache();
WPO_Page_Cache::delete_single_post_cache($post_id);
WPO_Page_Cache::delete_sitemap_cache();
WPO_Page_Cache::delete_post_feed_cache($post_id);
}
}
/**
* Purge archive pages on post update.
*
* @param integer $post_id
*/
public function purge_archive_pages_on_post_update($post_id) {
$post_type = get_post_type($post_id);
if (false === $post_type) return;
if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type) {
return;
}
$post_obj = get_post_type_object($post_type);
if (null === $post_obj) return;
if ('post' == $post_type) {
// delete blog page cache
$blog_post_id = get_option('page_for_posts');
if ($blog_post_id) {
WPO_Page_Cache::delete_cache_by_url(get_permalink($blog_post_id), true);
}
// delete next and previus posts cache.
$globals_post = isset($GLOBALS['post']) ? $GLOBALS['post'] : false;
$GLOBALS['post'] = get_post($post_id);
$previous_post = function_exists('get_previous_post') ? get_previous_post() : false;
$next_post = function_exists('get_next_post') ? get_next_post() : false;
if ($globals_post) $GLOBALS['post'] = $globals_post;
if ($previous_post) WPO_Page_Cache::delete_cache_by_url(get_permalink($previous_post), true);
if ($next_post) WPO_Page_Cache::delete_cache_by_url(get_permalink($next_post), true);
// delete all archive pages for post.
$post_date = get_post_time('Y-m-j', false, $post_id);
list($year, $month, $day) = $post_date;
$archive_links = array(
get_year_link($year),
get_month_link($year, $month),
get_day_link($year, $month, $day),
);
foreach ($archive_links as $link) {
WPO_Page_Cache::delete_cache_by_url($link, true);
}
} elseif ($post_obj->has_archive) {
// delete archive page for custom post type.
WPO_Page_Cache::delete_cache_by_url(get_post_type_archive_link($post_type), true);
}
}
/**
* We use it with edit_terms action filter to purge cached elements related
* to updated term when term updated.
*
* @param int $term_id Term taxonomy ID.
* @param string $taxonomy Taxonomy slug.
*/
public function purge_related_elements_on_term_updated($term_id, $taxonomy) {
if ('nav_menu' === $taxonomy) return;
// purge cached page for term.
$term = get_term($term_id, $taxonomy, ARRAY_A);
if (is_array($term)) {
$term_permalink = get_term_link($term['term_id']);
if (!is_wp_error($term_permalink)) {
WPO_Page_Cache::delete_cache_by_url($term_permalink, true);
}
}
// get posts which belongs to updated term.
$posts = get_posts(array(
'numberposts' => -1,
'post_type' => 'any',
'fields' => 'ids',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => $taxonomy,
'field' => 'term_id',
'terms' => $term_id,
)
),
));
if (!empty($posts)) {
foreach ($posts as $post_id) {
WPO_Page_Cache::delete_single_post_cache($post_id);
}
}
}
/**
* Triggered by set_object_terms action. Used to clear all the terms archives a post belongs to or belonged to before being saved.
*
* @param int $object_id Object ID.
* @param array $terms An array of object terms.
* @param array $tt_ids An array of term taxonomy IDs.
* @param string $taxonomy Taxonomy slug.
* @param bool $append Whether to append new terms to the old terms.
* @param array $old_tt_ids Old array of term taxonomy IDs.
*/
public function purge_related_elements_on_post_terms_change($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids) {
$post_type = get_post_type($object_id);
if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || 'product_type' === $taxonomy || 'action-group' === $taxonomy) {
return;
}
/**
* Adds a way to exit the purge of terms permalink using the provided parameters.
*
* @param bool $purge The value filtered, whether or not to purge the related elements
* @param int $object_id Object ID.
* @param array $terms An array of object terms.
* @param array $tt_ids An array of term taxonomy IDs.
* @param string $taxonomy Taxonomy slug.
* @param bool $append Whether to append new terms to the old terms.
* @param array $old_tt_ids Old array of term taxonomy IDs.
* @default true
* @return boolean
*/
if (!apply_filters('wpo_cache_purge_related_elements_on_post_terms_change', true, $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids)) return;
// get all affected terms.
$affected_terms_ids = array_unique(array_merge($tt_ids, $old_tt_ids));
if (!empty($affected_terms_ids)) {
// walk through all changed terms and purge cached pages for them.
foreach ($affected_terms_ids as $tt_id) {
$term = get_term($tt_id, $taxonomy, ARRAY_A);
if (!is_array($term)) continue;
$term_permalink = get_term_link($term['term_id']);
if (!is_wp_error($term_permalink)) {
$url = parse_url($term_permalink);
// Check if the permalink contains a valid path, to avoid deleting the whole cache.
if (!isset($url['path']) || '/' === $url['path']) return;
WPO_Page_Cache::delete_cache_by_url($term_permalink, true);
}
}
}
}
/**
* Purge product page upon stock update
*/
public function purge_product_page($product_with_stock) {
if (!empty($product_with_stock->get_id())) {
WPO_Page_Cache::delete_single_post_cache($product_with_stock->get_id());
}
}
/**
* Clears the cache.
*/
public function purge_cache() {
if (!empty($this->config['enable_page_caching'])) {
wpo_cache_flush();
}
}
/**
* Triggered by wpo_cache_config_updated.
*
* @param array $config
*/
public function cache_config_updated($config) {
// delete front page form cache if defined in the settings
if (is_array($config['cache_exception_urls']) && in_array('/', $config['cache_exception_urls'])) {
WPO_Page_Cache::delete_cache_by_url(home_url());
}
}
/**
* Returns an instance of the current class, creates one if it doesn't exist
*
* @return object
*/
public static function instance() {
if (empty(self::$instance)) {
self::$instance = new self();
}
return self::$instance;
}
}
endif;

View File

@@ -0,0 +1,55 @@
<?php
if (!defined('ABSPATH')) die('Access denied.');
if (!class_exists('Updraft_Task_1_2')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php');
class WP_Optimize_Load_Url_Task extends Updraft_Task_1_2 {
/**
* Default options.
*/
public function get_default_options() {
return array();
}
/**
* Run preload http requests with different user-agent values to cache pages for different devices.
*
* @return bool
*/
public function run() {
$url = $this->get_option('url');
if (empty($url)) return;
$cache_preloader = WP_Optimize_Page_Cache_Preloader::instance();
// load pages with different user-agents values.
$cache_preloader->preload_desktop($url);
$cache_preloader->preload_mobile($url);
$cache_preloader->preload_amp($url);
if (defined('WP_CLI') && WP_CLI) {
WP_CLI::log($url);
}
/**
* Action triggered after preloading a single url
*
* @param string $url The url to preload
* @param object $cache_preloader Cache preloader instance
*/
do_action('wpoptimize_after_preload_url', $url, $cache_preloader);
/**
* Allows to change the delay between each URL preload, to reduce server load.
*
* @param integer $preload_delay The delay between each request in microseconds (1000000 = 1 second).
*/
usleep(apply_filters('wpoptimize_preload_delay', 500000));
return true;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
/**
* File based page cache drop in
*/
require_once(dirname(__FILE__) . '/file-based-page-cache-functions.php');
if (!defined('WPO_CACHE_DIR')) define('WPO_CACHE_DIR', untrailingslashit(WP_CONTENT_DIR) . '/wpo-cache');
/**
* Load extensions.
*/
wpo_cache_load_extensions();
/**
* Action triggered when the cache extensions are all loaded. Allows to execute code depending on an other extension, without knowing the order in which the files are loaded.
*/
if (function_exists('do_action')) {
do_action('wpo_cache_extensions_loaded');
}
$no_cache_because = array();
// check if we want to cache current page.
if (function_exists('add_filter') && function_exists('apply_filters')) {
add_filter('wpo_restricted_cache_page_type', 'wpo_restricted_cache_page_type');
add_filter('wpo_url_in_conditional_tags_exceptions', 'wpo_url_in_conditional_tags_exceptions');
$restricted_cache_page_type = apply_filters('wpo_restricted_cache_page_type', false);
$conditional_tag_exceptions = wpo_url_in_conditional_tags_exceptions();
} else {
// On old WP versions, you can't filter the result
$restricted_cache_page_type = wpo_restricted_cache_page_type(false);
$conditional_tag_exceptions = wpo_url_in_conditional_tags_exceptions();
}
if ($restricted_cache_page_type) {
$no_cache_because[] = $restricted_cache_page_type;
}
if ($conditional_tag_exceptions) {
$no_cache_because[] = $conditional_tag_exceptions;
}
// Don't cache non-GET requests.
if (!isset($_SERVER['REQUEST_METHOD']) || 'GET' !== $_SERVER['REQUEST_METHOD']) {
$no_cache_because[] = 'The request method was not GET ('.(isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : '-').')';
}
$file_extension = $_SERVER['REQUEST_URI'];
$file_extension = preg_replace('#^(.*?)\?.*$#', '$1', $file_extension);
$file_extension = trim(preg_replace('#^.*\.(.*)$#', '$1', $file_extension));
// Don't cache disallowed extensions. Prevents wp-cron.php, xmlrpc.php, etc.
if (!preg_match('#index\.php$#i', $_SERVER['REQUEST_URI']) && !preg_match('#sitemap([a-zA-Z0-9_-]+)?\.xml$#i', $_SERVER['REQUEST_URI']) && in_array($file_extension, array('php', 'xml', 'xsl'))) {
$no_cache_because[] = 'The request extension is not suitable for caching';
}
// Don't cache if logged in.
if (!empty($_COOKIE)) {
$wp_cookies = array('wordpressuser_', 'wordpresspass_', 'wordpress_sec_', 'wordpress_logged_in_');
if (!wpo_cache_loggedin_users()) {
foreach ($_COOKIE as $key => $value) {
foreach ($wp_cookies as $cookie) {
if (false !== strpos($key, $cookie)) {
$no_cache_because[] = 'WordPress login cookies were detected';
break(2);
}
}
}
}
if (!empty($_COOKIE['wpo_commented_post'])) {
$no_cache_because[] = 'The user has commented on a post (comment cookie set)';
}
// get cookie exceptions from options.
$cache_exception_cookies = !empty($GLOBALS['wpo_cache_config']['cache_exception_cookies']) ? $GLOBALS['wpo_cache_config']['cache_exception_cookies'] : array();
// filter cookie exceptions, since WP 4.6
$cache_exception_cookies = function_exists('apply_filters') ? apply_filters('wpo_cache_exception_cookies', $cache_exception_cookies) : $cache_exception_cookies;
// check if any cookie exists from exception list.
if (!empty($cache_exception_cookies)) {
foreach ($_COOKIE as $key => $value) {
foreach ($cache_exception_cookies as $cookie) {
if ('' != trim($cookie) && false !== strpos($key, $cookie)) {
$no_cache_because[] = 'An excepted cookie was set ('.$key.')';
break 2;
}
}
}
}
}
// check in not disabled current user agent
if (!empty($_SERVER['HTTP_USER_AGENT']) && false === wpo_is_accepted_user_agent($_SERVER['HTTP_USER_AGENT'])) {
$no_cache_because[] = "In the settings, caching is disabled for matches for this request's user agent";
}
// Deal with optional cache exceptions.
if (wpo_url_in_exceptions(wpo_current_url())) {
$no_cache_because[] = 'In the settings, caching is disabled for matches for the current URL';
}
if (!empty($_GET)) {
// get variables used for building filename.
$get_variable_names = wpo_cache_query_variables();
$get_variables = wpo_cache_maybe_ignore_query_variables(array_keys($_GET));
// if GET variables include one or more undefined variable names then we don't cache.
$get_variables_diff = array_diff($get_variables, $get_variable_names);
if (!empty($get_variables_diff)) {
$no_cache_because[] = "In the settings, caching is disabled for matches for one of the current request's GET parameters";
}
}
if (!empty($no_cache_because)) {
$no_cache_because_message = implode(', ', $no_cache_because);
// Add http header
if (!defined('DOING_CRON') || !DOING_CRON) {
wpo_cache_add_nocache_http_header($no_cache_because_message);
}
// Only output if the user has turned on debugging output
if (((defined('WP_DEBUG') && WP_DEBUG) || isset($_GET['wpo_cache_debug'])) && (!defined('DOING_CRON') || !DOING_CRON)) {
wpo_cache_add_footer_output("Page not served from cache because: ".htmlspecialchars($no_cache_because_message));
}
return;
}
wpo_serve_cache();
ob_start('wpo_cache');

View File

@@ -0,0 +1,17 @@
<?php
/**
* Get path to wp-config.php when called from WP-CLI.
*
* @return string
*/
function wpo_wp_cli_locate_wp_config() {
$config_path = '';
if (is_callable('\WP_CLI\Utils\locate_wp_config')) {
// phpcs:ignore PHPCompatibility.LanguageConstructs.NewLanguageConstructs.t_ns_separatorFound
$config_path = \WP_CLI\Utils\locate_wp_config();
}
return $config_path;
}

View File

@@ -0,0 +1,47 @@
<?php
if (!defined('ABSPATH')) {
die('No direct access allowed');
}
/**
* Adds compatibility for Page Builder plugins.
*/
class WPO_Page_Builder_Compatibility {
/**
* Constructor.
*/
private function __construct() {
$this->disable_webp_alter_html_in_edit_mode();
}
/**
* Returns singleton instance.
*/
public static function instance() {
static $instance = null;
if (null == $instance) {
$instance = new static;
}
return $instance;
}
/**
* Checks if current page is in Page Builder edit mode.
*
* @return bool
*/
private function is_edit_mode() {
return isset($_GET['fl_builder']) || isset($_GET['et_fb']);
}
/**
* Disables altering HTML for WebP when current page is in edit mode.
*/
private function disable_webp_alter_html_in_edit_mode() {
if ($this->is_edit_mode()) {
add_filter('wpo_disable_webp_alter_html', '__return_true');
}
}
}

View File

@@ -0,0 +1,88 @@
<?php
if (!defined('ABSPATH')) {
die('No direct access allowed');
}
/**
* Adds compatibility for Polylang plugin.
*/
class WPO_Polylang_Compatibility {
/**
* Instance of this class
*
* @var WPO_Polylang_Compatibility|null
*/
protected static $instance = null;
/**
* Constructor.
*/
private function __construct() {
// Check if polylang is active
if (!class_exists('Polylang')) {
return;
}
// Add action hooks to delete cache for all languages
add_action('wpo_single_post_cache_deleted', array($this, 'polylang_delete_post_cache_for_all_languages'));
add_action('wpo_single_post_feed_cache_deleted', array($this, 'polylang_delete_post_feed_cache_for_all_languages'));
}
/**
* Returns singleton instance.
*
* @return WPO_Polylang_Compatibility
*/
public static function instance() {
if (null == self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
/**
* Deletes cache files for all connected langauges for a post.
*
* @param int $deleted_post_id Post id whose cache file is already deleted.
*/
public function polylang_delete_post_cache_for_all_languages($deleted_post_id) {
// Check if polylang translation function is available
if (!function_exists('pll_get_post_translations')) {
return;
}
$translated_post_ids = pll_get_post_translations($deleted_post_id);
// Delete cache for each translated post
foreach ($translated_post_ids as $post_id) {
if ($deleted_post_id !== $post_id) {
WPO_Page_Cache::really_delete_single_post_cache($post_id);
}
}
}
/**
* Deletes cache files for all connected langauges for a post feed.
*
* @param int $deleted_post_id Post id whose cache file for feed is already deleted.
*/
public function polylang_delete_post_feed_cache_for_all_languages($deleted_post_id) {
// Check if polylang translation function is available
if (!function_exists('pll_get_post_translations')) {
return;
}
$translated_post_ids = pll_get_post_translations($deleted_post_id);
// Delete cache for each translated post
foreach ($translated_post_ids as $post_id) {
if ($deleted_post_id !== $post_id) {
WPO_Page_Cache::really_delete_post_feed_cache($post_id);
}
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,606 @@
.wpo_hidden {
display: none !important;
}
.wpo_info {
background: #FFF;
color: #444;
font-family: -apple-system, "BlinkMacSystemFont", "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", sans-serif;
margin: 2em auto;
padding: 1em 2em;
max-width: 700px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.13);
}
#wp-optimize-wrap .widefat thead th, #wp-optimize-wrap .widefat thead td {
border-bottom: 1px solid #E1E1E1;
}
#wp-optimize-wrap .widefat td, #wp-optimize-wrap .widefat th {
padding: 8px 10px;
}
/* big button */
.wpo_primary_big {
padding: 4px 6px !important;
font-size: 22px !important;
min-height: 34px;
min-width: 200px;
}
/* SECTIONS */
.wpo_section {
clear: both;
padding: 0;
margin: 0;
}
.wp-optimize-settings {
margin-bottom: 16px;
}
.wp-optimize-settings td > label {
font-weight: bold;
display: block;
margin-bottom: 8px;
}
/* COLUMN SETUP */
.wpo_col {
display: block;
float: left;
margin: 1% 0 1% 1%;
}
.wpo_col:first-child {
margin-left: 0;
}
/* GROUPING */
.wpo_group:before,
.wpo_group:after {
content: "";
display: table;
}
.wpo_group:after {
clear: both;
}
.wpo_half_width {
width: 48%;
}
/* GRID OF THREE */
.wpo_span_3_of_3 {
width: 100%;
}
.wpo_span_2_of_3 {
width: 65.3%;
}
.wpo_span_1_of_3 {
width: 32.1%;
}
#wp-optimize-wrap .nav-tab-wrapper {
margin: 0;
}
@media screen and (min-width: 549px) {
.show_on_default_sizes {
display: block !important;
}
.show_on_mobile_sizes {
display: none !important;
}
}
@media screen and (max-width: 548px) {
.show_on_default_sizes {
display: none !important;
}
.show_on_mobile_sizes {
display: block !important;
}
}
@media screen and (max-width: 768px) {
.wpo_col {
margin: 1% 0;
}
.wpo_span_3_of_3 {
width: 100%;
}
.wpo_span_2_of_3 {
width: 100%;
}
.wpo_span_1_of_3 {
width: 100%;
}
.wpo_half_width {
width: 100%;
}
}
/* .wp-optimize-settings-clean-transient label, .wp-optimize-settings-clean-pingbacks label, .wp-optimize-settings-clean-trackbacks label, .wp-optimize-settings-clean-postmeta label, .wp-optimize-settings-clean-orphandata label, .wp-optimize-settings-clean-commentmeta label */
/* Optimizations tab */
.wp-optimize-setting-is-sensitive td > label::before {
content: "\f534";
font-family: "dashicons";
display: inline-block;
margin-right: 6px;
font-style: normal;
line-height: 1;
vertical-align: middle;
width: 20px;
font-size: 18px;
height: 20px;
text-align: center;
color: #72777C;
}
.wpo-run-optimizations__container {
margin-bottom: 15px;
}
.wp-optimize-optimizations-table-placeholder {
min-height: 80px;
}
td.wp-optimize-settings-optimization-checkbox {
width: 18px;
padding-left: 4px;
padding-right: 0px;
}
.wp-optimize-settings-optimization-checkbox input {
margin: 0px;
padding: 0px;
}
#retention-period, #revisions-count {
width: 60px;
}
.wp-optimize-settings-optimization-info {
font-size: 80%;
font-style: italic;
}
.wp-optimize-settings input[type=checkbox] {
/* width: 18px; */
}
/* Added for the Image on Addons tab*/
img.addons {
display: block;
margin-left: auto;
margin-right: auto;
margin-bottom: 20px;
max-height: 44px;
height: auto;
max-width: 100%;
}
.wpo_spinner {
width: 18px;
height: 18px;
padding-left: 10px;
display: none;
position: relative;
top: 4px;
}
.optimization_spinner {
width: 20px;
height: 20px;
}
#wp-optimize-auto-options {
margin: 20px 0 0 28px;
}
.display-none {
display: none;
}
.visibility-hidden {
visibility: hidden;
}
.margin-one-percent {
margin: 1%;
}
#save_done, .save-done {
color: #D94F00;
font-size: 220% !important;
}
.wp-optimize-settings-optimization-info a {
text-decoration: underline;
}
.wp-optimize-settings-optimization-run-spinner {
position: relative;
top: 2px;
}
@media screen and (min-width: 782px) {
td.wp-optimize-settings-optimization-run {
width: 180px;
padding-top: 16px;
}
}
#wpoptimize_table_list .tablesorter-filter-row {
display: none !important;
}
#wpoptimize_table_list .optimization_spinner {
position: relative;
top: 2px;
left: 5px;
}
#wpoptimize_table_list .optimization_spinner.visibility-hidden {
display: none;
}
#wpoptimize_table_list_filter {
width: 100%;
margin-bottom: 15px;
}
#wpoptimize_table_list_tables_not_found {
display: none;
margin: 20px 0;
}
div#wpoptimize_table_list_tables_not_found + h3 {
margin-top: 30px;
}
/* Hide First column */
#wpoptimize_table_list tr th:first-child,
#wpoptimize_table_list tr td:first-child {
display: none;
}
#wpoptimize_table_list tr td.no-table {
display: table-cell !important;
background: #FB8787;
font-weight: bold;
}
#optimize_form .select2-container,
#wp-optimize-auto-options .select2-container {
width: 50% !important;
top: -5px;
height: 40px;
margin-left: 10px;
}
#wpoptimize_table_list .optimization_done_icon {
color: #009B24;
font-size: 200%;
display: inline-block;
position: relative;
}
#wpo_sitelist_show_moreoptions_cron {
font-size: 13px;
line-height: 1.5;
letter-spacing: 1px;
}
#wp-optimize-nav-tab-contents-images .wpo_span_2_of_3 h3 {
display: inline-block;
}
.wpo_remove_selected_sizes_btn__container {
margin-top: 20px;
}
.unused-image-sizes__label {
display: block;
line-height: 1.6;
}
@media (max-width: 782px) {
.unused-image-sizes__label {
margin-left: 30px;
margin-bottom: 15px;
line-height: 1;
word-break: break-word;
}
.unused-image-sizes__label input[type=checkbox] {
margin-left: -30px;
}
body.rtl .unused-image-sizes__label {
margin-right: 30px;
margin-left: 0;
}
body.rtl .unused-image-sizes__label input[type=checkbox] {
margin-left: 4px;
margin-right: -30px;
}
}
#wp-optimize-nav-tab-contents-tables a {
vertical-align: middle;
}
#wpo_sitelist_moreoptions,
#wpo_sitelist_moreoptions_cron {
margin: 4px 16px 6px 0;
border: 1px dotted;
padding: 6px 10px;
max-height: 300px;
overflow-y: scroll;
overflow-x: hidden;
}
#wpo_sitelist_moreoptions {
max-height: 150px;
margin-right: 0;
}
#wpo_settings_sites_list li,
#wpo_settings_sites_list li a {
font-size: 13px;
line-height: 1.5;
}
#wpo_sitelist_moreoptions_cron li {
padding-left: 20px;
}
#wpo_import_error_message {
display: none;
color: #9B0000;
}
#wpo_import_success_message {
display: none;
color: #46B450;
}
#wp-optimize-logging-options {
margin-top: 10px;
background-color: #FFF;
border: 1px solid #CCC;
}
/* Logger settings*/
.wpo_logging_header {
font-weight: bold;
border-bottom: 1px solid #CCC;
padding: 12px 6px;
margin: 0;
}
.wpo_logging_row {
padding: 5px 0;
}
.wpo_logging_row:nth-child(even) {
background-color: #F9F9F9;
padding: 12px 0px;
}
.wpo_logging_logger_title,
.wpo_logging_options_title,
.wpo_logging_status_title,
.wpo_logging_actions_title,
.wpo_logging_logger_row,
.wpo_logging_options_row,
.wpo_logging_status_row,
.wpo_logging_actions_row {
display: inline-block;
vertical-align: middle;
}
.wpo_logging_logger_title,
.wpo_logging_logger_row {
width: 38%;
}
.wpo_logging_options_title,
.wpo_logging_options_row {
width: 44%;
}
.wpo_logging_status_title,
.wpo_logging_status_row {
width: 8%;
}
.wpo_logging_status_row.active {
color: #29AF29;
}
.wpo_logging_status_row.inactive {
color: #CDCFD3;
}
.wpo_logging_actions_title,
.wpo_logging_actions_row {
width: 7%;
}
.wpo_logging_actions_row {
text-align: left;
}
.wpo_logging_edit_row {
padding: 0px 6px;
display: none;
float: right;
}
.wpo_logging_edit_row .wpo_delete_logger {
margin-right: 5px;
}
.wpo_logging_options_row {
word-wrap: break-word;
}
.wpo_logging_actions_row .wpo_edit_logger {
color: #0085BA;
cursor: pointer;
text-decoration: underline;
}
.wpo_logging_actions_row .wpo_delete_logger {
color: #F00;
cursor: pointer;
text-decoration: underline;
}
.wpo_logging_row .wpo_additional_logger_options {
padding: 12px 6px;
}
.wpo_logging_row .wpo_additional_logger_options input.wpo_logger_addition_option {
margin-bottom: 10px;
}
.wpo_logging_actions_row .dashicons-no-alt,
.wpo_add_logger_form .dashicons-no-alt {
background-color: #F06666;
color: #FFF;
width: 20px;
height: 20px;
border-radius: 20px;
display: inline-block;
cursor: pointer;
margin-left: 5px;
}
.wpo_add_logger_form .dashicons-no-alt {
margin-top: 12px;
margin-right: 10px;
float: right;
}
.wpo_logger_type {
width: 90%;
margin-top: 10px;
}
.wpo_logger_addition_option {
width: 100%;
margin-top: 5px;
}
.wpo_alert_notice {
background-color: #F06666;
color: #FFF;
padding: 1em;
display: block;
margin-bottom: 10px;
border-radius: 5px;
}
.wpo_error_field {
border-color: #F06666 !important;
}
.save_settings_reminder {
display: none;
color: #333;
padding: 15px 20px;
background-color: #F0A5A4;
border-radius: 3px;
margin: 15px 0;
}
#wpo_remove_selected_sizes {
margin-top: 20px;
}
.wpo_unused_images_buttons_wrap {
float: right;
margin-right: 20px;
}
.wpo_unused_images_container h3 {
min-width: 150px;
}
#wpo_unused_images, #wpo_smush_images_grid {
max-height: 500px;
overflow-y: auto;
}
#wpo_unused_images a {
outline: none;
}
#wp-optimize-nav-tab-wpo_database-tables-contents .wpo-take-a-backup {
margin-left: 1%;
}
.run-single-table-delete {
margin-top: 3px;
}
.wpo-confirm h4 span.table-name {
font-style: italic;
display: inline-block;
background: #EFEFEF;
padding: 3px 7px;
border-radius: 4px;
}
#wpo_browser_cache_output,
#wpo_gzip_compression_output,
#wpo_advanced_cache_output {
background: #F0F0F0;
padding: 10px;
border: 1px solid #CCC;
white-space: pre-wrap;
}
#wpo_gzip_compression_error_message,
.wpo-error {
color: #9B0000;
}
.notice.wpo-error__enabling-cache {
white-space: pre-wrap;
margin-bottom: 15px;
}
.notice.wpo-warnings__enabling-cache {
margin-bottom: 15px;
}
.notice.wpo-warnings__enabling-cache ul, .notice.wpo-warnings__enabling-cache ul li {
list-style: inside disc;
}
a.loading.wpo-refresh-gzip-status {
color: rgba(68, 68, 68, 0.5);
text-decoration: none;
}
a.loading.wpo-refresh-gzip-status img.wpo_spinner.display-none {
display: inline-block;
}
#wpo_browser_cache_expire_days,
#wpo_browser_cache_expire_hours {
width: 50px;
}
.wpo-enabled .wpo-disabled {
display: none;
}
.wpo-disabled .wpo-enabled {
display: none;
}
.wpo-button-wrap {
margin-top: 10px;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,879 @@
/**
* Autosmush
*/
.wpo-fieldgroup .autosmush {
display: inline-block;
width: 100%;
}
.wpo-fieldgroup .autosmush h3 {
font-size: 1.2em;
margin: 3px 18px;
}
/**
* Compression Server
*/
.wpo-fieldgroup .compression_server div {
max-width: 300px;
}
.wpo-fieldgroup .compression_server h2 {
margin: 10px 0;
}
.wpo-fieldgroup .compression_server h3 {
clear: both;
width: 100%;
}
.wpo-fieldgroup .compression_server p {
margin: 1px;
}
.wpo-fieldgroup .compression_server p:last-of-type {
margin-bottom: 10px;
}
.wpo-fieldgroup .compression_server {
display: -ms-flexbox;
display: flex;
-ms-flex-flow: row wrap;
flex-flow: row wrap;
}
.wpo-fieldgroup .compression_server > div {
-ms-flex: 1;
flex: 1;
margin-right: 10px;
height: 100%;
position: relative;
}
.wpo-fieldgroup .compression_server input[type=radio] {
position: absolute;
z-index: 1;
top: calc(50% + 2px);
left: 20px;
transform: translatey(-50%);
}
.wpo-fieldgroup .compression_server input[type=radio] ~ label h4 {
color: #23282D;
margin-top: 0;
margin-bottom: 0.9em;
font-size: 1.2em;
}
.wpo-fieldgroup .compression_server label {
display: block;
position: relative;
box-sizing: border-box;
height: 100%;
background: #FFF;
text-align: left;
box-shadow: 0px 3px 10px -2px hsla(150, 5%, 65%, 0.5);
}
.wpo-fieldgroup .compression_server input[type=radio] + label {
padding: 20px;
border: 2px solid #FFF;
padding-left: 65px;
position: relative;
border-radius: 5px;
color: #82868B;
}
.wpo-fieldgroup .compression_server input[type=radio] + label::before {
content: "";
display: block;
position: absolute;
top: 0;
left: 52px;
height: 100%;
border-right: 1px solid #EDEFF0;
}
.wpo-fieldgroup .save-options {
margin: 10px 0;
}
.wpo-fieldgroup .compression_server input[type=radio]:focus + label,
.wpo-fieldgroup .compression_server input[type=radio] + label:hover {
border-color: rgba(0, 134, 184, 0.38);
}
.wpo-fieldgroup .compression_server input[type=radio]:focus + label {
box-shadow: 0px 3px 10px -2px #5B9DD9;
}
.wpo-fieldgroup .compression_server input[type=radio]:focus + label h4 {
color: #0086B9;
}
.wpo-fieldgroup .compression_server input[type=radio]:checked + label,
.wpo-fieldgroup .compression_server input[type=radio]:checked + label:hover {
border-color: #0086B9;
}
@media only screen and (max-width: 700px) {
.wpo-fieldgroup .compression_server {
-ms-flex-direction: column;
flex-direction: column;
}
.wpo-fieldgroup .compression_server > div {
margin-bottom: 15px;
max-width: 100%;
}
}
/**
* Compression Options
*/
.wpo-fieldgroup h4 {
margin: 1em 0;
width: 100%;
}
.wpo-fieldgroup .image_quality input[type=radio] {
position: absolute;
visibility: hidden;
display: none;
}
.wpo-fieldgroup .image_quality label {
color: #23282D;
display: inline-block;
cursor: pointer;
font-weight: bold;
padding: 5px 20px;
background: #F9F9F9;
float: left;
margin: 0 0.5px;
}
.wpo-fieldgroup .image_quality input[type=radio]:checked + label {
color: white;
background: #0088B9;
}
.wpo-fieldgroup .image_quality label + .wpo-fieldgroup .image_quality input[type=radio] + label {
border-left: solid 3px #675F6B;
}
.wpo-fieldgroup .image_quality.radio-group {
border: solid 0.5px #C4C4C4;
display: inline-block;
border-radius: 5px;
overflow: hidden;
border-bottom: solid 2px #C4C4C4;
background: #C4C4C4;
}
.wpo-fieldgroup .image_options input {
min-height: 16px;
min-width: 16px;
margin: 3px 2px;
}
img#wpo_smush_images_save_options_spinner {
max-width: 20px;
max-height: 20px;
}
span#wpo_smush_images_save_options_fail {
font-size: inherit;
color: red;
}
span#wpo_smush_images_save_options_done {
font-size: inherit;
color: green;
}
#smush-complete-summary span.clearfix {
height: 10px;
display: block;
clear: both;
}
#smush-complete-summary span.close {
display: block;
clear: both;
text-align: left;
color: #DF6927;
border: 2px solid;
border-radius: 50%;
cursor: pointer;
}
.modal-message-text {
margin: 0 25px;
}
.smush-options.custom_compression {
margin: 10px;
}
#smush-backup-delete-days {
width: 50px;
margin: 0 8px;
}
img#wpo_smush_delete_backup_spinner {
max-width: 20px;
max-height: 20px;
position: relative;
top: 4px;
}
span#wpo_smush_delete_backup_done {
font-size: inherit;
color: green;
}
.wpo-fieldgroup .smush-options.custom_compression {
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
margin-left: 24px;
}
.wpo-fieldgroup .smush-options.custom_compression > span {
display: inline-block;
padding: 6px;
border: 1px solid #CFD2D4;
border-radius: 4px;
font-size: 0.9em;
position: relative;
}
.wpo-fieldgroup .smush-options.custom_compression > span.slider-start::after {
content: "";
width: 6px;
height: 6px;
display: block;
position: absolute;
top: 0;
left: 100%;
transform: translate(-3px, 8px) rotate(45deg);
border-right: 1px solid #CFD2D4;
border-top: 1px solid #CFD2D4;
background: #EDEFF0;
}
.wpo-fieldgroup .smush-options.custom_compression > span.slider-end::before {
content: "";
width: 6px;
height: 6px;
display: block;
position: absolute;
top: 0;
right: 100%;
transform: translate(3px, 8px) rotate(45deg);
border-left: 1px solid #CFD2D4;
border-bottom: 1px solid #CFD2D4;
background: #EDEFF0;
}
.wpo-fieldgroup .smush-options.custom_compression > input {
margin-left: 8px;
margin-right: 8px;
}
@media screen and (max-width: 782px) {
.wpo-fieldgroup input[type=radio] {
height: 16px;
width: 16px;
}
.wpo-fieldgroup input[type=radio]:checked:before {
width: 6px;
height: 6px;
margin: 4px;
}
.wpo-fieldgroup .smush-options.custom_compression {
-ms-flex-direction: column;
flex-direction: column;
}
.wpo-fieldgroup .smush-options.custom_compression > input {
width: 100%;
}
.wpo-fieldgroup .smush-options.custom_compression > span {
display: block;
width: 100%;
}
.wpo-fieldgroup .smush-options.custom_compression > span.slider-start::after {
left: 0;
transform: translate(7px, 22px) rotate(135deg);
}
.wpo-fieldgroup .smush-options.custom_compression > span.slider-end::before {
right: auto;
left: 100%;
transform: translate(-14px, -5px) rotate(135deg);
}
}
/**
* Uncompressed images
*/
#wpo_smush_settings .align-left {
float: left;
}
#wpo_smush_settings .align-right {
float: right;
}
.wpo-fieldgroup .wpo_smush_images_buttons_wrap {
width: 100%;
}
.wpo-fieldgroup .smush-refresh-icon,
.wpo-fieldgroup .smush-select-actions {
font-size: 15px;
}
.wpo-fieldgroup img.wpo_smush_images_loader {
display: none;
min-height: 20px;
min-width: 20px;
}
.wpo-fieldgroup .dashicons.dashicons-image-rotate {
font-size: 15px;
}
.wpo-fieldgroup .wpo-toggle-advanced-options {
cursor: pointer;
text-decoration: underline;
color: #0088BC;
}
.wpo-fieldgroup .button.wpo-toggle-advanced-options {
display: block;
width: calc(100% + 40px);
margin-left: -20px;
margin-right: -20px;
padding-left: 20px;
padding-right: 20px;
position: relative;
text-decoration: none;
}
.wpo-fieldgroup .button.wpo-toggle-advanced-options span.dashicons {
text-decoration: none;
font-size: 16px;
height: 16px;
vertical-align: middle;
color: #444;
transition: 0.2s all;
}
.wpo-fieldgroup .wpo-toggle-advanced-options span.text {
background: #F2F4F4;
z-index: 1;
position: relative;
padding-right: 5px;
}
.wpo-fieldgroup .button.wpo-toggle-advanced-options:hover,
.wpo-fieldgroup .button.wpo-toggle-advanced-options:focus {
background: transparent;
}
.wpo-fieldgroup .button.wpo-toggle-advanced-options .wpo-toggle-advanced-options__text-show {
display: inline-block;
}
.wpo-fieldgroup .button.wpo-toggle-advanced-options .wpo-toggle-advanced-options__text-hide {
display: none;
}
.wpo-fieldgroup .button.wpo-toggle-advanced-options.opened .wpo-toggle-advanced-options__text-show {
display: none;
}
.wpo-fieldgroup .button.wpo-toggle-advanced-options.opened .wpo-toggle-advanced-options__text-hide {
display: inline-block;
margin-bottom: 20px;
}
.wpo-fieldgroup .button.wpo-toggle-advanced-options.opened::before {
content: "";
border-top: 1px solid #CCC;
width: 100%;
position: absolute;
top: 16px;
left: 0;
}
.wpo-fieldgroup .button.wpo-toggle-advanced-options.opened span.dashicons {
transform: rotate(180deg);
}
.wpo-fieldgroup .wpo-advanced-options {
display: none;
}
.wpo-advanced-options > fieldset:first-child {
margin-top: 10px;
}
.wpo-fieldgroup .button.wpo-toggle-advanced-options.opened + .wpo-advanced-options {
display: block;
}
.wpo_smush_image:focus-within label {
box-shadow: 0 0 4px #0272AA;
}
.wpo_smush_image .wpo_smush_image__input:checked + label {
border-color: #0272AA;
}
.uncompressed-images input[type=checkbox] {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.uncompressed-images small.red {
clear: both;
display: block;
margin: 5px;
}
.smush-actions .wpo_primary_small {
display: inline-block;
margin: 5px;
}
.smush-actions {
display: inline-block;
width: 100%;
margin: 10px 0;
}
.smush-actions .dashicons.dashicons-yes {
font-size: 15px;
margin: 0 5px;
}
.smush-actions img {
max-height: 25px;
max-width: 25px;
}
/**
* Log and panels
*/
#smush-log-modal {
width: 100%;
height: 100%;
}
#log-panel {
height: 80%;
overflow: scroll;
margin: 2%;
}
#log-panel pre {
text-align: left;
overflow: auto;
height: 100%;
background: gainsboro;
}
.smush-information {
margin-bottom: 10px;
}
/**
* Smush modal progress box & related styling
*/
#smush_stats {
text-align: center;
margin: 0 auto;
padding: 2%;
min-width: 350px;
font-size: larger;
}
#smush_stats .wpo_smush_stats_cta_btn {
clear: both;
display: block;
text-align: center;
}
#smush_stats .smush_stats_row td:first-child {
text-align: left;
}
#smush_stats tr.smush_stats_row td:last-child {
text-align: right;
}
#smush_stats #wpo_smush_images_information_container p {
padding: 10px;
}
#smush-complete-summary .checkmark-circle {
width: 50px;
height: 50px;
position: relative;
display: inline-block;
vertical-align: top;
}
#smush-complete-summary .checkmark-circle .background {
width: 50px;
height: 50px;
border-radius: 50%;
background: #DF6927;
position: absolute;
}
#smush-complete-summary .checkmark-circle .checkmark {
border-radius: 5px;
}
#smush-complete-summary .checkmark-circle .checkmark.draw:after {
animation-delay: 100ms;
animation-duration: 1s;
animation-timing-function: ease;
animation-name: checkmark;
transform: scalex(-1) rotate(135deg);
animation-fill-mode: forwards;
}
#smush-complete-summary .checkmark-circle .checkmark:after {
opacity: 1;
height: 25px;
width: 12.5px;
transform-origin: left top;
border-right: 5px solid white;
border-top: 5px solid white;
border-radius: 2.5px !important;
content: "";
left: 8.3333333333px;
top: 25px;
position: absolute;
}
#smush_stats .wpo_primary_small {
text-align: center;
}
#smush-complete-summary #summary-message {
margin: 15px auto;
}
img#wpo_smush_images_clear_stats_spinner {
width: 20px;
line-height: 1;
vertical-align: middle;
}
/* Animated progress bar */
#wpo_smush_images_information_container {
padding: 10px;
}
#wpo_smush_images_information_wrapper .progress-bar {
height: 25px;
padding: 1px;
width: 350px;
margin: 10px auto;
border-radius: 5px;
}
#wpo_smush_images_information_wrapper .progress-bar span {
display: inline-block;
height: 100%;
border-radius: 3px;
box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset;
transition: width 0.4s ease-in-out;
}
#wpo_smush_images_information_wrapper .orange span {
background-color: #DF6927;
}
#wpo_smush_images_information_wrapper .stripes span {
background-size: 30px;
background-image: linear-gradient(135deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
animation: animate-stripes 3s linear infinite;
}
/**
* Smush metabox
*/
#smush-metabox-inside-wrapper {
display: inline-table;
width: 100%;
}
#smush-metabox-inside-wrapper h4 {
margin: 2px 0;
}
#smush-metabox-inside-wrapper label {
margin-top: 5px;
clear: left;
display: block;
}
#smush-metabox-inside-wrapper .wpo_smush_single_image {
display: block;
}
#smush-metabox-inside-wrapper .wpo_smush_single_image.action_button {
padding: 5px 0;
}
#smush-metabox-inside-wrapper fieldset {
margin: 10px 0;
}
#smush-metabox-inside-wrapper input[type=radio] {
margin: -4px 4px 0 0;
}
#smush-metabox-inside-wrapper .alignleft {
float: left;
}
#smush-metabox-inside-wrapper p#smush_info {
margin: 20px auto;
padding-top: 10px;
clear: both;
}
#smush-metabox-inside-wrapper .wpo-toggle-advanced-options {
cursor: pointer;
display: block;
clear: both;
margin-top: 10px;
margin-bottom: 10px;
}
#smush-metabox-inside-wrapper .wpo-toggle-advanced-options:not(.opened) ~ .wpo-advanced-options {
display: none;
}
#smush-metabox-inside-wrapper .wpo-toggle-advanced-options.opened ~ .wpo-advanced-options {
display: block !important;
}
#smush-metabox-inside-wrapper .smush-options.custom_compression span {
display: block;
max-width: 30%;
clear: both;
}
#smush-metabox-inside-wrapper input#custom_compression_slider {
display: block;
clear: both;
width: 100%;
}
#smush-metabox-inside-wrapper .smush-options.custom_compression span.alignleft {
float: left;
}
#smush-metabox-inside-wrapper .smush-options.custom_compression span.alignright {
float: right;
text-align: right;
}
.smush-metabox-dashboard-link {
clear: both;
padding-top: 15px;
text-align: right;
}
.media-frame-content .attachment-compat .compat-item,
.compat-field-wpo_compress_image {
overflow: visible !important;
}
.compat-field-wpo_compress_image {
border-top: 1px solid #DDD;
}
.compat-field-wpo_compress_image span.dashicons {
text-align: left;
float: none;
min-height: 0;
padding-top: 2px;
}
.compat-field-wpo_compress_image td.field {
width: auto;
float: none;
}
.compat-field-wpo_compress_image td.field [data-tooltip] {
display: none;
}
.compat-field-wpo_compress_image th.label {
text-align: left;
min-width: 0;
float: none;
margin: 0;
}
.compat-field-wpo_compress_image th.label label span {
font-weight: 500;
text-align: left;
}
/* fix for elementor restore button position */
.wpo_restore_single_image .alignright {
float: right;
}
/**
* Force fix the modals
*/
.blockUI.blockMsg.blockPage {
z-index: 170000 !important;
right: 0;
left: 0 !important;
margin-right: auto !important;
margin-left: auto !important;
max-width: 90%;
cursor: default !important;
}
.blockUI.blockOverlay {
cursor: default !important;
}
/**
* Tooltip Styles
*/
/* Add this attribute to the element that needs a tooltip */
#smush-metabox-inside-wrapper [data-tooltip],
.wpo-fieldgroup [data-tooltip] {
position: relative;
cursor: pointer;
line-height: 18px;
}
/* Hide the tooltip content by default */
#smush-metabox-inside-wrapper [data-tooltip]:before,
#smush-metabox-inside-wrapper [data-tooltip]:after,
.wpo-fieldgroup [data-tooltip]:before,
.wpo-fieldgroup [data-tooltip]:after {
visibility: hidden;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: opacity(0%);
opacity: 0;
pointer-events: none;
}
/* Position tooltip above the element */
#smush-metabox-inside-wrapper [data-tooltip]:before,
.wpo-fieldgroup [data-tooltip]:before {
position: absolute;
bottom: 150%;
left: 50%;
margin-bottom: 5px;
margin-left: -140px;
padding: 12px;
width: 275px;
z-index: 9999;
border-radius: 3px;
background-color: #000;
background-color: hsla(0, 0%, 20%, 0.95);
color: #FFF;
content: attr(data-tooltip);
text-align: center;
font-size: 0.85rem;
font-weight: 400;
line-height: 1.4;
}
#smush-metabox-inside-wrapper [data-tooltip]:before {
margin-left: -280px;
}
/* Triangle hack to make tooltip look like a speech bubble */
#smush-metabox-inside-wrapper [data-tooltip]:after,
.wpo-fieldgroup [data-tooltip]:after {
position: absolute;
bottom: 150%;
left: 50%;
margin-left: -5px;
width: 0;
border-top: 5px solid #000;
border-top: 5px solid hsla(0, 0%, 20%, 0.9);
border-right: 5px solid transparent;
border-left: 5px solid transparent;
content: " ";
font-size: 0;
line-height: 0;
}
/* Show tooltip content on hover */
#smush-metabox-inside-wrapper [data-tooltip]:hover:before,
#smush-metabox-inside-wrapper [data-tooltip]:hover:after,
.wpo-fieldgroup [data-tooltip]:hover:before,
.wpo-fieldgroup [data-tooltip]:hover:after,
#smush-metabox-inside-wrapper [data-tooltip]:focus:before,
#smush-metabox-inside-wrapper [data-tooltip]:focus:after,
.wpo-fieldgroup [data-tooltip]:focus:before,
.wpo-fieldgroup [data-tooltip]:focus:after {
visibility: visible;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
filter: opacity(100%);
opacity: 1;
}
/**
* Animation needed for smush
*/
@keyframes checkmark {
0% {
height: 0;
width: 0;
opacity: 1;
}
20% {
height: 0;
width: 12.5px;
opacity: 1;
}
40% {
height: 25px;
width: 12.5px;
opacity: 1;
}
100% {
height: 25px;
width: 12.5px;
opacity: 1;
}
}
@keyframes animate-stripes {
0% {
background-position: 0 0;
}
100% {
background-position: 60px 0;
}
}
@keyframes animate-stripes {
0% {
background-position: 0 0;
}
100% {
background-position: 60px 0;
}
}
#wpo_smush_restore_all_compressed_images_btn + span > span {
line-height: 28px;
}

View File

@@ -0,0 +1 @@
.tablesorter-default{width:100%;font:12px/18px Arial,Sans-serif;color:#333;background-color:#fff;border-spacing:0;margin:10px 0 15px;text-align:left}.tablesorter-default th,.tablesorter-default thead td{font-weight:700;color:#000;background-color:#fff;border-collapse:collapse;border-bottom:#ccc 2px solid;padding:0}.tablesorter-default tfoot td,.tablesorter-default tfoot th{border:0}.tablesorter-default .header,.tablesorter-default .tablesorter-header{background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-position:center right;background-repeat:no-repeat;cursor:pointer;white-space:normal;padding:4px 20px 4px 4px}.tablesorter-default thead .headerSortUp,.tablesorter-default thead .tablesorter-headerAsc,.tablesorter-default thead .tablesorter-headerSortUp{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);border-bottom:#000 2px solid}.tablesorter-default thead .headerSortDown,.tablesorter-default thead .tablesorter-headerDesc,.tablesorter-default thead .tablesorter-headerSortDown{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);border-bottom:#000 2px solid}.tablesorter-default thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-default tfoot .tablesorter-headerAsc,.tablesorter-default tfoot .tablesorter-headerDesc,.tablesorter-default tfoot .tablesorter-headerSortDown,.tablesorter-default tfoot .tablesorter-headerSortUp{border-top:#000 2px solid}.tablesorter-default td{background-color:#fff;border-bottom:#ccc 1px solid;padding:4px;vertical-align:top}.tablesorter-default tbody>tr.even:hover>td,.tablesorter-default tbody>tr.hover>td,.tablesorter-default tbody>tr.odd:hover>td,.tablesorter-default tbody>tr:hover>td{background-color:#fff;color:#000}.tablesorter-default .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-default tr.odd>td{background-color:#dfdfdf}.tablesorter-default tr.even>td{background-color:#efefef}.tablesorter-default tr.odd td.primary{background-color:#bfbfbf}.tablesorter-default td.primary,.tablesorter-default tr.even td.primary{background-color:#d9d9d9}.tablesorter-default tr.odd td.secondary{background-color:#d9d9d9}.tablesorter-default td.secondary,.tablesorter-default tr.even td.secondary{background-color:#e6e6e6}.tablesorter-default tr.odd td.tertiary{background-color:#e6e6e6}.tablesorter-default td.tertiary,.tablesorter-default tr.even td.tertiary{background-color:#f2f2f2}.tablesorter-default>caption{background-color:#fff}.tablesorter-default .tablesorter-filter-row{background-color:#eee}.tablesorter-default .tablesorter-filter-row td{background-color:#eee;border-bottom:#ccc 1px solid;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-default .tablesorter-filter-row .disabled{opacity:.5;cursor:not-allowed}.tablesorter-default .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-default .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0}.tablesorter-default input.tablesorter-filter,.tablesorter-default select.tablesorter-filter{width:95%;height:auto;margin:4px auto;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
#wpadminbar .quicklinks .menupop.hover ul li.separator .ab-item.ab-empty-item{height:2px;line-height:2px;background:rgba(255,255,255,0.0901960784);margin:5px 10px;width:auto;min-width:0}#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats::before{content:"";display:block;margin-left:10px;margin-right:10px;border-top:1px solid rgba(114,119,124,0.48);padding-top:5px;margin-top:5px}#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats .ab-item{height:auto;line-height:1.2}#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats .ab-item span{line-height:1.5;font-size:80%;color:#989898}#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats .ab-item h4{font-weight:500;text-transform:uppercase;color:#FFF}#wpadminbar .quicklinks .menupop ul li .ab-item.loading{opacity:.2}#wpo_always_purge_this_post_type_select+.select2{width:90% !important}.wpo-collapsible-content .smush-details th{font-weight:bold}.wpo-collapsible-content .smush-details tr{display:table-row}.wpo-collapsible-content .smush-details th,.wpo-collapsible-content .smush-details td{text-align:left;padding:0 3px;font-size:.8em}.wpo-collapsible-content .smush-details td:first-child{word-break:break-all}.wpo-collapsible{cursor:pointer}.wpo-collapsible::before{display:inline-block;width:10px}.wpo-collapsible::before{content:"+"}.wpo-collapsible.opened::before{content:"-"}.wpo-collapsible-content{display:none}.wpo-collapsible.opened+.wpo-collapsible-content{display:block}
/*# sourceMappingURL=wp-optimize-global-3-2-14.min.css.map */

View File

@@ -0,0 +1 @@
{"version":3,"sources":["css/wp-optimize-global.css"],"names":[],"mappings":"AAAA,yBAAyB;AACzB;EACE,YAAY;EACZ,iBAAiB;EACjB,8CAA8C;EAC9C,iBAAiB;EACjB,YAAY;EACZ,aAAa;CACd;;AAED;EACE,YAAY;EACZ,eAAe;EACf,kBAAkB;EAClB,mBAAmB;EACnB,gDAAgD;EAChD,iBAAiB;EACjB,gBAAgB;CACjB;;AAED;EACE,aAAa;EACb,iBAAiB;CAClB;;AAED;EACE,iBAAiB;EACjB,eAAe;EACf,eAAe;CAChB;;AAED;EACE,iBAAiB;EACjB,0BAA0B;EAC1B,YAAY;CACb;;AAED;EACE,aAAa;CACd;;AAED;EACE,sBAAsB;CACvB;;AAED;EACE,kBAAkB;CACnB;;AAED;EACE,mBAAmB;CACpB;;AAED;;EAEE,iBAAiB;EACjB,eAAe;EACf,iBAAiB;CAClB;;AAED;EACE,sBAAsB;CACvB;;AAED;EACE,gBAAgB;CACjB;;AAED;EACE,sBAAsB;EACtB,YAAY;CACb;;AAED;EACE,aAAa;CACd;;AAED;EACE,aAAa;CACd;;AAED;EACE,cAAc;CACf;;AAED;EACE,eAAe;CAChB","file":"wp-optimize-global-3-2-14.min.css","sourcesContent":["/* Admin bar separator */\n#wpadminbar .quicklinks .menupop.hover ul li.separator .ab-item.ab-empty-item {\n height: 2px;\n line-height: 2px;\n background: rgba(255, 255, 255, 0.0901960784);\n margin: 5px 10px;\n width: auto;\n min-width: 0;\n}\n\n#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats::before {\n content: \"\";\n display: block;\n margin-left: 10px;\n margin-right: 10px;\n border-top: 1px solid rgba(114, 119, 124, 0.48);\n padding-top: 5px;\n margin-top: 5px;\n}\n\n#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats .ab-item {\n height: auto;\n line-height: 1.2;\n}\n\n#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats .ab-item span {\n line-height: 1.5;\n font-size: 80%;\n color: #989898;\n}\n\n#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats .ab-item h4 {\n font-weight: 500;\n text-transform: uppercase;\n color: #FFF;\n}\n\n#wpadminbar .quicklinks .menupop ul li .ab-item.loading {\n opacity: 0.2;\n}\n\n#wpo_always_purge_this_post_type_select + .select2 {\n width: 90% !important;\n}\n\n.wpo-collapsible-content .smush-details th {\n font-weight: bold;\n}\n\n.wpo-collapsible-content .smush-details tr {\n display: table-row;\n}\n\n.wpo-collapsible-content .smush-details th,\n.wpo-collapsible-content .smush-details td {\n text-align: left;\n padding: 0 3px;\n font-size: 0.8em;\n}\n\n.wpo-collapsible-content .smush-details td:first-child {\n word-break: break-all;\n}\n\n.wpo-collapsible {\n cursor: pointer;\n}\n\n.wpo-collapsible::before {\n display: inline-block;\n width: 10px;\n}\n\n.wpo-collapsible::before {\n content: \"+\";\n}\n\n.wpo-collapsible.opened::before {\n content: \"-\";\n}\n\n.wpo-collapsible-content {\n display: none;\n}\n\n.wpo-collapsible.opened + .wpo-collapsible-content {\n display: block;\n}"]}

View File

@@ -0,0 +1,88 @@
/* Admin bar separator */
#wpadminbar .quicklinks .menupop.hover ul li.separator .ab-item.ab-empty-item {
height: 2px;
line-height: 2px;
background: rgba(255, 255, 255, 0.0901960784);
margin: 5px 10px;
width: auto;
min-width: 0;
}
#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats::before {
content: "";
display: block;
margin-left: 10px;
margin-right: 10px;
border-top: 1px solid rgba(114, 119, 124, 0.48);
padding-top: 5px;
margin-top: 5px;
}
#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats .ab-item {
height: auto;
line-height: 1.2;
}
#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats .ab-item span {
line-height: 1.5;
font-size: 80%;
color: #989898;
}
#wpadminbar .quicklinks .menupop ul li.wpo-cache-stats .ab-item h4 {
font-weight: 500;
text-transform: uppercase;
color: #FFF;
}
#wpadminbar .quicklinks .menupop ul li .ab-item.loading {
opacity: 0.2;
}
#wpo_always_purge_this_post_type_select + .select2 {
width: 90% !important;
}
.wpo-collapsible-content .smush-details th {
font-weight: bold;
}
.wpo-collapsible-content .smush-details tr {
display: table-row;
}
.wpo-collapsible-content .smush-details th,
.wpo-collapsible-content .smush-details td {
text-align: left;
padding: 0 3px;
font-size: 0.8em;
}
.wpo-collapsible-content .smush-details td:first-child {
word-break: break-all;
}
.wpo-collapsible {
cursor: pointer;
}
.wpo-collapsible::before {
display: inline-block;
width: 10px;
}
.wpo-collapsible::before {
content: "+";
}
.wpo-collapsible.opened::before {
content: "-";
}
.wpo-collapsible-content {
display: none;
}
.wpo-collapsible.opened + .wpo-collapsible-content {
display: block;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 998 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 714 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1003 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 798 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 610 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 877 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -0,0 +1,103 @@
<?php
/**
* Normalize a filesystem path.
*/
if (!function_exists('wp_normalize_path')) {
/**
* WordPress function to normalize a filesystem path; was added to WP core in WP 3.9
*
* @see wp_normalize_path() https://developer.wordpress.org/reference/functions/wp_normalize_path/#source for the original source code
*
* @param string $path Path to normalize.
* @return string Normalized path.
*/
function wp_normalize_path($path) {
$wrapper = '';
if (wp_is_stream($path)) {
list($wrapper, $path) = explode('://', $path, 2);
$wrapper .= '://';
}
// Standardise all paths to use /
$path = str_replace('\\', '/', $path);
// Replace multiple slashes down to a singular, allowing for network shares having two slashes.
$path = preg_replace('|(?<=.)/+|', '/', $path);
// Windows paths should uppercase the drive letter
if (':' === substr($path, 1, 1)) {
$path = ucfirst($path);
}
return $wrapper.$path;
}
}
/**
* Unschedules all events attached to the hook.
*/
if (!function_exists('wp_unschedule_hook')) {
/**
* Unschedules all events attached to the hook.
*
* Can be useful for plugins when deactivating to clean up the cron queue.
*
* Warning: This function may return Boolean FALSE, but may also return a non-Boolean
* value which evaluates to FALSE. For information about casting to booleans see the
* {@link https://www.php.net/manual/en/language.types.boolean.php PHP documentation}. Use
* the `===` operator for testing the return value of this function.
*
* @since 4.9.0
* @since 5.1.0 Return value added to indicate success or failure.
*
* @param string $hook Action hook, the execution of which will be unscheduled.
* @return int|false On success an integer indicating number of events unscheduled (0 indicates no
* events were registered on the hook), false if unscheduling fails.
*/
function wp_unschedule_hook($hook) {
/**
* Filter to preflight or hijack clearing all events attached to the hook.
*
* Returning a non-null value will short-circuit the normal unscheduling
* process, causing the function to return the filtered value instead.
*
* For plugins replacing wp-cron, return the number of events successfully
* unscheduled (zero if no events were registered with the hook) or false
* if unscheduling one or more events fails.
*
* @since 5.1.0
*
* @param null|int|false $pre Value to return instead. Default null to continue unscheduling the hook.
* @param string $hook Action hook, the execution of which will be unscheduled.
*/
$pre = apply_filters('pre_unschedule_hook', null, $hook);
if (null !== $pre) {
return $pre;
}
$crons = _get_cron_array();
if (empty($crons)) {
return 0;
}
$results = array();
foreach ($crons as $timestamp => $args) {
if (!empty($crons[$timestamp][$hook])) {
$results[] = count($crons[$timestamp][$hook]);
}
unset($crons[$timestamp][$hook]);
if (empty($crons[$timestamp])) {
unset($crons[$timestamp]);
}
}
/*
* If the results are empty (zero events to unschedule), no attempt
* to update the cron array is required.
*/
if (empty($results)) {
return 0;
}
if (_set_cron_array($crons)) {
return array_sum($results);
}
return false;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,623 @@
/*!
* jQuery blockUI plugin
* Version 2.71.0-2020.12.08
* Requires jQuery v1.12 or later
*
* Examples at: http://malsup.com/jquery/block/
* Copyright (c) 2007-2013 M. Alsup
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Thanks to Amir-Hossein Sobhi for some excellent contributions!
*/
;(function() {
/*jshint eqeqeq:false curly:false latedef:false */
"use strict";
function setup($) {
var migrateDeduplicateWarnings = jQuery.migrateDeduplicateWarnings || false;
jQuery.migrateDeduplicateWarnings = false;
$.fn._fadeIn = $.fn.fadeIn;
var noOp = $.noop || function() {};
// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
// confusing userAgent strings on Vista)
var msie = /MSIE/.test(navigator.userAgent);
var ie6 = /MSIE 6.0/.test(navigator.userAgent) && ! /MSIE 8.0/.test(navigator.userAgent);
var mode = document.documentMode || 0;
var setExpr = "function" === typeof document.createElement('div').style.setExpression;
// global $ methods for blocking/unblocking the entire page
$.blockUI = function(opts) { install(window, opts); };
$.unblockUI = function(opts) { remove(window, opts); };
// convenience method for quick growl-like notifications (http://www.google.com/search?q=growl)
$.growlUI = function(title, message, timeout, onClose) {
var $m = $('<div class="growlUI"></div>');
if (title) $m.append('<h1>'+title+'</h1>');
if (message) $m.append('<h2>'+message+'</h2>');
if (timeout === undefined) timeout = 3000;
// Added by konapun: Set timeout to 30 seconds if this growl is moused over, like normal toast notifications
var callBlock = function(opts) {
opts = opts || {};
$.blockUI({
message: $m,
fadeIn : typeof opts.fadeIn !== 'undefined' ? opts.fadeIn : 700,
fadeOut: typeof opts.fadeOut !== 'undefined' ? opts.fadeOut : 1000,
timeout: typeof opts.timeout !== 'undefined' ? opts.timeout : timeout,
centerY: false,
showOverlay: false,
onUnblock: onClose,
css: $.blockUI.defaults.growlCSS
});
};
callBlock();
var nonmousedOpacity = $m.css('opacity');
$m.on('mouseover', function() {
callBlock({
fadeIn: 0,
timeout: 30000
});
var displayBlock = $('.blockMsg');
displayBlock.stop(); // cancel fadeout if it has started
displayBlock.fadeTo(300, 1); // make it easier to read the message by removing transparency
}).on('mouseout', function() {
$('.blockMsg').fadeOut(1000);
});
// End konapun additions
};
// plugin method for blocking element content
$.fn.block = function(opts) {
if ( this[0] === window ) {
$.blockUI( opts );
return this;
}
var fullOpts = $.extend({}, $.blockUI.defaults, opts || {});
this.each(function() {
var $el = $(this);
if (fullOpts.ignoreIfBlocked && $el.data('blockUI.isBlocked'))
return;
$el.unblock({ fadeOut: 0 });
});
return this.each(function() {
if ($.css(this,'position') == 'static') {
this.style.position = 'relative';
$(this).data('blockUI.static', true);
}
this.style.zoom = 1; // force 'hasLayout' in ie
install(this, opts);
});
};
// plugin method for unblocking element content
$.fn.unblock = function(opts) {
if ( this[0] === window ) {
$.unblockUI( opts );
return this;
}
return this.each(function() {
remove(this, opts);
});
};
$.blockUI.version = 2.70; // 2nd generation blocking at no extra cost!
// override these in your code to change the default behavior and style
$.blockUI.defaults = {
// message displayed when blocking (use null for no message)
message: '<h1>Please wait...</h1>',
title: null, // title string; only used when theme == true
draggable: true, // only used when theme == true (requires jquery-ui.js to be loaded)
theme: false, // set to true to use with jQuery UI themes
// styles for the message when blocking; if you wish to disable
// these and use an external stylesheet then do this in your code:
// $.blockUI.defaults.css = {};
css: {
padding: 0,
margin: 0,
width: '30%',
top: '40%',
left: '35%',
textAlign: 'center',
color: '#000',
border: '3px solid #aaa',
backgroundColor:'#fff',
cursor: 'wait'
},
// minimal style set used when themes are used
themedCSS: {
width: '30%',
top: '40%',
left: '35%'
},
// styles for the overlay
overlayCSS: {
backgroundColor: '#000',
opacity: 0.6,
cursor: 'wait'
},
// style to replace wait cursor before unblocking to correct issue
// of lingering wait cursor
cursorReset: 'default',
// styles applied when using $.growlUI
growlCSS: {
width: '350px',
top: '10px',
left: '',
right: '10px',
border: 'none',
padding: '5px',
opacity: 0.6,
cursor: 'default',
color: '#fff',
backgroundColor: '#000',
'-webkit-border-radius':'10px',
'-moz-border-radius': '10px',
'border-radius': '10px'
},
// IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
// (hat tip to Jorge H. N. de Vasconcelos)
/*jshint scripturl:true */
iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',
// force usage of iframe in non-IE browsers (handy for blocking applets)
forceIframe: false,
// z-index for the blocking overlay
baseZ: 1000,
// set these to true to have the message automatically centered
centerX: true, // <-- only effects element blocking (page block controlled via css above)
centerY: true,
// allow body element to be stetched in ie6; this makes blocking look better
// on "short" pages. disable if you wish to prevent changes to the body height
allowBodyStretch: true,
// enable if you want key and mouse events to be disabled for content that is blocked
bindEvents: true,
// be default blockUI will supress tab navigation from leaving blocking content
// (if bindEvents is true)
constrainTabKey: true,
// fadeIn time in millis; set to 0 to disable fadeIn on block
fadeIn: 200,
// fadeOut time in millis; set to 0 to disable fadeOut on unblock
fadeOut: 400,
// time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
timeout: 0,
// disable if you don't want to show the overlay
showOverlay: true,
// if true, focus will be placed in the first available input field when
// page blocking
focusInput: true,
// elements that can receive focus
focusableElements: ':input:enabled:visible',
// suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
// no longer needed in 2012
// applyPlatformOpacityRules: true,
// callback method invoked when fadeIn has completed and blocking message is visible
onBlock: null,
// callback method invoked when unblocking has completed; the callback is
// passed the element that has been unblocked (which is the window object for page
// blocks) and the options that were passed to the unblock call:
// onUnblock(element, options)
onUnblock: null,
// callback method invoked when the overlay area is clicked.
// setting this will turn the cursor to a pointer, otherwise cursor defined in overlayCss will be used.
onOverlayClick: null,
// don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
quirksmodeOffsetHack: 4,
// class name of the message block
blockMsgClass: 'blockMsg',
// if it is already blocked, then ignore it (don't unblock and reblock)
ignoreIfBlocked: false
};
// private data and functions follow...
var pageBlock = null;
var pageBlockEls = [];
function install(el, opts) {
var css, themedCSS;
var full = (el == window);
var msg = (opts && opts.message !== undefined ? opts.message : undefined);
opts = $.extend({}, $.blockUI.defaults, opts || {});
if (opts.ignoreIfBlocked && $(el).data('blockUI.isBlocked'))
return;
opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
if (opts.onOverlayClick)
opts.overlayCSS.cursor = 'pointer';
themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
msg = msg === undefined ? opts.message : msg;
// remove the current block (if there is one)
if (full && pageBlock)
remove(window, {fadeOut:0});
// if an existing element is being used as the blocking content then we capture
// its current place in the DOM (and current display style) so we can restore
// it when we unblock
if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
var node = msg.jquery ? msg[0] : msg;
var data = {};
$(el).data('blockUI.history', data);
data.el = node;
data.parent = node.parentNode;
data.display = node.style.display;
data.position = node.style.position;
if (data.parent)
data.parent.removeChild(node);
}
$(el).data('blockUI.onUnblock', opts.onUnblock);
var z = opts.baseZ;
// blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
// layer1 is the iframe layer which is used to supress bleed through of underlying content
// layer2 is the overlay layer which has opacity and a wait cursor (by default)
// layer3 is the message content that is displayed while blocking
var lyr1, lyr2, lyr3, s;
if (msie || opts.forceIframe)
lyr1 = $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>');
else
lyr1 = $('<div class="blockUI" style="display:none"></div>');
if (opts.theme)
lyr2 = $('<div class="blockUI blockOverlay ui-widget-overlay" style="z-index:'+ (z++) +';display:none"></div>');
else
lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
if (opts.theme && full) {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:fixed">';
if ( opts.title ) {
s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
}
s += '<div class="ui-widget-content ui-dialog-content"></div>';
s += '</div>';
}
else if (opts.theme) {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement ui-dialog ui-widget ui-corner-all" style="z-index:'+(z+10)+';display:none;position:absolute">';
if ( opts.title ) {
s += '<div class="ui-widget-header ui-dialog-titlebar ui-corner-all blockTitle">'+(opts.title || '&nbsp;')+'</div>';
}
s += '<div class="ui-widget-content ui-dialog-content"></div>';
s += '</div>';
}
else if (full) {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockPage" style="z-index:'+(z+10)+';display:none;position:fixed"></div>';
}
else {
s = '<div class="blockUI ' + opts.blockMsgClass + ' blockElement" style="z-index:'+(z+10)+';display:none;position:absolute"></div>';
}
lyr3 = $(s);
// if we have a message, style it
if (msg) {
if (opts.theme) {
lyr3.css(themedCSS);
lyr3.addClass('ui-widget-content');
}
else
lyr3.css(css);
}
// style the overlay
if (!opts.theme /*&& (!opts.applyPlatformOpacityRules)*/)
lyr2.css(opts.overlayCSS);
lyr2.css('position', full ? 'fixed' : 'absolute');
// make iframe layer transparent in IE
if (msie || opts.forceIframe)
lyr1.css('opacity',0.0);
//$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
var layers = [lyr1,lyr2,lyr3], $par = full ? $('body') : $(el);
$.each(layers, function() {
this.appendTo($par);
});
if (opts.theme && opts.draggable && $.fn.draggable) {
lyr3.draggable({
handle: '.ui-dialog-titlebar',
cancel: 'li'
});
}
// ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
var expr = setExpr && ( "CSS1Compat" !== document.compatMode || $('object,embed', full ? null : el).length > 0);
if (ie6 || expr) {
// give body 100% height
if (full && opts.allowBodyStretch && "CSS1Compat" === document.compatMode)
$('html,body').css('height','100%');
// fix ie6 issue when blocked element has a border width
if ((ie6 || "CSS1Compat" !== document.compatMode) && !full) {
var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
var fixT = t ? '(0 - '+t+')' : 0;
var fixL = l ? '(0 - '+l+')' : 0;
}
// simulate fixed position
$.each(layers, function(i,o) {
var s = o[0].style;
s.position = 'absolute';
if (i < 2) {
if (full)
s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - ("CSS1Compat" === document.compatMode?0:'+opts.quirksmodeOffsetHack+') + "px"');
else
s.setExpression('height','this.parentNode.offsetHeight + "px"');
if (full)
s.setExpression('width','"CSS1Compat" === document.compatMode && document.documentElement.clientWidth || document.body.clientWidth + "px"');
else
s.setExpression('width','this.parentNode.offsetWidth + "px"');
if (fixL) s.setExpression('left', fixL);
if (fixT) s.setExpression('top', fixT);
}
else if (opts.centerY) {
if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
s.marginTop = 0;
}
else if (!opts.centerY && full) {
var top = (opts.css && opts.css.top) ? parseInt(opts.css.top, 10) : 0;
var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
s.setExpression('top',expression);
}
});
}
// show the message
if (msg) {
if (opts.theme)
lyr3.find('.ui-widget-content').append(msg);
else
lyr3.append(msg);
if (msg.jquery || msg.nodeType)
$(msg).show();
}
if ((msie || opts.forceIframe) && opts.showOverlay)
lyr1.show(); // opacity is zero
if (opts.fadeIn) {
var cb = opts.onBlock ? opts.onBlock : noOp;
var cb1 = (opts.showOverlay && !msg) ? cb : noOp;
var cb2 = msg ? cb : noOp;
if (opts.showOverlay)
lyr2._fadeIn(opts.fadeIn, cb1);
if (msg)
lyr3._fadeIn(opts.fadeIn, cb2);
}
else {
if (opts.showOverlay)
lyr2.show();
if (msg)
lyr3.show();
if (opts.onBlock)
opts.onBlock.bind(lyr3)();
}
// bind key and mouse events
bind(1, el, opts);
if (full) {
pageBlock = lyr3[0];
pageBlockEls = $(opts.focusableElements,pageBlock);
if (opts.focusInput)
setTimeout(focus, 20);
}
else
center(lyr3[0], opts.centerX, opts.centerY);
if (opts.timeout) {
// auto-unblock
var to = setTimeout(function() {
if (full)
$.unblockUI(opts);
else
$(el).unblock(opts);
}, opts.timeout);
$(el).data('blockUI.timeout', to);
}
}
// remove the block
function remove(el, opts) {
var count;
var full = (el == window);
var $el = $(el);
var data = $el.data('blockUI.history');
var to = $el.data('blockUI.timeout');
if (to) {
clearTimeout(to);
$el.removeData('blockUI.timeout');
}
opts = $.extend({}, $.blockUI.defaults, opts || {});
bind(0, el, opts); // unbind events
if (opts.onUnblock === null) {
opts.onUnblock = $el.data('blockUI.onUnblock');
$el.removeData('blockUI.onUnblock');
}
var els;
if (full) // crazy selector to handle odd field errors in ie6/7
els = $('body').children().filter('.blockUI').add('body > .blockUI');
else
els = $el.find('>.blockUI');
// fix cursor issue
if ( opts.cursorReset ) {
if ( els.length > 1 )
els[1].style.cursor = opts.cursorReset;
if ( els.length > 2 )
els[2].style.cursor = opts.cursorReset;
}
if (full)
pageBlock = pageBlockEls = null;
if (opts.fadeOut) {
count = els.length;
els.stop().fadeOut(opts.fadeOut, function() {
if ( --count === 0)
reset(els,data,opts,el);
});
}
else
reset(els, data, opts, el);
}
// move blocking element back into the DOM where it started
function reset(els,data,opts,el) {
var $el = $(el);
if ( $el.data('blockUI.isBlocked') )
return;
els.each(function(i,o) {
// remove via DOM calls so we don't lose event handlers
if (this.parentNode)
this.parentNode.removeChild(this);
});
if (data && data.el) {
data.el.style.display = data.display;
data.el.style.position = data.position;
data.el.style.cursor = 'default'; // #59
if (data.parent)
data.parent.appendChild(data.el);
$el.removeData('blockUI.history');
}
if ($el.data('blockUI.static')) {
$el.css('position', 'static'); // #22
}
if (typeof opts.onUnblock == 'function')
opts.onUnblock(el,opts);
// fix issue in Safari 6 where block artifacts remain until reflow
var body = $(document.body), w = body.width(), cssW = body[0].style.width;
body.width(w-1).width(w);
body[0].style.width = cssW;
}
// bind/unbind the handler
function bind(b, el, opts) {
var full = el == window, $el = $(el);
// don't bother unbinding if there is nothing to unbind
if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
return;
$el.data('blockUI.isBlocked', b);
// don't bind events when overlay is not in use or if bindEvents is false
if (!full || !opts.bindEvents || (b && !opts.showOverlay))
return;
// bind anchors and inputs for mouse and key events
var events = 'mousedown mouseup keydown keypress keyup touchstart touchend touchmove';
if (b)
$(document).on(events, opts, handler);
else
$(document).off(events, handler);
// former impl...
// var $e = $('a,:input');
// b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
}
// event handler to suppress keyboard/mouse events when blocking
function handler(e) {
// allow tab navigation (conditionally)
if (e.type === 'keydown' && e.keyCode && e.keyCode == 9) {
if (pageBlock && e.data.constrainTabKey) {
var els = pageBlockEls;
var fwd = !e.shiftKey && e.target === els[els.length-1];
var back = e.shiftKey && e.target === els[0];
if (fwd || back) {
setTimeout(function(){focus(back);},10);
return false;
}
}
}
var opts = e.data;
var target = $(e.target);
if (target.hasClass('blockOverlay') && opts.onOverlayClick)
opts.onOverlayClick(e);
// allow events within the message content
if (target.parents('div.' + opts.blockMsgClass).length > 0)
return true;
// allow events for content that is not being blocked
return target.parents().children().filter('div.blockUI').length === 0;
}
function focus(back) {
if (!pageBlockEls)
return;
var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
if (e)
e.focus();
}
function center(el, x, y) {
var p = el.parentNode, s = el.style;
var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
if (x) s.left = l > 0 ? (l+'px') : '0';
if (y) s.top = t > 0 ? (t+'px') : '0';
}
function sz(el, p) {
return parseInt($.css(el,p),10)||0;
}
jQuery.migrateDeduplicateWarnings = migrateDeduplicateWarnings;
}
/*global define:true */
if (typeof define === 'function' && define.amd && define.amd.jQuery) {
define(['jquery'], setup);
} else {
setup(jQuery);
}
})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,200 @@
<?php
/**
* A sample implementation using the Resmush.it API and our tasks library
*/
if (!defined('ABSPATH')) die('Access denied.');
if (!class_exists('Re_Smush_It_Task')) :
class Re_Smush_It_Task extends Updraft_Smush_Task {
public $label = 're-smush-it';
const MAX_FILESIZE = 5242880;
const API_URL = 'http://api.resmush.it/';
/**
* Checks if the server is online
*
* @return boolean - true if yes, false otherwise
*/
public static function is_server_online() {
global $wp_version;
$test_image = WPO_PLUGIN_MAIN_PATH . 'images/icon/wpo.png';
$boundary = wp_generate_password(12);
$file_name = basename($test_image);
$body = "--$boundary";
$body .= "\r\n";
$body .= "Content-Disposition: form-data; name=\"files\"; filename=\"$file_name\"\r\n";
$body .= "\r\n";
$body .= file_get_contents($test_image);
$body .= "\r\n";
$body .= "--$boundary";
$request = array(
'headers' => array( "content-type" => "multipart/form-data; boundary=$boundary" ),
'user-agent' => "WordPress $wp_version/WP-Optimize ".WPO_VERSION.' - anonymous', // Anonymous until Resmushit has a clear privacy statement that we can link to
'timeout' => 10,
'body' => $body,
);
$response = wp_remote_post(self::API_URL, $request);
if (is_wp_error($response)) {
update_option(__CLASS__, $response->get_error_message());
return false;
}
$data = json_decode(wp_remote_retrieve_body($response));
if (empty($data)) {
update_option(__CLASS__, "Empty data returned by server");
return false;
}
if (isset($data->error)) {
update_option(__CLASS__, $data->error_long);
return false;
}
return true;
}
/**
* Prepares the image as part of the post data for the specific implementation
*
* @param String $local_file - The image to e optimised
* @param array $options - Eventual options
*/
public function prepare_post_request($local_file, $options) {
global $wp_version;
$boundary = wp_generate_password(12);
$headers = array( "content-type" => "multipart/form-data; boundary=$boundary" );
$lossy = $this->get_option('lossy_compression');
if ($lossy) {
$quality = $this->get_option('image_quality');
} else {
$quality = 100;
}
if (isset($options['quality']) && is_int($options['quality']) && 0 < $options['quality']) $quality = $options['quality'];
$this->log($quality);
$post_fields = array(
'qlty' => $quality,
'exif' => $this->get_option('preserve_exif', false)
);
$payload = '';
$file_name = basename($local_file);
foreach ($post_fields as $name => $value) {
$payload .= "--$boundary";
$payload .= "\r\n";
$payload .= "Content-Disposition: form-data; name='$name' \r\n\r\n $value";
$payload .= "\r\n";
}
$payload .= "--$boundary";
$payload .= "\r\n";
$payload .= "Content-Disposition: form-data; name=\"files\"; filename=\"$file_name\"\r\n";
$payload .= "\r\n";
$payload .= file_get_contents($local_file);
$payload .= "\r\n";
$payload .= "--$boundary";
return array(
'headers' => $headers,
'timeout' => $this->get_option('request_timeout'),
'user-agent' => "WordPress $wp_version/WP-Optimize ".WPO_VERSION.' - anonymous', // Anonymous until Resmushit has a clear privacy statement that we can link to
'body' => $payload,
);
}
/**
* Processes the response recieved from the remote server
*
* @param String $response - The response object
*/
public function process_server_response($response) {
global $http_response_header;
$response = parent::process_server_response($response);
$data = json_decode(wp_remote_retrieve_body($response));
if (!$data) {
$this->log("Cannot establish connection with reSmush.it webservice. Please try later");
return false;
}
if (isset($data->error)) {
$this->fail($data->error, $data->error_long);
return false;
}
if (!property_exists($data, 'dest')) {
$this->fail("invalid_response", "The response does not contain the compressed file URL");
$this->log("data: ".json_encode($data));
return false;
}
$compressed_image_response = wp_remote_get($data->dest);
if (!is_wp_error($compressed_image_response)) {
$image_contents = wp_remote_retrieve_body($compressed_image_response);
if ($this->is_downloaded_image_buffer_mime_type_valid($image_contents)) {
return $image_contents;
} else {
$this->log("The downloaded resource does not have a matching mime type.");
return false;
}
} else {
$this->fail("invalid_response", "The compression apparently succeeded, but WP-Optimize could not retrieve the compressed image from the remote server.");
$this->log("data: ".json_encode($data));
if (!empty($http_response_header) && is_array($http_response_header)) {
$this->log("headers: ".implode("\n", $http_response_header));
}
return false;
}
}
/**
* Retrieve features for this service
*
* @return Array - an array of options
*/
public static function get_features() {
return array(
'max_filesize' => self::MAX_FILESIZE,
'lossy_compression' => false,
'preserve_exif' => true,
);
}
/**
* Retrieve default options for this task type.
*
* @return Array - an array of options
*/
public function get_default_options() {
return array(
'allowed_file_types' => array('gif', 'png', 'jpg', 'tif', 'jpeg'),
'request_timeout' => 30,
'keep_original' => true,
'preserve_exif' => false,
'image_quality' => 98,
'api_endpoint' => self::API_URL,
'max_filesize' => self::MAX_FILESIZE,
'version' => '0.1.13',
'backup_prefix' => '-updraft-pre-smush-original.'
);
}
}
endif;

View File

@@ -0,0 +1,177 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
if (class_exists('Updraft_Abstract_Logger')) return;
require_once 'class-updraft-log-levels.php';
require_once 'class-updraft-logger-interface.php';
/**
* Class Updraft_Abstract_Logger
*/
abstract class Updraft_Abstract_Logger implements Updraft_Logger_Interface {
/**
* True if logger enabled.
*
* @var bool
*/
protected $enabled = true;
/**
* True if possible to add multiple loggers.
*
* @var bool
*/
protected $allow_multiple = false;
/**
* Logger options.
*
* @var array
*/
protected $options = array();
/**
* Updraft_Abstract_Logger constructor
*/
public function __construct() {
}
/**
* True if logger is available for use, i.e. required plugins installed.
*
* @return bool
*/
public function is_available() {
return true;
}
/**
* Returns true if allow multiple.
*
* @return bool
*/
public function is_allow_multiple() {
return $this->allow_multiple;
}
/**
* Returns current options in text.
*
* @return string
*/
public function get_options_text() {
$options_values = $this->get_options_values();
if (array_key_exists('active', $options_values)) {
unset($options_values['active']);
}
return join(', ', $options_values);
}
/**
* Returns list of logger options.
*
* @return array
*/
public function get_options_list() {
return array(
// 'option_name' => __('Placeholder', 'wp-optimize')
);
}
/**
* Returns array with options values list.
*
* @return array
*/
public function get_options_values() {
$options_values = array();
$options_list = $this->get_options_list();
if (empty($options_list)) return $options_values;
foreach (array_keys($options_list) as $option_name) {
$options_values[$option_name] = $this->get_option($option_name);
}
return $options_values;
}
/**
* Returns true if logger is active
*
* @return boolean
*/
public function is_enabled() {
return $this->enabled;
}
/**
* Enable logger
*/
public function enable() {
$this->enabled = true;
}
/**
* Disable logger
*/
public function disable() {
$this->enabled = false;
}
/**
* Return option $name value
*
* @param string $name Name of the option.
* @param string $default Add default value.
* @return array An array of options.
*/
public function get_option($name, $default = '') {
if (!array_key_exists($name, $this->options)) return $default;
return $this->options[$name];
}
/**
* Set option $name value.
*
* @param string $name The name of the option.
* @param string $value The value of the option.
*/
public function set_option($name, $value = '') {
if (is_array($name)) {
$this->options = array_merge($this->options, $name);
} else {
$this->options[$name] = $value;
}
}
/**
* Returns logger description
*
* @return mixed
*/
public abstract function get_description();
/**
* For the Logger: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
*
* @param string $message
* @param array $context
* @return string
*/
protected function interpolate($message, array $context = array()) {
$replace = array();
foreach ($context as $key => $val) {
// Check that the value can be casted to string.
if (!is_array($val) && (!is_object($val) || method_exists($val, '__toString'))) {
$replace['{' . $key . '}'] = $val;
}
}
return strtr($message, $replace);
}
}

View File

@@ -0,0 +1,198 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
if (class_exists('Updraft_Email_Logger')) return;
/**
* Class Updraft_Email_Logger
*/
class Updraft_Email_Logger extends Updraft_Abstract_Logger {
protected $allow_multiple = true;
/**
* Updraft_Email_Logger constructor
*/
public function __construct() {
}
/**
* Returns logger description
*
* @return string
*/
public function get_description() {
return __('Log events to email', 'wp-optimize');
}
/**
* Returns list of logger options.
*
* @return array
*/
public function get_options_list() {
return array(
'emails' => array(
__('Enter email for logs here', 'wp-optimize'),
'email', // validator
)
);
}
/**
* Emergency message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function emergency($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::EMERGENCY, $context);
}
/**
* Alert message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function alert($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::ALERT, $context);
}
/**
* Critical message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function critical($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::CRITICAL, $context);
}
/**
* Error message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function error($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::ERROR, $context);
}
/**
* Warning message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function warning($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::WARNING, $context);
}
/**
* Notice message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function notice($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::NOTICE, $context);
}
/**
* Info message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function info($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::INFO, $context);
}
/**
* Debug message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function debug($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::DEBUG, $context);
}
/**
* Log message with any level
*
* @param string $message
* @param mixed $level
* @param array $context
* @return null|void
*/
public function log($message, $level, array $context = array()) {
if (!$this->is_enabled()) return false;
$log = WP_Optimize()->get_options()->get_option('updraft_mail_logger_log', array());
$message = '['.Updraft_Log_Levels::to_text($level).'] : '.$this->interpolate($message, $context);
$log[] = $message;
WP_Optimize()->get_options()->update_option('updraft_mail_logger_log', $log);
}
/**
* Add recipient email
*
* @param string $email
*/
public function add_email($email) {
$emails = $this->get_option('emails', array());
$emails[] = $email;
$this->set_option('emails', $emails);
}
/**
* Return list of recipients email
*
* @return null
*/
public function get_emails() {
return $this->get_option('emails', get_option('admin_email'));
}
/**
* Email and clear log
*/
public function flush_log() {
$log = $this->get_log();
if (empty($log)) return;
WP_Optimize()->get_options()->update_option('updraft_mail_logger_log', array());
if (!$this->is_enabled()) return;
$email_addresses = $this->get_emails();
$subject = $this->get_option('updraft_mail_logger_subject', 'Updraft Email Log');
$log = join("\n", $log);
wp_mail($email_addresses, $subject, $log);
}
/**
* Return log messages
*
* @return mixed|void
*/
public function get_log() {
return WP_Optimize()->get_options()->get_option('updraft_mail_logger_log', array());
}
}

View File

@@ -0,0 +1,176 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
if (class_exists('Updraft_File_Logger')) return;
/**
* Class Updraft_File_Logger
*/
class Updraft_File_Logger extends Updraft_Abstract_Logger {
/**
* Path to the log file
*
* @var String
*/
private $logfile;
/**
* Updraft_File_Logger constructor
*/
public function __construct($logfile) {
$this->logfile = $logfile;
}
/**
* Returns logger description
*
* @return string|void
*/
public function get_description() {
return __('Log events into a log file', 'wp-optimize');
}
/**
* Emergency message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function emergency($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::EMERGENCY, $context);
}
/**
* Alert message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function alert($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::ALERT, $context);
}
/**
* Critical message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function critical($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::CRITICAL, $context);
}
/**
* Error message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function error($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::ERROR, $context);
}
/**
* Warning message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function warning($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::WARNING, $context);
}
/**
* Notice message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function notice($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::NOTICE, $context);
}
/**
* Info message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function info($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::INFO, $context);
}
/**
* Debug message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function debug($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::DEBUG, $context);
}
/**
* Log message with any level
*
* @param string $message
* @param mixed $level
* @param array $context
* @return null|void
*/
public function log($message, $level, array $context = array()) {
if (!$this->is_enabled()) return false;
$message = sprintf("[%s : %s] - %s \n", date("Y-m-d H:i:s"), Updraft_Log_Levels::to_text($level), $this->interpolate($message, $context));
if (false == file_put_contents($this->logfile, $message, FILE_APPEND)) {
error_log($message);
}
}
/**
* Delete logs older than specified date
*
* @param string $how_old
* @return boolean Success or failure
*/
public function prune_logs($how_old = "5 days ago") {
if (strtotime($how_old)) {
$how_old = "5 days ago";
}
// phpcs:disable
// We ignore a few lines here to avoid warnings on file operations
// WP.VIP does not like us writing directly to the filesystem
$logfile_handle = fopen($this->logfile, "r");
$temp_file = fopen(preg_replace("/\.log$/", "-temp.log", $this->logfile), "a");
// Stream is the preferred way because of potentially large file sizes
while ($line = stream_get_line($logfile_handle, 1024 * 1024, "\n")) {
$entry_time = strtotime(strstr($line, " : ", true));
if ($entry_time > $how_old) {
fwrite($temp_file, $line."\n");
}
}
fclose($logfile_handle);
fclose($temp_file);
return rename(preg_replace("/\.log$/", "-temp.log", $this->logfile), $this->logfile);
// phpcs:enable
}
}

View File

@@ -0,0 +1,44 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
if (class_exists('Updraft_Log_Levels')) return;
/**
* Class Updraft_Log_Levels
*/
class Updraft_Log_Levels {
const EMERGENCY = 'emergency';
const ALERT = 'alert';
const CRITICAL = 'critical';
const ERROR = 'error';
const WARNING = 'warning';
const NOTICE = 'notice';
const INFO = 'info';
const DEBUG = 'debug';
/**
* Return level text catption
*
* @param string $level Text of level Type.
* @return string Returns the Level type.
*/
static public function to_text($level) {
$text = array(
self::EMERGENCY => 'EMERGENCY',
self::ALERT => 'ALERT',
self::CRITICAL => 'CRITICAL',
self::ERROR => 'ERROR',
self::WARNING => 'WARNING',
self::NOTICE => 'NOTICE',
self::INFO => 'INFO',
self::DEBUG => 'DEBUG',
);
if (array_key_exists($level, $text)) return $text[$level];
return '';
}
}

View File

@@ -0,0 +1,115 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
if (class_exists('Updraft_Logger_Interface')) return false;
/**
* Describes a logger instance
*
* The message MUST be a string or object implementing __toString().
*
* The message MAY contain placeholders in the form: {foo} where foo
* will be replaced by the context data in key "foo".
*
* The context array can contain arbitrary data, the only assumption that
* can be made by implementors is that if an Exception instance is given
* to produce a stack trace, it MUST be in a key named "exception".
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
* for the full interface specification.
*/
interface Updraft_Logger_Interface {
/**
* System is unusable.
*
* @param string $message
* @param array $context
* @return null
*/
public function emergency($message, array $context = array());
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
* @return null
*/
public function alert($message, array $context = array());
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
* @return null
*/
public function critical($message, array $context = array());
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param array $context
* @return null
*/
public function error($message, array $context = array());
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
* @return null
*/
public function warning($message, array $context = array());
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
* @return null
*/
public function notice($message, array $context = array());
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
* @return null
*/
public function info($message, array $context = array());
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
* @return null
*/
public function debug($message, array $context = array());
/**
* Logs with an arbitrary level.
*
* @param string $message
* @param mixed $level
* @param array $context
* @return null
*/
public function log($message, $level, array $context = array());
}

View File

@@ -0,0 +1,236 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
require_once('class-updraft-logger-interface.php');
require_once('class-updraft-log-levels.php');
require_once('class-updraft-abstract-logger.php');
require_once('class-updraft-logger.php');
if (class_exists('Updraft_Logger')) return;
/**
* Class Updraft_Logger
*/
class Updraft_Logger implements Updraft_Logger_Interface {
protected $_loggers = array();
/**
* Constructor method
*
* @param Updraft_Logger_Interface $logger
*/
public function __construct(Updraft_Logger_Interface $logger = null) {
if (!empty($logger)) $this->_loggers = array($logger);
}
/**
* Returns singleton instance object
*
* @return Updraft_Logger Returns `Updraft_Logger` object
*/
public static function instance() {
static $_instance = null;
if (null === $_instance) {
$_instance = new self();
}
return $_instance;
}
/**
* Add logger to loggers list
*
* @param Updraft_Logger_Interface $logger
*/
public function add_logger(Updraft_Logger_Interface $logger) {
$logger_id = $logger_class = get_class($logger);
// don't add logger if it doesn't support multiple loggers.
if (!empty($this->_loggers) && array_key_exists($logger_id, $this->_loggers) && false == $logger->is_allow_multiple()) return false;
$index = 0;
// get free id key.
while (array_key_exists($logger_id, $this->_loggers)) {
$index++;
$logger_id = $logger_class.'_'.$index;
}
$this->_loggers[$logger_id] = $logger;
}
/**
* Return list of loggers
*
* @return array
*/
public function get_loggers() {
return $this->_loggers;
}
/**
* System is unusable.
*
* @param string $message
* @param array $context
* @return null
*/
public function emergency($message, array $context = array()) {
if (empty($this->_loggers)) return false;
foreach ($this->_loggers as $logger) {
$logger->emergency($message, $context);
}
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
* @return null
*/
public function alert($message, array $context = array()) {
if (empty($this->_loggers)) return false;
foreach ($this->_loggers as $logger) {
$logger->alert($message, $context);
}
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
* @return null
*/
public function critical($message, array $context = array()) {
if (empty($this->_loggers)) return false;
foreach ($this->_loggers as $logger) {
$logger->critical($message, $context);
}
}
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param array $context
* @return null
*/
public function error($message, array $context = array()) {
if (empty($this->_loggers)) return false;
foreach ($this->_loggers as $logger) {
$logger->error($message, $context);
}
}
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
* @return null
*/
public function warning($message, array $context = array()) {
if (empty($this->_loggers)) return false;
foreach ($this->_loggers as $logger) {
$logger->warning($message, $context);
}
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
* @return null
*/
public function notice($message, array $context = array()) {
if (empty($this->_loggers)) return false;
foreach ($this->_loggers as $logger) {
$logger->notice($message, $context);
}
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
* @return null
*/
public function info($message, array $context = array()) {
if (empty($this->_loggers)) return false;
foreach ($this->_loggers as $logger) {
$logger->info($message, $context);
}
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
* @return null
*/
public function debug($message, array $context = array()) {
if (empty($this->_loggers)) return false;
foreach ($this->_loggers as &$logger) {
$logger->debug($message, $context);
}
}
/**
* Logs with an arbitrary level.
*
* @param mixed $level
* @param string $message
* @param array $context
* @return null
*/
public function log($level, $message, array $context = array()) {
if (empty($this->_loggers)) return false;
foreach ($this->_loggers as $logger) {
$logger->log($message, $level, $context);
}
}
}

View File

@@ -0,0 +1,130 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
if (class_exists('Updraft_PHP_Logger')) return;
/**
* Class Updraft_PHP_Logger
*/
class Updraft_PHP_Logger extends Updraft_Abstract_Logger {
/**
* Updraft_PHP_Logger constructor
*/
public function __construct() {
}
/**
* Returns logger description
*
* @return string|void
*/
public function get_description() {
return __('Log events into the PHP error log', 'wp-optimize');
}
/**
* Emergency message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function emergency($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::EMERGENCY, $context);
}
/**
* Alert message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function alert($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::ALERT, $context);
}
/**
* Critical message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function critical($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::CRITICAL, $context);
}
/**
* Error message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function error($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::ERROR, $context);
}
/**
* Warning message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function warning($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::WARNING, $context);
}
/**
* Notice message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function notice($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::NOTICE, $context);
}
/**
* Info message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function info($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::INFO, $context);
}
/**
* Debug message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function debug($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::DEBUG, $context);
}
/**
* Log message with any level
*
* @param string $message
* @param mixed $level
* @param array $context
* @return null|void
*/
public function log($message, $level, array $context = array()) {
if (!$this->is_enabled()) return false;
$message = '['.Updraft_Log_Levels::to_text($level).'] : '.$this->interpolate($message, $context);
error_log($message);
}
}

View File

@@ -0,0 +1,193 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
if (class_exists('Updraft_Ring_Logger')) return;
/**
* Class Updraft_Ring_Logger
*/
class Updraft_Ring_Logger extends Updraft_Abstract_Logger {
/**
* Updraft_Ring_Logger constructor
*/
public function __construct() {
}
/**
* Returns logger description
*
* @return string|void
*/
public function get_description() {
return __('Store the most recent log entries in the WordPress database', 'wp-optimize');
}
/**
* Returns list of logger options.
*
* @return array
*/
public function get_options_list() {
return array(
'ring_logger_limit' => __('How many last records store?', 'wp-optimize')
);
}
/**
* Emergency message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function emergency($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::EMERGENCY, $context);
}
/**
* Alert message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function alert($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::ALERT, $context);
}
/**
* Critical message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function critical($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::CRITICAL, $context);
}
/**
* Error message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function error($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::ERROR, $context);
}
/**
* Warning message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function warning($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::WARNING, $context);
}
/**
* Notice message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function notice($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::NOTICE, $context);
}
/**
* Info message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function info($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::INFO, $context);
}
/**
* Debug message
*
* @param string $message
* @param array $context
* @return null|void
*/
public function debug($message, array $context = array()) {
$this->log($message, Updraft_Log_Levels::DEBUG, $context);
}
/**
* Log message with any level
*
* @param string $message
* @param mixed $level
* @param array $context
* @return null|void
*/
public function log($message, $level, array $context = array()) {
if (!$this->is_enabled()) return false;
$message = date("Y-m-d H:i:s").' ['.Updraft_Log_Levels::to_text($level).'] : '.$this->interpolate($message, $context);
$this->add_log($message);
}
/**
* Add message to log
*
* @param string $message Message to be added to log.
*/
public function add_log($message) {
$log_option_name = $this->get_logger_option_name();
$log_limit = $this->get_logger_limit();
$log = $this->get_log();
$log[] = $message;
while (count($log) > 0 && count($log) > $log_limit) {
array_shift($log);
}
update_option($log_option_name, $log);
}
/**
* Return logger option name value
*
* @return string
*/
public function get_logger_option_name() {
return 'updraft_ring_log';
}
/**
* Return logger limit value
*
* @return string
*/
public function get_logger_limit() {
return $this->get_option('ring_logger_limit', 20);
}
/**
* Set logger wordpress option name where log will stored
*
* @param string $option_name Name for logger option.
*/
public function set_logger_option_name($option_name) {
$this->set_option('ring_logger_option_name', $option_name);
}
/**
* Return log content
*
* @return mixed|void
*/
public function get_log() {
return get_option($this->get_logger_option_name(), array());
}
}

View File

@@ -0,0 +1,553 @@
<?php
/**
* A Smush Task manager class
*/
if (!defined('ABSPATH')) die('Access denied.');
if (!class_exists('Updraft_Task_Manager_Commands_1_0')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-manager-commands.php');
if (!class_exists('Updraft_Smush_Manager_Commands')) :
class Updraft_Smush_Manager_Commands extends Updraft_Task_Manager_Commands_1_0 {
/**
* The commands constructor
*
* @param mixed $task_manager - A task manager instance
*/
public function __construct($task_manager) {
parent::__construct($task_manager);
}
/**
* Returns a list of commands available for smush related operations
*/
public static function get_allowed_ajax_commands() {
$commands = apply_filters('updraft_task_manager_allowed_ajax_commands', array());
$smush_commands = array(
'compress_single_image',
'restore_single_image',
'process_bulk_smush',
'update_smush_options',
'get_ui_update',
'process_pending_images',
'clear_pending_images',
'clear_smush_stats',
'check_server_status',
'get_smush_logs',
'mark_as_compressed',
'mark_all_as_uncompressed',
'clean_all_backup_images',
'reset_webp_serving_method',
'convert_to_webp_format',
);
return array_merge($commands, $smush_commands);
}
/**
* Process the compression of a single image
*
* @param mixed $data - sent in via AJAX
* @return WP_Error|array - information about the operation or WP_Error object on failure
*/
public function compress_single_image($data) {
$options = !empty($data['smush_options']) ? $data['smush_options'] : $this->task_manager->get_smush_options();
$image = isset($data['selected_image']) ? filter_var($data['selected_image']['attachment_id'], FILTER_SANITIZE_NUMBER_INT) : false;
$blog = isset($data['selected_image']) ? filter_var($data['selected_image']['blog_id'], FILTER_SANITIZE_NUMBER_INT) : false;
// A subsite administrator can only compress their own image. If the blog ID isn't theirs, return an error.
if ($blog && is_multisite() && get_current_blog_id() != $blog && !current_user_can('manage_network_options')) {
return new WP_Error('compression_not_permitted', __('The blog ID provided does not match the current blog.', 'wp-optimize'));
}
$server = sanitize_text_field($options['compression_server']);
$lossy = filter_var($options['lossy_compression'], FILTER_VALIDATE_BOOLEAN) ? true : false;
$backup = filter_var($options['back_up_original'], FILTER_VALIDATE_BOOLEAN) ? true : false;
$exif = filter_var($options['preserve_exif'], FILTER_VALIDATE_BOOLEAN) ? true : false;
$quality = filter_var($options['image_quality'], FILTER_SANITIZE_NUMBER_INT);
$options = array(
'attachment_id' => $image,
'blog_id' => $blog,
'image_quality' => $quality,
'keep_original' => $backup,
'lossy_compression' => $lossy,
'preserve_exif' => $exif
);
if (filesize(get_attached_file($image)) > 5242880) {
$options['request_timeout'] = 180;
}
$success = $this->task_manager->compress_single_image($image, $options, $server);
if (!$success) {
return new WP_Error('compress_failed', get_post_meta($image, 'smush-info', true));
}
$response = array();
$response['status'] = true;
$response['operation'] = 'compress';
$response['options'] = $options;
$response['server'] = $server;
$response['success'] = $success;
$response['restore_possible'] = $backup;
$response['summary'] = get_post_meta($image, 'smush-info', true);
$smush_stats = get_post_meta($image, 'smush-stats', true);
if (isset($smush_stats['sizes-info'])) {
$response['sizes-info'] = WP_Optimize()->include_template('images/smush-details.php', true, array('sizes_info' => $smush_stats['sizes-info']));
}
return $response;
}
/**
* Restores a single image, if backup is available
*
* @param mixed $data - Sent in via AJAX
* @return WP_Error|array - information about the operation or a WP_Error object on failure
*/
public function restore_single_image($data) {
$blog_id = isset($data['blog_id']) ? $data['blog_id'] : false;
$image_id = isset($data['selected_image']) ? $data['selected_image'] : false;
$success = $this->task_manager->restore_single_image($image_id, $blog_id);
if (is_wp_error($success)) {
return $success;
}
$response = array();
$response['status'] = true;
$response['operation'] = 'restore';
$response['blog_id'] = $blog_id;
$response['image'] = $image_id;
$response['success'] = $success;
$response['summary'] = __('The image was restored successfully', 'wp-optimize');
return $response;
}
/**
* Process the compression of multiple images
*
* @param mixed $data - Sent in via AJAX
*/
public function process_bulk_smush($data = array()) {
$images = isset($data['selected_images']) ? $data['selected_images'] : array();
$ui_update = $this->get_ui_update($images);
$this->close_browser_connection(json_encode($ui_update));
$this->task_manager->process_bulk_smush($images);
// Since we already sent back data and closed the browser connection, we must not return (that would result in further sending back of JSON).
die();
}
/**
* Returns useful information for the UI and closes the connection
*
* @param mixed $data - Sent in via AJAX
*
* @return mixed - Information for the UI
*/
public function get_ui_update($data) {
$ui_update = array();
$ui_update['status'] = true;
$ui_update['is_multisite'] = is_multisite() ? 1 : 0;
$pending_tasks = $this->task_manager->get_pending_tasks();
$ui_update['pending_tasks'] = is_array($pending_tasks) ? count($this->task_manager->get_pending_tasks()) : 0;
$ui_update['unsmushed_images'] = $this->task_manager->get_uncompressed_images();
$ui_update['admin_urls'] = $this->task_manager->get_admin_urls();
$ui_update['completed_task_count'] = $this->task_manager->options->get_option('completed_task_count', 0);
$ui_update['bytes_saved'] = WP_Optimize()->format_size($this->task_manager->options->get_option('total_bytes_saved', 0));
$ui_update['percent_saved'] = number_format($this->task_manager->options->get_option('total_percent_saved', 1), 2).'%';
$ui_update['failed_task_count'] = $this->task_manager->get_failed_task_count();
$ui_update['summary'] = sprintf(__("Since your compression statistics were last reset, a total of %d image(s) were compressed on this site, saving approximately %s of space at an average of %02d percent per image.", 'wp-optimize'), $ui_update['completed_task_count'], $ui_update['bytes_saved'], $ui_update['percent_saved']);
$ui_update['failed'] = sprintf(__("%d image(s) could not be compressed. Please see the logs for more information, or try again later.", 'wp-optimize'), $ui_update['failed_task_count']);
$ui_update['pending'] = sprintf(__("%d image(s) images were selected for compressing previously, but were not all processed. You can either complete them now or cancel and retry later.", 'wp-optimize'), $ui_update['pending_tasks']);
$ui_update['smush_complete'] = $this->task_manager->is_queue_processed();
if (isset($data['image_list'])) {
$images = $data['image_list'];
$stats = $this->task_manager->get_session_stats($images);
$ui_update['session_stats'] = "";
if (!empty($stats['success'])) {
$ui_update['session_stats'] .= sprintf(__("A total of %d image(s) were successfully compressed in this iteration. ", 'wp-optimize'), $stats['success']);
}
if (!empty($stats['fail'])) {
$ui_update['session_stats'] .= sprintf(__("%d selected image(s) could not be compressed. Please see the logs for more information, you may try again later.", 'wp-optimize'), $stats['fail']);
}
}
return $ui_update;
}
/**
* Updates smush related options
*
* @param mixed $data - Sent in via AJAX
* @return WP_Error|array - information about the operation or WP_Error object on failure
*/
public function update_smush_options($data) {
$options = array();
$options['compression_server'] = sanitize_text_field($data['compression_server']);
$options['lossy_compression'] = filter_var($data['lossy_compression'], FILTER_VALIDATE_BOOLEAN) ? true : false;
$options['back_up_original'] = filter_var($data['back_up_original'], FILTER_VALIDATE_BOOLEAN) ? true : false;
$options['back_up_delete_after'] = filter_var($data['back_up_delete_after'], FILTER_VALIDATE_BOOLEAN) ? true : false;
$options['back_up_delete_after_days'] = filter_var($data['back_up_delete_after_days'], FILTER_SANITIZE_NUMBER_INT);
$options['preserve_exif'] = filter_var($data['preserve_exif'], FILTER_VALIDATE_BOOLEAN) ? true : false;
$options['autosmush'] = filter_var($data['autosmush'], FILTER_VALIDATE_BOOLEAN) ? true : false;
$options['image_quality'] = filter_var($data['image_quality'], FILTER_SANITIZE_NUMBER_INT);
$options['show_smush_metabox'] = filter_var($data['show_smush_metabox'], FILTER_VALIDATE_BOOLEAN) ? 'show' : 'hide';
$options['webp_conversion'] = filter_var($data['webp_conversion'], FILTER_VALIDATE_BOOLEAN) ? true : false;
$success = $this->task_manager->update_smush_options($options);
if (!$this->is_webp_enabled($options['webp_conversion'])) {
$this->remove_webp_redirect_rules();
}
if (!$success) {
return new WP_Error('update_failed', __('Smush options could not be updated', 'wp-optimize'));
}
do_action('wpo_save_images_settings');
$response = array();
$response['status'] = true;
$response['saved'] = $success;
$response['summary'] = __('Options updated successfully', 'wp-optimize');
return $response;
}
/**
* Clears any smush related stats
*
* @return WP_Error|array - information about the operation or WP_Error object on failure
*/
public function clear_smush_stats() {
$success = $this->task_manager->clear_smush_stats();
if (!$success) {
return new WP_Error('update_failed', __('Stats could not be cleared', 'wp-optimize'));
}
$response = array();
$response['status'] = true;
$response['summary'] = __('Stats cleared successfully', 'wp-optimize');
return $response;
}
/**
* Checks if the selected server is online
*
* @param mixed $data - Sent in via AJAX
*/
public function check_server_status($data) {
$server = sanitize_text_field($data['server']);
$response = array();
$response['status'] = true;
$response['online'] = $this->task_manager->check_server_online($server);
if (!$response['online']) {
$response['error'] = get_option($this->task_manager->get_associated_task($server));
}
return $response;
}
/**
* Completes any pending tasks
*/
public function process_pending_images() {
$this->process_bulk_smush();
}
/**
* Deletes and removes any pending tasks from queue
*
* @return WP_Error|array - information about the operation or WP_Error object on failure
*/
public function clear_pending_images() {
$success = $this->task_manager->clear_pending_images();
if (!$success) {
return new WP_Error('error_deleting_tasks', __('Pending tasks could not be cleared', 'wp-optimize'));
}
$response = array();
$response['status'] = true;
$response['summary'] = __('Pending tasks cleared successfully', 'wp-optimize');
return $response;
}
/**
* Mark selected images as already compressed.
*
* @param array $data
* @return array
*/
public function mark_as_compressed($data) {
$response = array();
$selected_images = array();
$unmark = isset($data['unmark']) && $data['unmark'];
foreach ($data['selected_images'] as $image) {
if (!array_key_exists($image['blog_id'], $selected_images)) $selected_images[$image['blog_id']] = array();
$selected_images[$image['blog_id']][] = $image['attachment_id'];
}
$info = __('This image is marked as already compressed by another tool.', 'wp-optimize');
foreach (array_keys($selected_images) as $blog_id) {
if (is_multisite()) switch_to_blog($blog_id);
foreach ($selected_images[$blog_id] as $attachment_id) {
if ($unmark) {
delete_post_meta($attachment_id, 'smush-complete');
delete_post_meta($attachment_id, 'smush-marked');
delete_post_meta($attachment_id, 'smush-info');
} else {
update_post_meta($attachment_id, 'smush-complete', true);
update_post_meta($attachment_id, 'smush-marked', true);
update_post_meta($attachment_id, 'smush-info', $info);
}
}
if (is_multisite()) restore_current_blog();
}
$response['status'] = true;
if ($unmark) {
$response['summary'] = _n('The selected image was successfully marked as uncompressed', 'The selected images were successfully marked as uncompressed', count($data['selected_images']), 'wp-optimize');
} else {
$response['summary'] = _n('The selected image was successfully marked as compressed', 'The selected images were successfully marked as compressed', count($data['selected_images']), 'wp-optimize');
}
$response['info'] = $info;
return $response;
}
/**
* Mark all images as uncompressed and if posted restore_backup argument
* then try to restore images form backup.
*
* @param array $data
* @return array
*/
public function mark_all_as_uncompressed($data) {
$restore_backup = isset($data['restore_backup']) && $data['restore_backup'];
$images_per_request = apply_filters('mark_all_as_uncompressed_images_per_request', 100);
$delete_only_backups_meta = isset($data['delete_only_backups_meta']) && $data['delete_only_backups_meta'];
if (is_multisite()) {
// option where we store last completed blog id
$option_name = 'mark_as_uncompressed_last_blog_id';
// set default value for response
$response = array(
'completed' => true,
'message' => __('All the compressed images were successfully restored.', 'wp-optimize'),
);
// get all blogs ids
$blogs = WP_Optimize()->get_sites();
$blogs_ids = wp_list_pluck($blogs, 'blog_id');
sort($blogs_ids);
// select the blog for processing
$last_completed_blog_id = $this->task_manager->options->get_option($option_name, false);
$index = $last_completed_blog_id ? array_search($last_completed_blog_id, $blogs_ids) + 1 : 0;
if ($index < count($blogs_ids)) {
$blog_id = $blogs_ids[$index];
$response = $this->task_manager->bulk_restore_compressed_images($restore_backup, $blog_id, $images_per_request, $delete_only_backups_meta);
// if we get completed the current blog then update last completed blog option value
// and if we have other blogs for processing then set complete to false as we have not
// processed all blogs
if ($response['completed']) {
if ($index + 1 < count($blogs_ids)) {
$response['completed'] = false;
} else {
if ($delete_only_backups_meta) {
$response['message'] = __('All the compressed images were successfully restored.', 'wp-optimize');
} else {
$response['message'] = __('All the compressed images were successfully marked as uncompressed.', 'wp-optimize');
}
}
$this->task_manager->options->update_option($option_name, $blog_id);
}
}
// if we get an error or completed the work then delete option with last completed blog id.
if ($response['completed'] || isset($response['error'])) {
$this->task_manager->options->delete_option($option_name);
}
} else {
$response = $this->task_manager->bulk_restore_compressed_images($restore_backup, 0, $images_per_request, $delete_only_backups_meta);
}
return $response;
}
/**
* Returns the log file
*
* @return WP_Error|file - logfile or WP_Error object on failure
*/
public function get_smush_logs() {
$logfile = $this->task_manager->get_logfile_path();
if (!file_exists($logfile)) {
$this->task_manager->write_log_header();
}
if (is_file($logfile)) {
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($logfile).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($logfile));
readfile($logfile);
exit;
} else {
return new WP_Error('log_file_error', __('Log file does not exist or could not be read', 'wp-optimize'));
}
}
/**
* Clean all backup images command.
*
* @return array
*/
public function clean_all_backup_images() {
$upload_dir = wp_upload_dir(null, false);
$base_dir = $upload_dir['basedir'];
$this->task_manager->clear_backup_images_directory($base_dir, 0);
return array(
'status' => true,
);
}
/**
* Close browser connection so that it can resume AJAX polling
*
* @param array $txt Response to browser; this must be JSON (or if not, alter the Content-Type header handling below)
* @return void
*/
public function close_browser_connection($txt = '') {
header('Content-Length: '.((!empty($txt)) ? 4+strlen($txt) : '0'));
header('Content-Type: application/json');
header('Connection: close');
header('Content-Encoding: none');
if (session_id()) session_write_close();
echo "\r\n\r\n";
echo $txt;
$levels = ob_get_level();
for ($i = 0; $i < $levels; $i++) {
ob_end_flush();
}
flush();
if (function_exists('fastcgi_finish_request')) fastcgi_finish_request();
}
/**
* Resets webp serving method
*
* @return array
*/
public function reset_webp_serving_method() {
$success = WP_Optimize()->get_webp_instance()->reset_webp_serving_method();
return array(
'success' => $success,
);
}
/**
* Convert the image to webp format
*
* @param array $data
* @return array
*/
public function convert_to_webp_format($data) {
$attachment_id = isset($data['attachment_id']) ? $data['attachment_id'] : 0;
if (0 === $attachment_id) return $this->image_not_found_response();
$images = WPO_Image_Utils::get_attachment_files($attachment_id);
if (empty($images)) return $this->image_not_found_response();
$images['original'] = get_attached_file($attachment_id);
foreach ($images as $image) {
WPO_Image_Utils::do_webp_conversion($image);
}
return array(
'success' => __('Image is converted to WebP format.', 'wp-optimize'),
);
}
/**
* Returns image not found response
*
* @return array
*/
private function image_not_found_response() {
return array(
'error' => __('Image not found', 'wp-optimize'),
);
}
/**
* Decides whether to use webp images option is enabled or not
*
* @param bool $webp_option
*
* @return bool
*/
private function is_webp_enabled($webp_option) {
return true === $webp_option;
}
/**
* Removes webp redirect rules in .htaccess file
*
* @return void
*/
private function remove_webp_redirect_rules() {
WP_Optimize()->get_webp_instance()->empty_htaccess_file();
}
}
endif;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,429 @@
<?php
/**
* A sample implementation using the Resmush.it API and our tasks library
*/
if (!defined('ABSPATH')) die('Access denied.');
if (!class_exists('Updraft_Task_1_2')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php');
if (!class_exists('Updraft_Smush_Task')) :
abstract class Updraft_Smush_Task extends Updraft_Task_1_2 {
/**
* A flag indicating if the operation was succesful
*
* @var bool
*/
protected $success = false;
/**
* A text descriptor describing the stage of the task
*
* @var string
*/
protected $stage;
/**
* Initialise the task
*
* @param Array $options - options to use
*/
public function initialise($options = array()) {
parent::initialise($options);
$this->set_current_stage('initialised');
do_action('ud_task_initialised', $this);
}
/**
* Runs the task
*
* @return bool - true if complete, false otherwise
*/
public function run() {
$this->set_status('active');
do_action('ud_task_started', $this);
$attachment_id = $this->get_option('attachment_id');
if (is_multisite()) {
switch_to_blog($this->get_option('blog_id', 1));
$file_path = get_attached_file($attachment_id);
restore_current_blog();
} else {
$file_path = get_attached_file($attachment_id);
}
if (!$this->validate_file($file_path)) return false;
$api_endpoint = $this->get_option('api_endpoint');
if (false === filter_var($api_endpoint, FILTER_VALIDATE_URL)) {
$this->fail('invalid_api_url', "The API endpoint supplied {$api_endpoint} is invalid");
return false;
}
$original_image = $file_path;
$backup_original_image = $this->get_option('keep_original', true);
// add possibility to exclude certain image sizes from smush.
$dont_smush_sizes = apply_filters('wpo_dont_smush_sizes', array());
$this->update_option('original_filesize', filesize($file_path));
// build list of files for smush.
$files = array_merge(array('full' => $file_path), WPO_Image_Utils::get_attachment_files($attachment_id));
$sizes_info = array();
foreach ($files as $size => $file_path) {
if (in_array($size, $dont_smush_sizes)) continue;
$file_size = filesize($file_path);
if ($file_size > 5242880) {
$this->update_option('request_timeout', 180);
}
$this->log($this->get_description());
$ext = WPO_Image_Utils::get_extension($file_path);
$allowed_extensions = WPO_Image_Utils::get_allowed_extensions();
$allowed_extensions = array_diff($allowed_extensions, array('gif'));
if (WPO_Image_Utils::can_do_webp_conversion()) {
if (WPO_Image_Utils::is_supported_extension($ext, $allowed_extensions)) {
WPO_Image_Utils::do_webp_conversion($file_path);
}
} else {
$this->log('There were no WebP conversion tools found on your server.');
}
/**
* Filters the options for a single image to compress.
* Currently supports:
* - 'quality': Will use the image quality set in this filter, instead of the one defined in the settings.
*
* @param array $options - The options (default: empty array)
* @param integer $attachment_id - The attachment post ID
* @param string $file_path - The path to the file being compressed
* @param string $size - The size name (e.g. 'thumbnail')
*/
$options = apply_filters('wpo_image_compression_single_image_options', array(), $attachment_id, $file_path, $size);
$post_data = $this->prepare_post_request($file_path, $options);
$response = $this->post_to_remote_server($api_endpoint, $post_data);
$optimised_image = $this->process_server_response($response);
if ($optimised_image) {
$backup_image = ($original_image == $file_path) ? $backup_original_image : false;
$this->save_optimised_image($file_path, $optimised_image, $backup_image);
clearstatcache($file_path);
$sizes_info[$size] = array(
'original' => $file_size,
'compressed' => filesize($file_path),
);
}
}
$this->update_option('smush-sizes-info', $sizes_info);
return $this->success;
}
/**
* Posts the supplied data to the API url and returns a response
*
* @param String $api_endpoint - the url to post the form to
* @param String $post_data - the post data as specified by the server
* @return mixed - the response
*/
public function post_to_remote_server($api_endpoint, $post_data) {
$this->set_current_stage('connecting');
$response = wp_remote_post($api_endpoint, $post_data);
if (is_wp_error($response)) {
$this->fail($response->get_error_code(), $response->get_error_message());
return false;
}
return $response;
}
/**
* Processes the response recieved from the remote server
*
* @param mixed $response - the response object
* @return mixed - the response
*/
public function process_server_response($response) {
$this->set_current_stage('processing_response');
return $response;
}
/**
* Checks if a file is valid and capable of being smushed
*
* @param String $file_path - the path of the original image
* @return bool - true on success, false otherwise
*/
public function validate_file($file_path) {
$allowed_file_types = $this->get_option('allowed_file_types');
if (!file_exists($file_path)) {
$this->fail("invalid_file_path", "The linked attachment ID does not have a valid file path");
return false;
}
if (filesize($file_path) > $this->get_option('max_filesize')) {
$this->fail("exceeded_max_filesize", "$file_path - cannot be optimized, file size is above service provider limit");
return false;
}
if (!in_array(strtolower(pathinfo($file_path, PATHINFO_EXTENSION)), $allowed_file_types)) {
$this->fail("invalid_file_type", "$file_path - cannot be optimized, it has an invalid file type");
return false;
}
return true;
}
/**
* Creates a backup of the original image
*
* @param String $file_path - the path of the original image
* @return bool - true on success, false otherwise
*/
public function backup_original_image($file_path) {
$this->set_current_stage('backup_original');
if (is_multisite()) {
switch_to_blog($this->get_option('blog_id', 1));
}
$file = pathinfo($file_path);
$back_up = wp_normalize_path($file['dirname'].'/'.basename($file['filename'].$this->get_option('backup_prefix').$file['extension']));
$uploads_dir = wp_upload_dir();
// Make path relative and safe for migrations
$back_up_relative_path = preg_replace('#^'.wp_normalize_path($uploads_dir['basedir'].'/').'#', '', $back_up);
update_post_meta($this->get_option('attachment_id'), 'original-file', $back_up_relative_path);
if (is_multisite()) {
restore_current_blog();
}
$this->log("Backing up the original image - {$back_up_relative_path}");
return copy($file_path, $back_up);
}
/**
* Creates a backup of the original image
*
* @param String $file_path - the path of the original image
* @param Mixes $optimised_image - the contents of the image
* @param bool $backup_original - backup original image
*
* @return bool - true on success, false otherwise
*/
private function save_optimised_image($file_path, $optimised_image, $backup_original) {
$this->set_current_stage('saving_image');
if ($backup_original)
$this->backup_original_image($file_path);
if (false !== file_put_contents($file_path, $optimised_image)) {
$this->success = true;
} else {
$this->success = false;
}
return $this->success;
}
/**
* Fires if the task succeds, any clean up code and logging goes here
*/
public function complete() {
$attachment_id = $this->get_option('attachment_id');
if (is_multisite()) {
switch_to_blog($this->get_option('blog_id', 1));
$file_path = get_attached_file($attachment_id);
restore_current_blog();
} else {
$file_path = get_attached_file($attachment_id);
}
$original_size = $this->get_option('original_filesize');
$this->set_current_stage('completed');
clearstatcache(true, $file_path); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.clearstatcache_clear_realpath_cacheFound,PHPCompatibility.FunctionUse.NewFunctionParameters.clearstatcache_filenameFound
if (0 == $original_size) {
$saved = '';
$info = sprintf(__("The file was compressed to %s using WP-Optimize", 'wp-optimize'), WP_Optimize()->format_size(filesize($file_path)));
} else {
$saved = round((($original_size - filesize($file_path)) / $original_size * 100), 2);
$info = sprintf(__("The file was compressed from %s to %s saving %s percent using WP-Optimize", 'wp-optimize'), WP_Optimize()->format_size($original_size), WP_Optimize()->format_size(filesize($file_path)), $saved);
}
$stats = array(
'smushed-with' => $this->label,
'original-size' => $original_size,
'smushed-size' => filesize($file_path),
'savings-percent' => $saved,
'sizes-info' => $this->get_option('smush-sizes-info'),
);
if (is_multisite()) {
switch_to_blog($this->get_option('blog_id', 1));
update_post_meta($attachment_id, 'smush-complete', true);
update_post_meta($attachment_id, 'smush-info', $info);
update_post_meta($attachment_id, 'smush-stats', $stats);
restore_current_blog();
} else {
update_post_meta($attachment_id, 'smush-complete', true);
update_post_meta($attachment_id, 'smush-info', $info);
update_post_meta($attachment_id, 'smush-stats', $stats);
}
$this->log("Successfully optimized the image - {$file_path}." . $info);
$this->set_status('complete');
return parent::complete();
}
/**
* Fires if the task fails, any clean up code and logging goes here
*
* @param String $error_code - A code for the failure
* @param String $error_message - A description for the failure
*/
public function fail($error_code = "Unknown", $error_message = "Unknown") {
$attachment_id = $this->get_option('attachment_id');
$info = sprintf(__("Failed with error code %s - %s", 'wp-optimize'), $error_code, $error_message);
if (is_multisite()) {
switch_to_blog($this->get_option('blog_id', 1));
update_post_meta($attachment_id, 'smush-info', $info);
update_post_meta($attachment_id, 'smush-complete', false);
restore_current_blog();
} else {
update_post_meta($attachment_id, 'smush-info', $info);
update_post_meta($attachment_id, 'smush-complete', false);
}
do_action('ud_smush_task_failed', $this, $error_code, $error_message);
return parent::fail($error_code, $error_message);
}
/**
* Get all the supported task stages.
*
* @return array - list of task stages.
*/
public function get_allowed_stages() {
$stages = array(
'initialised' => __('Initialised', 'wp-optimize'),
'connecting' => __('Connecting to API server', 'wp-optimize'),
'processing_response' => __('Processing response', 'wp-optimize'),
'backup_original' => __('Backing up original image', 'wp-optimize'),
'saving_image' => __('Saving optimized image', 'wp-optimize'),
'completed' => __('Successful', 'wp-optimize'),
);
return apply_filters('allowed_task_stages', $stages);
}
/**
* Get features available with this service
*
* @return Array - an array of features
*/
public static function get_features() {
return array(
'max_filesize' => self::MAX_FILESIZE,
'lossy_compression' => true,
'preserve_exif' => true,
);
}
/**
* Retrieve default options for this task.
* This method should normally be over-ridden by the child.
*
* @return Array - an array of options
*/
public function get_default_options() {
return array(
'allowed_file_types' => WPO_Image_Utils::get_allowed_extensions(),
'request_timeout' => 15,
'image_quality' => 90,
'backup_prefix' => '-updraft-pre-smush-original.'
);
}
/**
* Sets the task stage.
*
* @param String $stage - the current stage of the task
* @return bool - the result of the update
*/
public function set_current_stage($stage) {
if (array_key_exists($stage, self::get_allowed_stages())) {
$this->stage = $stage;
return $this->update_option('current_stage', $this->stage);
}
return false;
}
/**
* Gets the task stage
*
* @return String $stage - the current stage of the task
*/
public function get_current_stage() {
if (isset($this->stage))
return $this->stage;
else return $this->get_option('current_stage');
}
/**
* Check the mime type of a downloaded file, returns true if it is a valid image mime type.
*
* @param string $file_buffer The buffer string downloaded from the compression service
* @return boolean
*/
protected function is_downloaded_image_buffer_mime_type_valid($file_buffer) {
// If the required class does not exist, return true to avoid breaking the functionality
if (!class_exists('finfo')) return true;
$accepted_types = apply_filters('wpo_image_compression_accepted_mime_types', array('image/png', 'image/jpeg', 'image/jpg', 'image/gif', 'image/webp'));
// The ignore rule below is added because "finfo" doesn't exist in PHP5.2.
$finfo = new finfo(FILEINFO_MIME_TYPE); // phpcs:ignore PHPCompatibility.Classes.NewClasses.finfoFound, PHPCompatibility.Constants.NewConstants.fileinfo_mime_typeFound
$mime_type = $finfo->buffer($file_buffer);
return in_array($mime_type, $accepted_types);
}
}
endif;

View File

@@ -0,0 +1,41 @@
<?php
if (!defined('WPO_PLUGIN_MAIN_PATH')) die('No direct access allowed');
/**
* This is a small glue class, which makes available all the commands in WP_Optimize_Commands, and translates the response from WP_Optimize_Commands (which is either data to return, or a WP_Error) into the format used by UpdraftCentral.
*/
class UpdraftCentral_WP_Optimize_Commands extends UpdraftCentral_Commands {
private $commands;
/**
* Class constructor
*/
public function __construct() {
$this->commands = new WP_Optimize_Commands();
}
/**
* Magic method to pass on the command to WP_Optimize_Commands
*
* @param String $name - command name
* @param Array $arguments - command parameters
*
* @return Array - response
*/
public function __call($name, $arguments) {
if (!is_callable(array($this->commands, $name))) {
return $this->_generic_error_response('wp_optimize_no_such_command', $name);
}
$result = call_user_func_array(array($this->commands, $name), $arguments);
if (is_wp_error($result)) {
return $this->_generic_error_response($result->get_error_code(), $result->get_error_data());
} else {
return $this->_response($result);
}
}
}

View File

@@ -0,0 +1,487 @@
<?php
if (!defined('WPO_VERSION')) die('No direct access allowed');
/**
* Parent class for all optimizations.
*/
abstract class WP_Optimization {
/**
* Ideally, these would all be the same. But, historically, some are not; hence, three separate IDs.
*
* @var $id
*/
public $id;
protected $setting_id;
protected $dom_id;
protected $auto_id;
protected $available_for_auto;
protected $ui_sort_order;
protected $run_sort_order = 1000;
public $run_multisite = true;
public $support_preview = true; // if true then optimization support preview action for optimization data.
protected $support_ajax_get_info = false; // set to true if optimization support getting info about optimization asynchronously.
/**
* This property indicates whether running this optimization is likely to change the overall table optimization state. We set this to 'true' on optimizations that run SQL OPTIMIZE commands. It is only used for the UI. Strictly, of course, any optimization that deletes something can cause increased fragmentation; so; in that sense, it would be true for every optimization; but since we are just using it to keep the UI reasonably fresh, and since there is a manual "refresh" button, we set it only on some optimizations.
*
* @var [$changes_table_data
*/
protected $changes_table_data;
protected $optimizer;
protected $options;
protected $logger;
protected $data;
/**
* Blogs ids for optimization.
*
* @var $blogs_ids
*/
public $blogs_ids;
/**
* Count of blogs for optimization.
*
* @var $blogs_count
*/
public $blogs_count;
/**
* Store count of optimized items.
*
* @var $processed_count
*/
public $processed_count;
/**
* Store found items for optimization. Used in get_info() and related functions.
*
* @var $found_count;
*/
public $found_count;
public $retention_enabled;
public $retention_period;
public $revisions_retention_enabled;
public $revisions_retention_count;
/**
* Results. These should be accessed via get_results()
*
* @var $output
*/
private $output;
private $meta;
private $sql_commands;
protected $wpdb;
/**
* This is abstracted so as to provide future possibilities, e.g. logging.
*
* @param string $sql The quesry for SQL to be ran.
* @return array Return array of results
*/
protected function query($sql) {
$this->sql_commands[] = $sql;
do_action('wp_optimize_optimization_query', $sql, $this);
$result = $this->wpdb->query($sql);
return apply_filters('wp_optimize_optimization_query_result', $result, $sql, $this);
}
/**
* Display or hide optimization in optimizations list.
*
* @return bool
*/
public function display_in_optimizations_list() {
return true;
}
/**
* Returns data those should be optimized. Used to display this information in a popup tool
* for previewing and removing certain data for optimization.
*
* @param array $params
*
* @return array
*/
public function preview($params) {
return array(
'id_key' => 'id', // key used used to identify data.
'offset' => $params['offset'],
'limit' => $params['limit'],
'total' => 0,
'data' => array(), // returned data as associative array where keys are column names and values - database cell values.
);
}
/**
* Convert all applicable characters to HTML entities in array. Used to prepare data for output in browser for preview.
*
* @param array $array source array
* @param array $exclude_keys what items shoudn't be encoded.
*
* @return array
*/
public function htmlentities_array($array, $exclude_keys = array()) {
if (!is_array($array) || empty($array)) return $array;
foreach ($array as $key => $value) {
if (in_array($key, $exclude_keys)) continue;
if (!is_array($value)) {
$array[$key] = htmlentities($value);
} else {
$array[$key] = $this->htmlentities_array($value);
}
}
return $array;
}
/**
* Do actions before get_info() function.
*/
public function before_get_info() {
$this->found_count = 0;
}
/**
* Do actions after get_info() function.
*/
public function after_get_info() {
}
abstract public function get_info();
/**
* Do actions before optimize() function.
*/
public function before_optimize() {
$this->processed_count = 0;
}
/**
* Do actions after optimize() function.
*/
public function after_optimize() {
}
abstract public function optimize();
abstract public function settings_label();
/**
* WP_Optimization constructor.
*
* @param array $data initial data for optimization.
*/
public function __construct($data = array()) {
$class_name = get_class($this);
// Remove the prefixed WP_Optimization_.
$this->id = substr($class_name, 16);
$this->data = $data;
$this->optimizer = WP_Optimize()->get_optimizer();
$this->options = WP_Optimize()->get_options();
$this->logger = WP_Optimize()->get_logger();
$wpdb = $GLOBALS['wpdb'];
$this->wpdb = $wpdb;
$this->blogs_ids = $this->get_optimization_blogs();
$this->init();
}
/**
* This triggers the do_optimization function
* within class-wp-optimizer.php to kick off the optimizations.
* It also passed the data array from the wpadmin.js.
*
* @return array array of results that includes sql_commands, output and meta
*/
public function do_optimization() {
return $this->optimizer->do_optimization($this);
}
/**
* This gathers the optimization information to be displayed
* before triggering any optimizations
*
* @return array Returns an array of optimization information
*/
public function get_optimization_info() {
return $this->optimizer->get_optimization_info($this);
}
/**
* Returns array of blog ids
*
* @return array
*/
public function get_optimization_blogs() {
$objects = array();
if ($this->is_multisite_mode()) {
$all_sites = false;
$selected_sites = array();
// support both arrays and single values in data site id parameter.
if (isset($this->data['site_id']) && !is_array($this->data['site_id'])) {
$this->data['site_id'] = array($this->data['site_id']);
}
$optimization_sites = (isset($this->data['site_id'])) ? $this->data['site_id'] : $this->options->get_wpo_sites_option();
// check selected sites field.
if (!empty($optimization_sites)) {
foreach ($optimization_sites as $site_id) {
if ('all' == $site_id) {
$all_sites = true;
} else {
$selected_sites[] = $site_id;
}
}
}
$sites = $this->get_sites();
if (!empty($sites)) {
foreach ($sites as $site) {
if ($all_sites || (in_array($site->blog_id, $selected_sites))) {
$objects[] = $site->blog_id;
}
}
} else {
$objects[] = 1;
}
} else {
$objects[] = 1;
}
return apply_filters('get_optimization_blogs', $objects);
}
/**
* Returns true if optimization works in multisite mode
*
* @return bool
*/
public function is_multisite_mode() {
return WP_Optimize()->is_multisite_mode();
}
/**
* Returns list of all sites in multisite
*
* @return array
*/
public function get_sites() {
return WP_Optimize()->get_sites();
}
/**
* Wrapper for switch_to_blog Wordpress MU function
*
* @param int $new_blog new blog id.
* @return bool|void - if on multisite, then always true (see https://codex.wordpress.org/Function_Reference/switch_to_blog)
*/
public function switch_to_blog($new_blog) {
if (function_exists('switch_to_blog') && $this->is_multisite_mode()) {
return switch_to_blog($new_blog);
}
}
/**
* Wrapper for restore_current_blog Wordpress MU function
*
* @return bool
*/
public function restore_current_blog() {
if (function_exists('restore_current_blog') && $this->is_multisite_mode()) {
return restore_current_blog();
}
}
/**
* This function adds output to the current registered output
*
* @param array $output Array of various outputs.
*/
public function register_output($output) {
$this->output[] = $output;
}
/**
* This function adds meta-data associated with the result to the registered output
*
* @param string $key The key value.
* @param string $value The value to be passed.
*/
public function register_meta($key, $value) {
$this->meta[$key] = $value;
}
/**
* Get meta-data added to the registered output.
*
* @return array
*/
public function get_meta() {
return $this->meta;
}
public function init() {
$this->output = array();
$this->meta = array();
$this->sql_commands = array();
list ($retention_enabled, $retention_period) = $this->optimizer->get_retain_info();
$this->retention_enabled = $retention_enabled;
$this->retention_period = $retention_period;
list($revisions_retention_enabled, $revisions_retention_count) = $this->optimizer->get_revisions_retain_info();
$this->revisions_retention_enabled = $revisions_retention_enabled;
$this->revisions_retention_count = $revisions_retention_count;
}
/**
* The next three functions reflect the fact that historically, WP-Optimize has not, for all optimizations, used the same ID consistently throughout forms, saved settings, and saved settings for scheduled clean-ups. Mostly, it has; but some flexibility is needed for the exceptions.
*/
public function get_setting_id() {
return empty($this->setting_id) ? 'user-'.$this->id : 'user-'.$this->setting_id;
}
public function get_dom_id() {
return empty($this->dom_id) ? 'clean-'.$this->id : $this->dom_id;
}
public function get_auto_id() {
return empty($this->auto_id) ? $this->id : $this->auto_id;
}
public function get_changes_table_data() {
return empty($this->changes_table_data) ? false : true;
}
public function get_run_sort_order() {
return empty($this->run_sort_order) ? 0 : $this->run_sort_order;
}
/**
* Only used if $available_for_auto is true, in which case this function should be over-ridden
*
* @return string Error message.
*/
public function get_auto_option_description() {
return 'Error: missing scheduled option description ('.$this->id.')';
}
/**
* What is returned must be at least convertible to an array
*
* @return array Array of results.
*/
public function get_results() {
// As yet, we have no need for a dedicated object type for our results.
$results = new stdClass;
$results->sql_commands = $this->sql_commands;
$results->output = $this->output;
$results->meta = $this->meta;
return apply_filters('wp_optimize_optimization_results', $results, $this->id, $this);
}
/**
* Generate information about optimization required for show it.
*
* @param bool $ajax_get_info if true then information about optimization will not generated, i.e. get_optimization_info() won't call.
*
* @return array
*/
public function get_settings_html($ajax_get_info = false) {
$wpo_user_selection = $this->options->get_main_settings();
$setting_id = $this->get_setting_id();
$dom_id = $this->get_dom_id();
// N.B. Some of the optimizations used to have an onclick call to fCheck(). But that function was commented out, so did nothing.
$settings_label = $this->settings_label();
$setting_activated = ((empty($wpo_user_selection[$setting_id]) || 'false' == $wpo_user_selection[$setting_id]) ? false : true);
$info = ($ajax_get_info && $this->support_ajax_get_info) ? '...' : $this->get_optimization_info()->output;
$settings_html = array(
'dom_id' => $dom_id,
'activated' => $setting_activated,
'settings_label' => $settings_label,
'info' => $info,
'support_ajax_get_info' => $this->support_ajax_get_info
);
if (empty($settings_label)) {
// Error_log, as this is a defect.
error_log("Optimization with setting ID ".$setting_id." lacks a settings label (method: settings_label())");
}
return $settings_html;
}
/**
* Wrap $text as a link for preview action. If preview is not supported then return just $text.
*
* @param string $text
* @param array $attributes
*
* @return string
*/
public function get_preview_link($text, $attributes = array()) {
// if preview is not supported then return just $text.
if (false == $this->support_preview || false == WP_Optimize::is_premium()) return $text;
$attributes = array_merge(
array(
'title' => __('Preview found items', 'wp-optimize'),
'data-id' => $this->id,
'data-title' => $this->settings_label(),
),
$attributes
);
$str_attr = '';
foreach ($attributes as $key => $value) {
$str_attr .= ' '.$key.'="'.esc_attr($value).'"';
}
$link = '<a href="#" class="wpo-optimization-preview"'.$str_attr.'>'.$text.'</a>';
return $link;
}
}

View File

@@ -0,0 +1,730 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
if (!class_exists('WP_Optimize_Admin')) :
class WP_Optimize_Admin {
/**
* Class constructor
*/
public function __construct() {
if (is_multisite()) {
add_action('network_admin_menu', array($this, 'admin_menu'));
} else {
add_action('admin_menu', array($this, 'admin_menu'));
}
}
/**
* Returns singleton instance object
*
* @return WP_Optimize_Admin Returns `WP_Optimize_Admin` object
*/
public static function instance() {
static $_instance = null;
if (empty($_instance)) {
$_instance = new self();
}
return $_instance;
}
/**
* Builds the Tabs that should be displayed
*
* @return array Returns all tabs specified array
*/
public function get_tabs($page) {
// define tabs for pages.
$pages_tabs = array(
'WP-Optimize' => array(
'optimize' => __('Optimizations', 'wp-optimize'),
'tables' => __('Tables', 'wp-optimize'),
'settings' => __('Settings', 'wp-optimize'),
),
'wpo_images' => array(
'smush' => __('Compress images', 'wp-optimize'),
'unused' => __('Unused images and sizes', 'wp-optimize').'<span class="menu-pill premium-only">Premium</span>',
'lazyload' => __('Lazy-load', 'wp-optimize').'<span class="menu-pill premium-only">Premium</span>',
),
'wpo_cache' => array(
'cache' => __('Page cache', 'wp-optimize'),
'preload' => __('Preload', 'wp-optimize'),
'advanced' => __('Advanced settings', 'wp-optimize'),
'gzip' => __('Gzip compression', 'wp-optimize'),
'settings' => __('Static file headers', 'wp-optimize') // Adds a settings tab
),
'wpo_minify' => array(
"status" => __('Minify status', 'wp-optimize'),
"js" => __('JavaScript', 'wp-optimize').'<span class="menu-pill disabled hidden">'.__('Disabled', 'wp-optimize').'</span>',
"css" => __('CSS', 'wp-optimize').'<span class="menu-pill disabled hidden">'.__('Disabled', 'wp-optimize').'</span>',
"font" => __('Fonts', 'wp-optimize'),
"settings" => __('Settings', 'wp-optimize'),
"preload" => __('Preload', 'wp-optimize'),
"advanced" => __('Advanced', 'wp-optimize')
),
'wpo_settings' => array(
'settings' => array(
'title' => __('Settings', 'wp-optimize'),
),
),
'wpo_support' => array('support' => __('Support / FAQs', 'wp-optimize')),
'wpo_mayalso' => array('may_also' => __('Premium / Plugin family', 'wp-optimize')),
);
$tabs = (array_key_exists($page, $pages_tabs)) ? $pages_tabs[$page] : array();
return apply_filters('wp_optimize_admin_page_'.$page.'_tabs', $tabs);
}
/**
* Main page structure.
*/
public function display_admin() {
$capability_required = WP_Optimize()->capability_required();
$can_run_optimizations = WP_Optimize()->can_run_optimizations();
$can_manage_options = WP_Optimize()->can_manage_options();
if (!current_user_can($capability_required) || (!$can_run_optimizations && !$can_manage_options)) {
echo "Permission denied.";
return;
}
$this->register_admin_content();
echo '<div id="wp-optimize-wrap">';
WP_Optimize()->include_template('admin-page-header.php', false, array('show_notices' => !(WP_Optimize()->get_install_or_update_notice()->show_current_notice())));
do_action('wpo_admin_after_header');
echo '<div id="actions-results-area"></div>';
$pages = $this->get_submenu_items();
foreach ($pages as $page) {
if (isset($page['menu_slug'])) {
$this->display_admin_page($page['menu_slug']);
}
}
do_action('wpo_admin_before_closing_wrap');
// closes main plugin wrapper div. #wp-optimize-wrap
echo '</div><!-- END #wp-optimize-wrap -->';
}
/**
* Prepare and display admin page with $page id.
*
* @param string $page wp-optimize page id i.e. dashboard, database, images, cache, ...
*/
public function display_admin_page($page) {
$active_page = !empty($_REQUEST['page']) ? $_REQUEST['page'] : '';
echo '<div class="wpo-page' . ($active_page == $page ? ' active' : '') . '" data-whichpage="'.$page.'">';
echo '<div class="wpo-main">';
// get defined tabs for $page.
$tabs = $this->get_tabs($page);
// if no tabs defined for $page then use $page as $active_tab for load template, doing related actions e t.c.
if (empty($tabs)) {
$active_tab = $page;
} else {
$tab_keys = array_keys($tabs);
$default_tab = apply_filters('wp_optimize_admin_'.$page.'_default_tab', $tab_keys[0]);
$active_tab = isset($_GET['tab']) ? substr($_GET['tab'], 12) : $default_tab;
if (!in_array($active_tab, array_keys($tabs))) $active_tab = $default_tab;
}
do_action('wp_optimize_admin_page_'.$page, $active_tab);
// if tabs defined then display
if (!empty($tabs)) {
WP_Optimize()->include_template('admin-page-header-tabs.php', false, array('page' => $page, 'active_tab' => $active_tab, 'tabs' => $tabs, 'wpo_is_premium' => WP_Optimize::is_premium()));
}
foreach ($tabs as $tab_id => $tab_description) {
// output wrap div for tab with id #wp-optimize-nav-tab-contents-'.$page.'-'.$tab_id
echo '<div class="wp-optimize-nav-tab-contents" id="wp-optimize-nav-tab-'.$page.'-'.$tab_id.'-contents" '.(($tab_id == $active_tab) ? '' : 'style="display:none;"').'>';
echo '<div class="postbox wpo-tab-postbox">';
// call action for generate tab content.
do_action('wp_optimize_admin_page_'.$page.'_'.$tab_id);
// closes postbox.
echo '</div><!-- END .postbox -->';
// closes tab wrapper.
echo '</div><!-- END .wp-optimize-nav-tab-contents -->';
}
echo '</div><!-- END .wpo-main -->';
do_action('wp_optimize_admin_after_page_'.$page, $active_tab);
echo '</div><!-- END .wpo-page -->';
}
/**
* Define required actions for admin pages.
*/
public function register_admin_content() {
do_action('wp_optimize_register_admin_content');
/**
* SETTINGS
*/
add_action('wp_optimize_admin_page_wpo_settings_settings', array($this, 'output_dashboard_settings_tab'), 20);
/**
* Premium / other plugins
*/
add_action('wp_optimize_admin_page_wpo_mayalso_may_also', array($this, 'output_dashboard_other_plugins_tab'), 20);
/**
* DATABASE
*/
add_action('wp_optimize_admin_page_WP-Optimize_optimize', array($this, 'output_database_optimize_tab'), 20);
add_action('wp_optimize_admin_page_WP-Optimize_tables', array($this, 'output_database_tables_tab'), 20);
add_action('wp_optimize_admin_page_WP-Optimize_settings', array($this, 'output_database_settings_tab'), 20);
/**
* CACHE
*/
add_action('wp_optimize_admin_page_wpo_cache_cache', array($this, 'output_page_cache_tab'), 20);
if (!WP_Optimize()->does_server_handles_cache()) {
add_action('wp_optimize_admin_page_wpo_cache_preload', array($this, 'output_page_cache_preload_tab'), 20);
add_action('wp_optimize_admin_page_wpo_cache_advanced', array($this, 'output_page_cache_advanced_tab'), 20);
}
add_action('wp_optimize_admin_page_wpo_cache_gzip', array($this, 'output_cache_gzip_tab'), 20);
add_action('wp_optimize_admin_page_wpo_cache_settings', array($this, 'output_cache_settings_tab'), 20);
add_action('wpo_page_cache_advanced_settings', array($this, 'output_cloudflare_settings'), 20);
/**
* SUPPORT
*/
add_action('wp_optimize_admin_page_wpo_support_support', array($this, 'output_dashboard_support_tab'), 20);
// Display Support page.
if (!WP_Optimize::is_premium()) {
/**
* Add action for display Images > Unused images and sizes tab.
*/
add_action('wp_optimize_admin_page_wpo_images_unused', array($this, 'admin_page_wpo_images_unused'));
/**
* Add action for display Dashboard > Lazyload tab.
*/
add_action('wp_optimize_admin_page_wpo_images_lazyload', array($this, 'admin_page_wpo_images_lazyload'));
} else {
/**
* Add filter for display footer review message and link.
*/
add_filter('admin_footer_text', array($this, 'display_footer_review_message'));
}
}
/**
* Database settings
*/
public function output_database_settings_tab() {
if (WP_Optimize()->can_manage_options()) {
WP_Optimize()->include_template('database/settings.php');
} else {
$this->prevent_manage_options_info();
}
}
/**
* Dashboard settings
*/
public function output_dashboard_settings_tab() {
$options = WP_Optimize()->get_options();
if ('POST' == $_SERVER['REQUEST_METHOD']) {
// Nonce check.
check_admin_referer('wpo_settings');
$output = $options->save_settings($_POST);
if (isset($_POST['wp-optimize-settings'])) {
// save settings request sent.
$output = $options->save_settings($_POST);
}
$this->wpo_render_output_messages($output);
}
if (WP_Optimize()->can_manage_options()) {
WP_Optimize()->include_template('settings/settings.php');
} else {
$this->prevent_manage_options_info();
}
}
/**
* Dashboard support tab
*/
public function output_dashboard_support_tab() {
WP_Optimize()->include_template('settings/support-and-faqs.php');
}
/**
* Dashboard Other plugins / premium tab
*/
public function output_dashboard_other_plugins_tab() {
WP_Optimize()->include_template('settings/may-also-like.php');
}
/**
* Cache tab
*/
public function output_page_cache_tab() {
$wpo_cache = WP_Optimize()->get_page_cache();
$wpo_cache_options = $wpo_cache->config->get();
$display = $wpo_cache->is_enabled() ? "style='display:block'" : "style='display:none'";
WP_Optimize()->include_template('cache/page-cache.php', false, array(
'wpo_cache' => $wpo_cache,
'active_cache_plugins' => WP_Optimize_Detect_Cache_Plugins::instance()->get_active_cache_plugins(),
'wpo_cache_options' => $wpo_cache_options,
'cache_size' => $wpo_cache->get_cache_size(),
'display' => $display,
'can_purge_the_cache' => WP_Optimize()->get_page_cache()->can_purge_cache(),
'does_server_handles_cache' => WP_Optimize()->does_server_handles_cache(),
));
}
/**
* Preload tab
*/
public function output_page_cache_preload_tab() {
$wpo_cache = WP_Optimize()->get_page_cache();
$wpo_cache_options = $wpo_cache->config->get();
$wpo_cache_preloader = WP_Optimize_Page_Cache_Preloader::instance();
$is_running = $wpo_cache_preloader->is_running();
$status = $wpo_cache_preloader->get_status_info();
WP_Optimize()->include_template('cache/page-cache-preload.php', false, array(
'wpo_cache_options' => $wpo_cache_options,
'is_running' => $is_running,
'status_message' => isset($status['message']) ? $status['message'] : '',
'schedule_options' => array(
'wpo_use_cache_lifespan' => __('Same as cache lifespan', 'wp-optimize'),
'wpo_daily' => __('Daily', 'wp-optimize'),
'wpo_weekly' => __('Weekly', 'wp-optimize'),
'wpo_fortnightly' => __('Fortnightly', 'wp-optimize'),
'wpo_monthly' => __('Monthly (approx. - every 30 days)', 'wp-optimize')
)
));
}
/**
* Advanced tab
*/
public function output_page_cache_advanced_tab() {
$wpo_cache = WP_Optimize()->get_page_cache();
$wpo_cache_options = $wpo_cache->config->get();
$cache_exception_conditional_tags = is_array($wpo_cache_options['cache_exception_conditional_tags']) ? join("\n", $wpo_cache_options['cache_exception_conditional_tags']) : '';
$cache_exception_urls = is_array($wpo_cache_options['cache_exception_urls']) ? join("\n", $wpo_cache_options['cache_exception_urls']) : '';
$cache_exception_cookies = is_array($wpo_cache_options['cache_exception_cookies']) ? join("\n", $wpo_cache_options['cache_exception_cookies']) : '';
$cache_exception_browser_agents = is_array($wpo_cache_options['cache_exception_browser_agents']) ? join("\n", $wpo_cache_options['cache_exception_browser_agents']) : '';
WP_Optimize()->include_template('cache/page-cache-advanced.php', false, array(
'wpo_cache' => $wpo_cache,
'wpo_cache_options' => $wpo_cache_options,
'cache_exception_urls' => $cache_exception_urls,
'cache_exception_conditional_tags' => $cache_exception_conditional_tags,
'cache_exception_cookies' => $cache_exception_cookies,
'cache_exception_browser_agents' => $cache_exception_browser_agents,
));
}
/**
* Gzip tab
*/
public function output_cache_gzip_tab() {
$wpo_gzip_compression = WP_Optimize()->get_gzip_compression();
$wpo_gzip_compression_enabled = $wpo_gzip_compression->is_gzip_compression_enabled(true);
$wpo_gzip_headers_information = $wpo_gzip_compression->get_headers_information();
$is_cloudflare_site = $this->is_cloudflare_site();
$is_gzip_compression_section_exists = $wpo_gzip_compression->is_gzip_compression_section_exists();
$wpo_gzip_compression_enabled_by_wpo = $is_gzip_compression_section_exists && $wpo_gzip_compression_enabled && !$is_cloudflare_site && !(is_array($wpo_gzip_headers_information) && 'brotli' == $wpo_gzip_headers_information['compression']);
WP_Optimize()->include_template('cache/gzip-compression.php', false, array(
'wpo_gzip_headers_information' => $wpo_gzip_headers_information,
'wpo_gzip_compression_enabled' => $wpo_gzip_compression_enabled,
'is_cloudflare_site' => $is_cloudflare_site,
'wpo_gzip_compression_enabled_by_wpo' => $wpo_gzip_compression_enabled_by_wpo,
'wpo_gzip_compression_settings_added' => $is_gzip_compression_section_exists,
'info_link' => 'https://getwpo.com/gzip-compression-explained/',
'faq_link' => 'https://getwpo.com/gzip-faq-link/',
'class_name' => (!is_wp_error($wpo_gzip_compression_enabled) && $wpo_gzip_compression_enabled ? 'wpo-enabled' : 'wpo-disabled')
));
}
/**
* Cache tab
*/
public function output_cache_settings_tab() {
$wpo_browser_cache = WP_Optimize()->get_browser_cache();
$wpo_browser_cache_enabled = $wpo_browser_cache->is_enabled();
WP_Optimize()->include_template('cache/browser-cache.php', false, array(
'wpo_browser_cache_enabled' => $wpo_browser_cache_enabled,
'is_cloudflare_site' => $this->is_cloudflare_site(),
'wpo_browser_cache_settings_added' => $wpo_browser_cache->is_browser_cache_section_exists(),
'class_name' => (true === $wpo_browser_cache_enabled ? 'wpo-enabled' : 'wpo-disabled'),
'wpo_browser_cache_expire_days' => WP_Optimize()->get_options()->get_option('browser_cache_expire_days', '28'),
'wpo_browser_cache_expire_hours' => WP_Optimize()->get_options()->get_option('browser_cache_expire_hours', '0'),
'info_link' => 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching',
'faq_link' => 'https://www.digitalocean.com/community/tutorials/how-to-implement-browser-caching-with-nginx-s-header-module-on-ubuntu-16-04',
));
}
/**
* Check if is the current site handled with Cloudflare.
*
* @return bool
*/
public function is_cloudflare_site() {
return isset($_SERVER['HTTP_CF_RAY']);
}
/**
* Include Cloudflare settings template.
*/
public function output_cloudflare_settings() {
if (WP_Optimize::is_premium() || !apply_filters('show_cloudflare_settings', $this->is_cloudflare_site())) return;
WP_Optimize()->include_template('cache/page-cache-cloudflare-placeholder.php');
}
/**
* Outputs the DB optimize Tab
*/
public function output_database_optimize_tab() {
$optimizer = WP_Optimize()->get_optimizer();
$options = WP_Optimize()->get_options();
// check if nonce passed.
$nonce_passed = (!empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'wpo_optimization')) ? true : false;
// save options.
if ($nonce_passed && isset($_POST['wp-optimize'])) $options->save_sent_manual_run_optimization_options($_POST, true);
$optimize_db = ($nonce_passed && isset($_POST["optimize-db"])) ? true : false;
$optimization_results = (($nonce_passed) ? $optimizer->do_optimizations($_POST) : false);
// display optimizations table or restricted access message.
if (WP_Optimize()->can_run_optimizations()) {
WP_Optimize()->include_template('database/optimize-table.php', false, array('optimize_db' => $optimize_db, 'optimization_results' => $optimization_results, 'load_data' => false, 'does_server_allows_table_optimization' => WP_Optimize()->does_server_allows_table_optimization()));
} else {
$this->prevent_run_optimizations_message();
}
}
/**
* Outputs the DB Tables Tab
*/
public function output_database_tables_tab() {
// check if nonce passed.
$nonce_passed = (!empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], 'wpo_optimization')) ? true : false;
$optimize_db = ($nonce_passed && isset($_POST["optimize-db"])) ? true : false;
if (!WP_Optimize()->does_server_allows_table_optimization()) {
$message = __('Your server takes care of table optimization', 'wp-optimize');
$this->prevent_run_optimizations_message($message);
} elseif (WP_Optimize()->can_run_optimizations()) {
WP_Optimize()->include_template('database/tables.php', false, array('optimize_db' => $optimize_db, 'load_data' => WP_Optimize()->template_should_include_data()));
} else {
$this->prevent_run_optimizations_message();
}
}
/**
* Runs upon the WP action admin_page_wpo_images_unused
*/
public function admin_page_wpo_images_unused() {
WP_Optimize()->include_template('images/unused.php');
}
/**
* Runs upon the WP action wp_optimize_admin_page_wpo_images_lazyload
*/
public function admin_page_wpo_images_lazyload() {
WP_Optimize()->include_template('images/lazyload.php');
}
/**
* Show footer review message and link.
*
* @return string
*/
public function display_footer_review_message() {
$message = sprintf(
__('Enjoyed %s? Please leave us a %s rating. We really appreciate your support!', 'wp-optimize'),
'<b>WP-Optimize</b>',
'<a href="https://www.g2.com/products/wp-optimize/reviews" target="_blank">&starf;&starf;&starf;&starf;&starf;</a>'
);
return $message;
}
/**
* Adds menu in admin bar
*/
public function wpo_admin_bar() {
$wp_admin_bar = $GLOBALS['wp_admin_bar'];
if (defined('WPOPTIMIZE_ADMINBAR_DISABLE') && WPOPTIMIZE_ADMINBAR_DISABLE) return;
// Show menu item in top bar only for super admins.
if (is_multisite() & !is_super_admin(get_current_user_id())) return;
// Add a link called at the top admin bar.
$args = array(
'id' => 'wp-optimize-node',
'title' => apply_filters('wpoptimize_admin_node_title', 'WP-Optimize')
);
$wp_admin_bar->add_node($args);
$pages = $this->get_submenu_items();
foreach ($pages as $page_id => $page) {
if (!isset($page['create_submenu']) || !$page['create_submenu']) {
if (isset($page['icon']) && 'separator' == $page['icon']) {
$args = array(
'id' => 'wpo-separator-'.$page_id,
'parent' => 'wp-optimize-node',
'meta' => array(
'class' => 'separator',
),
);
$wp_admin_bar->add_node($args);
}
continue;
}
// 'menu_slug' => 'WP-Optimize',
$menu_page_url = menu_page_url($page['menu_slug'], false);
if (is_multisite()) {
$menu_page_url = network_admin_url('admin.php?page='.$page['menu_slug']);
}
$args = array(
'id' => 'wpoptimize_admin_node_'.$page_id,
'title' => $page['menu_title'],
'parent' => 'wp-optimize-node',
'href' => $menu_page_url,
);
$wp_admin_bar->add_node($args);
}
}
/**
* Manages the admin bar menu for caching (currently page and minify)
*/
public function cache_admin_bar($wp_admin_bar) {
$options = WP_Optimize()->get_options();
if (!$options->get_option('enable_cache_in_admin_bar', true)) return;
/**
* The "purge cache" menu items
*
* @param array $menu_items - The menu items, in the format required by $wp_admin_bar->add_menu()
* @param object $wp_admin_bar
*/
$menu_items = apply_filters('wpo_cache_admin_bar_menu_items', array(), $wp_admin_bar);
if (empty($menu_items) || !is_array($menu_items)) return;
$wp_admin_bar->add_menu(array(
'id' => 'wpo_purge_cache',
'title' => __('Purge cache', 'wp-optimize'),
'href' => '#',
'meta' => array(
'title' => __('Purge cache', 'wp-optimize'),
),
'parent' => false,
));
foreach ($menu_items as $item) {
$wp_admin_bar->add_menu($item);
}
}
/**
* Adds and displays menu and submenu pages
*/
public function admin_menu() {
$capability_required = WP_Optimize()->capability_required();
$can_run_optimizations = WP_Optimize()->can_run_optimizations();
$can_manage_options = WP_Optimize()->can_manage_options();
if (!current_user_can($capability_required) || (!$can_run_optimizations && !$can_manage_options)) return;
$icon_svg = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmlld0JveD0iMCAwIDE2IDE2IgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJzdmc0MzE2IgogICBoZWlnaHQ9IjE2IgogICB3aWR0aD0iMTYiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0MzE4IiAvPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTQzMjEiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSI+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6I2EwYTVhYTtmaWxsLW9wYWNpdHk6MSIKICAgICAgIGlkPSJwYXRoNTciCiAgICAgICBkPSJtIDEwLjc2ODgwOSw2Ljc2MTYwNTEgMCwwIGMgLTAuMDE2ODgsLTAuMDE2ODc4IC0wLjAyNTMxLC0wLjA0MjE4MSAtMC4wMzM3NCwtMC4wNjc0OTkgLTAuMDA4NCwtMC4wMDgzOSAtMC4wMDg0LC0wLjAxNjg3OCAtMC4wMTY4OCwtMC4wMzM3NDMgQyA5Ljk5MjYxMTIsNS4xOTIzMzY2IDguMjIwODU1Nyw0LjU4NDg3ODEgNi43NDQzOTEyLDUuMjkzNTc5NyA1LjY3MjkwMDUsNS44MDgyMzI4IDUuMDU3MDA0Myw2Ljg4ODE2MTMgNS4wNjU0NDIsOC4wMDE4MzY1IDQuNDU3OTgyMiw3LjMxMDAwNzYgMy42OTg2NTg0LDYuNzk1MzU0NSAyLjg1NDk2NDIsNi40OTE2MjUzIDMuMjY4Mzc0Myw1LjA2NTc4MzEgNC4yNTU0OTYsMy44MTcxMTY2IDUuNjg5Nzc0NiwzLjEyNTI4NzggOC4zNjQyODMyLDEuODM0NDM2OCAxMS41NzAzMTksMi45Mzk2NzQ0IDEyLjg4NjQ4MSw1LjU4ODg3MjYgMTMuNDUxNzU1LDYuNzI3ODU5NiAxNC42NDk4MDEsNy4zNTIxOTIxIDE1Ljg0Nzg0Niw3LjIzNDA3NSAxNS43NjM0ODIsNi4zMzk3NiAxNS41MTg4MDUsNS40MzcwMDg2IDE1LjEwNTM5Niw0LjU3NjQ0MDQgMTMuMjE1NTIxLDAuNjg3MDEzNCA4LjUzMzAyMjYsLTAuOTQxMzE2MjcgNC42NDM1OTQzLDAuOTQwMTIxNzkgMi4zMjM0MzcsMi4wNjIyMzM0IDAuODA0Nzg4MTQsNC4xNzk5MDQ0IDAuMzU3NjMxMzIsNi41MzM4MDk4IDIuNDE2MjQzOCw2LjQyNDEyOSA0LjQzMjY3MTcsNy41MDQwNTc0IDUuNDM2NjY2Miw5LjQzNjExNjcgbCAwLjAwODM5LDAgYyAwLjc1OTMxOTIsMS4zNzUyMjAzIDIuNDcyMDE3OCwxLjk0MDQ5NTMgMy45MDYyOTYsMS4yNDg2NjczIDEuMDQ2MTc5OCwtMC41MDYyMTggMS42NTM2NDA4LC0xLjUzNTUyMzggMS42Nzg5NTA4LC0yLjYxNTQ1MTIgMC41ODIxNDgsMC43MDg3MDE4IDEuMzMzMDM1LDEuMjQ4NjY2OCAyLjE1OTg1NiwxLjU3NzcwNjQgLTAuNDM4NzIxLDEuMzU4MzQ3OCAtMS40MDA1MzMsMi41NDc5NTQ4IC0yLjc5MjYyNywzLjIxNDQ3ODggLTIuNTkwMTM4NywxLjI0ODY1OCAtNS42NzgwNTc0LDAuMjUzMTA0IC03LjA2MTcxNTEsLTIuMjI3MzU3IGwgMCwwIEMgMi43NjIxMDQ4LDkuNDUyOTg5NCAxLjUxMzQzODMsOC44MjAyMTkxIDAuMjgxNjQ1OTIsOC45NzIwODQ0IDAuMzgyODg3NjUsOS43OTg5MDQ2IDAuNjE5MTIzMzEsMTAuNjE3Mjg3IDAuOTk4Nzg1MiwxMS40MDE5MjIgYyAxLjg4MTQzNjgsMy44OTc4NjQgNi41NjM5MzcsNS41MjYxOTggMTAuNDYxODAwOCwzLjY0NDc2IDIuMjQ0MjI2LC0xLjA4ODM2OSAzLjczNzU2MiwtMy4xMDQ3OTYgNC4yMzUzNDIsLTUuMzc0MzMyMyAtMS45OTk1NTQsMC4wNDIxODEgLTMuOTQ4NDg2LC0xLjAyOTMwNjMgLTQuOTI3MTcsLTIuOTEwNzQzMyB6IgogICAgICAgY2xhc3M9InN0MTciIC8+CiAgPC9nPgo8L3N2Zz4K';
// Removes the admin menu items on the left WP bar.
if (!is_multisite() || (is_multisite() && is_network_admin())) {
add_menu_page("WP-Optimize", "WP-Optimize", $capability_required, "WP-Optimize", array($this, "display_admin"), $icon_svg);
$sub_menu_items = $this->get_submenu_items();
foreach ($sub_menu_items as $menu_item) {
if ($menu_item['create_submenu']) add_submenu_page('WP-Optimize', $menu_item['page_title'], $menu_item['menu_title'], $capability_required, $menu_item['menu_slug'], $menu_item['function']);
}
}
$options = WP_Optimize()->get_options();
if ('true' == $options->get_option('enable-admin-menu', 'false')) {
add_action('wp_before_admin_bar_render', array($this, 'wpo_admin_bar'));
}
}
/**
* Get the submenu items
*
* @return array
*/
public function get_submenu_items() {
$sub_menu_items = array(
array(
'page_title' => __('Database', 'wp-optimize'),
'menu_title' => __('Database', 'wp-optimize'),
'menu_slug' => 'WP-Optimize',
'function' => array($this, 'display_admin'),
'icon' => 'cloud',
'create_submenu' => true,
'order' => 20,
),
array(
'page_title' => __('Images', 'wp-optimize'),
'menu_title' => __('Images', 'wp-optimize'),
'menu_slug' => 'wpo_images',
'function' => array($this, 'display_admin'),
'icon' => 'images-alt2',
'create_submenu' => true,
'order' => 30,
),
array(
'page_title' => __('Cache', 'wp-optimize'),
'menu_title' => __('Cache', 'wp-optimize'),
'menu_slug' => 'wpo_cache',
'function' => array($this, 'display_admin'),
'icon' => 'archive',
'create_submenu' => true,
'order' => 40,
),
array(
'page_title' => __('Minify', 'wp-optimize'),
'menu_title' => __('Minify', 'wp-optimize'),
'menu_slug' => 'wpo_minify',
'function' => array($this, 'display_admin'),
'icon' => 'dashboard',
'create_submenu' => true,
'order' => 50,
),
array(
'create_submenu' => false,
'order' => 55,
'icon' => 'separator',
),
array(
'page_title' => __('Settings', 'wp-optimize'),
'menu_title' => __('Settings', 'wp-optimize'),
'menu_slug' => 'wpo_settings',
'function' => array($this, 'display_admin'),
'icon' => 'admin-settings',
'create_submenu' => true,
'order' => 60,
),
array(
'page_title' => __('Support & FAQs', 'wp-optimize'),
'menu_title' => __('Help', 'wp-optimize'),
'menu_slug' => 'wpo_support',
'function' => array($this, 'display_admin'),
'icon' => 'sos',
'create_submenu' => true,
'order' => 60,
),
array(
'page_title' => __('Premium Upgrade', 'wp-optimize'),
'menu_title' => __('Premium Upgrade', 'wp-optimize'),
'menu_slug' => 'wpo_mayalso',
'function' => array($this, 'display_admin'),
'icon' => 'admin-plugins',
'create_submenu' => true,
'order' => 70,
),
);
$sub_menu_items = apply_filters('wp_optimize_sub_menu_items', $sub_menu_items);
usort($sub_menu_items, array($this, 'order_sort'));
return $sub_menu_items;
}
/**
* Order sorting function
*/
public function order_sort($a, $b) {
if ($a['order'] == $b['order']) return 0;
return ($a['order'] > $b['order']) ? 1 : -1;
}
/**
* Output information message for users who have no permissions to run optimizations.
*
* @param string $message Message to display
*/
public function prevent_run_optimizations_message($message = '') {
if (empty($message)) {
$message = __('You have no permissions to run optimizations.', 'wp-optimize');
}
WP_Optimize()->include_template('info-message.php', false, array('message' => $message));
}
/**
* Output information message for users who have no permissions to manage settings.
*/
public function prevent_manage_options_info() {
WP_Optimize()->include_template('info-message.php', false, array('message' => __('You have no permissions to manage WP-Optimize settings.', 'wp-optimize')));
}
/**
* Output success/error messages from $output array.
*
* @param array $output ['messages' => success messages, 'errors' => error messages]
*/
private function wpo_render_output_messages($output) {
foreach ($output['messages'] as $item) {
echo '<div class="updated fade below-h2"><strong>'.$item.'</strong></div>';
}
foreach ($output['errors'] as $item) {
echo '<div class="error fade below-h2"><strong>'.$item.'</strong></div>';
}
}
}
endif;

View File

@@ -0,0 +1,312 @@
<?php
if (!defined('WPO_VERSION')) die('No direct access allowed');
require_once 'class-wp-optimize-htaccess.php';
/**
* Class WP_Optimize_Browser_Cache
*/
class WP_Optimize_Browser_Cache {
private $_htaccess = null;
private $_options = null;
private $_wp_optimize = null;
/**
* Browser cache section in htaccess will wrapped with this comment
*
* @var string
*/
private $_htaccess_section_comment = 'WP-Optimize Browser Cache';
/**
* WP_Optimize_Browser_Cache constructor.
*/
public function __construct() {
$this->_wp_optimize = WP_Optimize();
$this->_htaccess = new WP_Optimize_Htaccess();
$this->_options = $this->_wp_optimize->get_options();
}
/**
* Returns singleton instance object
*
* @return WP_Optimize_Browser_Cache Returns `WP_Optimize_Browser_Cache` object
*/
public static function instance() {
static $_instance = null;
if (null === $_instance) {
$_instance = new self();
}
return $_instance;
}
/**
* Check headers for Cache-Control and Etag. And if they are exist return true.
*
* @return bool|WP_Error
**/
public function is_enabled() {
static $is_enabled;
if (isset($is_enabled)) return $is_enabled;
$headers = WP_Optimize()->get_stylesheet_headers();
if (is_wp_error($headers)) return $headers;
if (array_key_exists('cache-control', $headers) && array_key_exists('expires', $headers)) {
$is_enabled = true;
} else {
$is_enabled = false;
}
if ($this->is_browser_cache_section_exists() && false === $this->_wp_optimize->is_apache_module_loaded(array('mod_expires', 'mod_headers'))) {
$is_enabled = new WP_Error('Browser cache', __('We successfully updated your .htaccess file. But it seems one of Apache modules - mod_expires or mod_headers is not active.', 'wp-optimize'));
}
return $is_enabled;
}
/**
* Enable browser cache - add settings into .htaccess.
*
* @param string $expiry_time
*/
public function enable($expiry_time = '1 month') {
$this->_htaccess->update_commented_section($this->prepare_browser_cache_section($expiry_time), $this->_htaccess_section_comment);
$this->_htaccess->write_file();
$this->_options->update_option('enable_browser_cache', true);
}
/**
* Disable cache - remove settings from .htaccess added in enable() function.
*/
public function disable() {
$this->_htaccess->remove_commented_section($this->_htaccess_section_comment);
$this->_htaccess->write_file();
$this->_options->update_option('enable_browser_cache', false);
}
/**
* Check if browser chache option is set to true then add section with gzip settings into .htaccess (used when plugin being activated).
*/
public function restore() {
$expire_days = $this->_options->get_option('browser_cache_expire_days', '');
$expire_hours = $this->_options->get_option('browser_cache_expire_hours', '');
$expiry_time = $this->prepare_interval($expire_days, $expire_hours);
$enabled = ('' == $expiry_time) ? false : true;
if ($enabled && $this->_htaccess->is_writable()) $this->enable($expiry_time);
}
/**
* Check if section with browser cache settings already exists.
*/
public function is_browser_cache_section_exists() {
return $this->_htaccess->is_commented_section_exists($this->_htaccess_section_comment);
}
/**
* Handle for enable_browser_cache command used in WP_Optimize_Commands.
*
* @param array $params - ['browser_cache_expire' => '1 month 15 days 2 hours' || '' - for disable cache]
* @return array
*/
public function enable_browser_cache_command_handler($params) {
$expire_days = isset($params['browser_cache_expire_days']) ? $params['browser_cache_expire_days'] : '';
$expire_hours = isset($params['browser_cache_expire_hours']) ? $params['browser_cache_expire_hours'] : '';
$current_expire_days = $this->_options->get_option('browser_cache_expire_days', '');
$current_expire_hours = $this->_options->get_option('browser_cache_expire_hours', '');
$section_updated = false;
$expiry_time = $this->prepare_interval($expire_days, $expire_hours);
$enable = ('' == $expiry_time) ? false : true;
/**
* If we don't need to do anything in .htaccess then return message.
*/
if ($enable == $this->_htaccess->is_commented_section_exists() && $expire_days == $current_expire_days && $expire_hours == $current_expire_hours) {
$message = __('Browser static caching settings already exists in the .htaccess file', 'wp-optimize');
return array(
'success' => true,
'enabled' => $enable,
'message' => $message,
);
}
if ($this->_htaccess->is_writable()) {
// update commented section
if ($enable) {
$this->enable($expiry_time);
} else {
$this->disable();
}
// read updated file.
$this->_htaccess->read_file();
// check if section added or removed successfully.
$section_exists = $this->_htaccess->is_commented_section_exists();
// set correct $section-updated flag.
$section_updated = $enable === $section_exists;
}
if ($section_updated) {
$enabled = $this->is_enabled();
// save $expire value to options.
$this->_options->update_option('browser_cache_expire_days', $expire_days);
$this->_options->update_option('browser_cache_expire_hours', $expire_hours);
if (is_wp_error($enabled)) {
return array(
'success' => true,
'enabled' => $enabled,
'error_message' => $enabled->get_error_message(),
);
} else {
return array(
'success' => true,
'enabled' => $enabled,
'message' => __('We successfully updated your .htaccess file.', 'wp-optimize'),
);
}
} else {
$cache_section = $this->prepare_browser_cache_section($expiry_time);
if ($enable) {
$message = sprintf(__('We can\'t update your %s file. Please try to add following lines manually:', 'wp-optimize'), $this->_htaccess->get_filename());
$output = htmlentities($this->_htaccess->get_section_begin_comment() . PHP_EOL .
join(PHP_EOL, $this->_htaccess->get_flat_array($cache_section)).
PHP_EOL . $this->_htaccess->get_section_end_comment());
} else {
$message = sprintf(__('We can\'t update your %s file. Please try to remove following lines manually:', 'wp-optimize'), $this->_htaccess->get_filename());
$output = htmlentities($this->_htaccess->get_section_begin_comment() . PHP_EOL .
' ... ... ... '.
PHP_EOL . $this->_htaccess->get_section_end_comment());
}
return array(
'success' => false,
'enabled' => $this->is_enabled(),
'error_message' => $message,
'output' => $output,
);
}
}
/**
* Use $days an $hours values to build correct time interval as a string like '2 days 3 hours' or empty string if date is empty.
*
* @param int $days
* @param int $hours
* @return string
*/
private function prepare_interval($days, $hours) {
$days = is_numeric($days) ? floor($days) : 0;
$hours = is_numeric($hours) ? floor($hours) : 0;
if (0 == $days && 0 == $hours) {
return '';
}
$parts = array();
// if hours value more than one day then fix it.
$days += floor($hours / 24);
$hours = $hours % 24;
$years = floor($days / 365);
$days = $days % 365;
$months = floor($days / 30);
$days = $days % 30;
if ($years > 0) {
$parts[] = $years . ($years > 1 ? ' years' : ' year');
}
if ($months > 0) {
$parts[] = $months . ($months > 1 ? ' months' : ' month');
}
if ($days > 0) {
$parts[] = $days . ($days > 1 ? ' days' : ' day');
}
if ($hours > 0) {
$parts[] = $hours . ($hours > 1 ? ' hours' : ' hour');
}
return join(' ', $parts);
}
/**
* Build browser cache section array.
*
* @param string $expire - value like - 1 day 12 hours 15 minutes
* @return array
*/
public function prepare_browser_cache_section($expire) {
return array(
array(
'<IfModule mod_expires.c>',
'ExpiresActive On',
'ExpiresByType text/css "access '.$expire.'"',
'ExpiresByType text/html "access '.$expire.'"',
'ExpiresByType image/gif "access '.$expire.'"',
'ExpiresByType image/png "access '.$expire.'"',
'ExpiresByType image/jpg "access '.$expire.'"',
'ExpiresByType image/jpeg "access '.$expire.'"',
'ExpiresByType image/webp "access '.$expire.'"',
'ExpiresByType image/x-icon "access '.$expire.'"',
'ExpiresByType application/pdf "access '.$expire.'"',
'ExpiresByType application/javascript "access '.$expire.'"',
'ExpiresByType text/x-javascript "access '.$expire.'"',
'ExpiresByType application/x-shockwave-flash "access '.$expire.'"',
'ExpiresDefault "access '.$expire.'"',
'</IfModule>',
),
'',
array(
'<IfModule mod_headers.c>',
array(
'<filesMatch "\.(ico|jpe?g|png|gif|webp|swf)$">',
'Header set Cache-Control "public"',
'</filesMatch>',
),
array(
'<filesMatch "\.(css)$">',
'Header set Cache-Control "public"',
'</filesMatch>',
),
array(
'<filesMatch "\.(js)$">',
'Header set Cache-Control "private"',
'</filesMatch>',
),
array(
'<filesMatch "\.(x?html?|php)$">',
'Header set Cache-Control "private, must-revalidate"',
'</filesMatch>',
),
'</IfModule>',
),
'',
'#Disable ETag',
'FileETag None',
);
}
}

View File

@@ -0,0 +1,631 @@
<?php
if (!defined('WPO_PLUGIN_MAIN_PATH')) die('No direct access allowed');
/**
* All commands that are intended to be available for calling from any sort of control interface (e.g. wp-admin, UpdraftCentral) go in here. All public methods should either return the data to be returned, or a WP_Error with associated error code, message and error data.
*/
class WP_Optimize_Commands {
private $optimizer;
private $options;
private $wpo_sites; // used in get_optimizations_info command.
public function __construct() {
$this->optimizer = WP_Optimize()->get_optimizer();
$this->options = WP_Optimize()->get_options();
}
public function get_version() {
return WPO_VERSION;
}
public function enable_or_disable_feature($data) {
$type = (string) $data['type'];
$enable = (boolean) $data['enable'];
$options = array($type => $enable);
return $this->optimizer->trackback_comment_actions($options);
}
public function save_manual_run_optimization_options($sent_options) {
return $this->options->save_sent_manual_run_optimization_options($sent_options);
}
public function get_status_box_contents() {
return WP_Optimize()->include_template('database/status-box-contents.php', true, array('optimize_db' => false));
}
/**
* Get the database tabs information.
*
* @return string auto cleanup content.
*/
public function get_settings_auto_cleanup_contents() {
return WP_Optimize()->include_template('database/settings-auto-cleanup.php', true, array('optimize_db' => false, 'show_innodb_option' => WP_Optimize()->template_should_include_data() && $this->optimizer->show_innodb_force_optimize()));
}
/**
* Get the settings tab information.
*
* @return string logging settings content.
*/
public function get_logging_settings_contents() {
return WP_Optimize()->include_template('settings/settings-logging.php', true, array('optimize_db' => false));
}
/**
* Get the database tabs information
*
* @return string database table optimization rendered content
*/
public function get_optimizations_table() {
return WP_Optimize()->include_template('database/optimizations-table.php', true, array('does_server_allows_table_optimization' => WP_Optimize()->does_server_allows_table_optimization()));
}
/**
* Pulls and return the "WP Optimize" template contents. Primarily used for UpdraftCentral
* content display through ajax request.
*
* @return array An array containing the WPO translations and the "WP Optimize" tab's rendered contents
*/
public function get_wp_optimize_contents() {
$content = WP_Optimize()->include_template('database/optimize-table.php', true, array('optimize_db' => false, 'load_data' => WP_Optimize()->template_should_include_data(), 'does_server_allows_table_optimization' => WP_Optimize()->does_server_allows_table_optimization()));
if (WP_Optimize()->is_updraft_central_request()) {
$content .= $this->get_status_box_contents();
}
return array(
'content' => $content,
'translations' => $this->get_js_translation()
);
}
/**
* Pulls and return the "Table Information" template contents. Primarily used for UpdraftCentral
* content display through ajax request.
*
* @return array An array containing the WPO translations and the "Table Information" tab's rendered contents
*/
public function get_table_information_contents() {
$content = WP_Optimize()->include_template('database/tables.php', true, array('optimize_db' => false, 'load_data' => WP_Optimize()->template_should_include_data()));
return array(
'content' => $content,
'translations' => $this->get_js_translation()
);
}
/**
* Pulls and return the "Settings" template contents. Primarily used for UpdraftCentral
* content display through ajax request.
*
* @return array An array containing the WPO translations and the "Settings" tab's rendered contents
*/
public function get_settings_contents() {
$admin_settings = '<form action="#" method="post" enctype="multipart/form-data" name="settings_form" id="settings_form">';
$admin_settings .= WP_Optimize()->include_template('database/settings-general.php', true, array('optimize_db' => false));
$admin_settings .= WP_Optimize()->include_template('database/settings-auto-cleanup.php', true, array('optimize_db' => false, 'show_innodb_option' => WP_Optimize()->template_should_include_data() && $this->optimizer->show_innodb_force_optimize()));
$admin_settings .= WP_Optimize()->include_template('settings/settings-logging.php', true, array('optimize_db' => false));
$admin_settings .= '<input id="wp-optimize-settings-save" class="button button-primary" type="submit" name="wp-optimize-settings" value="' . esc_attr('Save settings', 'wp-optimize') .'" />';
$admin_settings .= '</form>';
$admin_settings .= WP_Optimize()->include_template('settings/settings-trackback-and-comments.php', true, array('optimize_db' => false));
$content = $admin_settings;
return array(
'content' => $content,
'translations' => $this->get_js_translation()
);
}
/**
* Returns array of translations used by the WPO plugin. Primarily used for UpdraftCentral
* consumption.
*
* @return array The WPO translations
*/
public function get_js_translation() {
$translations = WP_Optimize()->wpo_js_translations();
// Make sure that we include the loggers classes info whenever applicable before
// returning the translations to UpdraftCentral.
if (is_callable(array(WP_Optimize(), 'get_loggers_classes_info'))) {
$translations['loggers_classes_info'] = WP_Optimize()->get_loggers_classes_info();
}
return $translations;
}
/**
* Save settings command.
*
* @param string $data
* @return array
*/
public function save_settings($data) {
parse_str(stripslashes($data), $posted_settings);
$saved_settings = $this->options->save_settings($posted_settings);
// We now have $posted_settings as an array.
return array(
'save_results' => $saved_settings,
'status_box_contents' => $this->get_status_box_contents(),
'optimizations_table' => $this->get_optimizations_table(),
'settings_auto_cleanup_contents' => $this->get_settings_auto_cleanup_contents(),
'logging_settings_contents' => $this->get_logging_settings_contents(),
);
}
/**
* Wipe settings command.
*
* @return bool|false|int
*/
public function wipe_settings() {
return $this->options->wipe_settings();
}
/**
* Save lazy load settings.
*
* @param string $data
* @return array
*/
public function save_lazy_load_settings($data) {
parse_str(stripslashes($data), $posted_settings);
return array(
'save_result' => $this->options->save_lazy_load_settings($posted_settings)
);
}
/**
* This sends the selected tick value over to the save function
* within class-wp-optimize-options.php
*
* @param array $data An array of data that includes true or false for click option.
* @return array
*/
public function save_auto_backup_option($data) {
return array('save_auto_backup_option' => $this->options->save_auto_backup_option($data));
}
/**
* Save option which sites to optimize in multisite mode.
*
* @param array $data Array of settings.
* @return bool
*/
public function save_site_settings($data) {
return $this->options->save_wpo_sites_option($data['wpo-sites']);
}
/**
* Perform the requested optimization
*
* @param array $params Should have keys 'optimization_id' and 'data'.
* @return array
*/
public function do_optimization($params) {
if (!isset($params['optimization_id'])) {
$results = array(
'result' => false,
'messages' => array(),
'errors' => array(
__('No optimization was indicated.', 'wp-optimize')
)
);
} else {
$optimization_id = $params['optimization_id'];
$data = isset($params['data']) ? $params['data'] : array();
$include_ui_elements = isset($data['include_ui_elements']) ? $data['include_ui_elements'] : false;
$optimization = $this->optimizer->get_optimization($optimization_id, $data);
$result = is_a($optimization, 'WP_Optimization') ? $optimization->do_optimization() : null;
$results = array(
'result' => $result,
'messages' => array(),
'errors' => array(),
);
if ($include_ui_elements) {
$results['status_box_contents'] = $this->get_status_box_contents();
}
if (is_wp_error($optimization)) {
$results['errors'][] = $optimization->get_error_message().' ('.$optimization->get_error_code().')';
}
if ($include_ui_elements && $optimization->get_changes_table_data()) {
$table_list = $this->get_table_list();
$results['table_list'] = $table_list['table_list'];
$results['total_size'] = $table_list['total_size'];
}
}
return $results;
}
/**
* Preview command, used to show information about data should be optimized in popup tool.
*
* @param array $params Should have keys 'optimization_id', 'offset' and 'limit'.
*
* @return array
*/
public function preview($params) {
if (!isset($params['optimization_id'])) {
$results = array(
'result' => false,
'messages' => array(),
'errors' => array(
__('No optimization was indicated.', 'wp-optimize')
)
);
} else {
$optimization_id = $params['optimization_id'];
$data = isset($params['data']) ? $params['data'] : array();
$params['offset'] = isset($params['offset']) ? (int) $params['offset'] : 0;
$params['limit'] = isset($params['limit']) ? (int) $params['limit'] : 50;
$optimization = $this->optimizer->get_optimization($optimization_id, $data);
if (is_a($optimization, 'WP_Optimization')) {
if (isset($params['site_id'])) {
$optimization->switch_to_blog((int) $params['site_id']);
}
$result = $optimization->preview($params);
} else {
$result = null;
}
$results = array(
'result' => $result,
'messages' => array(),
'errors' => array()
);
}
return $results;
}
/**
* Get information about requested optimization.
*
* @param array $params Should have keys 'optimization_id' and 'data'.
* @return array
*/
public function get_optimization_info($params) {
if (!isset($params['optimization_id'])) {
$results = array(
'result' => false,
'messages' => array(),
'errors' => array(
__('No optimization was indicated.', 'wp-optimize')
)
);
} else {
$optimization_id = $params['optimization_id'];
$data = isset($params['data']) ? $params['data'] : array();
$include_ui_elements = isset($data['include_ui_elements']) ? $data['include_ui_elements'] : false;
$optimization = $this->optimizer->get_optimization($optimization_id, $data);
$result = is_a($optimization, 'WP_Optimization') ? $optimization->get_optimization_info() : null;
$results = array(
'result' => $result,
'messages' => array(),
'errors' => array(),
);
if ($include_ui_elements) {
$results['status_box_contents'] = $this->get_status_box_contents();
}
}
return $results;
}
/**
* Get the data for the tables tab
*
* @param array $data
* @return array
*/
public function get_table_list($data = array()) {
if (isset($data['refresh_plugin_json']) && filter_var($data['refresh_plugin_json'], FILTER_VALIDATE_BOOLEAN)) WP_Optimize()->get_db_info()->update_plugin_json();
$size = $this->optimizer->get_current_db_size();
return apply_filters('wpo_get_tables_data', array(
'table_list' => WP_Optimize()->include_template('database/tables-body.php', true, array('optimize_db' => false)),
'total_size' => $size[0]
));
}
/**
* Get the database tabs information
*
* @return array
*/
public function get_database_tabs() {
return array_merge(array('optimizations' => $this->get_optimizations_table(), 'does_server_allows_table_optimization' => WP_Optimize()->does_server_allows_table_optimization()), $this->get_table_list());
}
/**
* Do action wp_optimize_after_optimizations
* used in ajax request after all optimizations completed
*
* @return boolean
*/
public function optimizations_done() {
$this->options->update_option('total-cleaned', 0);
// Run action after all optimizations completed.
do_action('wp_optimize_after_optimizations');
return true;
}
/**
* Return information about all optimizations.
*
* @param array $params
* @return array
*/
public function get_optimizations_info($params) {
$this->wpo_sites = isset($params['wpo-sites']) ? $params['wpo-sites'] : 0;
add_filter('get_optimization_blogs', array($this, 'get_optimization_blogs_filter'));
$results = array();
$optimizations = $this->optimizer->get_optimizations();
foreach ($optimizations as $optimization_id => $optimization) {
if (false === $optimization->display_in_optimizations_list()) continue;
$results[$optimization_id] = $optimization->get_settings_html();
}
return $results;
}
/**
* Filter for get_optimizations_blogs function, used in get_optimizations_info command.
* Not intended for direct usage as a command (is used internally as a WP filter)
*
* The class variable $wpo_sites is used for performing the filtering.
*
* @param array $sites - unfiltered list of sites
* @return array - after filtering
*/
public function get_optimization_blogs_filter($sites) {
$sites = array();
if (!empty($this->wpo_sites)) {
foreach ($this->wpo_sites as $site) {
if ('all' !== $site) $sites[] = $site;
}
}
return $sites;
}
/**
* Checks overdue crons and return message
*/
public function check_overdue_crons() {
$overdue_crons = WP_Optimize()->howmany_overdue_crons();
if ($overdue_crons >= 4) {
return array('m' => WP_Optimize()->show_admin_warning_overdue_crons($overdue_crons));
}
}
/**
* Enable or disable Gzip compression.
*
* @param array $params - ['enable' => true|false]
* @return array
*/
public function enable_gzip_compression($params) {
return WP_Optimize()->get_gzip_compression()->enable_gzip_command_handler($params);
}
/**
* Get the current gzip compression status
*
* @return array
*/
public function get_gzip_compression_status() {
$status = WP_Optimize()->get_gzip_compression()->is_gzip_compression_enabled(true);
return is_wp_error($status) ? array('error' => __('We could not determine if Gzip compression is enabled.', 'wp-optimize'), 'code' => $status->get_error_code(), 'message' => $status->get_error_message()) : array('status' => $status);
}
/**
* Import WP-Optimize settings.
*
* @param array $params array with 'settings' item where 'settings' json-encoded string.
*
* @return Array - the results of the import operation
*/
public function import_settings($params) {
if (empty($params['settings'])) {
return array('errors' => array(__('Please upload a valid settings file.', 'wp-optimize')));
}
$params['settings'] = stripslashes($params['settings']);
$settings = json_decode($params['settings'], true);
// check if valid json file posted (requires PHP 5.3+)
if ((function_exists('json_last_error') && 0 != json_last_error()) || empty($settings)) {
return array('errors' => array(__('Please upload a valid settings file.', 'wp-optimize')));
}
$cache_settings = $settings['cache_settings'];
$minify_settings = $settings['minify_settings'];
$smush_settings = $settings['smush_settings'];
$database_settings = $settings['database_settings'];
$cache = WP_Optimize()->get_page_cache();
$cache->create_folders();
if ($cache_settings['enable_page_caching']) {
$cache->enable();
}
$wpo_browser_cache = WP_Optimize()->get_browser_cache();
if ($cache_settings['enable_browser_cache']) {
$browser_cache = array(
'browser_cache_expire_days' => $cache_settings['browser_cache_expire_days'],
'browser_cache_expire_hours' => $cache_settings['browser_cache_expire_hours']
);
$wpo_browser_cache->enable_browser_cache_command_handler($browser_cache);
}
$message = '';
$cache_result = WP_Optimize()->get_page_cache()->config->update($cache_settings);
$minify_result = WP_Optimize()->get_minify()->minify_commands->save_minify_settings($minify_settings);
$smush_result = WP_Optimize()->get_task_manager()->commands->update_smush_options($smush_settings);
$this->save_settings($database_settings);
if (is_wp_error($cache_result)) {
$message .= $cache_result->get_error_message() . PHP_EOL;
}
if (!$minify_result['success']) {
$message .= isset($minify_result['message']) ? $minify_result['message'] . PHP_EOL : '';
$message .= isset($minify_result['error']) ? $minify_result['error'] . PHP_EOL : '';
}
if (is_wp_error($smush_result)) {
$message .= $smush_result->get_error_message() . PHP_EOL;
}
return array(
'success' => true,
'message' => empty($message) ? __('The settings were imported successfully.', 'wp-optimize') : $message
);
}
/**
* Dismiss install or updated notice
*
* @return mixed
*/
public function dismiss_install_or_update_notice() {
if (!is_a(WP_Optimize()->get_install_or_update_notice(), 'WP_Optimize_Install_Or_Update_Notice') || !is_callable(array(WP_Optimize()->get_install_or_update_notice(), 'dismiss'))) {
return array('errors' => array('The notice could not be dismissed. The method "dismiss" on the object instance "install_or_update_notice" does not seem to exist.'));
}
if (!WP_Optimize()->get_install_or_update_notice()->dismiss()) {
return array('errors' => array('The notice could not be dismissed. The settings could not be updated'));
}
return true;
}
/**
* Run images trash command.
*/
public function images_trash_command($params) {
if (!class_exists('WP_Optimize_Images_Trash_Manager_Commands')) {
return array(
'errors' => array('WP_Optimize_Images_Trash_Manager_Commands class not found'),
);
}
// get posted command.
$trash_command = isset($params['images_trash_command']) ? $params['images_trash_command'] : '';
// check if command is allowed.
$allowed_commands = WP_Optimize_Images_Trash_Manager_Commands::get_allowed_ajax_commands();
if (!in_array($trash_command, $allowed_commands)) {
return array(
'errors' => array('No such command found'),
);
}
$results = call_user_func(array(WP_Optimize_Images_Trash_Manager()->commands, $trash_command), $params);
if (is_wp_error($results)) {
$results = array(
'errors' => array($results->get_error_message()),
);
}
return $results;
}
/**
* Power tweak handling
*
* @param array $params
* @return mixed
*/
public function power_tweak($params) {
global $wp_optimize_premium;
if (!is_a($wp_optimize_premium, 'WP_Optimize_Premium') || !property_exists($wp_optimize_premium, 'power_tweaks') || !isset($params['sub_action'])) return array(
'errors' => array(__('No such command found', 'wp-optimize')),
);
$action = $params['sub_action'];
$data = $params['data'] ? $params['data'] : array();
if (!isset($data['tweak'])) return array(
'errors' => array(__('No tweak provided', 'wp-optimize'))
);
$tweak = sanitize_title($data['tweak']);
$pt = $wp_optimize_premium->power_tweaks;
switch($action) {
case 'activate':
$result = $pt->activate($tweak);
break;
case 'deactivate':
$result = $pt->deactivate($tweak);
break;
case 'run':
$result = $pt->run($tweak);
break;
}
if ($result && !is_wp_error($result)) {
return is_array($result) ? array_merge(array('success' => true), $result) : array('success' => true, 'message' => $result);
} else {
$error_message = is_wp_error($result) ? $result->get_error_message() : sprintf(__('The command %s failed', 'wp-optimize'), $action);
return array(
'success' => false,
'errors' => array($error_message)
);
}
}
/**
* Ignores the table delete warning for the current user
*
* @return boolean
*/
public function user_ignores_table_delete_warning() {
return array(
'success' => update_user_meta(get_current_user_id(), 'wpo-ignores-table-delete-warning', true)
);
}
/**
* Exports unused images as a CSV file to the `uploads` folder
*
* @return array
*/
public function export_csv() {
WP_Optimization_images::instance()->output_csv();
return array(
'success' => true
);
}
}

View File

@@ -0,0 +1,660 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
class WP_Optimize_Database_Information {
const UNKNOWN_DB = 'unknown';
const MARIA_DB = 'MariaDB';
const PERCONA_DB = 'Percona';
// for some reason coding standard parser give error here WordPress.DB.RestrictedFunctions.mysql_mysql_db
const MYSQL_DB = 'MysqlDB';
const MYISAM_ENGINE = 'MyISAM';
const MEMORY_ENGINE = 'Memory';
const INNODB_ENGINE = 'InnoDB';
const ARCHIVE_ENGINE = 'ARCHIVE';
const CSV_ENGINE = 'CSV';
const NDB_ENGINE = 'NDB';
const ARIA_ENGINE = 'Aria'; // MariaDB
const VIEW = 'VIEW';
/**
* Returns singleton instance object
*
* @return WP_Optimize_Database_Information Returns `WP_Optimize_Database_Information` object
*/
public static function instance() {
static $_instance = null;
if (null === $_instance) {
$_instance = new self();
}
return $_instance;
}
/**
* Returns server type MySQL or MariaDB if mysql database or Unknown if not mysql.
*
* @return string
*/
public function get_server_type() {
global $wpdb;
static $server_type = null;
if (!$wpdb->is_mysql) return self::UNKNOWN_DB;
if (null !== $server_type) return $server_type;
$server_type = self::MYSQL_DB;
$variables = $wpdb->get_results('SHOW SESSION VARIABLES LIKE "version%"');
if (!empty($variables)) {
foreach ($variables as $variable) {
if (preg_match('/mariadb/i', $variable->Value)) {
$server_type = self::MARIA_DB;
}
if (preg_match('/percona/i', $variable->Value)) {
$server_type = self::PERCONA_DB;
}
}
}
return $server_type;
}
/**
* Returns database server version
*
* @return string|bool
*/
public function get_version() {
$version = $this->get_option_value('version');
if (!empty($version)) {
if (preg_match('/^(\d+)(\.\d+)+/', $version, $match)) {
return $match[0];
}
}
return false;
}
/**
* Return table type by $table_name.
*
* @param String $table_name Database table name.
* @return String|Boolean - returns false upon failure
*/
public function get_table_type($table_name) {
$table_info = $this->get_table_status($table_name);
if ($table_info) {
if (!$table_info->Engine && $this->is_view($table_name)) return self::VIEW;
return $table_info->Engine;
}
return false;
}
/**
* Returns information about database table.
*
* @param string $table_name
* @param bool $update if true, then force request to database and don't use cached values.
* @return bool|mixed
*/
public function get_table_status($table_name, $update = false) {
$tables_info = $this->get_show_table_status($update, $table_name);
foreach ($tables_info as $table_info) {
if ($table_name == $table_info->Name) return $table_info;
}
return false;
}
/**
* Returns result for query SHOW TABLE STATUS.
*
* @param bool $update refresh or no cached data
* @return array
*/
public function get_show_table_status($update = false, $table_name = '') {
global $wpdb;
static $tables_info = array();
static $fetched_all_tables = false;
// If a table name is provided, and the whole record hasn't been fetched yet, only fetch the information for the current table.
// This allows for a big preformance gain when using WP-CLI or doing single optimizations.
if ($table_name && !$fetched_all_tables) {
$sql = $wpdb->prepare("SHOW TABLE STATUS LIKE '%s'", $table_name);
$tables_info = $wpdb->get_results($sql);
} else {
if ($update || empty($tables_info) || !is_array($tables_info) || !$fetched_all_tables) {
$tables_info = $wpdb->get_results('SHOW TABLE STATUS');
$fetched_all_tables = true;
foreach ($tables_info as $i => $table) {
$rows_count = get_transient('wpo_' . $table->Name . '_count');
if (false === $rows_count) break;
$tables_info[$i]->Rows = $rows_count;
}
}
}
// If option innodb_file_per_table is disabled then Data_free column will have summary overhead value for all table.
if (!empty($tables_info)) {
foreach ($tables_info as $i => $table) {
if (self::INNODB_ENGINE == $table->Engine && false == $this->is_option_enabled('innodb_file_per_table')) {
$tables_info[$i]->Data_free = 0;
}
}
}
return $tables_info;
}
/**
* Whether a table exists
*
* @return boolean
*/
public function table_exists($table_name, $use_default_prefix = true) {
global $wpdb;
return null !== $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $wpdb->esc_like($use_default_prefix ? $wpdb->prefix.$table_name : $table_name)));
}
/**
* Returns result for query SHOW FULL TABLES as associative array [table_name] => table_type.
*
* @return array
*/
public function get_show_full_tables() {
global $wpdb;
static $tables_info = array();
if (empty($tables_info) || !is_array($tables_info)) {
$_tables_info = $wpdb->get_results('SHOW FULL TABLES', ARRAY_N);
if (!empty($_tables_info)) {
foreach ($_tables_info as $row) {
$tables_info[$row[0]] = $row[1];
}
}
}
return $tables_info;
}
/**
* Checks if table is a VIEW.
*
* @param string $table_name
* @return bool
*/
public function is_view($table_name) {
$tables_info = $this->get_show_full_tables();
if (!array_key_exists($table_name, $tables_info)) return false;
return ('VIEW' == $tables_info[$table_name]);
}
/**
* Returns true if DDL supported.
*
* @return bool
*/
public function has_online_ddl() {
if (self::MYSQL_DB == $this->get_server_type()) {
if (version_compare($this->get_version(), '5.7', '>=')) {
return true;
} else {
return false;
}
} elseif (self::MARIA_DB == $this->get_server_type()) {
if (version_compare($this->get_version(), '10.0.0', '>=')) {
return true;
} else {
return false;
}
}
return false;
}
/**
* Returns database option variable
*
* @param string $option_name Name of database option.
* @return mixed|null
*/
public function get_option_value($option_name) {
global $wpdb;
static $options = array();
if (array_key_exists($option_name, $options)) return $options[$option_name];
$option = $wpdb->get_row(
$wpdb->prepare('SHOW SESSION VARIABLES LIKE %s', $option_name)
);
if (!empty($option)) {
$options[$option_name] = $option->Value;
return $option->Value;
}
return null;
}
/**
* Returns true if database option $option_name
*
* @param string $option_name Name of database option name.
* @return bool
*/
public function is_option_enabled($option_name) {
$option_value = $this->get_option_value($option_name);
if ('ON' == strtoupper($option_value)) return true;
return false;
}
/**
* Returns true if table $table_name is optimizable
*
* @param string $table_name Name of database table
* @return bool
*/
public function is_table_optimizable($table_name) {
$server_type = $this->get_server_type();
$server_version = $this->get_version();
$table_type = $this->get_table_type($table_name);
// return true if table is MyISAM.
if (self::MYISAM_ENGINE == $table_type) return true;
// return true if table is Archive or Aria.
if (self::ARCHIVE_ENGINE == $table_type || self::ARIA_ENGINE == $table_type) return true;
// if InnoDB then check if we can optimize.
if (self::INNODB_ENGINE == $table_type) {
// check for MysqlDB.
if (self::MYSQL_DB == $server_type && $this->has_online_ddl()) {
return true;
}
// check for MariaDB.
if (self::MARIA_DB == $server_type) {
// if innodb_file_per_table enabled or version not older than 10.1.1 and innodb_defragment enabled.
if ($this->is_option_enabled('innodb_file_per_table') || (version_compare($server_version, '10.1.1', '>=') && $this->is_option_enabled('innodb_defragment'))) {
return true;
}
}
}
// otherwise return false.
return false;
}
/**
* Returns true if table type is supported for optimization.
*
* @param string $table_name Name of database table
* @return bool
*/
public function is_table_type_optimize_supported($table_name) {
$table_type = $this->get_table_type($table_name);
$supported_table_types = array(
self::MYISAM_ENGINE,
self::INNODB_ENGINE,
self::ARCHIVE_ENGINE,
self::ARIA_ENGINE,
);
return in_array($table_type, $supported_table_types);
}
/**
* Returns true if table type is supported for repair.
*
* @param string $table_name
* @return bool
*/
public function is_table_type_repair_supported($table_name) {
$table_type = $this->get_table_type($table_name);
$supported_table_types = array(
self::MYISAM_ENGINE,
self::ARCHIVE_ENGINE,
self::CSV_ENGINE,
);
return in_array($table_type, $supported_table_types);
}
/**
* Run CHECK TABLE query and returns statuses for single or list of tables.
*
* @param array|string $table
*/
public function check_table($table) {
global $wpdb;
if (is_array($table)) {
$table = join('`,`', $table);
}
$result = array();
if (empty($table)) return $result;
$query_result = $wpdb->get_results('CHECK TABLE `'.$table.'`;');
if (empty($query_result)) return $result;
foreach ($query_result as $row) {
$table_name_parts = explode('.', rtrim($row->Table, ' .'));
$table_name = array_pop($table_name_parts);
if (!array_key_exists($table_name, $result)) {
$result[$table_name] = array(
'status' => '',
'corrupted' => false,
);
}
if ('error' == $row->Msg_type) {
$result[$table_name]['status'] = $row->Msg_type;
if (preg_match('/corrupt/i', $row->Msg_text)) {
$result[$table_name]['corrupted'] = true;
} else {
$result[$table_name]['message'] = $row->Msg_text;
}
}
if ('status' == $row->Msg_type) {
$result[$table_name]['status'] = $row->Msg_text;
}
}
return $result;
}
/**
* Check all supported for repair tables and return statuses for them.
*
* @return array
*/
public function check_all_tables() {
static $result = null;
if (null !== $result) return $result;
$tables = $this->get_show_table_status();
$supported_tables = array();
foreach ($tables as $table) {
if ('' == $table->Engine || $this->is_table_type_repair_supported($table->Name)) {
$supported_tables[] = $table->Name;
}
}
$result = $this->check_table($supported_tables);
return $result;
}
/**
* Returns true if table needing repair.
*
* @param string $table_name Database table name.
*/
public function is_table_needing_repair($table_name) {
$table_statuses = $this->check_all_tables();
if (!$this->is_table_type_repair_supported($table_name)) return false;
if (is_array($table_statuses) && array_key_exists($table_name, $table_statuses) && $table_statuses[$table_name]['corrupted']) {
return true;
} else {
return false;
}
}
/**
* Check if $table using by any of installed plugins.
*
* @param string $table
* @return bool
*/
public function is_table_using_by_plugin($table) {
$plugin_names = $this->get_table_plugin($table);
// if we can't determine which plugin use $table then return true.
if (false == $plugin_names) {
return true;
}
// is WordPress core table or using by any of installed plugins then return true.
foreach ($plugin_names as $plugin_name) {
if (__('WordPress core', 'wp-optimize') == $plugin_name || in_array($plugin_name, $this->get_all_installed_plugins())) {
return true;
}
}
return false;
}
/**
* Get blog_id
*
* @param string $table_name
* @return int
*/
public function get_table_blog_id($table_name) {
global $wpdb;
if (is_multisite()) {
$blogs_ids = wp_list_pluck(WP_Optimize()->get_sites(), 'blog_id');
// if match with base_prefix_(number)_
if (preg_match('/^'.$wpdb->base_prefix.'(\d+)_/', $table_name, $match)) {
// check if matched number in available sites.
if (false !== array_search($match[1], $blogs_ids)) return $match[1];
}
}
return 1;
}
/**
* Get information about relations between tables and plugins. [ 'table' => ['plugin1', 'plugin2', ...], ... ].
*
* @return array
*/
private function get_all_plugin_tables_relationship() {
static $plugin_tables = array();
if (!empty($plugin_tables)) return $plugin_tables;
$wp_core_tables = array(
'blogs',
'blog_versions',
'commentmeta',
'comments',
'links',
'options',
'postmeta',
'posts',
'registration_log',
'signups',
'term_relationships',
'term_taxonomy',
'termmeta',
'terms',
'usermeta',
'users',
'site',
'sitemeta',
);
$plugin_tables_json_file = $this->get_plugin_json_file_path();
$fallback_plugin_tables_json_file = WPO_PLUGIN_MAIN_PATH.'plugin.json';
if (is_file($plugin_tables_json_file) && is_readable($plugin_tables_json_file)) {
// get data from plugin.json file.
$plugin_tables = json_decode(file_get_contents($plugin_tables_json_file), true);
}
// Fallback to the bundled version if the list is empty
if (empty($plugin_tables)) {
if (is_file($fallback_plugin_tables_json_file) && is_readable($fallback_plugin_tables_json_file)) {
// get data from the bundled plugin.json file.
$plugin_tables = json_decode(file_get_contents($fallback_plugin_tables_json_file), true);
}
}
foreach ($wp_core_tables as $table) {
$plugin_tables[$table][] = __('WordPress core', 'wp-optimize');
}
// add WP-Optimize tables.
$wpo = 'wp-optimize';
if (false === array_search($wpo, $plugin_tables['tm_taskmeta']) && false === array_search($wpo, $plugin_tables['tm_tasks'])) {
$plugin_tables['tm_taskmeta'][] = $wpo;
$plugin_tables['tm_tasks'][] = $wpo;
}
return $plugin_tables;
}
/**
* Try to get plugin name by table name and return it or return false if plugin is not defined.
*
* @param string $table
* @return array|bool - array with plugin slugs or false.
*/
public function get_table_plugin($table) {
global $wpdb;
// delete table prefix.
$table = preg_replace('/^'.$wpdb->prefix.'([0-9]+_)?/', '', $table);
$plugins_tables = $this->get_all_plugin_tables_relationship();
if (array_key_exists($table, $plugins_tables)) {
return $plugins_tables[$table];
}
return false;
}
/**
* Get the path where the updated plugin.json is stored
*
* @return string
*/
private function get_plugin_json_file_path() {
$uploads_dir = wp_upload_dir(null, false);
return apply_filters('wpo_get_plugin_json_file_path', trailingslashit($uploads_dir['basedir']).'wpo-plugins-tables-list.json');
}
/**
* Get all installed plugin slugs.
*
* @return array
*/
public function get_all_installed_plugins() {
static $installed_plugins;
if (is_array($installed_plugins)) return $installed_plugins;
$installed_plugins = array();
if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
$plugins = get_plugins();
foreach ($plugins as $plugin_file => $plugin_data) {
if ('' != $plugin_data['TextDomain']) {
$installed_plugins[] = $plugin_data['TextDomain'];
} else {
$plugin_file_parts = explode('/', $plugin_file);
$installed_plugins[]= $plugin_file_parts[0];
}
}
return $installed_plugins;
}
/**
* Check current plugin status installed/not installed and active/inactive.
*
* @param string $plugin
* @return array - ['installed' => true|false, 'active' => true|false]
*/
public function get_plugin_status($plugin) {
if (!function_exists('get_plugins')) include_once(ABSPATH.'wp-admin/includes/plugin.php');
$plugins = get_plugins();
// return true for wp-optimize without checking.
if ('wp-optimize' == $plugin) {
return array(
'installed' => true,
'active' => true,
);
}
$installed = false;
$active = false;
foreach ($plugins as $plugin_file => $plugin_data) {
$plugin_file_parts = explode('/', $plugin_file);
$plugin_slug = $plugin_file_parts[0];
if ($plugin == $plugin_slug) {
$installed = true;
$active = is_plugin_active($plugin_file);
}
}
return array(
'installed' => $installed,
'active' => $active,
);
}
/**
* Update list in plugin.json, if necessary
*
* @return void
*/
public function update_plugin_json() {
// Add the possibility to turn this off.
if (!apply_filters('wpo_update_plugin_json', true)) return;
$update_request = wp_remote_get('https://plugins.svn.wordpress.org/wp-optimize/trunk/plugin.json', array('timeout' => 3000));
if (200 !== wp_remote_retrieve_response_code($update_request)) return;
$json_content = wp_remote_retrieve_body($update_request);
if (json_decode($json_content)) {
file_put_contents($this->get_plugin_json_file_path(), $json_content);
}
}
/**
* Cache all table rows count
*/
public function wpo_update_record_count() {
global $wpdb;
$tables_info = $wpdb->get_results('SHOW TABLE STATUS');
foreach ($tables_info as $table) {
$rows_count = $wpdb->get_var("SELECT COUNT(*) FROM `$table->Name`");
set_transient('wpo_' . $table->Name . '_count', $rows_count, 24*60*60);
}
}
}

View File

@@ -0,0 +1,295 @@
<?php
/**
* Class WP_Optimize_Gzip_Compression
*/
class WP_Optimize_Gzip_Compression {
/**
* WP_Optimize_Htaccess instance.
*
* @var WP_Optimize_Htaccess
*/
private $_htaccess = null;
/**
* WP_Optimize instance.
*
* @var WP_Optimize
*/
private $_wp_optimize = null;
/**
* Gzip section in htaccess will wrapped with this comment
*
* @var string
*/
private $_htaccess_section_comment = 'WP-Optimize Gzip compression';
/**
* WP_Optimize_Gzip_Compression constructor.
*/
public function __construct() {
$this->_wp_optimize = WP_Optimize();
$this->_htaccess = $this->_wp_optimize->get_htaccess();
}
/**
* Returns singleton instance object
*
* @return WP_Optimize_Gzip_Compression Returns `WP_Optimize_Gzip_Compression` object
*/
public static function instance() {
static $_instance = null;
if (null === $_instance) {
$_instance = new self();
}
return $_instance;
}
/**
* Make http request to theme style.css, get 'server' line and check headers for gzip/brotli encoding option.
*
* @return array|WP_Error
*/
public function get_headers_information() {
static $headers_information;
if (isset($headers_information)) return $headers_information;
$headers = WP_Optimize()->get_stylesheet_headers();
if (is_wp_error($headers)) return $headers;
$headers_information = array(
'server' => array_key_exists('server', $headers) ? $headers['server'] : '',
);
if (array_key_exists('content-encoding', $headers) && preg_match('/^(.*\W|)br(\W.*|)$/i', $headers['content-encoding'])) {
// check if there exists Content-encoding header with br(Brotli) value.
$headers_information['compression'] = 'brotli';
$this->disable();
} elseif (array_key_exists('content-encoding', $headers) && preg_match('/gzip/i', $headers['content-encoding'])) {
// check if there exists Content-encoding header with gzip value.
$headers_information['compression'] = 'gzip';
} else {
$headers_information['compression'] = false;
}
return $headers_information;
}
/**
* Make request to checkgzipcompression.com api and check if gzip option enabled.
*
* @return bool|WP_Error
*/
public function check_api_for_gzip() {
$url = get_template_directory_uri() . '/style.css';
$api_url = 'https://checkgzipcompression.com/js/checkgzip.json?url=' . urlencode($url);
$result = wp_remote_get($api_url, array('timeout' => 10));
if (is_wp_error($result)) return $result;
if (!isset($result['body'])) return new WP_Error('Gzip', __("We can't definitely determine Gzip status as API doesn't return correct answer.", 'wp-optimize'));
$body = json_decode($result['body']);
if (isset($body->error) && $body->error) return new WP_Error('Gzip', __("We can't definitely determine Gzip status as API doesn't return correct answer.", 'wp-optimize'));
if ($body->result->gzipenabled && !$body->error) {
return true;
}
return false;
}
/**
* Check if Gzip compression is enabled.
*
* @param boolean $force_check - force the check
* @return bool|WP_Error
*/
public function is_gzip_compression_enabled($force_check = false) {
if (!$force_check) return WP_Optimize()->get_options()->get_option('is_gzip_compression_enabled');
// trying to get info about gzip in headers.
$headers_info = $this->get_headers_information();
// we can't determine then return WP_Error.
if (is_wp_error($headers_info)) return $headers_info;
$is_gzip_compression_enabled = $headers_info['compression'];
// if we got error then trying to get info from api otherwise get result from check_headers_for_gzip().
// $is_gzip_compression_enabled = is_wp_error($is_gzip_compression_enabled) ? $this->check_api_for_gzip() : $is_gzip_compression_enabled;
// if Gzip is not enabled but we have added settings and Apache modules nt loaded then return error.
if (false == $is_gzip_compression_enabled && $this->is_gzip_compression_section_exists()) {
if (false === $this->_wp_optimize->is_apache_module_loaded(array('mod_filter', 'mod_deflate'))) {
return new WP_Error('gzip_missing_module', __('We successfully added Gzip compression settings into .htaccess file.', 'wp-optimize').' '.__('However, the test file we fetched was not Gzip-compressed.', 'wp-optimize').' '.__('It seems one of Apache modules - mod_filter or mod_deflate - is not active.', 'wp-optimize'));
} elseif (WP_Optimize()->is_apache_server()) {
return new WP_Error('gzip_missing_module', __('We successfully added Gzip compression settings into .htaccess file.', 'wp-optimize').' '.__('However, the test file we fetched was not Gzip-compressed.', 'wp-optimize').' '.__('Possible causes include that Apache (your webserver) is not configured to allow .htaccess files to take effect, or one of Apache modules - mod_filter or mod_deflate - is not active, or the webserver is configured to disallow Gzip compression.', 'wp-optimize').' '.__('You should speak to your web hosting support to find how to enable it.', 'wp-optimize'));
} else {
return new WP_Error('gzip_unsuccessful', __('We successfully added Gzip compression settings into .htaccess file.', 'wp-optimize').' '.__('However, the test file we fetched was not Gzip-compressed.', 'wp-optimize').' '.__('You should speak to your web hosting support to find how to enable it.', 'wp-optimize'));
}
}
WP_Optimize()->get_options()->update_option('is_gzip_compression_enabled', $is_gzip_compression_enabled);
return $is_gzip_compression_enabled;
}
/**
* Check if section with Gzip options already exists in htaccess file.
*
* @return bool
*/
public function is_gzip_compression_section_exists() {
return $this->_htaccess->is_commented_section_exists($this->_htaccess_section_comment);
}
/**
* Enable Gzip compression - add settings into .htaccess.
*/
public function enable() {
$this->_htaccess->update_commented_section($this->prepare_gzip_section(), $this->_htaccess_section_comment);
$this->_htaccess->write_file();
}
/**
* Disable Gzip compression - remove settings from .htaccess.
*/
public function disable() {
$this->_htaccess->remove_commented_section($this->_htaccess_section_comment);
$this->_htaccess->write_file();
}
/**
* Check if gzip compression option is set to true then add section with gzip settings into .htaccess (used when plugin being activated).
*/
public function restore() {
$enabled = WP_Optimize()->get_options()->get_option('is_gzip_compression_enabled');
if ($enabled && $this->_htaccess->is_writable()) $this->enable();
}
/**
* Handler for Gzip compression enable command, called from WP_Optimize_Commands.
*
* @param array $params - ['enable' => true|false]
* @return array
*/
public function enable_gzip_command_handler($params) {
$section_updated = false;
$enable = (isset($params['enable']) && $params['enable']) ? true : false;
if ($this->_htaccess->is_writable()) {
// update commented section
if ($enable) {
$this->enable();
} else {
$this->disable();
}
// read updated file.
$this->_htaccess->read_file();
// check if section added or removed successfully.
$section_exists = $this->_htaccess->is_commented_section_exists($this->_htaccess_section_comment);
// set correct $section-updated flag.
$section_updated = $enable === $section_exists;
}
$is_gzip_compression_enabled = $this->is_gzip_compression_enabled(true);
if ($section_updated) {
return array(
'success' => true,
'enabled' => is_wp_error($is_gzip_compression_enabled) ? false : $is_gzip_compression_enabled,
// if we can't determine gzip status then return error message.
'message' => is_wp_error($is_gzip_compression_enabled) ? $is_gzip_compression_enabled->get_error_message() : '',
);
} else {
$gzip_section = $this->prepare_gzip_section();
if ($is_gzip_compression_enabled) {
$message = sprintf(__('We can\'t update your %s file. Please try to remove following lines manually:', 'wp-optimize'), $this->_htaccess->get_filename());
} else {
$message = sprintf(__('We can\'t update your %s file. Please try to add following lines manually:', 'wp-optimize'), $this->_htaccess->get_filename());
}
return array(
'success' => false,
'enabled' => is_wp_error($is_gzip_compression_enabled) ? false : $is_gzip_compression_enabled,
'message' => $message,
'output' =>
htmlentities($this->_htaccess->get_section_begin_comment($this->_htaccess_section_comment).PHP_EOL.
join(PHP_EOL, $this->_htaccess->get_flat_array($gzip_section)).
PHP_EOL.$this->_htaccess->get_section_end_comment($this->_htaccess_section_comment)),
);
}
}
/**
* Prepare array with options to switch on gzip in htaccess.
*
* @return array
*/
private function prepare_gzip_section() {
return array(
array(
'<IfModule mod_filter.c>',
array(
'<IfModule mod_deflate.c>',
'# Compress HTML, CSS, JavaScript, Text, XML and fonts',
'AddType application/vnd.ms-fontobject .eot',
'AddType font/ttf .ttf',
'AddType font/otf .otf',
'AddType font/x-woff .woff',
'AddType image/svg+xml .svg',
'',
'AddOutputFilterByType DEFLATE application/javascript',
'AddOutputFilterByType DEFLATE application/rss+xml',
'AddOutputFilterByType DEFLATE application/vnd.ms-fontobject',
'AddOutputFilterByType DEFLATE application/x-font',
'AddOutputFilterByType DEFLATE application/x-font-opentype',
'AddOutputFilterByType DEFLATE application/x-font-otf',
'AddOutputFilterByType DEFLATE application/x-font-truetype',
'AddOutputFilterByType DEFLATE application/x-font-ttf',
'AddOutputFilterByType DEFLATE application/x-font-woff',
'AddOutputFilterByType DEFLATE application/x-javascript',
'AddOutputFilterByType DEFLATE application/xhtml+xml',
'AddOutputFilterByType DEFLATE application/xml',
'AddOutputFilterByType DEFLATE font/opentype',
'AddOutputFilterByType DEFLATE font/otf',
'AddOutputFilterByType DEFLATE font/ttf',
'AddOutputFilterByType DEFLATE font/woff',
'AddOutputFilterByType DEFLATE image/svg+xml',
'AddOutputFilterByType DEFLATE image/x-icon',
'AddOutputFilterByType DEFLATE text/css',
'AddOutputFilterByType DEFLATE text/html',
'AddOutputFilterByType DEFLATE text/javascript',
'AddOutputFilterByType DEFLATE text/plain',
'AddOutputFilterByType DEFLATE text/xml',
'',
'# Remove browser bugs (only needed for really old browsers)',
'BrowserMatch ^Mozilla/4 gzip-only-text/html',
'BrowserMatch ^Mozilla/4\.0[678] no-gzip',
'BrowserMatch \bMSIE !no-gzip !gzip-only-text/html',
array(
'<IfModule mod_headers.c>',
'Header append Vary User-Agent',
'</IfModule>',
),
'</IfModule>',
),
'</IfModule>',
),
);
}
}

View File

@@ -0,0 +1,337 @@
<?php
if (!defined('WPO_VERSION')) die('No direct access allowed');
class WP_Optimize_Htaccess {
/**
* Full path to .htaccess file.
*
* @var string
*/
private $_htaccess_file = '';
/**
* Structured content of .htaccess file.
*
* @var array
*/
private $_file_tree = array();
/**
* WP_Optimize_Htaccess constructor.
*
* @param string $htaccess_file Full path to .htaccess file.
*/
public function __construct($htaccess_file = '') {
$this->_htaccess_file = ('' != $htaccess_file) ? $htaccess_file : $this->get_home_path() . '.htaccess';
// read .htaccess content into $_file_tree.
$this->read_file();
}
/**
* Returns .htaccess filename.
*
* @return string
*/
public function get_filename() {
return $this->_htaccess_file;
}
/**
* Checks if .htaccess file exists.
*
* @return bool
*/
public function is_exists() {
return is_file($this->_htaccess_file);
}
/**
* Checks if .htaccess file is readaable.
*
* @return bool
*/
public function is_readable() {
return is_readable($this->_htaccess_file);
}
/**
* Checks if .htaccess file is writable.
*
* @return bool
*/
public function is_writable() {
return is_writable($this->_htaccess_file);
}
/**
* Read content of .htaccess file and store it as a tree in $_file_tree variable.
* For ex.
* [0] => '# BEGIN WordPress',
* [1] => [
* [0] => '<IfModule mod_rewrite.c>',
* [1] => 'RewriteEngine On',
* [2] => 'RewriteBase /',
* [3] => 'RewriteRule ^index\.php$ - [L]',
* [4] => 'RewriteCond %{REQUEST_FILENAME} !-f',
* [5] => 'RewriteCond %{REQUEST_FILENAME} !-d',
* [6] => 'RewriteRule . /index.php [L]',
* [7] => '</IfModule>',
* [2] => '# END WordPress'
*
* @return void
*/
public function read_file() {
if (false == $this->is_exists() || false == $this->is_readable()) return;
$content = file_get_contents($this->_htaccess_file);
$content = explode("\n", $content);
$content_tree = array();
$section = array();
$sections = array();
foreach ($content as $line) {
$line = trim($line);
if (preg_match("/^\<\/(.+)(\s.*)?\>/", $line, $matches)) {
$section[] = $line;
// close section
if (!empty($sections)) {
$_section = $section;
$section = array_pop($sections);
$section[] = $_section;
} else {
$content_tree[] = $section;
$section = array();
}
} elseif (preg_match('/^\<(.+)>/', $line, $matches)) {
// open section
if (!empty($section)) {
$sections[] = $section;
}
$section = array();
$section[] = $line;
} elseif (!empty($section)) {
$section[] = $line;
} else {
$content_tree[] = $line;
}
}
$this->_file_tree = $content_tree;
}
/**
* Write current $_file_tree content into .htaccess file.
*/
public function write_file() {
$content = implode(PHP_EOL, $this->get_flat_array($this->_file_tree));
if ($this->is_writable()) {
file_put_contents($this->_htaccess_file, $content);
}
}
/**
* Recursive function used to prepare data for output - build flat array from $_file_tree.
*
* @param array $array
* @param string $prefix
*
* @return array
*/
public function get_flat_array($array, $prefix = '') {
$flat_array = array();
if (!empty($array)) {
foreach ($array as $item) {
if (is_array($item)) {
$item = $this->get_flat_array($item, "\t");
$flat_array = array_merge($flat_array, $item);
} else {
$flat_array[] = $item;
}
}
}
reset($flat_array);
$first = key($flat_array);
end($flat_array);
$last = key($flat_array);
foreach ($flat_array as $key => $value) {
if ('' != $value && '#' == $value[0]) {
// never add prefix for comment lines.
$flat_array[$key] = $value;
} else {
$flat_array[$key] = ($key == $first || $key == $last) ? $value : $prefix . $value;
}
}
return $flat_array;
}
/**
* Update commented section in array $_file_tree, i.e. section wrapped with comments
* # BEGIN WP-Optimize Browser Cache
* ...
* # END WP-Optimize Browser Cache
*
* @param array $content
* @param string $section
*/
public function update_commented_section($content, $section = 'WP-Optimize Browser Cache') {
$section_begin = $this->get_section_begin_comment($section);
$section_end = $this->get_section_end_comment($section);
// add begin-end section comments.
array_unshift($content, $section_begin);
array_push($content, $section_end);
$section_index = $this->search_commented_section($section);
// check if section with cache settings already in the file.
if (false === $section_index) {
// no section in file then add it to the end of file.
$this->_file_tree = array_merge($this->_file_tree, $content);
} else {
$remove_length = (false === $section_index['end']) ? null : ($section_index['end'] - $section_index['begin'] + 1);
array_splice($this->_file_tree, $section_index['begin'], $remove_length, $content);
}
}
/**
* Removes commented section in $_file_tree, i.e. section wrapped with comments
* # BEGIN WP-Optimize Browser Cache
* ...
* # END WP-Optimize Browser Cache
*
* @param string $comment
*
* @return bool
*/
public function remove_commented_section($comment = 'WP-Optimize Browser Cache') {
$section_index = $this->search_commented_section($comment);
if (false === $section_index) return false;
$remove_length = (false === $section_index['end']) ? null : ($section_index['end'] - $section_index['begin'] + 1);
array_splice($this->_file_tree, $section_index['begin'], $remove_length);
$this->_file_tree = array_values($this->_file_tree);
return true;
}
/**
* Check if section exists wrapped by comments like
*
* # BEGIN WP-Optimize Browser Cache
* ...
* # END WP-Optimize Browser Cache
*
* @param string $section
* @return bool
*/
public function is_commented_section_exists($section = 'WP-Optimize Browser Cache') {
$search = $this->search_commented_section($section);
return (false === $search) ? false : true;
}
/**
* Search section in $_file_tree array wrapped by begin and end comments.
*
* @param string $section
* @return array|bool
*/
private function search_commented_section($section) {
$section_begin = $this->get_section_begin_comment($section);
$section_end = $this->get_section_end_comment($section);
$section_begin_index = $section_end_index = false;
$section_begin_normalized = $this->normalize_string($section_begin);
$section_end_normalized = $this->normalize_string($section_end);
foreach ($this->_file_tree as $i => $value) {
// if it is subsection then we don't go in deep.
if (is_array($value)) continue;
$value = $this->normalize_string($value);
if ($value == $section_begin_normalized) $section_begin_index = $i;
if ($value == $section_end_normalized) $section_end_index = $i;
}
if (false == $section_begin_index) {
return false;
} else {
return array(
'begin' => $section_begin_index,
'end' => $section_end_index,
);
}
}
/**
* Generate begin cache section comment.
*
* @param string $section
* @return string
*/
public function get_section_begin_comment($section = 'WP-Optimize Browser Cache') {
return '# BEGIN ' . $section;
}
/**
* Generate end cache section comment.
*
* @param string $section
* @return string
*/
public function get_section_end_comment($section = 'WP-Optimize Browser Cache') {
return '# END ' . $section;
}
/**
* Normalize string - make all letters lowercase and remove spaces.
*
* @param string $string
* @return string
*/
private function normalize_string($string) {
return strtolower(str_replace(array("\n", "\r", ' '), '', $string));
}
/**
* Get the absolute filesystem path to the root of the WordPress installation.
* WP_Core function from wp-admin/includes/file.php.
*
* @since 1.5.0
*
* @return string Full filesystem path to the root of the WordPress installation
*/
private function get_home_path() {
if (function_exists('get_home_path')) {
return get_home_path();
}
$home = set_url_scheme(get_option('home'), 'http');
$siteurl = set_url_scheme(get_option('siteurl'), 'http');
if (!empty($home) && 0 !== strcasecmp($home, $siteurl)) {
$wp_path_rel_to_home = str_ireplace($home, '', $siteurl); /* $siteurl - $home */
$pos = strripos(str_replace('\\', '/', $_SERVER['SCRIPT_FILENAME']), trailingslashit($wp_path_rel_to_home));
$home_path = substr($_SERVER['SCRIPT_FILENAME'], 0, $pos);
$home_path = trailingslashit($home_path);
} else {
$home_path = ABSPATH;
}
return str_replace('\\', '/', $home_path);
}
}

View File

@@ -0,0 +1,121 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
/**
* Install or update notice
* Manages the notice shown when the user activates or updates WPO
*
* The class is included during `admin_init`
*/
class WP_Optimize_Install_Or_Update_Notice {
/**
* Notice Version.
* If we need to later show a similar notice with a different content,
* We can reuse this by changing the version number and updating the content in the template file.
*
* @var string
*/
private $version = '1.1';
/**
* Options object
*
* @var WP_Optimize_Options
*/
protected $options;
public function __construct() {
$this->options = WP_Optimize()->get_options();
if ($this->show_current_notice()) {
add_action('wpo_admin_after_header', array($this, 'output_notice'), 20);
}
}
/**
* Determines if the current notice was shown
*
* @return boolean
*/
public function show_current_notice() {
// Check the option
$latest_saved_notice = $this->options->get_option('install-or-update-notice-version', false);
if ($latest_saved_notice && version_compare($latest_saved_notice, $this->version, '>=')) {
return false;
}
$notice_show_time = $this->options->get_option('install-or-update-notice-show-time', false);
// If notice has been showing for more than 14days, automatically dismiss it.
if ($notice_show_time && (time() - $notice_show_time) > (14 * 86400)) {
$this->dismiss();
return false;
}
if (!$notice_show_time) {
// Save the first time the notice was shown
$this->options->update_option('install-or-update-notice-show-time', time());
}
return true;
}
/**
* Outputs the notice
*
* @return void
*/
public function output_notice() {
WP_Optimize()->include_template('notices/install-or-update-notice.php', false, array(
'is_new_install' => $this->is_new_install(),
'is_premium' => WP_Optimize::is_premium(),
'is_updraftplus_installed' => $this->is_updraftplus_installed()
));
}
/**
* Attempts to find out if WPO was newly installed or updated
*
* @return boolean
*/
private function is_new_install() {
if ($this->options->get_option('newly-activated', false)) {
return true;
}
return false;
}
/**
* Dismiss the notice
*
* @return boolean
*/
public function dismiss() {
if ($this->is_new_install()) {
$this->options->delete_option('newly-activated');
}
if (!$this->options->update_option('install-or-update-notice-version', $this->version)) {
return false;
}
// Delete Notice show time option, to allow re-creating next time we need to show it.
$this->options->delete_option('install-or-update-notice-show-time');
return true;
}
/**
* Check if updraftplus is installed.
*
* @return bool
*/
private function is_updraftplus_installed() {
$status = WP_Optimize()->get_db_info()->get_plugin_status('updraftplus');
return $status['installed'];
}
}

View File

@@ -0,0 +1,399 @@
<?php
if (!defined('WPO_PLUGIN_MAIN_PATH')) die('No direct access allowed');
if (!class_exists('Updraft_Notices_1_2')) require_once(WPO_PLUGIN_MAIN_PATH.'/vendor/team-updraft/common-libs/src/updraft-notices/updraft-notices.php');
class WP_Optimize_Notices extends Updraft_Notices_1_2 {
private $initialized = false;
protected $self_affiliate_id = 216;
protected $notices_content = array();
/**
* Returns singleton instance object
*
* @return WP_Optimize_Notices Returns `WP_Optimize_Notices` object
*/
public static function instance() {
static $_instance = null;
if (null === $_instance) {
$_instance = new self();
}
return $_instance;
}
/**
* This method gets any parent notices and adds its own notices to the notice array
*
* @return Array returns an array of notices
*/
protected function populate_notices_content() {
$parent_notice_content = parent::populate_notices_content();
$sale_description = __('Make your site even faster with Premium.', 'wp-optimize') . ' ';
$sale_description .= __('Identify orphaned images, load webpages faster and get premium support.', 'wp-optimize') . ' ';
$sale_description .= __('Get advanced options, like the ability to optimize your site using WP-CLI.', 'wp-optimize') . ' ';
$sale_description .= __('Premium is compatible with WordPress multisite, WooCommerce and other add-ons, including multilingual and multi-currency WordPress plugins.', 'wp-optimize');
$checkout_html = '<a class="updraft_notice_link" href="https://getwpo.com/buy/">'.__('checkout', 'wp-optimize').'</a>';
$child_notice_content = array(
'updraftplus' => array(
'prefix' => '',
'title' => __('Make sure you backup before you optimize your database', 'wp-optimize'),
'text' => __("UpdraftPlus is the world's most trusted backup plugin from the owners of WP-Optimize", 'wp-optimize'),
'image' => 'notices/updraft_logo.png',
'button_link' => 'https://wordpress.org/plugins/updraftplus/',
'button_meta' => 'updraftplus',
'dismiss_time' => 'dismiss_page_notice_until',
'supported_positions' => $this->dashboard_top_or_report,
'validity_function' => 'is_updraftplus_installed',
),
'updraftcentral' => array(
'prefix' => '',
'title' => __('Save Time and Money. Manage multiple WordPress sites from one location.', 'wp-optimize'),
'text' => __('UpdraftCentral is a highly efficient way to take backup, update and manage multiple WP sites from one location.', 'wp-optimize'),
'image' => 'notices/updraft_logo.png',
'button_link' => 'https://updraftcentral.com',
'button_meta' => 'updraftcentral',
'dismiss_time' => 'dismiss_page_notice_until',
'supported_positions' => $this->dashboard_top_or_report,
'validity_function' => 'is_updraftcentral_installed',
),
'rate_plugin' => array(
'text' => __("Hey - We noticed WP-Optimize has kept your site running fast for a while. If you like us, please consider leaving a positive review to spread the word. Or if you have any issues or questions please leave us a support message", 'wp-optimize') . ' <a href="https://wordpress.org/support/plugin/wp-optimize/" target="_blank">' . __('here', 'wp-optimize') . '.</a><br>' . __('Thank you so much!', 'wp-optimize') . ' - <b>WP-Optimize</b><br>',
'image' => 'notices/ud_smile.png',
'button_link' => 'https://wordpress.org/support/plugin/wp-optimize/reviews/?rate=5#new-post',
'button_meta' => 'review',
'dismiss_time' => 'dismiss_review_notice',
'supported_positions' => $this->dashboard_top,
'validity_function' => 'show_rate_notice'
),
'translation_needed' => array(
'prefix' => '',
'title' => 'Can you translate? Want to improve WP-Optimize for speakers of your language?',
'text' => $this->url_start(true, 'translate.wordpress.org/projects/wp-plugins/wp-optimize')."Please go here for instructions - it is easy.".$this->url_end(true, 'translate.wordpress.org/projects/wp-plugins/wp-optimize'),
'text_plain' => $this->url_start(false, 'translate.wordpress.org/projects/wp-plugins/wp-optimize')."Please go here for instructions - it is easy.".$this->url_end(false, 'translate.wordpress.org/projects/wp-plugins/wp-optimize'),
'image' => 'notices/wp_optimize_logo.png',
'button_link' => false,
'dismiss_time' => false,
'supported_positions' => $this->anywhere,
'validity_function' => 'translation_needed',
),
'wpo-premium' => array(
'prefix' => '',
'title' => __("Perform optimizations while your visitors sleep", "wp-optimize"),
'text' => __("WP-Optimize Premium features an advanced scheduling system that allows you to run optimizations at the quietest time of day (or night).", "wp-optimize"),
'image' => 'notices/wp_optimize_logo.png',
'button_link' => 'https://getwpo.com',
'button_meta' => 'wpo-premium',
'dismiss_time' => 'dismiss_notice',
'supported_positions' => $this->anywhere,
'validity_function' => 'is_wpo_premium_installed',
),
'wpo-premium-multisite' => array(
'prefix' => '',
'title' => __("Manage a multisite installation? Need extra control?", "wp-optimize"),
'text' => __("WP-Optimize Premium's multisite feature includes a locking system that restricts optimization commands to users with the right permissions.", "wp-optimize"),
'image' => 'notices/wp_optimize_logo.png',
'button_link' => 'https://getwpo.com',
'button_meta' => 'wpo-premium',
'dismiss_time' => 'dismiss_notice',
'supported_positions' => $this->anywhere,
'validity_function' => 'is_wpo_premium_installed',
),
'wpo-premium2' => array(
'prefix' => '',
'title' => __("WP-Optimize Premium offers unparalleled choice and flexibility", "wp-optimize"),
'text' => __("Upgrade today to combine over a dozen optimization options.", "wp-optimize"),
'image' => 'notices/wp_optimize_logo.png',
'button_link' => 'https://getwpo.com',
'button_meta' => 'wpo-premium',
'dismiss_time' => 'dismiss_notice',
'supported_positions' => $this->anywhere,
'validity_function' => 'is_wpo_premium_installed',
),
'wpo-premium3' => array(
'prefix' => '',
'title' => __("Remove unwanted images for better site performance.", "wp-optimize"),
'text' => __("WP-Optimize Premium comes with a feature to easily remove orphaned images, or images that exceed a certain size from your website.", "wp-optimize"),
'image' => 'notices/wp_optimize_logo.png',
'button_link' => 'https://getwpo.com',
'button_meta' => 'wpo-premium',
'dismiss_time' => 'dismiss_notice',
'supported_positions' => $this->anywhere,
'validity_function' => 'is_wpo_premium_installed',
),
'wpo-power-tweaks' => array(
'prefix' => '',
'title' => __("Power tweaks for advanced users and better site performance.", "wp-optimize"),
'text' => __("WP-Optimize Premium comes with the power tweaks that will enable you to improve performance by targeting specific weak points, either in WordPress Core, or in popular plugins.", "wp-optimize"),
'image' => 'notices/wp_optimize_logo.png',
'button_link' => 'https://getwpo.com/faqs/#Power-tweaks-2-',
'button_meta' => 'wpo-premium',
'dismiss_time' => 'dismiss_notice',
'supported_positions' => $this->anywhere,
'validity_function' => 'is_wpo_premium_installed',
),
'subscriben' => array(
'prefix' => '',
'title' => 'Subscriben ' .__('by', 'wp-optimize'). ' UpdraftPlus',
'text' => __("The WordPress subscription extension for WooCommerce store owners.", "wp-optimize"),
'image' => 'notices/subscriben.png',
'button_link' => 'https://subscribenplugin.com',
'button_meta' => 'read_more',
'dismiss_time' => 'dismiss_notice',
'supported_positions' => $this->anywhere,
),
// The sale adverts content starts here
'blackfriday' => array(
'prefix' => '',
'title' => __('Black Friday Sale', 'wp-optimize'),
'text' => $sale_description . '<br>' . sprintf(__('Get 20%% off with code %s at %s. Hurry, offer ends 28th November.', 'wp-optimize'), '<b>blackfridaysale2023</b>', $checkout_html),
'image' => 'notices/black_friday.png',
'button_link' => 'https://getwpo.com',
// 'button_meta' => 'wp-optimize',
'dismiss_time' => 'dismiss_season',
// 'discount_code' => 'blackfridaysale2022',
'valid_from' => '2023-11-20 00:00:00',
'valid_to' => '2023-11-28 23:59:59',
'supported_positions' => $this->dashboard_top_or_report,
'validity_function' => 'is_wpo_premium_installed',
),
'newyear' => array(
'prefix' => '',
'title' => __('New Year Sale', 'wp-optimize'),
'text' => $sale_description . '<br>' . sprintf(__('Get 20%% off. Use code %s at %s. Hurry, offer ends 14th January.', 'wp-optimize'), '<b>newyearsale2024</b>', $checkout_html),
'image' => 'notices/new_year.png',
'button_link' => 'https://getwpo.com',
// 'button_meta' => 'wp-optimize',
'dismiss_time' => 'dismiss_season',
// 'discount_code' => 'newyearsale2023',
'valid_from' => '2023-12-26 00:00:00',
'valid_to' => '2024-01-14 23:59:59',
'supported_positions' => $this->dashboard_top_or_report,
'validity_function' => 'is_wpo_premium_installed',
),
'spring' => array(
'prefix' => '',
'title' => __('Spring Sale', 'wp-optimize'),
'text' => $sale_description . '<br>' . sprintf(__('Get 20%% off. Use code %s at %s. Hurry, offer ends 31st May.', 'wp-optimize'), '<b>springsale2023</b>', $checkout_html),
'image' => 'notices/spring.png',
'button_link' => 'https://getwpo.com',
// 'button_meta' => 'wp-optimize',
'dismiss_time' => 'dismiss_season',
// 'discount_code' => 'springsale2022',
'valid_from' => '2023-05-01 00:00:00',
'valid_to' => '2023-05-31 23:59:59',
'supported_positions' => $this->dashboard_top_or_report,
'validity_function' => 'is_wpo_premium_installed',
),
'summer' => array(
'prefix' => '',
'title' => __('Summer Sale', 'wp-optimize'),
'text' => $sale_description . '<br>' . sprintf(__('Get 20%% off. Use code %s at %s. Hurry, offer ends 31st July.', 'wp-optimize'), '<b>summersale2023</b>', $checkout_html),
'image' => 'notices/summer.png',
'button_link' => 'https://getwpo.com',
// 'button_meta' => 'wp-optimize',
'dismiss_time' => 'dismiss_season',
// 'discount_code' => 'summersale2022',
'valid_from' => '2023-07-01 00:00:00',
'valid_to' => '2023-07-31 23:59:59',
'supported_positions' => $this->dashboard_top_or_report,
'validity_function' => 'is_wpo_premium_installed',
),
'collection' => array(
'prefix' => '',
'title' => __('The UpdraftPlus Plugin Collection Sale', 'wp-optimize'),
'text' => sprintf(__('Visit any of our websites and use code %s at the checkout to get 20%% off all our plugins. Be quick, offer ends 30th September. ', 'wp-optimize'), '<b>WPO2023</b>'),
'image' => 'notices/wp_optimize_logo.png',
'button_link' => 'https://teamupdraft.com',
'campaign' => 'collection',
'button_meta' => 'collection',
'dismiss_time' => 'dismiss_season',
// 'discount_code' => 'WPO2022',
'valid_from' => '2023-09-01 00:00:00',
'valid_to' => '2023-09-30 23:59:59',
'supported_positions' => $this->dashboard_top_or_report,
)
);
return array_merge($parent_notice_content, $child_notice_content);
}
/**
* Call this method to setup the notices
*/
public function notices_init() {
if ($this->initialized) return;
$this->initialized = true;
$this->notices_content = (defined('WP_OPTIMIZE_NOADS_B') && WP_OPTIMIZE_NOADS_B) ? array() : $this->populate_notices_content();
}
/**
* This method will call the parent is_plugin_installed and pass in the product updraftplus to check if that plugin is installed if it is then we shouldn't display the notice
*
* @param string $product the plugin slug
* @param boolean $also_require_active a bool to indicate if the plugin should also be active
* @return boolean a bool to indicate if the notice should be displayed or not
*/
protected function is_updraftplus_installed($product = 'updraftplus', $also_require_active = false) {
return parent::is_plugin_installed($product, $also_require_active);
}
/**
* This method will call the parent is_plugin_installed and pass in the product updraftcentral to check if that plugin is installed if it is then we shouldn't display the notice
*
* @param string $product the plugin slug
* @param boolean $also_require_active a bool to indicate if the plugin should also be active
* @return boolean a bool to indicate if the notice should be displayed or not
*/
protected function is_updraftcentral_installed($product = 'updraftcentral', $also_require_active = false) {
return parent::is_plugin_installed($product, $also_require_active);
}
/**
* This method will call the is premium function in the WPO object to check if this install is premium and if it is we won't display the notice
*
* @return boolean a bool to indicate if we should display the notice or not
*/
protected function is_wpo_premium_installed() {
if (WP_Optimize::is_premium()) {
return false;
}
return true;
}
/**
* This method will check to see if a number of different backup plugins are installed and if they are we won't display the notice
*
* @param String $product the plugin slug
* @param boolean $also_require_active a bool to indicate if the plugin should be active or not
* @return boolean a bool to indicate if the notice should be displayed or not
*/
public function is_backup_plugin_installed($product = null, $also_require_active = false) {
$backup_plugins = array('updraftplus' => 'UpdraftPlus', 'backwpup' => 'BackWPup', 'backupwordpress' => 'BackupWordPress', 'vaultpress' => 'VaultPress', 'wp-db-backup' => 'WP-DB-Backup', 'backupbuddy' => 'BackupBuddy');
foreach ($backup_plugins as $slug => $title) {
if (!parent::is_plugin_installed($slug, $also_require_active)) {
return $title;
}
}
return apply_filters('wp_optimize_is_backup_plugin_installed', false);
}
/**
* This function will check if we should display the rate notice or not
*
* @return boolean - to indicate if we should show the notice or not
*/
protected function show_rate_notice() {
$options = WP_Optimize()->get_options();
$installed = $options->get_option('installed-for', 0);
$installed_for = time() - $installed;
if ($installed && $installed_for > 28*86400) {
return true;
}
return false;
}
/**
* This method calls the parent verson and will work out if the user is using a non english language and if so returns true so that they can see the translation advert.
*
* @param String $plugin_base_dir the plugin base directory
* @param String $product_name the name of the plugin
* @return Boolean returns true if the user is using a non english language and could translate otherwise false
*/
protected function translation_needed($plugin_base_dir = null, $product_name = null) {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
return parent::translation_needed(WPO_PLUGIN_MAIN_PATH, 'wp-optimize');
}
/**
* This method is used to generate the correct URL output for the start of the URL
*
* @param Boolean $html_allowed a boolean value to indicate if HTML can be used or not
* @param String $url the url to use
* @param Boolean $https a boolean value to indicate if https should be used or not
* @param String $website_home a string to be displayed
* @return String returns a string of the completed url
*/
protected function url_start($html_allowed, $url, $https = false, $website_home = 'getwpo.com') {
return parent::url_start($html_allowed, $url, $https, $website_home);
}
/**
* This method checks to see if the notices dismiss_time parameter has been dismissed
*
* @param String $dismiss_time a string containing the dimiss time ID
* @return Boolean returns true if the notice has been dismissed and shouldn't be shown otherwise display it
*/
protected function check_notice_dismissed($dismiss_time) {
$time_now = (defined('WP_OPTIMIZE_NOTICES_FORCE_TIME') ? WP_OPTIMIZE_NOTICES_FORCE_TIME : time());
$options = WP_Optimize()->get_options();
$notice_dismiss = ($time_now < $options->get_option($dismiss_time, 0));
return $notice_dismiss;
}
/**
* Check notice data for seasonal info and return true if we should display this notice.
*
* @param array $notice_data
* @return bool
*/
protected function skip_seasonal_notices($notice_data) {
$time_now = defined('WPO_NOTICES_FORCE_TIME') ? WPO_NOTICES_FORCE_TIME : time();
// Do not show seasonal notices in Premium version.
if (false === WP_Optimize::is_premium()) {
$valid_from = strtotime($notice_data['valid_from']);
$valid_to = strtotime($notice_data['valid_to']);
$dismiss = $this->check_notice_dismissed($notice_data['dismiss_time']);
if (($time_now >= $valid_from && $time_now <= $valid_to) && !$dismiss) {
// return true so that we return this notice to be displayed
return true;
}
}
return false;
}
/**
* This method will create the chosen notice and the template to use and depending on the parameters either echo it to the page or return it
*
* @param Array $advert_information an array with the notice information in
* @param Boolean $return_instead_of_echo a bool value to indicate if the notice should be printed to page or returned
* @param String $position a string to indicate what template should be used
* @return String a notice to display
*/
protected function render_specified_notice($advert_information, $return_instead_of_echo = false, $position = 'top') {
if ('bottom' == $position) {
$template_file = 'bottom-notice.php';
} elseif ('report' == $position) {
$template_file = 'report.php';
} elseif ('report-plain' == $position) {
$template_file = 'report-plain.php';
} else {
$template_file = 'horizontal-notice.php';
}
$extract_variables = array_merge($advert_information, array('wp_optimize_notices' => $this));
return WP_Optimize()->include_template('notices/'.$template_file, $return_instead_of_echo, $extract_variables);
}
}
$GLOBALS['wp_optimize_notices'] = WP_Optimize_Notices::instance();

View File

@@ -0,0 +1,502 @@
<?php
if (!defined('WPO_VERSION')) die('No direct access allowed');
/**
* The proper way to obtain access to the instance is via WP_Optimize()->get_options().
*/
class WP_Optimize_Options {
/**
* Returns singleton instance object
*
* @return WP_Optimize_Options Returns `WP_Optimize_Options` object
*/
public static function instance() {
static $_instance = null;
if (null === $_instance) {
$_instance = new self();
}
return $_instance;
}
public $default_settings = array(
'settings' => '',
'schedule' => 'false',
'schedule-type' => 'wpo_weekly',
'retention-enabled' => 'false',
'retention-period' => '',
'enable-admin-menu' => 'false',
'enable_cache_in_admin_bar' => true,
'trackbacks_action' => array(),
'comments_action' => array(),
'auto' => '',
'logging' => '',
'logging-additional' => '',
);
/**
* Returns url to WP-Optimize admin dashboard.
*
* @return string
*/
public function admin_page_url($page = 'WP-Optimize') {
if (is_multisite()) {
return network_admin_url('admin.php?page='.$page);
} else {
return admin_url('admin.php?page='.$page);
}
}
/**
* Returns WP-Optimize option value.
*
* @param string $option Option name.
* @param bool $default
* @return mixed|void
*/
public function get_option($option, $default = false) {
if (is_multisite()) {
$blog_changed = false;
// make sure that we are on main blog.
if (!is_main_site()) {
// get main blog is
if (function_exists('get_network')) {
$main_blog_id = get_network()->site_id;
} else {
global $current_site;
$main_blog_id = $current_site->blog_id;
}
$blog_changed = true;
switch_to_blog($main_blog_id);
}
// check option value for old plugin versions.
$old_version_option_value = get_option('wp-optimize-'.$option, null);
// if blog was changed.
if ($blog_changed) restore_current_blog();
// check option value for new plugin versions.
$new_version_option_value = get_site_option('wp-optimize-mu-'.$option, null);
// if it is exists old version value and doesn't exists new version option then return value.
if (null !== $old_version_option_value && null === $new_version_option_value) return $old_version_option_value;
return get_site_option('wp-optimize-mu-'.$option, $default);
} else {
return get_option('wp-optimize-'.$option, $default);
}
}
/**
* Update WP-Optimize option value.
*
* @param string $option Option name.
* @param mixed $value Option value.
* @return bool
*/
public function update_option($option, $value) {
if (is_multisite()) {
return update_site_option('wp-optimize-mu-'.$option, $value);
} else {
return update_option('wp-optimize-'.$option, $value);
}
}
/**
* Delete WP-Optimize.
*
* @param string $option Option name.
*/
public function delete_option($option) {
if (is_multisite()) {
delete_site_option('wp-optimize-mu-'.$option);
} else {
delete_option('wp-optimize-'.$option);
}
}
public function get_option_keys() {
return apply_filters(
'wp_optimize_option_keys',
array('defaults', 'weekly-schedule', 'schedule', 'retention-enabled', 'retention-period', 'last-optimized', 'enable-admin-menu', 'schedule-type', 'total-cleaned', 'current-cleaned', 'email-address', 'email', 'auto', 'settings', 'dismiss_page_notice_until', 'dismiss_dash_notice_until', 'enable_cache_in_admin_bar')
);
}
/**
* This particular option has its own functions abstracted to make it easier to change the format in future.
* To allow callers to always assume the latest format (because get_main_settings() will convert, if needed).
*
* @param array $settings Array of optimization settings.
* @return array
*/
private function save_manual_run_optimizations_settings($settings) {
$settings['last_saved_in'] = WPO_VERSION;
return $this->update_option('settings', $settings);
}
public function get_main_settings() {
return $this->get_option('settings');
}
/**
* This saves the tick box options for enabling auto backup
*
* @param array $settings Array of information with the state of the tick box selected.
* @return array Message Array for being completed.
*/
public function save_auto_backup_option($settings) {
if (isset($settings['auto_backup']) && 'true' == $settings['auto_backup']) {
$this->update_option('enable-auto-backup', 'true');
} else {
$this->update_option('enable-auto-backup', 'false');
}
$this->save_additional_auto_backup_options($settings);
$output = array('messages' => array());
$output['messages'][] = __('Auto backup option updated.', 'wp-optimize');
return $output;
}
/**
* Save option which sites to optimize in multisite mode
*
* @param array $settings array of blog ids or "all" item for all sites.
* @return bool
*/
public function save_wpo_sites_option($settings) {
return $this->update_option('wpo-sites', $settings);
}
/**
* Return list of blog ids to optimize in multisite mode
*
* @return mixed|void
*/
public function get_wpo_sites_option() {
return $this->get_option('wpo-sites', array('all'));
}
/**
* Save options
*
* @return array
*/
public function save_settings($settings) {
$output = array('messages' => array(), 'errors' => array());
if (!empty($settings["enable-schedule"])) {
$this->update_option('schedule', 'true');
wpo_cron_deactivate();
if (isset($settings["schedule_type"])) {
$schedule_type = (string) $settings['schedule_type'];
$this->update_option('schedule-type', $schedule_type);
} else {
$this->update_option('schedule-type', 'wpo_weekly');
}
WP_Optimize()->cron_activate();
} else {
$this->update_option('schedule', 'false');
$this->update_option('schedule-type', 'wpo_weekly');
wpo_cron_deactivate();
}
if (!empty($settings["enable-retention"])) {
$retention_period = (int) $settings['retention-period'];
$this->update_option('retention-enabled', 'true');
$this->update_option('retention-period', $retention_period);
} else {
$this->update_option('retention-enabled', 'false');
}
if (!empty($settings["enable-revisions-retention"])) {
$revisions_retention_count = (int) $settings['revisions-retention-count'];
$this->update_option('revisions-retention-enabled', 'true');
$this->update_option('revisions-retention-count', $revisions_retention_count);
} else {
$this->update_option('revisions-retention-enabled', 'false');
}
// Get saved admin menu value before check.
$saved_admin_bar = $this->get_option('enable-admin-menu', 'false');
// Set refresh of default false so it doesnt refresh after save.
$output['refresh'] = false;
if (!empty($settings['enable-admin-bar'])) {
$this->update_option('enable-admin-menu', 'true');
} else {
$this->update_option('enable-admin-menu', 'false');
}
// Make sure inbound input is a string.
$updated_admin_bar = (isset($settings['enable-admin-bar']) && $settings['enable-admin-bar']) ? 'true' : 'false';
// Check if the value is refreshed .
if ($saved_admin_bar != $updated_admin_bar) {
// Set refresh to true as the values have changed.
$output['refresh'] = true;
}
// Save cache toolbar display setting
$saved_enable_cache_in_admin_bar = $this->get_option('enable_cache_in_admin_bar', true);
if ($saved_enable_cache_in_admin_bar != $settings['enable_cache_in_admin_bar']) {
$this->update_option('enable_cache_in_admin_bar', $settings['enable_cache_in_admin_bar']);
$output['refresh'] = true;
}
do_action("auto_option_settings", $settings);
/** Save multisite options */
if (isset($settings['wpo-sites-cron'])) {
$this->update_option('wpo-sites-cron', $settings['wpo-sites-cron']);
}
if (isset($settings['wpo-sites'])) {
$this->save_wpo_sites_option($settings['wpo-sites']);
}
/** Save logging options */
$logger_type = isset($settings['wpo-logger-type']) ? $settings['wpo-logger-type'] : '';
$logger_options = isset($settings['wpo-logger-options']) ? $settings['wpo-logger-options'] : '';
$this->update_option('logging', $logger_type);
$this->update_option('logging-additional', $logger_options);
// Save selected optimization settings.
if (isset($settings['optimization-options'])) {
$this->save_sent_manual_run_optimization_options($settings['optimization-options'], false, false);
}
// Save auto backup option value.
$enable_auto_backup = (isset($settings['enable-auto-backup']) ? 'true' : 'false');
$this->update_option('enable-auto-backup', $enable_auto_backup);
// Save additional auto backup option values.
$this->save_additional_auto_backup_options($settings);
// Save force DB optimization value.
$enable_db_force_optimize = (isset($settings['innodb-force-optimize']) ? 'true' : 'false');
$this->update_option('enable-db-force-optimize', $enable_db_force_optimize);
$output['messages'][] = __('Settings updated.', 'wp-optimize');
return $output;
}
/**
* Wipe all options from database options tables.
*
* @return bool|false|int
*/
public function wipe_settings() {
global $wpdb;
wp_cache_flush();
// Delete the user meta if user meta is set for ignores the table delete warning
$user_query = new WP_User_Query(array('meta_key' => 'wpo-ignores-table-delete-warning', 'meta_value' => '1', 'fields' => 'ID'));
$users = $user_query->get_results();
if (!empty($users)) {
foreach ($users as $user_id) {
delete_user_meta($user_id, 'wpo-ignores-table-delete-warning');
}
}
// disable cache and clean any information related to WP-Optimize Cache.
WP_Optimize()->get_page_cache()->clean_up();
// delete settings from .htaccess
WP_Optimize()->get_browser_cache()->disable();
WP_Optimize()->get_gzip_compression()->disable();
// delete settings from options table.
$keys = '"' . implode('", "', $this->get_additional_settings_keys()) . '"';
if (is_multisite()) {
$result = $wpdb->query("DELETE FROM {$wpdb->sitemeta} WHERE `meta_key` LIKE 'wp-optimize-mu-%' OR `meta_key` IN ({$keys})");
} else {
$result = $wpdb->query("DELETE FROM {$wpdb->options} WHERE `option_name` LIKE 'wp-optimize-%' OR `option_name` IN ({$keys})");
}
return $result;
}
/**
* Get list of WP-Optimize settings database keys which are don't use default `wp-optimize-` prefix.
*
* @return array
*/
public function get_additional_settings_keys() {
return array(
'wpo_cache_config',
'wpo_minify_config',
'wpo_update_version',
);
}
/**
* Saves auto optimization settings
*
* @param array $settings Auto optimization settings array submitted by user
*
* @return void
*/
public function auto_option_settings($settings) {
$optimizer = WP_Optimize()->get_optimizer();
if (!empty($settings["schedule_type"])) {
$options_from_user = isset($settings['wp-optimize-auto']) ? $settings['wp-optimize-auto'] : array();
if (!is_array($options_from_user)) $options_from_user = array();
$new_auto_options = array();
$optimizations = $optimizer->get_optimizations();
foreach ($optimizations as $optimization) {
if (empty($optimization->available_for_auto)) continue;
$auto_id = $optimization->get_auto_id();
$new_auto_options[$auto_id] = empty($options_from_user[$auto_id]) ? 'false' : 'true';
}
$this->update_option('auto', $new_auto_options);
}
}
/**
* Save lazy load settings
*
* @param array $settings
* @return bool
*/
public function save_lazy_load_settings($settings) {
/** Save Lazy Load settings */
if (isset($settings['lazyload'])) {
$this->update_option('lazyload', $settings['lazyload']);
} else {
$this->update_option('lazyload', array());
}
return true;
}
/**
* The $use_dom_id parameter is legacy, for when saving options not with AJAX (in which case the dom ID comes via the $_POST array)
*
* @param array $sent_options Options sent from Ajax.
* @param boolean $use_dom_id Parameter is legacy.
* @param boolean $available_for_saving_only Save only available for saving optimization state.
* @return array User Options
*/
public function save_sent_manual_run_optimization_options($sent_options, $use_dom_id = false, $available_for_saving_only = true) {
$optimizations = WP_Optimize()->get_optimizer()->get_optimizations();
$user_options = array();
foreach ($optimizations as $optimization_id => $optimization) {
// In current code, not all options can be saved.
// Revisions, drafts, spams, unapproved, optimize.
if (is_wp_error($optimization) || ($available_for_saving_only && empty($optimization->available_for_saving))) continue;
$setting_id = $optimization->get_setting_id();
$id_in_sent = (($use_dom_id) ? $optimization->get_dom_id() : $optimization_id);
// 'true' / 'false' are indeed strings here; this is the historical state. It may be possible to change later using our abstraction interface.
$user_options[$setting_id] = isset($sent_options[$id_in_sent]) ? 'true' : 'false';
}
return $this->save_manual_run_optimizations_settings($user_options);
}
public function delete_all_options() {
$option_keys = $this->get_option_keys();
foreach ($option_keys as $key) {
$this->delete_option($key);
}
}
/**
* Setup options if not exists already.
*/
public function set_default_options() {
$deprecated = null;
$autoload_no = 'no';
if (false === $this->get_option('schedule')) {
// The option hasn't been added yet. We'll add it with $autoload_no set to 'no'.
$this->update_option('schedule', 'false', $deprecated, $autoload_no);
$this->update_option('last-optimized', 'Never', $deprecated, $autoload_no);
$this->update_option('schedule-type', 'wpo_weekly', $deprecated, $autoload_no);
// Deactivate cron.
wpo_cron_deactivate();
}
if (false === $this->get_option('retention-enabled')) {
$this->update_option('retention-enabled', 'false', $deprecated, $autoload_no);
$this->update_option('retention-period', '2', $deprecated, $autoload_no);
}
if (false === $this->get_option('enable-admin-menu')) {
$this->update_option('enable-admin-menu', 'false', $deprecated, $autoload_no);
}
if (false === $this->get_option('total-cleaned')) {
$this->update_option('total-cleaned', '0', $deprecated, $autoload_no);
}
$optimizer = WP_Optimize()->get_optimizer();
$optimizations = $optimizer->get_optimizations();
$auto_options = $this->get_option('auto');
$new_auto_options = array();
// Auto options doesn't exists or invalid. Set default.
if (empty($auto_options)) {
foreach ($optimizations as $optimization) {
if (empty($optimization->available_for_auto)) continue;
$auto_id = $optimization->get_auto_id();
$new_auto_options[$auto_id] = empty($optimization->auto_default) ? 'false' : 'true';
}
$this->update_option('auto', apply_filters('wpo_default_auto_options', $new_auto_options));
}
// Settings for main screen.
if (false === $this->get_main_settings()) {
$optimizer = WP_Optimize()->get_optimizer();
$optimizations = $optimizer->get_optimizations();
$new_settings = array();
foreach ($optimizations as $optimization) {
if (is_wp_error($optimization)) continue;
$setting_id = $optimization->get_setting_id();
$new_settings[$setting_id] = empty($optimization->setting_default) ? 'false' : 'true';
}
$this->save_manual_run_optimizations_settings($new_settings);
}
}
/**
* Save additional auto backup checkbox values.
*
* @param array $settings array with options.
*/
private function save_additional_auto_backup_options($settings) {
// Save additional auto backup option values.
foreach ($settings as $key => $value) {
if (preg_match('/enable\-auto\-backup\-/', $key)) {
$value = ('true' == $value) ? 'true' : 'false';
$this->update_option($key, $value);
}
}
}
}

View File

@@ -0,0 +1,616 @@
<?php
if (!defined('ABSPATH')) die('No direct access allowed');
if (!class_exists('Updraft_Task_Manager_1_3')) require_once(WPO_PLUGIN_MAIN_PATH . 'vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task-manager.php');
abstract class WP_Optimize_Preloader extends Updraft_Task_Manager_1_3 {
protected $options;
/**
* WP_Optimize_Page_Cache_Preloader constructor.
*/
public function __construct() {
parent::__construct();
$this->options = WP_Optimize()->get_options();
// setup loggers
$this->set_loggers(WP_Optimize()->wpo_loggers());
add_action('wpo_' . $this->preload_type . '_preload_continue', array($this, 'process_tasks_queue'));
add_filter('updraft_interrupt_tasks_queue_'.$this->task_type, array($this, 'maybe_interrupt_queue'), 20);
}
/**
* Get a schedule interval
*
* @param string $schedule_key The schedule to check
* @return integer
*/
protected function get_schedule_interval($schedule_key) {
$schedules = wp_get_schedules();
if (!isset($schedules[$schedule_key])) {
$this->log('Could not get interval for event of type '.$schedule_key);
return 0;
}
return isset($schedules[$schedule_key]['interval']) ? $schedules[$schedule_key]['interval'] : 0;
}
/**
* Get the interval to continuing a preload task
*
* @return integer
*/
public function get_continue_preload_cron_interval() {
/**
* Filters the interval between each preload attempt, in seconds.
*/
return (int) apply_filters('wpo_' . $this->preload_type . '_preload_continue_interval', 600);
}
/**
* Schedule action for continuously preload.
*/
public function schedule_preload_continue_action() {
$continue_in = wp_next_scheduled('wpo_' . $this->preload_type .'_preload_continue');
// Action is still scheduled
if ($continue_in && $continue_in > 0) return;
// Action is overdue, delete it and re schedule it
if ($continue_in && $continue_in < 0) $this->delete_preload_continue_action();
wp_schedule_event(time() + $this->get_schedule_interval('wpo_' . $this->preload_type . '_preload_continue_interval'), 'wpo_' . $this->preload_type . '_preload_continue_interval', 'wpo_' . $this->preload_type . '_preload_continue');
}
/**
* Delete scheduled action for continuously preload.
*/
public function delete_preload_continue_action() {
wp_clear_scheduled_hook('wpo_' . $this->preload_type . '_preload_continue');
}
/**
* Run preload. If task queue is empty it creates tasks for site urls.
*
* @param string $type - The preload type (schedule | manual)
* @param array $response - Specific response for echo into output thread when browser connection closing.
* @return array|void - Void when closing the browser connection
*/
public function run($type = 'scheduled', $response = null) {
if (!$this->is_option_active()) {
return $this->get_option_disabled_error();
}
do_action('wpo_before_' . $this->preload_type . '_preload');
if (empty($response)) {
$response = array('success' => true);
}
$this->delete_cancel_flag();
// trying to lock semaphore.
$creating_tasks_semaphore = new Updraft_Semaphore_3_0('wpo_' . $this->preload_type . '_preloader_creating_tasks');
$lock = $creating_tasks_semaphore->lock();
// if semaphore haven't locked then just return response.
if (!$lock) {
return $this->get_preload_already_running_error();
}
$is_wp_cli = defined('WP_CLI') && WP_CLI;
// close browser connection and continue work.
// don't close connection for WP-CLI
if (false == $is_wp_cli) {
WP_Optimize()->close_browser_connection(json_encode($response));
}
// trying to change time limit.
WP_Optimize()->change_time_limit();
$status = $this->get_status($this->task_type);
if (0 == $status['all_tasks'] && $lock) {
if (is_multisite()) {
$sites = WP_Optimize()->get_sites();
foreach ($sites as $site) {
switch_to_blog($site->blog_id);
$this->create_tasks_for_preload_site_urls($type);
restore_current_blog();
}
} else {
$this->create_tasks_for_preload_site_urls($type);
}
}
if ($lock) $creating_tasks_semaphore->release();
$this->process_tasks_queue();
// return $response in WP-CLI mode
if ($is_wp_cli) {
return $response;
}
}
/**
* Process tasks queue.
*/
public function process_tasks_queue() {
// schedule continue preload action.
$this->schedule_preload_continue_action();
if (!$this->process_queue($this->task_type)) {
return;
}
// delete scheduled continue preload action.
$this->delete_preload_continue_action();
// update last preload time only if processing any tasks, else process was cancelled.
if ($this->is_running()) {
$this->options->update_option('wpo_last_' . $this->preload_type . '_preload', time());
}
$this->clean_up_old_tasks($this->task_type);
}
/**
* Find out if the current queue should be interrupted
*
* @param boolean $interrupt
* @return boolean
*/
public function maybe_interrupt_queue($interrupt) {
if ($interrupt) return $interrupt;
static $memory_threshold = null;
if (null == $memory_threshold) {
/**
* Filters the minimum memory required before stopping a queue. Default: 10MB
*/
$memory_threshold = apply_filters('wpo_' . $this->preload_type . '_preload_memory_threshold', 10485760);
}
return WP_Optimize()->get_free_memory() < $memory_threshold;
}
/**
* Delete all preload tasks from queue.
*/
public function cancel_preload() {
$this->set_cancel_flag();
$this->delete_tasks($this->task_type);
$this->delete_preload_continue_action();
}
/**
* Set 'cancel' option to true.
*/
public function set_cancel_flag() {
$this->options->update_option("last_{$this->preload_type}_preload_cancel", true);
}
/**
* Delete 'cancel' option.
*/
public function delete_cancel_flag() {
$this->options->delete_option('last_' . $this->preload_type . '_preload_cancel');
}
/**
* Check if the last preload is cancelled.
*
* @return bool
*/
public function is_cancelled() {
return $this->options->get_option("last_{$this->preload_type}_preload_cancel", false);
}
/**
* Check if preloading queue is processing.
*
* @return bool
*/
public function is_busy() {
return $this->is_semaphore_locked($this->task_type) || $this->is_semaphore_locked('wpo_' . $this->preload_type . '_preloader_creating_tasks');
}
/**
* Get current status of preloading urls.
*
* @return array
*/
public function get_status_info() {
$status = $this->get_status($this->task_type);
$preload_data = $this->get_preload_data();
if ($this->is_semaphore_locked('wpo_' . $this->preload_type . '_preloader_creating_tasks') && !$this->is_cancelled()) {
// we are still creating tasks.
return $this->get_preloading_message($preload_data);
} elseif ($status['complete_tasks'] == $status['all_tasks']) {
$gmt_offset = (int) (3600 * get_option('gmt_offset'));
$last_preload_time = $this->options->get_option('wpo_last_' . $this->preload_type . '_preload');
if ($last_preload_time) {
$last_preload_time_str = date_i18n(get_option('time_format').', '.get_option('date_format'), $last_preload_time + $gmt_offset);
return $this->get_last_preload_message($preload_data, $last_preload_time_str);
} else {
return $this->get_preload_success_message($preload_data);
}
} else {
$preload_resuming_time = wp_next_scheduled('wpo_' . $this->preload_type . '_preload_continue');
$preload_resuming_in = $preload_resuming_time ? $preload_resuming_time - time() : 0;
$preloaded_message = sprintf(_n('%1$s out of %2$s URL preloaded', '%1$s out of %2$s URLs preloaded', $status['all_tasks'], 'wp-optimize'), $status['complete_tasks'], $status['all_tasks']);
if ('sitemap' == $this->options->get_option('wpo_last_' . $this->preload_type . '_preload_type', '')) {
$preloaded_message = __('Preloading posts found in sitemap:', 'wp-optimize') .' '. $preloaded_message;
}
$return = $this->get_preload_progress_message($preload_data, $preloaded_message, $preload_resuming_in);
if (defined('DOING_AJAX') && DOING_AJAX) {
// if no cron was found or cron is overdue more than 20s, trigger it
if (!$preload_resuming_time || $preload_resuming_in < -20) {
$this->run($return);
}
}
return $return;
}
}
/**
* Check if preload action in process.
*
* @return bool
*/
public function is_running() {
$status = $this->get_status($this->task_type);
if ($status['all_tasks'] > 0) return true;
}
/**
* Preload desktop version from url.
*
* @param string $url
*
* @return void
*/
public function preload_desktop($url) {
$desktop_args = array(
'httpversion' => '1.1',
'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
'timeout' => 10,
'headers' => apply_filters('wpo_preload_headers', array()),
);
$desktop_args = apply_filters('wpo_' . $this->preload_type . '_preloader_desktop_args', $desktop_args, $url);
$this->log('preload_desktop - '. $url);
wp_remote_get($url, $desktop_args);
}
/**
* Preload amp version from $url.
*
* @param string $url
*
* @return void
*/
public function preload_amp($url) {
if (!apply_filters('wpo_should_preload_amp', false, $url)) return;
$amp_args = array(
'httpversion' => '1.1',
'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.89 Safari/537.36',
'timeout' => 10,
'headers' => apply_filters('wpo_preload_headers', array()),
);
$url = untrailingslashit($url) . '/amp/';
$amp_args = apply_filters('wpo_' . $this->preload_type . '_preloader_amp_args', $amp_args, $url);
$this->log('preload_amp - ' . $url);
wp_remote_get($url, $amp_args);
}
/**
* Get sitemap filename.
*
* @return string
*/
protected function get_sitemap_filename() {
/**
* Filter the sitemap file used to collect the URLs to preload
*
* @param string $filename - The sitemap name
* @default sitemap.xml
*/
return apply_filters('wpo_cache_preload_sitemap_filename', 'sitemap.xml');
}
/**
* Check if sitemap exists then returns list of urls from sitemap file otherwise returns all posts urls.
*
* @return array
*/
public function get_site_urls() {
$urls = $this->get_sitemap_urls();
if (!empty($urls)) {
$this->options->update_option('wpo_last_' . $this->preload_type . '_preload_type', 'sitemap');
} else {
$urls = $this->get_post_urls();
$this->options->update_option('wpo_last_' . $this->preload_type . '_preload_type', 'posts');
}
$this->log(sprintf(_n('%d url found.', '%d urls found.', count($urls), 'wp-optimize'), count($urls)));
/**
* Filter the URLs which will be preloaded
*
* @param array $urls
* @return array
*/
return apply_filters('wpo_preload_get_site_urls', $urls);
}
/**
* Loads sitemap file and returns list of urls.
*
* @param string $sitemap_url
*
* @return array|bool
*/
public function get_sitemap_urls($sitemap_url = '') {
$urls = array();
// if sitemap url is empty then use main sitemap file name.
$sitemap_url = ('' === $sitemap_url) ? site_url('/'.$this->get_sitemap_filename()) : $sitemap_url;
// if simplexml_load_string not available then we don't load sitemap.
if (!function_exists('simplexml_load_string')) {
return $urls;
}
// load sitemap file.
$response = wp_remote_get($sitemap_url, array('timeout' => 30));
// if we get error then
if (is_wp_error($response)) {
$response = file_get_contents($sitemap_url);
// if response is empty then try load from file.
if (empty($response) && '' == $sitemap_url) {
$sitemap_file = $this->get_local_sitemap_file();
$response = file_get_contents($sitemap_file);
}
if (empty($response)) return $urls;
$xml = @simplexml_load_string($response); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
} else {
// parse xml answer.
$xml = @simplexml_load_string(wp_remote_retrieve_body($response)); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
}
// xml file has not valid xml content then return false.
if (false === $xml) return false;
// if exists urls then return them.
if (isset($xml->url)) {
foreach ($xml->url as $element) {
if (!isset($element->loc)) continue;
$urls[] = (string) $element->loc;
}
} elseif (isset($xml->sitemap)) {
// if has links to other sitemap files then get urls from them.
foreach ($xml->sitemap as $element) {
if (!isset($element->loc)) continue;
$sitemap_urls = $this->get_sitemap_urls($element->loc);
if (is_array($sitemap_urls)) {
$urls = array_merge($urls, $sitemap_urls);
}
}
}
return $urls;
}
/**
* Get the path to a local sitemap file
*
* @return string
*/
protected function get_local_sitemap_file() {
// Make the scope of $wp_file_descriptions global, so that when wp-admin/includes/file.php assigns to it, it is adjusting the global variable as intended
global $wp_file_descriptions; // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
if (!function_exists('get_home_path')) {
include_once ABSPATH . '/wp-admin/includes/file.php';
}
return trailingslashit(get_home_path()) . $this->get_sitemap_filename();
}
/**
* Get all posts of any post type and returns urls for them.
*
* @return array
*/
public function get_post_urls() {
global $post;
$offset = 0;
$posts_per_page = 1000;
$urls = array();
$urls[] = site_url('/');
do {
$query = new WP_Query(array(
'post_type' => 'any',
'post_status' => 'publish',
'posts_per_page' => $posts_per_page,
'offset' => $offset,
'orderby' => 'ID',
'order' => 'ASC',
'cache_results' => false, // disable cache to avoid memory error.
));
$posts_loaded = $query->post_count;
while ($query->have_posts()) {
$query->the_post();
$permalink = get_permalink();
$urls[] = $permalink;
// check page separators in the post content
preg_match_all('/\<\!--nextpage--\>/', $post->post_content, $matches);
// if there any separators add urls for each page
if (count($matches[0])) {
$prefix = strpos($permalink, '?') ? '&page=' : '';
for ($page = 0; $page < count($matches[0]); $page++) {
if ('' != $prefix) {
$urls[] = $permalink . $prefix . ($page+2);
} else {
$urls[] = trailingslashit($permalink) . ($page+2);
}
}
}
}
$offset += $posts_loaded;
} while ($posts_loaded > 0);
/**
* If domain mapping enabled then replace domains in urls.
*/
if ($this->is_domain_mapping_enabled()) {
$blog_id = get_current_blog_id();
$mapped_domain = $this->get_mapped_domain($blog_id);
$blog_details = get_blog_details($blog_id);
if ($mapped_domain) {
foreach ($urls as $i => $url) {
$urls[$i] = preg_replace('/'.$blog_details->domain.'/i', $mapped_domain, $url, 1);
}
}
}
wp_reset_postdata();
return $urls;
}
/**
* Check if domain mapping enabled.
*
* @return bool
*/
public function is_domain_mapping_enabled() {
// SUNRISE constant is defined with installation WordPress MU Domain Mapping plugin.
$enabled = is_multisite() && defined('SUNRISE') && 'on' == strtolower(SUNRISE);
/**
* Filters if Multisite Domain mapping is enabled.
* Currently, we can only detect if the WordPress MU Domain Mapping plugin is in use.
* Using the WP Core functionality should not require this, unless if the domain name is set somewhere else but in the site url option.
*/
return apply_filters('wpo_is_domain_mapping_enabled', $enabled);
}
/**
* Return mapped domain by $blog_id.
*
* @param int $blog_id
*
* @return string
*/
public function get_mapped_domain($blog_id) {
global $wpdb;
$domain = '';
$multisite_plugin_table_name = $wpdb->base_prefix.'domain_mapping';
// Check if table exists
if ($wpdb->get_var("SHOW TABLES LIKE '$multisite_plugin_table_name'") != $multisite_plugin_table_name) {
// This table created in WordPress MU Domain Mapping plugin.
$row = $wpdb->get_row("SELECT `domain` FROM {$multisite_plugin_table_name} WHERE `blog_id` = {$blog_id} AND `active` = 1", ARRAY_A);
if (!empty($row)) {
$domain = $row['domain'];
}
} else {
// When using the WP Core method, the site url option contains the mapped domain.
$domain = get_site_url($blog_id);
}
/**
* Filters the mapped domain name
*
* @param string $domain The domain name
* @param integer $blog_id The blog ID
*/
return apply_filters('wpo_get_mapped_domain', $domain, $blog_id);
}
/**
* Captures and logs any interesting messages
*
* @param String $message - the error message
* @param String $error_type - the error type
*/
public function log($message, $error_type = 'info') {
if (isset($this->loggers)) {
foreach ($this->loggers as $logger) {
$logger->log($message, $error_type);
}
}
}
/**
* Check if semaphore is locked.
*
* @param string $semaphore
* @return bool
*/
protected function is_semaphore_locked($semaphore) {
$semaphore = new Updraft_Semaphore_3_0($semaphore);
if ($semaphore->lock()) {
$semaphore->release();
return false;
}
return true;
}
abstract protected function is_option_active();
abstract protected function get_option_disabled_error();
abstract protected function get_preload_already_running_error();
abstract protected function create_tasks_for_preload_site_urls($type);
abstract protected function get_preload_data();
abstract protected function get_preloading_message($data);
abstract protected function get_last_preload_message($data, $last_preload_time_str);
abstract protected function get_preload_success_message($data);
abstract protected function get_preload_progress_message($data, $preloaded_message, $preload_resuming_in);
}

View File

@@ -0,0 +1,162 @@
<?php
if (!defined('WPO_VERSION')) die('No direct access allowed');
/**
* Class WP_Optimize_Transients_Cache
*/
class WP_Optimize_Transients_Cache {
private $_cache = array();
private $_expiration = array();
private $_keep_free_mem = false;
/**
* WP_Optimize_Transients_Cache constructor.
*/
public function __construct() {
}
/**
* Return instance of WP_Optimize_Transients_Cache.
*
* @return WP_Optimize_Transients_Cache
*/
public static function get_instance() {
static $instance;
if (null === $instance) {
$instance = new self();
}
return $instance;
}
/**
* Save $value to memory or to database depends on free memory.
*
* @param string $key
* @param mixed $value
* @param int $expiration
*/
public function set($key, &$value, $expiration = 0) {
$keep_free_mem = $this->_keep_free_mem ? $this->_keep_free_mem : 16 * 1048576;
$used_memory = memory_get_usage();
$free_memory = WP_Optimize()->get_free_memory();
$released_memory = 0;
$cache_keys = array_keys($this->_cache);
// release memory while we need.
while ($keep_free_mem > $free_memory + $released_memory && !empty($cache_keys)) {
$this->flush_value(array_shift($cache_keys));
$released_memory = $used_memory - memory_get_usage();
}
// if we have enough of free memory then save to memory.
if (WP_Optimize()->get_free_memory() > $keep_free_mem) {
$this->_cache[$key] = $value;
$this->_expiration[$key] = $expiration;
} else {
if (isset($this->_cache[$key])) {
unset($this->_cache[$key]);
}
if (isset($this->_expiration[$key])) {
unset($this->_expiration[$key]);
}
$this->set_transient($key, $value, $expiration);
}
}
/**
* Return value from cache by $key.
*
* @param string $key
* @return mixed
*/
public function get($key) {
if (array_key_exists($key, $this->_cache)) return $this->_cache[$key];
return $this->get_transient($key);
}
/**
* Delete value from cache.
*
* @param string $key
*/
public function delete($key) {
if (array_key_exists($key, $this->_cache)) {
unset($this->_cache[$key], $this->_expiration[$key]);
}
$this->delete_transient($key);
}
/**
* Set transient.
*
* @param int $key
* @param mixed $value
* @param int $expiration
*/
public function set_transient($key, $value, $expiration = 0) {
if (WP_Optimize()->is_multisite_mode()) {
set_site_transient($key, $value, $expiration);
} else {
set_transient($key, $value, $expiration);
}
}
/**
* Get transient.
*
* @param string $key
* @return mixed
*/
public function get_transient($key) {
if (WP_Optimize()->is_multisite_mode()) {
$value = get_site_transient($key);
} else {
$value = get_transient($key);
}
return $value;
}
/**
* Delete transient.
*
* @param string $key
*/
public function delete_transient($key) {
if (WP_Optimize()->is_multisite_mode()) {
delete_site_transient($key);
} else {
delete_transient($key);
}
}
/**
* Save value to database and remove from $_cache array.
*
* @param string $key
*/
public function flush_value($key) {
$this->set_transient($key, $this->_cache[$key], $this->_expiration[$key]);
unset($this->_cache[$key], $this->_expiration[$key]);
}
/**
* Save all _cache values to database.
*/
public function flush() {
foreach (array_keys($this->_cache) as $key) {
$this->flush_value($key);
}
}
}

View File

@@ -0,0 +1,187 @@
<?php
/**
* WP_Optimize_Updates class using for run updates in database from version to version.
*/
if (!defined('ABSPATH')) die('Access denied.');
if (!class_exists('WP_Optimize_Updates')) :
class WP_Optimize_Updates {
/**
* Format: key=<version>, value=array of method names to call
* Example Usage:
* private static $db_updates = array(
* '1.0.1' => array(
* 'update_101_add_new_column',
* ),
* );
*
* @var Mixed
*/
private static $updates = array(
'3.0.12' => array('delete_old_locks'),
'3.0.17' => array('disable_cache_directories_viewing'),
'3.1.0' => array('reset_wpo_plugin_cron_tasks_schedule'),
'3.1.4' => array('enable_minify_defer'),
'3.1.5' => array('update_minify_excludes'),
'3.2.14' => array('update_3214_modify_cache_config_in_windows'),
);
/**
* See if any database schema updates are needed, and perform them if so.
* Example Usage:
* public static function update_101_add_new_column() {
* $wpdb = $GLOBALS['wpdb'];
* $wpdb->query('ALTER TABLE tm_tasks ADD task_expiry varchar(300) AFTER id');
* }
*/
public static function check_updates() {
$our_version = WPO_VERSION;
$db_version = get_option('wpo_update_version');
if (!$db_version || version_compare($our_version, $db_version, '>')) {
foreach (self::$updates as $version => $updates) {
if (version_compare($version, $db_version, '>')) {
foreach ($updates as $update) {
call_user_func(array(__CLASS__, $update));
}
}
}
update_option('wpo_update_version', WPO_VERSION);
}
}
/**
* Delete old semaphore locks from options database table.
*/
public static function delete_old_locks() {
global $wpdb;
// using this query we delete all rows related to locks.
$query = "DELETE FROM {$wpdb->options}".
" WHERE (option_name LIKE ('updraft_semaphore_%')".
" OR option_name LIKE ('updraft_last_lock_time_%')".
" OR option_name LIKE ('updraft_locked_%')".
" OR option_name LIKE ('updraft_unlocked_%'))".
" AND ".
"(option_name LIKE ('%smush')".
" OR option_name LIKE ('%load-url-task'));";
$wpdb->query($query);
}
/**
* Disable cache directories viewing.
*/
public static function disable_cache_directories_viewing() {
wpo_disable_cache_directories_viewing();
}
public static function reset_wpo_plugin_cron_tasks_schedule() {
wp_clear_scheduled_hook('wpo_plugin_cron_tasks');
}
/**
* Update Minify Defer option (The option was hidden until now, but we're changing the setting)
*
* @return void
*/
public static function enable_minify_defer() {
if (!function_exists('wp_optimize_minify_config')) {
include_once WPO_PLUGIN_MAIN_PATH . '/minify/class-wp-optimize-minify-config.php';
}
$current_setting = wp_optimize_minify_config()->get('enable_defer_js');
if (true === $current_setting) {
wp_optimize_minify_config()->update(array('enable_defer_js' => 'all'));
} else {
wp_optimize_minify_config()->update(array('enable_defer_js' => 'individual'));
}
}
/**
* Update Minify default exclude options
*
* @return void
*/
public static function update_minify_excludes() {
if (!WPO_MINIFY_PHP_VERSION_MET) return;
if (!function_exists('wp_optimize_minify_config')) {
include_once WPO_PLUGIN_MAIN_PATH . '/minify/class-wp-optimize-minify-config.php';
}
if (!class_exists('WP_Optimize_Minify_Functions')) {
include_once WPO_PLUGIN_MAIN_PATH . '/minify/class-wp-optimize-minify-functions.php';
}
$new_default_items = array(
'elementor-admin-bar',
'pdfjs-dist',
'wordpress-popular-posts',
);
$user_excluded_blacklist_items = array();
$user_excluded_ignorelist_items = array();
// Get the lists as saved in the DB
$current_blacklist = wp_optimize_minify_config()->get('blacklist');
$current_ignorelist = wp_optimize_minify_config()->get('ignore_list');
// Only proceed if the the upgrade hasn't been done yet, i.e. the values aren't arrays
if (is_array($current_blacklist) && is_array($current_ignorelist)) return;
$current_blacklist = array_map('trim', explode("\n", $current_blacklist));
$current_ignorelist = array_map('trim', explode("\n", $current_ignorelist));
// Get the default lists
$default_blacklist = WP_Optimize_Minify_Functions::get_default_ie_blacklist();
$default_ignorelist = WP_Optimize_Minify_Functions::get_default_ignore();
foreach ($default_blacklist as $bl_item) {
// If a blacklist item isn't in the list, it was manually removed by the user, so we save that.
if (!in_array($bl_item, $current_blacklist)) $user_excluded_blacklist_items[] = $bl_item;
}
foreach ($default_ignorelist as $il_item) {
if (!in_array($il_item, $current_ignorelist) && !in_array($il_item, $new_default_items)) $user_excluded_ignorelist_items[] = $il_item;
}
// Update the options
wp_optimize_minify_config()->update(array('blacklist' => $user_excluded_blacklist_items));
wp_optimize_minify_config()->update(array('ignore_list' => $user_excluded_ignorelist_items));
}
/**
* Checks if it's a new installation of the plugin, as opposed to being updated.
*
* @return bool
*/
public static function is_new_install() {
$db_version = get_option('wpo_update_version');
return !$db_version;
}
/**
* Modifies the cache configuration for Windows OS by regenerating the 'uploads' path.
*/
public static function update_3214_modify_cache_config_in_windows() {
// Check if the OS is Windows and it's not a new installation.
if ('WIN' !== strtoupper(substr(PHP_OS, 0, 3)) || self::is_new_install()) {
return;
}
// Retrieve the current cache configuration
$config = WPO_Cache_Config::instance()->get();
// Remove the 'uploads' path from the configuration, this will force the 'uploads' path to regenerate from the defaults
if (isset($config['uploads'])) {
unset($config['uploads']);
}
// Update the cache configuration
WPO_Cache_Config::instance()->update($config);
}
}
endif;

View File

@@ -0,0 +1,607 @@
<?php
if (!defined('WPO_VERSION')) die('No direct access allowed');
/**
* This class invokes optimiazations. The optimizations themselves live in the 'optimizations' sub-directory of the plugin. The proper way to obtain access to the instance is via WP_Optimize()->get_optimizer()
*/
class WP_Optimizer {
/**
* Returns singleton instance object
*
* @return WP_Optimizer Returns `WP_Optimizer` object
*/
public static function instance() {
static $_instance = null;
if (null === $_instance) {
$_instance = new self();
}
return $_instance;
}
public function get_retain_info() {
$options = WP_Optimize()->get_options();
$retain_enabled = $options->get_option('retention-enabled', 'false');
$retain_period = (($retain_enabled) ? $options->get_option('retention-period', '2') : null);
return array($retain_enabled, $retain_period);
}
/**
* Get data retention options
*
* @return array
*/
public function get_revisions_retain_info() {
$options = WP_Optimize()->get_options();
$revisions_retention_enabled = $options->get_option('revisions-retention-enabled', 'false');
$revisions_retention_count = $revisions_retention_enabled ? $options->get_option('revisions-retention-count', '2') : null;
return array($revisions_retention_enabled, $revisions_retention_count);
}
public function get_optimizations_list() {
$optimizations = array();
$optimizations_dir = WPO_PLUGIN_MAIN_PATH.'optimizations';
if ($dh = opendir($optimizations_dir)) {
while (($file = readdir($dh)) !== false) {
if ('.' == $file || '..' == $file || '.php' != substr($file, -4, 4) || !is_file($optimizations_dir.'/'.$file) || 'inactive-' == substr($file, 0, 9)) continue;
$optimizations[] = substr($file, 0, (strlen($file) - 4));
}
closedir($dh);
}
return apply_filters('wp_optimize_get_optimizations_list', $optimizations);
}
/**
* Currently, there is only one sort rule (so, the parameter's value is ignored)
*
* @param array $optimizations An array of optimizations (i.e. WP_Optimization instances).
* @param string $sort_on Specify sort.
* @param string $sort_rule Sort Rule.
* @return array
*/
public function sort_optimizations($optimizations, $sort_on = 'ui_sort_order', $sort_rule = 'traditional') {// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
if ('run_sort_order' == $sort_on) {
uasort($optimizations, array($this, 'sort_optimizations_run_traditional'));
} else {
uasort($optimizations, array($this, 'sort_optimizations_ui_traditional'));
}
return $optimizations;
}
public function sort_optimizations_ui_traditional($a, $b) {
return $this->sort_optimizations_traditional($a, $b, 'ui_sort_order');
}
public function sort_optimizations_run_traditional($a, $b) {
return $this->sort_optimizations_traditional($a, $b, 'run_sort_order');
}
public function sort_optimizations_traditional($a, $b, $sort_on = 'ui_sort_order') {
if (!is_a($a, 'WP_Optimization')) return (!is_a($b, 'WP_Optimization')) ? 0 : 1;
if (!is_a($b, 'WP_Optimization')) return -1;
$sort_order_a = empty($a->$sort_on) ? 0 : $a->$sort_on;
$sort_order_b = empty($b->$sort_on) ? 0 : $b->$sort_on;
if ($sort_order_a == $sort_order_b) return 0;
return ($sort_order_a < $sort_order_b) ? (-1) : 1;
}
/**
* This method returns an array of available optimizations.
* Each array key is an optimization ID, and the value is an object,
* as returned by get_optimization()
*
* @return [array] array of optimizations or WP_Error objects
*/
public function get_optimizations() {
$optimizations = $this->get_optimizations_list();
$optimization_objects = array();
foreach ($optimizations as $optimization) {
$optimization_object = $this->get_optimization($optimization);
if (is_wp_error($optimization_object)) {
WP_Optimize()->log('Failed to load optimization ' . $optimization . ' - ' . $optimization_object->get_error_message());
} else {
$optimization_objects[$optimization] = $optimization_object;
}
}
return apply_filters('wp_optimize_get_optimizations', $optimization_objects);
}
/**
* This method returns an object for a specific optimization.
*
* @param string $which_optimization An optimization ID.
* @param array $data An array of anny options $data.
* @return array WP_Error Will return the optimization, or a WP_Error object if it was not found.
*/
public function get_optimization($which_optimization, $data = array()) {
$optimization_class = apply_filters('wp_optimize_optimization_class', 'WP_Optimization_'.$which_optimization);
if (!class_exists('WP_Optimization')) include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-wp-optimization.php');
if (!class_exists($optimization_class)) {
$optimization_file = WPO_PLUGIN_MAIN_PATH.'optimizations/'.$which_optimization.'.php';
$class_file = apply_filters('wp_optimize_optimization_class_file', $optimization_file);
if (!preg_match('/^[a-z]+$/', $which_optimization) || !file_exists($class_file)) {
return new WP_Error('no_such_optimization', __('No such optimization', 'wp-optimize'), $which_optimization);
}
include_once($class_file);
if (!class_exists($optimization_class)) {
return new WP_Error('no_such_optimization', __('No such optimization', 'wp-optimize'), $which_optimization);
}
}
// set sites option for Multisite cron job.
if (defined('DOING_CRON') && DOING_CRON && is_multisite()) {
$options = WP_Optimize()->get_options();
$data['optimization_sites'] = $options->get_option('wpo-sites-cron', array('all'));
}
$optimization = new $optimization_class($data);
return $optimization;
}
/**
* The method to call to perform an optimization.
*
* @param string|object $which_optimization An optimization ID, or a WP_Optimization object.
* @return array Array of results from the optimization.
*/
public function do_optimization($which_optimization) {
$optimization = (is_object($which_optimization) && is_a($which_optimization, 'WP_Optimization')) ? $which_optimization : $this->get_optimization($which_optimization);
if (is_wp_error($optimization)) {
WP_Optimize()->log('Error occurred. Unknown optimization.');
return $optimization;
}
WP_Optimize()->change_time_limit();
$optimization->init();
if (apply_filters('wp_optimize_do_optimization', true, $which_optimization, $optimization)) {
$optimization->before_optimize();
if ($optimization->run_multisite) {
foreach ($optimization->blogs_ids as $blog_id) {
$optimization->switch_to_blog($blog_id);
$optimization->optimize();
$optimization->restore_current_blog();
}
} else {
$optimization->optimize();
}
$optimization->after_optimize();
}
do_action('wp_optimize_after_optimization', $which_optimization, $optimization);
$results = $optimization->get_results();
return $results;
}
/**
* The method to call to get information about an optimization.
* As with do_optimization, it is somewhat modelled after the template interface
*
* @param string|object $which_optimization An optimization ID, or a WP_Optimization object.
* @return array returns the optimization information
*/
public function get_optimization_info($which_optimization) {
$optimization = (is_object($which_optimization) && is_a($which_optimization, 'WP_Optimization')) ? $which_optimization : $this->get_optimization($which_optimization);
if (is_wp_error($optimization)) return $optimization;
WP_Optimize()->change_time_limit();
$optimization->before_get_info();
if ($optimization->run_multisite) {
foreach ($optimization->blogs_ids as $blog_id) {
$optimization->switch_to_blog($blog_id);
$optimization->get_info();
$optimization->restore_current_blog();
}
} else {
$optimization->get_info();
}
$optimization->after_get_info();
return $optimization->get_results();
}
/**
* THis runs the list of optimizations.
*
* @param array $optimization_options Whether to do an optimization depends on what keys are set (legacy - can be changed hopefully).
* @param string $which_option Specify which option.
* @return array Returns an array of result objects.
*/
public function do_optimizations($optimization_options, $which_option = 'dom') {
$results = array();
if (empty($optimization_options)) return $results;
$optimizations = $this->sort_optimizations($this->get_optimizations(), 'run_sort_order');
foreach ($optimizations as $optimization_id => $optimization) {
$option_id = call_user_func(array($optimization, 'get_'.$which_option.'_id'));
if (isset($optimization_options[$option_id])) {
// if options saved as a string then compare with string (for support different versions)
if (is_string($optimization_options[$option_id]) && 'false' === $optimization_options[$option_id]) continue;
if ('auto' == $which_option && empty($optimization->available_for_auto)) continue;
WP_Optimize()->change_time_limit();
$results[$optimization_id] = $this->do_optimization($optimization);
}
}
// Run action after all optimizations completed.
do_action('wp_optimize_after_optimizations');
return $results;
}
public function get_table_prefix($allow_override = false) {
$wpdb = $GLOBALS['wpdb'];
if (is_multisite() && !defined('MULTISITE')) {
// In this case (which should only be possible on installs upgraded from pre WP 3.0 WPMU), $wpdb->get_blog_prefix() cannot be made to return the right thing. $wpdb->base_prefix is not explicitly marked as public, so we prefer to use get_blog_prefix if we can, for future compatibility.
$prefix = $wpdb->base_prefix;
} else {
$prefix = $wpdb->get_blog_prefix(0);
}
return ($allow_override) ? apply_filters('wp_optimize_get_table_prefix', $prefix) : $prefix;
}
/**
* Returns information about database tables.
*
* @param bool $update refresh or no cached data
*
* @return mixed
*/
public function get_tables($update = false) {
static $tables_info = null;
if (false === $update && null !== $tables_info) return $tables_info;
$wpo_db_info = WP_Optimize()->get_db_info();
$table_status = $wpo_db_info->get_show_table_status($update);
// Filter on the site's DB prefix (was not done in releases up to 1.9.1).
$table_prefix = $this->get_table_prefix();
if (is_array($table_status)) {
$corrupted_tables_count = 0;
foreach ($table_status as $index => $table) {
$table_name = $table->Name;
$include_table = (0 === stripos($table_name, $table_prefix));
$include_table = apply_filters('wp_optimize_get_tables_include_table', $include_table, $table_name, $table_prefix);
if (!$include_table && '' !== $table_prefix) {
unset($table_status[$index]);
continue;
}
$table_status[$index]->Engine = $wpo_db_info->get_table_type($table_name);
$table_status[$index]->is_optimizable = $wpo_db_info->is_table_optimizable($table_name);
$table_status[$index]->is_type_supported = $wpo_db_info->is_table_type_optimize_supported($table_name);
// add information about corrupted tables.
$is_needing_repair = $wpo_db_info->is_table_needing_repair($table_name);
$table_status[$index]->is_needing_repair = $is_needing_repair;
if ($is_needing_repair) $corrupted_tables_count++;
$table_status[$index] = $this->join_plugin_information($table_name, $table_status[$index]);
$table_status[$index]->blog_id = $wpo_db_info->get_table_blog_id($table_name);
}
WP_Optimize()->get_options()->update_option('corrupted-tables-count', $corrupted_tables_count);
}
$tables_info = apply_filters('wp_optimize_get_tables', $table_status);
return $tables_info;
}
/**
* Returns information about single table by table name.
*
* @param String $table_name table name
* @return Object|Boolean table information object.
*/
public function get_table($table_name) {
$db_info = WP_Optimize()->get_db_info();
$table = $db_info->get_table_status($table_name);
if (false === $table) return false;
$table->is_optimizable = $db_info->is_table_optimizable($table_name);
$table->is_type_supported = $db_info->is_table_type_optimize_supported($table_name);
$table->is_needing_repair = $db_info->is_table_needing_repair($table_name);
// add information about plugins.
$table = $this->join_plugin_information($table_name, $table);
$table = apply_filters('wp_optimize_get_table', $table);
return $table;
}
/**
* Add information about relationship database tables with plugins.
*
* @param {string} $table_name
* @param {object} $table_obj
*
* @return {object}
*/
public function join_plugin_information($table_name, $table_obj) {
// set can be removed flag.
$can_be_removed = false;
// set WP core table flag.
$wp_core_table = false;
// set WP actionscheduler table flag.
$wp_actionscheduler_table = (false !== stripos($table_name, 'actionscheduler_'));
// add information about using table by any of installed plugins.
$table_obj->is_using = WP_Optimize()->get_db_info()->is_table_using_by_plugin($table_name);
// if table belongs to any plugin then add plugins status.
$plugins = WP_Optimize()->get_db_info()->get_table_plugin($table_name);
if (false !== $plugins) {
// if belongs to any of plugin then we can remove table if plugin not active.
$can_be_removed = true;
$plugin_status = array();
foreach ($plugins as $plugin) {
$status = WP_Optimize()->get_db_info()->get_plugin_status($plugin);
if (__('WordPress core', 'wp-optimize') == $plugin) $wp_core_table = true;
// if plugin is active then we can't remove.
if ($wp_core_table || $status['active'] || $wp_actionscheduler_table) $can_be_removed = false;
if ($status['installed'] || $status['active'] || !$table_obj->is_using) {
$plugin_status[] = array(
'plugin' => $plugin,
'status' => $status,
);
}
}
$table_obj->plugin_status = $plugin_status;
}
$table_obj->wp_core_table = $wp_core_table;
$table_obj->can_be_removed = $can_be_removed;
return $table_obj;
}
/**
* This function grabs a list of tables
* and information regarding each table and returns
* the results to optimizations-table.php and optimizationstable.php
*
* @param int $blog_id filter tables by prefix
*
* @return Array - an array of data such as table list, innodb info and data free
*/
public function get_table_information($blog_id = 0) {
// Get table information.
$tablesstatus = $this->get_tables();
// Set defaults.
$table_information = array();
$table_information['total_gain'] = 0;
$table_information['inno_db_tables'] = 0;
$table_information['non_inno_db_tables'] = 0;
$table_information['table_list'] = '';
$table_information['is_optimizable'] = true;
// Make a list of tables to optimize.
foreach ($tablesstatus as $each_table) {
// if $blog_id is set then filter tables
if ($blog_id > 0 && $blog_id != $each_table->blog_id) continue;
$table_information['table_list'] .= $each_table->Name.'|';
// check if table type supported.
if (!$each_table->is_type_supported) continue;
// check if table is optimizable.
if (!$each_table->is_optimizable) {
$table_information['is_optimizable'] = false;
}
// calculate total gain value.
$table_information['total_gain'] += $each_table->Data_free;
// count InnoDB tables.
if ('InnoDB' == $each_table->Engine) {
$table_information['inno_db_tables']++;
} else {
$table_information['non_inno_db_tables']++;
}
}
return $table_information;
}
/**
* What sort of linkback to enable or disable: valid values are 'trackbacks' or 'comments', and whether to enable or disable.
*
* @param string $type Specify the type of linkbacks.
* @param boolean $enable If it is enabled or disabled.
*/
public function enable_linkbacks($type, $enable = true) {
$wpdb = $GLOBALS['wpdb'];
$wpo_options = WP_Optimize()->get_options();
$new_status = $enable ? 'open' : 'closed';
switch ($type) {
case "trackbacks":
$thissql = "UPDATE `".$wpdb->posts."` SET ping_status='".$new_status."' WHERE post_status = 'publish' AND post_type = 'post';";
$wpdb->query($thissql);
break;
case "comments":
$thissql = "UPDATE `".$wpdb->posts."` SET comment_status='".$new_status."' WHERE post_status = 'publish' AND post_type = 'post';";
$wpdb->query($thissql);
break;
default:
break;
}
$wpo_options->update_option($type.'_action', array('action' => $enable, 'timestamp' => time()));
}
/**
* This function will return total database size and a possible gain of db in KB.
*
* @param boolean $update - Wether to update the values or not
* @return string total db size gained.
*/
public function get_current_db_size($update = false) {
if (!$update && $db_size = get_transient('wpo_get_current_db_size')) {
return $db_size;
}
$wp_optimize = WP_Optimize();
$total_gain = 0;
$total_size = 0;
$row_usage = 0;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $row_usage Used in the foreach below
$data_usage = 0;
$index_usage = 0;
$overhead_usage = 0;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $overhead_usage Used in the foreach below
$tablesstatus = $this->get_tables();
foreach ($tablesstatus as $tablestatus) {
$row_usage += $tablestatus->Rows;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $row_usage declared up above
$total_gain += $tablestatus->Data_free;
$data_usage += $tablestatus->Data_length;
$index_usage += $tablestatus->Index_length;
if ('InnoDB' != $tablestatus->Engine) {
$overhead_usage += $tablestatus->Data_free;// phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable -- $overhead_usage declared up above
$total_gain += $tablestatus->Data_free;
}
}
$total_size = ($data_usage + $index_usage);
$db_size = array($wp_optimize->format_size($total_size), $wp_optimize->format_size($total_gain));
set_transient('wpo_get_current_db_size', $db_size, 3600);
return $db_size;
}
/**
* This function will return total saved data in KB.
*
* @param string $current How big the data is.
* @return string Returns new total value.
*/
public function update_total_cleaned($current) {
$options = WP_Optimize()->get_options();
$previously_saved = floatval($options->get_option('total-cleaned', '0'));
$converted_current = floatval($current);
$total_now = strval($previously_saved + $converted_current);
$options->update_option('total-cleaned', $total_now);
return $total_now;
}
public function trackback_comment_actions($options) {
$output = array();
$messages = array();
if (isset($options['comments'])) {
if (!$options['comments']) {
$this->enable_linkbacks('comments', false);
$output[] = __('Comments have now been disabled on all current and previously published posts.', 'wp-optimize');
$messages[] = sprintf(__('All comments on existing posts were disabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
} else {
$this->enable_linkbacks('comments');
$output[] = __('Comments have now been enabled on all current and previously published posts.', 'wp-optimize');
$messages[] = sprintf(__('All comments on existing posts were enabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
}
}
if (isset($options['trackbacks'])) {
if (!$options['trackbacks']) {
$this->enable_linkbacks('trackbacks', false);
$output[] = __('Trackbacks have now been disabled on all current and previously published posts.', 'wp-optimize');
$messages[] = sprintf(__('All trackbacks on existing posts were disabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
} else {
$this->enable_linkbacks('trackbacks');
$output[] = __('Trackbacks have now been enabled on all current and previously published posts.', 'wp-optimize');
$messages[] = sprintf(__('All trackbacks on existing posts were enabled at %s.', 'wp-optimize'), WP_Optimize()->format_date_time(time()));
}
}
return array('output' => $output,'messages' => $messages);
}
/**
* Wether InnoDB tables require confirmation to be optimized
*
* @return boolean
*/
public function show_innodb_force_optimize() {
$tablesstatus = $this->get_table_information();
return false === $tablesstatus['is_optimizable'] && $tablesstatus['inno_db_tables'] > 0;
}
}

View File

@@ -0,0 +1,380 @@
<?php
if (!defined('ABSPATH')) die('Access denied.');
if (!class_exists('WPO_Ajax')) :
class WPO_Ajax {
private $nonce;
private $subaction;
private $data;
private $commands;
private $results;
/**
* Constructor
*/
private function __construct() {
add_action('wp_ajax_wp_optimize_ajax', array($this, 'handle_ajax_requests'));
}
/**
* Return singleton instance
*
* @return WPO_Ajax Returns WPO_Ajax object
*/
public static function get_instance() {
static $instance = null;
if (null === $instance) {
$instance = new self();
}
return $instance;
}
/**
* Handles ajax requests
*
* @return void
*/
public function handle_ajax_requests() {
$this->set_nonce();
$this->set_subaction();
$this->set_data();
if (!$this->is_valid_request()) {
$this->send_security_check_failed_error_response();
}
if (!$this->is_user_capable()) {
$this->send_user_capability_error_response();
}
if (is_multisite() && !current_user_can('manage_network_options')) {
if (!$this->is_valid_multisite_command()) {
$this->send_invalid_multisite_command_error_response();
}
}
if ($this->is_subaction_a_dismissed_notice()) {
$this->handle_notice_dismissals();
} else {
$this->set_commands();
if ($this->is_invalid_command()) {
$this->add_invalid_command_error_log_entry();
$this->set_invalid_command_error_response();
} else {
$this->execute_command();
$this->maybe_fix_status_box_content();
$this->set_error_response_on_wp_error();
$this->maybe_set_results_as_null();
}
}
$this->json_encode_results();
$json_last_error = json_last_error();
if ($json_last_error) {
$this->set_error_response_on_json_encode_error($json_last_error);
}
echo $this->results;
die;
}
/**
* Sets nonce property value
*/
private function set_nonce() {
$this->nonce = empty($_POST['nonce']) ? '' : $_POST['nonce'];
}
/**
* Sets subaction property value
*/
private function set_subaction() {
$this->subaction = empty($_POST['subaction']) ? '' : stripcslashes($_POST['subaction']);
}
/**
* Sets data property value
*/
private function set_data() {
$this->data = isset($_POST['data']) ? stripslashes_deep($_POST['data']) : null;
}
/**
* Checks whether the request is valid or not
*
* @return bool
*/
private function is_valid_request() {
return wp_verify_nonce($this->nonce, 'wp-optimize-ajax-nonce') && !empty($this->subaction);
}
/**
* Send security check failed error response to browser and die
*/
private function send_security_check_failed_error_response() {
wp_send_json(array(
'result' => false,
'error_code' => 'security_check',
'error_message' => __('The security check failed; try refreshing the page.', 'wp-optimize')
));
}
/**
* Checks whether current user capable of doing this action or not
*
* @return bool
*/
private function is_user_capable() {
return current_user_can(WP_Optimize()->capability_required());
}
/**
* Send user capability check failed error response to browser and die
*/
private function send_user_capability_error_response() {
wp_send_json(array(
'result' => false,
'error_code' => 'security_check',
'error_message' => __('You are not allowed to run this command.', 'wp-optimize')
));
}
/**
* Checks whether subaction is a valid multisite command
*
* @return bool
*/
private function is_valid_multisite_command() {
/**
* Filters the commands allowed to the sub site admins. Other commands are only available to network admin. Only used in a multisite context.
*/
$allowed_multisite_commands = apply_filters('wpo_multisite_allowed_commands', array('check_server_status', 'compress_single_image', 'restore_single_image'));
return in_array($this->subaction, $allowed_multisite_commands);
}
/**
* Send invalid multisite command error response to browser and die
*/
private function send_invalid_multisite_command_error_response() {
wp_send_json(array(
'result' => false,
'error_code' => 'update_failed',
'error_message' => __('Options can only be saved by network admin', 'wp-optimize')
));
}
/**
* Checks if subaction is a notice dismissal or not
*
* @return bool True for notice dismiss actions, false otherwise
*/
private function is_subaction_a_dismissed_notice() {
$dismiss_actions = $this->get_dismiss_actions();
return in_array($this->subaction, $dismiss_actions);
}
/**
* Returns an array of notice dismiss action names
*
* @return array An array of notice dismiss actions
*/
private function get_dismiss_actions() {
return array(
'dismiss_dash_notice_until',
'dismiss_season',
'dismiss_page_notice_until',
'dismiss_notice',
'dismiss_review_notice',
);
}
/**
* Handles notice dismissals
*/
private function handle_notice_dismissals() {
$options = WP_Optimize()->get_options();
// Some commands that are available via AJAX only.
if (in_array($this->subaction, array('dismiss_dash_notice_until', 'dismiss_season'))) {
$options->update_option($this->subaction, (time() + 366 * 86400));
} elseif (in_array($this->subaction, array('dismiss_page_notice_until', 'dismiss_notice'))) {
$options->update_option($this->subaction, (time() + 84 * 86400));
} elseif ('dismiss_review_notice' == $this->subaction) {
if (empty($this->data['dismiss_forever'])) {
$options->update_option($this->subaction, time() + 84 * 86400);
} else {
$options->update_option($this->subaction, 100 * (365.25 * 86400));
}
}
}
/**
* Sets commands property value
*/
private function set_commands() {
$this->commands = new WP_Optimize_Commands();
$minify_commands = $this->get_minify_commands();
if ($this->is_subaction_a_minify_command($minify_commands)) {
$this->commands = $minify_commands;
}
$cache_commands = $this->get_cache_commands();
if ($this->is_subaction_a_cache_command($cache_commands)) {
$this->commands = $cache_commands;
}
}
/**
* Gets minify commands
*
* @return WP_Optimize_Minify_Commands
*/
private function get_minify_commands() {
return new WP_Optimize_Minify_Commands();
}
/**
* Gets cache commands
*
* @return WP_Optimize_Cache_Commands|WP_Optimize_Cache_Commands_Premium
*/
private function get_cache_commands() {
if (WP_Optimize::is_premium()) {
$cache_commands = new WP_Optimize_Cache_Commands_Premium();
} else {
$cache_commands = new WP_Optimize_Cache_Commands();
}
return $cache_commands;
}
/**
* Checks if applied ajax command is a minify command or not
*
* @param WP_Optimize_Minify_Commands $minify_commands an instance of minify commands class
*
* @return bool Returns true if ajax command is a minify command, false otherwise
*/
private function is_subaction_a_minify_command($minify_commands) {
return !is_callable(array($this->commands, $this->subaction)) && is_callable(array($minify_commands, $this->subaction));
}
/**
* Checks if applied ajax command is a cache command or not
*
* @param WP_Optimize_Cache_Commands|WP_Optimize_Cache_Commands_Premium $cache_commands an instance of cache commands
*
* @return bool Returns true if ajax command is a cache command, false otherwise
*/
private function is_subaction_a_cache_command($cache_commands) {
return !is_callable(array($this->commands, $this->subaction)) && is_callable(array($cache_commands, $this->subaction));
}
/**
* Checks if applied ajax command is an invalid command or not
*
* @return bool Returns true if ajax command is an invalid command, false otherwise
*/
private function is_invalid_command() {
return !is_callable(array($this->commands, $this->subaction));
}
/**
* Log an error message for invalid ajax command
*/
private function add_invalid_command_error_log_entry() {
error_log("WP-Optimize: ajax_handler: no such command (" . $this->subaction . ")");
}
/**
* Set `results` property with error response array for invalid ajax command
*
* @return void
*/
private function set_invalid_command_error_response() {
$this->results = array(
'result' => false,
'error_code' => 'command_not_found',
'error_message' => sprintf(__('The command "%s" was not found', 'wp-optimize'), $this->subaction)
);
}
/**
* Execute the ajax command
*/
private function execute_command() {
$this->results = call_user_func(array($this->commands, $this->subaction), $this->data);
}
/**
* If status box content is present, fix it.
*/
private function maybe_fix_status_box_content() {
// clean status box content, it broke json sometimes.
// Git commit wp-optimize/-/commit/c05686b39959b863f4e168af3fa54421c4870470
if (isset($this->results['status_box_contents'])) {
$this->results['status_box_contents'] = str_replace(array("\n", "\t"), '', $this->results['status_box_contents']);
}
}
/**
* Set `results` property with error message
*/
private function set_error_response_on_wp_error() {
if (is_wp_error($this->results)) {
$this->results = array(
'result' => false,
'error_code' => $this->results->get_error_code(),
'error_message' => $this->results->get_error_message(),
'error_data' => $this->results->get_error_data(),
);
}
}
/**
* Set `results` property to null, if it is not yet set
*/
private function maybe_set_results_as_null() {
// if nothing was returned for some reason, set as result null.
if (empty($this->results)) {
$this->results = array(
'result' => null
);
}
}
/**
* Sets `results` property with json encode error
*
* @param int $json_last_error
*
* @return void
*/
private function set_error_response_on_json_encode_error($json_last_error) {
$this->results = array(
'result' => false,
'error_code' => $json_last_error,
'error_message' => 'json_encode error : ' . $json_last_error,
'error_data' => '',
);
$this->results = json_encode($this->results);
}
/**
* Json encode the `results` property value
*/
private function json_encode_results() {
$this->results = json_encode($this->results);
}
}
endif;

Some files were not shown because too many files have changed in this diff Show More