259 lines
5.4 KiB
PHP
259 lines
5.4 KiB
PHP
|
<?php
|
||
|
|
||
|
namespace Sphere\Debloat;
|
||
|
|
||
|
/**
|
||
|
* Debloat processing setup for JS and CSS optimizations.
|
||
|
*
|
||
|
* @author asadkn
|
||
|
* @since 1.0.0
|
||
|
*/
|
||
|
class Process
|
||
|
{
|
||
|
/**
|
||
|
* Init happens too early around plugins_loaded
|
||
|
*/
|
||
|
public function init()
|
||
|
{
|
||
|
// Setup a few extra options.
|
||
|
Plugin::options()->delay_css_type = 'interact';
|
||
|
Plugin::options()->delay_js_type = 'interact';
|
||
|
|
||
|
// Setup at init but before template_redirect.
|
||
|
add_action('init', [$this, 'setup']);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Setup filters for processing
|
||
|
*
|
||
|
* @since 1.1.0
|
||
|
*/
|
||
|
public function setup()
|
||
|
{
|
||
|
if ($this->should_process()) {
|
||
|
|
||
|
// Load integrations.
|
||
|
$integrations = array_unique(array_merge(
|
||
|
(array) Plugin::options()->integrations_js,
|
||
|
(array) Plugin::options()->integrations_css
|
||
|
));
|
||
|
|
||
|
if ($integrations) {
|
||
|
if (in_array('elementor', $integrations) && class_exists('\Elementor\Plugin', false)) {
|
||
|
new Integrations\Elementor;
|
||
|
}
|
||
|
|
||
|
if (in_array('wpbakery', $integrations) && class_exists('Vc_Manager')) {
|
||
|
new Integrations\Wpbakery;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Process HTML for inline and local stylesheets.
|
||
|
*
|
||
|
* wp_ob_end_flush_all() will take care of flushing it.
|
||
|
*
|
||
|
* Note: Autoptimize starts at priority 2 so we use 3 to process BEFORE AO.
|
||
|
*/
|
||
|
add_action('template_redirect', function() {
|
||
|
if (!apply_filters('debloat/should_process', true)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Can't go in should_process() as that's too early.
|
||
|
if (function_exists('\amp_is_request') && \amp_is_request()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Shouldn't process feeds, embeds (iframe), or robots.txt request.
|
||
|
if (\is_feed() || \is_embed() || \is_robots()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
ob_start([$this, 'process_markup']);
|
||
|
}, -999);
|
||
|
|
||
|
// DEBUG: Devs if your output is disappearing - which you need for debugging,
|
||
|
// uncomment below and comment the init action above.
|
||
|
// add_action('template_redirect', function() { ob_start(); }, -999);
|
||
|
// add_action('shutdown', function() {
|
||
|
// $content = ob_get_clean();
|
||
|
// echo $this->process_markup($content);
|
||
|
// }, -10);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Process DOM Markup provided with the html.
|
||
|
*
|
||
|
* @param string $html
|
||
|
* @return string
|
||
|
*/
|
||
|
public function process_markup($html)
|
||
|
{
|
||
|
do_action('debloat/process_markup', $this);
|
||
|
|
||
|
if (!$this->is_valid_markup($html)) {
|
||
|
return $html;
|
||
|
}
|
||
|
|
||
|
$dom = null;
|
||
|
|
||
|
if ($this->should_optimize_css()) {
|
||
|
$dom = $this->get_dom($html);
|
||
|
$optimize = new OptimizeCss($dom, $html);
|
||
|
$html = $optimize->process();
|
||
|
}
|
||
|
|
||
|
if ($this->should_optimize_js()) {
|
||
|
$optimize_js = new OptimizeJs($html);
|
||
|
$html = $optimize_js->process();
|
||
|
}
|
||
|
|
||
|
// Add delay load JS and extras as needed.
|
||
|
$html = Plugin::delay_load()->render($html);
|
||
|
|
||
|
// Failed at processing DOM, return original.
|
||
|
if (!$dom) {
|
||
|
return $html;
|
||
|
}
|
||
|
|
||
|
return $html;
|
||
|
}
|
||
|
|
||
|
public function is_valid_markup($html)
|
||
|
{
|
||
|
if (stripos($html, '<html') === false) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get DOM object for the provided HTML.
|
||
|
*
|
||
|
* @param string $html
|
||
|
* @return boolean|\DOMDocument
|
||
|
*/
|
||
|
protected function get_dom($html)
|
||
|
{
|
||
|
if (!$html) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
$libxml_previous = libxml_use_internal_errors(true);
|
||
|
$dom = new \DOMDocument();
|
||
|
$result = $dom->loadHTML($html);
|
||
|
|
||
|
libxml_clear_errors();
|
||
|
libxml_use_internal_errors($libxml_previous);
|
||
|
|
||
|
// Deprecating xpath querying.
|
||
|
// if ($result) {
|
||
|
// $dom->xpath = new \DOMXPath($dom);
|
||
|
// }
|
||
|
|
||
|
return $result ? $dom : false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Should any processing be done at all.
|
||
|
*
|
||
|
* @return boolean
|
||
|
*/
|
||
|
public function should_process()
|
||
|
{
|
||
|
if (is_admin()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (function_exists('is_customize_preview') && is_customize_preview()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (isset($_GET['nodebloat'])) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (Util\is_elementor()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// WPBakery Page Builder. vc_is_page_editable() isn't reliable at all hooks.
|
||
|
if (!empty($_GET['vc_editable'])) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (Plugin::options()->disable_for_admins && current_user_can('manage_options')) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Should the JS be optimized.
|
||
|
*
|
||
|
* @return boolean
|
||
|
*/
|
||
|
public function should_optimize_js()
|
||
|
{
|
||
|
$valid = true;
|
||
|
return apply_filters('debloat/should_optimize_js', $valid);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Should the CSS be optimized.
|
||
|
*
|
||
|
* @return boolean
|
||
|
*/
|
||
|
public function should_optimize_css()
|
||
|
{
|
||
|
$valid = Plugin::options()->remove_css || Plugin::options()->optimize_css;
|
||
|
return apply_filters('debloat/should_optimize_css', $valid);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Conditions test to see if current page matches in the provided valid conditions.
|
||
|
*
|
||
|
* @param array $enable_on
|
||
|
* @return boolean
|
||
|
*/
|
||
|
public function check_enabled(array $enable_on)
|
||
|
{
|
||
|
if (in_array('all', $enable_on)) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
$conditions = [
|
||
|
'pages' => 'is_page',
|
||
|
'posts' => 'is_single',
|
||
|
'archives' => 'is_archive',
|
||
|
'archive' => 'is_archive', // Alias
|
||
|
'categories' => 'is_category',
|
||
|
'tags' => 'is_tag',
|
||
|
'search' => 'is_search',
|
||
|
'404' => 'is_404',
|
||
|
'home' => function() {
|
||
|
return is_home() || is_front_page();
|
||
|
},
|
||
|
];
|
||
|
|
||
|
$satisfy = false;
|
||
|
foreach ($enable_on as $key) {
|
||
|
if (!isset($conditions[$key]) || !is_callable($conditions[$key])) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$satisfy = call_user_func($conditions[$key]);
|
||
|
|
||
|
// Stop going further in loop once satisfied.
|
||
|
if ($satisfy) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return $satisfy;
|
||
|
}
|
||
|
}
|