first commit
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
1
wp-content/plugins/wp-optimize/includes/blockui/jquery.blockUI-3-2-14.min.js
vendored
Normal file
1
wp-content/plugins/wp-optimize/includes/blockui/jquery.blockUI-3-2-14.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -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 || ' ')+'</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 || ' ')+'</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);
|
||||
}
|
||||
|
||||
})();
|
||||
1
wp-content/plugins/wp-optimize/includes/blockui/jquery.blockUI.min-3-2-14.min.js
vendored
Normal file
1
wp-content/plugins/wp-optimize/includes/blockui/jquery.blockUI.min-3-2-14.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
wp-content/plugins/wp-optimize/includes/blockui/jquery.blockUI.min.js
vendored
Normal file
1
wp-content/plugins/wp-optimize/includes/blockui/jquery.blockUI.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 '';
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
236
wp-content/plugins/wp-optimize/includes/class-updraft-logger.php
Normal file
236
wp-content/plugins/wp-optimize/includes/class-updraft-logger.php
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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">★★★★★</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;
|
||||
@@ -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',
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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'];
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
607
wp-content/plugins/wp-optimize/includes/class-wp-optimizer.php
Normal file
607
wp-content/plugins/wp-optimize/includes/class-wp-optimizer.php
Normal 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;
|
||||
}
|
||||
}
|
||||
380
wp-content/plugins/wp-optimize/includes/class-wpo-ajax.php
Normal file
380
wp-content/plugins/wp-optimize/includes/class-wpo-ajax.php
Normal 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;
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
if (!defined('ABSPATH')) die('Access denied.');
|
||||
|
||||
if (!class_exists('WPO_Image_Utils')) :
|
||||
|
||||
class WPO_Image_Utils {
|
||||
|
||||
/**
|
||||
* Get image paths to resized attachment images.
|
||||
*
|
||||
* @param int $attachment_id
|
||||
* @return array
|
||||
*/
|
||||
public static function get_attachment_files($attachment_id) {
|
||||
$attachment_images = array();
|
||||
$upload_dir = wp_get_upload_dir();
|
||||
|
||||
// get sizes info from attachment meta data.
|
||||
$meta = wp_get_attachment_metadata($attachment_id);
|
||||
if (!is_array($meta) || !array_key_exists('sizes', $meta)) return $attachment_images;
|
||||
|
||||
$image_sizes = array_keys($meta['sizes']);
|
||||
|
||||
// build list of resized images.
|
||||
foreach ($image_sizes as $size) {
|
||||
$image = image_get_intermediate_size($attachment_id, $size);
|
||||
|
||||
if (is_array($image)) {
|
||||
$file = trailingslashit($upload_dir['basedir']) . $image['path'];
|
||||
if (is_file($file) && !in_array($file, $attachment_images)) {
|
||||
$attachment_images[$size] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $attachment_images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether we can do webp conversion or not
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function can_do_webp_conversion() {
|
||||
$webp_conversion = WP_Optimize()->get_options()->get_option('webp_conversion', false);
|
||||
$webp_converters = WP_Optimize()->get_options()->get_option('webp_converters', false);
|
||||
return $webp_conversion && !empty($webp_converters);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert given image file to webp format
|
||||
*
|
||||
* @param string $source Path of image file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function do_webp_conversion($source) {
|
||||
$webp_converter = new WPO_WebP_Convert();
|
||||
$webp_converter->convert($source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of allowed extensions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_allowed_extensions() {
|
||||
return array('gif', 'jpeg', 'jpg', 'png');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns given file extension
|
||||
*
|
||||
* @param string $file
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get_extension($file) {
|
||||
$file_type = wp_check_filetype($file);
|
||||
return $file_type['ext'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if given extension is present in allowed extensions array
|
||||
*
|
||||
* @param string $ext Extension to check
|
||||
* @param array $allowed_extensions Array of allowed extensions
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_supported_extension($ext, $allowed_extensions) {
|
||||
return in_array($ext, $allowed_extensions);
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
42
wp-content/plugins/wp-optimize/includes/updraftcentral.php
Normal file
42
wp-content/plugins/wp-optimize/includes/updraftcentral.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
if (!defined('WPO_PLUGIN_MAIN_PATH')) die('No direct access allowed');
|
||||
|
||||
/**
|
||||
* This file is the bootstrapper for UpdraftCentral integration: i.e. it registers what is necessary to deal with commands in the wpoptimize namespace.
|
||||
*/
|
||||
class WP_Optimize_UpdraftCentral {
|
||||
|
||||
public function __construct() {
|
||||
add_filter('updraftplus_remotecontrol_command_classes', array($this, 'updraftcentral_remotecontrol_command_classes'));
|
||||
add_filter('updraftcentral_remotecontrol_command_classes', array($this, 'updraftcentral_remotecontrol_command_classes'));
|
||||
add_action('updraftcentral_command_class_wanted', array($this, 'updraftcentral_command_class_wanted'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register our class
|
||||
*
|
||||
* @param string $command_classes Passing over an array of command classes.
|
||||
*/
|
||||
public function updraftcentral_remotecontrol_command_classes($command_classes) {
|
||||
if (is_array($command_classes)) $command_classes['wpoptimize'] = 'UpdraftCentral_WP_Optimize_Commands';
|
||||
return $command_classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the class when required
|
||||
*
|
||||
* @param string $command_php_class Passing over if there are any command classes.
|
||||
*/
|
||||
public function updraftcentral_command_class_wanted($command_php_class) {
|
||||
if ('UpdraftCentral_WP_Optimize_Commands' == $command_php_class) {
|
||||
// This fragment is only needed for compatibility with UD < 1.12.30 - thenceforth, the class can be assumed to exist.
|
||||
if (!class_exists('UpdraftCentral_Commands')) {
|
||||
include_once(apply_filters('updraftcentral_command_base_class_at', UPDRAFTPLUS_DIR.'/central/commands.php'));
|
||||
}
|
||||
include_once(WPO_PLUGIN_MAIN_PATH.'includes/class-updraftcentral-wp-optimize-commands.php');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new WP_Optimize_UpdraftCentral();
|
||||
Reference in New Issue
Block a user