Commit inicial - WordPress Análisis de Precios Unitarios

- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 additions and 0 deletions

View File

@@ -0,0 +1,107 @@
<?php
/**
* Plugin Name: Allow Unfiltered HTML
* Description: Permite a administradores guardar HTML/CSS/JS sin filtros de WordPress
* Version: 7.0.0
* Author: PODC4
*/
if (!defined('ABSPATH')) exit;
// ============================================
// CAPACIDAD PARA ADMINISTRADORES
// ============================================
add_action('init', function () {
if (is_multisite()) return;
$role = get_role('administrator');
if ($role && !$role->has_cap('unfiltered_html')) {
$role->add_cap('unfiltered_html');
}
}, 1);
// ============================================
// DESACTIVAR KSES AL GUARDAR (SOLO ADMINS)
// ============================================
add_action('init', function () {
if (defined('DISALLOW_UNFILTERED_HTML') && DISALLOW_UNFILTERED_HTML) return;
if (!current_user_can('unfiltered_html')) return;
remove_filter('content_save_pre', 'wp_filter_post_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
remove_filter('excerpt_save_pre', 'wp_filter_post_kses');
remove_filter('content_save_pre', 'wp_filter_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_kses');
remove_filter('excerpt_save_pre', 'wp_filter_kses');
add_action('wp_loaded', function () {
remove_filter('content_save_pre', 'wp_filter_post_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
remove_filter('excerpt_save_pre', 'wp_filter_post_kses');
remove_filter('content_save_pre', 'wp_filter_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_kses');
remove_filter('excerpt_save_pre', 'wp_filter_kses');
}, 9999);
}, 20);
// ============================================
// CONFIGURACIÓN TINYMCE (SOLO ADMINS)
// ============================================
add_filter('tiny_mce_before_init', function ($init) {
if (!current_user_can('unfiltered_html')) return $init;
$init['valid_elements'] = '*[*]';
$init['extended_valid_elements'] = 'script[src|type|async|defer|referrerpolicy|crossorigin],style[type|media],iframe[src|width|height|frameborder|allowfullscreen|allow]';
$init['paste_remove_styles'] = false;
$init['paste_as_text'] = false;
$init['verify_html'] = false;
$init['cleanup'] = false;
$init['forced_root_block'] = false;
return $init;
});
// ============================================
// PERMITIR TAGS EN WP_KSES (SOLO ADMINS)
// ============================================
add_filter('wp_kses_allowed_html', function ($allowed, $context) {
if (!current_user_can('unfiltered_html')) return $allowed;
if (!\is_array($allowed)) $allowed = [];
if ($context === 'post' || $context === null) {
$allowed['script'] = [
'src' => true,
'type' => true,
'async' => true,
'defer' => true,
'referrerpolicy' => true,
'crossorigin' => true,
];
$allowed['style'] = [
'type' => true,
'media' => true,
];
$allowed['iframe'] = [
'src' => true,
'width' => true,
'height' => true,
'frameborder' => true,
'allowfullscreen' => true,
'allow' => true,
];
}
return $allowed;
}, 10, 2);
// ============================================
// REFUERZO: wp_insert_post_data
// ============================================
add_filter('wp_insert_post_data', function($data, $postarr) {
if (!current_user_can('unfiltered_html')) return $data;
if (isset($postarr['content']) && !empty($postarr['content'])) {
$data['post_content'] = $postarr['content'];
$data['post_content_filtered'] = '';
}
return $data;
}, 99, 2);

View File

@@ -0,0 +1,333 @@
<?php
/**
* Plugin Name: HTML Raw Mode (Thrive Compatible)
* Description: Renderiza HTML/CSS/JS para TODOS los visitantes. Solo Admins pueden GUARDAR código. Compatible con Thrive Architect.
* Version: 6.0.0
* Author: PODC4
* License: GPL-2.0-or-later
*/
if (!defined('ABSPATH')) exit;
// ============================================
// FUNCIÓN: DETECTAR PÁGINAS DE THRIVE ARCHITECT
// ============================================
function is_thrive_architect_page($post_id = null) {
if (!$post_id) {
global $post;
if (!$post) return false;
$post_id = $post->ID;
}
$thrive_meta_keys = [
'tcb_editor_enabled',
'tve_updated_post',
'tve_landing_page',
'thrive_tcb_post_fonts',
'tve_globals',
'tcb2_ready',
];
foreach ($thrive_meta_keys as $key) {
$value = get_post_meta($post_id, $key, true);
if (!empty($value)) {
return true;
}
}
return false;
}
// ============================================
// CAPACIDADES PARA ADMINISTRADORES
// ============================================
add_action('init', function () {
if (is_multisite()) return;
$role = get_role('administrator');
if ($role && !$role->has_cap('unfiltered_html')) {
$role->add_cap('unfiltered_html');
}
}, 1);
// ============================================
// DESACTIVAR KSES AL GUARDAR (SOLO ADMINS)
// ============================================
add_action('init', function () {
if (defined('DISALLOW_UNFILTERED_HTML') && DISALLOW_UNFILTERED_HTML) return;
if (!current_user_can('unfiltered_html')) return;
remove_filter('content_save_pre', 'wp_filter_post_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
remove_filter('excerpt_save_pre', 'wp_filter_post_kses');
remove_filter('content_save_pre', 'wp_filter_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_kses');
remove_filter('excerpt_save_pre', 'wp_filter_kses');
add_action('wp_loaded', function () {
remove_filter('content_save_pre', 'wp_filter_post_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
remove_filter('excerpt_save_pre', 'wp_filter_post_kses');
remove_filter('content_save_pre', 'wp_filter_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_kses');
remove_filter('excerpt_save_pre', 'wp_filter_kses');
}, 9999);
}, 20);
// ============================================
// FRONTEND: RENDERIZAR HTML CRUDO PARA TODOS (EXCEPTO THRIVE)
// ============================================
add_action('init', function () {
if (is_admin()) return;
// Quita filtros KSES típicos en frontend para TODOS
foreach (['wp_kses_post', 'wp_kses_data', 'wp_filter_kses'] as $cb) {
if (has_filter('the_content', $cb)) {
remove_filter('the_content', $cb);
}
}
// Red de seguridad: elimina filtros KSES globales (TODOS los usuarios)
if (function_exists('kses_remove_filters')) {
kses_remove_filters();
}
// Acepta <script> y <style> si algún filtro externo aplica wp_kses
add_filter('wp_kses_allowed_html', function ($allowed, $context) {
if (!is_array($allowed)) $allowed = [];
if ($context === 'post' || $context === null) {
$allowed['script'] = [
'src' => true,
'type' => true,
'async' => true,
'defer' => true,
'referrerpolicy' => true,
'crossorigin' => true,
];
$allowed['style'] = [
'type' => true,
'media' => true,
];
$allowed['iframe'] = [
'src' => true,
'width' => true,
'height' => true,
'frameborder' => true,
'allowfullscreen' => true,
'allow' => true,
];
}
return $allowed;
}, 10, 2);
// FUERZA contenido crudo desde BD para TODOS los visitantes (máxima prioridad)
add_filter('the_content', function ($content) {
if (is_admin()) return $content;
global $post;
if (!$post) return $content;
// NO TOCAR páginas de Thrive Architect
if (is_thrive_architect_page($post->ID)) {
return $content;
}
// Obtén contenido crudo desde la base de datos (sin filtros)
$raw = get_post_field('post_content', $post->ID, 'raw');
if ($raw === '' || $raw === null) return $content;
// Aplica shortcodes si los usas
if (function_exists('do_shortcode')) {
$raw = do_shortcode($raw);
}
// NO aplicar wp_kses ni filtros. Retorna HTML/CSS/JS crudo para TODOS
return $raw;
}, PHP_INT_MAX);
}, 30);
// ============================================
// CONFIGURACIÓN TINYMCE (SOLO ADMINS, EXCEPTO THRIVE)
// ============================================
add_filter('tiny_mce_before_init', function ($init) {
if (!current_user_can('unfiltered_html')) return $init;
global $post;
if ($post && is_thrive_architect_page($post->ID)) {
return $init;
}
$init['valid_elements'] = '*[*]';
$init['extended_valid_elements'] = 'script[src|type|async|defer|referrerpolicy|crossorigin],style[type|media],iframe[src|width|height|frameborder|allowfullscreen|allow]';
$init['paste_remove_styles'] = false;
$init['paste_as_text'] = false;
$init['verify_html'] = false;
$init['cleanup'] = false;
$init['forced_root_block'] = false;
return $init;
});
// ============================================
// DESACTIVAR WPAUTOP PARA TODOS EN FRONTEND (CRÍTICO)
// ============================================
/**
* IMPORTANTE: Esta función NO verifica capacidades porque debe aplicar
* a TODOS los visitantes (logueados o no) en el frontend.
* Solo afecta la visualización, no el guardado.
*/
add_action('init', function () {
if (is_admin()) return; // Solo frontend
// Desactiva wpautop para TODOS los usuarios
remove_filter('the_content', 'wpautop');
remove_filter('the_excerpt', 'wpautop');
}, 20);
// Hook adicional con prioridad 0 para asegurar que se ejecute antes que todo
add_filter('the_content', function($content) {
if (is_admin()) return $content;
global $post;
if ($post && is_thrive_architect_page($post->ID)) {
return $content; // Mantener wpautop para Thrive
}
// Para páginas normales: desactiva wpautop (TODOS los usuarios)
remove_filter('the_content', 'wpautop');
remove_filter('the_excerpt', 'wpautop');
return $content;
}, 0);
// ============================================
// HOOK ADICIONAL: wp_insert_post_data (REFUERZO)
// ============================================
add_filter('wp_insert_post_data', function($data, $postarr) {
// Solo para admins y si NO es Thrive
if (!current_user_can('unfiltered_html')) return $data;
if (isset($postarr['ID']) && is_thrive_architect_page($postarr['ID'])) return $data;
// Guarda el contenido exactamente como viene
if (isset($postarr['content']) && !empty($postarr['content'])) {
$data['post_content'] = $postarr['content'];
$data['post_content_filtered'] = '';
}
return $data;
}, 99, 2);
// ============================================
// OPTIMIZACIÓN: REMOVER CSS DE BLOQUES
// ============================================
add_action('wp_enqueue_scripts', function() {
global $post;
if ($post && is_thrive_architect_page($post->ID)) {
return;
}
wp_dequeue_style('wp-block-library');
wp_dequeue_style('wp-block-library-theme');
wp_dequeue_style('wc-blocks-style');
wp_dequeue_style('global-styles');
wp_dequeue_style('classic-theme-styles');
}, 100);
// ============================================
// COLUMNA EN LISTADO DE PÁGINAS
// ============================================
add_filter('manage_pages_columns', function($columns) {
$new_columns = [];
foreach ($columns as $key => $value) {
$new_columns[$key] = $value;
if ($key === 'title') {
$new_columns['page_editor_type'] = '🔧 Editor';
}
}
return $new_columns;
});
add_action('manage_pages_custom_column', function($column, $post_id) {
if ($column === 'page_editor_type') {
if (is_thrive_architect_page($post_id)) {
echo '<span style="color: #00a32a; font-weight: bold;">🎨 Thrive</span>';
} else {
echo '<span style="color: #2271b1;">📝 HTML Raw</span>';
}
}
}, 10, 2);
// ============================================
// NOTIFICACIONES EN ADMIN
// ============================================
add_action('admin_notices', function() {
global $post, $pagenow;
if (!in_array($pagenow, ['post.php', 'post-new.php'])) return;
if (!$post) return;
if (is_thrive_architect_page($post->ID)) {
echo '<div class="notice notice-success">';
echo '<p><strong>🎨 Thrive Architect</strong> - Esta página no será afectada por HTML Raw Mode.</p>';
echo '</div>';
} else {
$screen = get_current_screen();
if ($screen && !$screen->is_block_editor()) {
echo '<div class="notice notice-info">';
echo '<p><strong>📝 Modo HTML Raw</strong> - Usa la pestaña <strong>"Texto"</strong> para pegar HTML/CSS/JS sin restricciones. El contenido se verá igual para TODOS los visitantes.</p>';
echo '</div>';
}
}
});
add_action('admin_notices', function() {
$screen = get_current_screen();
if ($screen->id !== 'dashboard') return;
if (!is_plugin_active('classic-editor/classic-editor.php')) {
echo '<div class="notice notice-warning is-dismissible">';
echo '<p><strong>⚠️ HTML Raw Mode:</strong> Se recomienda instalar <strong>"Classic Editor"</strong> para deshabilitar bloques.</p>';
echo '<p><a href="' . admin_url('plugin-install.php?s=classic+editor&tab=search&type=term') . '" class="button button-primary">Instalar Classic Editor</a></p>';
echo '</div>';
}
});
// ============================================
// SCRIPT ADMIN: Destacar pestaña TEXTO
// ============================================
add_action('admin_head', function() {
global $post;
if (!$post || !current_user_can('unfiltered_html')) return;
if (is_thrive_architect_page($post->ID)) return;
?>
<style>
#content-html {
background: #2271b1 !important;
color: white !important;
font-weight: bold !important;
}
</style>
<?php
});
// ============================================
// PROTECCIÓN EXTRA PARA THRIVE
// ============================================
add_action('admin_init', function() {
if (isset($_GET['tve']) || isset($_GET['tcbf']) || isset($_GET['tar_edit_mode'])) {
// Estamos en el editor de Thrive, no modificar nada
return;
}
});

View File

@@ -0,0 +1,333 @@
<?php
/**
* Plugin Name: HTML Raw Mode (Thrive Compatible)
* Description: Renderiza HTML/CSS/JS para TODOS los visitantes. Solo Admins pueden GUARDAR código. Compatible con Thrive Architect.
* Version: 6.0.0
* Author: PODC4
* License: GPL-2.0-or-later
*/
if (!defined('ABSPATH')) exit;
// ============================================
// FUNCIÓN: DETECTAR PÁGINAS DE THRIVE ARCHITECT
// ============================================
function is_thrive_architect_page($post_id = null) {
if (!$post_id) {
global $post;
if (!$post) return false;
$post_id = $post->ID;
}
$thrive_meta_keys = [
'tcb_editor_enabled',
'tve_updated_post',
'tve_landing_page',
'thrive_tcb_post_fonts',
'tve_globals',
'tcb2_ready',
];
foreach ($thrive_meta_keys as $key) {
$value = get_post_meta($post_id, $key, true);
if (!empty($value)) {
return true;
}
}
return false;
}
// ============================================
// CAPACIDADES PARA ADMINISTRADORES
// ============================================
add_action('init', function () {
if (is_multisite()) return;
$role = get_role('administrator');
if ($role && !$role->has_cap('unfiltered_html')) {
$role->add_cap('unfiltered_html');
}
}, 1);
// ============================================
// DESACTIVAR KSES AL GUARDAR (SOLO ADMINS)
// ============================================
add_action('init', function () {
if (defined('DISALLOW_UNFILTERED_HTML') && DISALLOW_UNFILTERED_HTML) return;
if (!current_user_can('unfiltered_html')) return;
remove_filter('content_save_pre', 'wp_filter_post_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
remove_filter('excerpt_save_pre', 'wp_filter_post_kses');
remove_filter('content_save_pre', 'wp_filter_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_kses');
remove_filter('excerpt_save_pre', 'wp_filter_kses');
add_action('wp_loaded', function () {
remove_filter('content_save_pre', 'wp_filter_post_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
remove_filter('excerpt_save_pre', 'wp_filter_post_kses');
remove_filter('content_save_pre', 'wp_filter_kses');
remove_filter('content_filtered_save_pre', 'wp_filter_kses');
remove_filter('excerpt_save_pre', 'wp_filter_kses');
}, 9999);
}, 20);
// ============================================
// FRONTEND: RENDERIZAR HTML CRUDO PARA TODOS (EXCEPTO THRIVE)
// ============================================
add_action('init', function () {
if (is_admin()) return;
// Quita filtros KSES típicos en frontend para TODOS
foreach (['wp_kses_post', 'wp_kses_data', 'wp_filter_kses'] as $cb) {
if (has_filter('the_content', $cb)) {
remove_filter('the_content', $cb);
}
}
// Red de seguridad: elimina filtros KSES globales (TODOS los usuarios)
if (function_exists('kses_remove_filters')) {
kses_remove_filters();
}
// Acepta <script> y <style> si algún filtro externo aplica wp_kses
add_filter('wp_kses_allowed_html', function ($allowed, $context) {
if (!is_array($allowed)) $allowed = [];
if ($context === 'post' || $context === null) {
$allowed['script'] = [
'src' => true,
'type' => true,
'async' => true,
'defer' => true,
'referrerpolicy' => true,
'crossorigin' => true,
];
$allowed['style'] = [
'type' => true,
'media' => true,
];
$allowed['iframe'] = [
'src' => true,
'width' => true,
'height' => true,
'frameborder' => true,
'allowfullscreen' => true,
'allow' => true,
];
}
return $allowed;
}, 10, 2);
// FUERZA contenido crudo desde BD para TODOS los visitantes (máxima prioridad)
add_filter('the_content', function ($content) {
if (is_admin()) return $content;
global $post;
if (!$post) return $content;
// NO TOCAR páginas de Thrive Architect
if (is_thrive_architect_page($post->ID)) {
return $content;
}
// Obtén contenido crudo desde la base de datos (sin filtros)
$raw = get_post_field('post_content', $post->ID, 'raw');
if ($raw === '' || $raw === null) return $content;
// Aplica shortcodes si los usas
if (function_exists('do_shortcode')) {
$raw = do_shortcode($raw);
}
// NO aplicar wp_kses ni filtros. Retorna HTML/CSS/JS crudo para TODOS
return $raw;
}, PHP_INT_MAX);
}, 30);
// ============================================
// CONFIGURACIÓN TINYMCE (SOLO ADMINS, EXCEPTO THRIVE)
// ============================================
add_filter('tiny_mce_before_init', function ($init) {
if (!current_user_can('unfiltered_html')) return $init;
global $post;
if ($post && is_thrive_architect_page($post->ID)) {
return $init;
}
$init['valid_elements'] = '*[*]';
$init['extended_valid_elements'] = 'script[src|type|async|defer|referrerpolicy|crossorigin],style[type|media],iframe[src|width|height|frameborder|allowfullscreen|allow]';
$init['paste_remove_styles'] = false;
$init['paste_as_text'] = false;
$init['verify_html'] = false;
$init['cleanup'] = false;
$init['forced_root_block'] = false;
return $init;
});
// ============================================
// DESACTIVAR WPAUTOP PARA TODOS EN FRONTEND (CRÍTICO)
// ============================================
/**
* IMPORTANTE: Esta función NO verifica capacidades porque debe aplicar
* a TODOS los visitantes (logueados o no) en el frontend.
* Solo afecta la visualización, no el guardado.
*/
add_action('init', function () {
if (is_admin()) return; // Solo frontend
// Desactiva wpautop para TODOS los usuarios
remove_filter('the_content', 'wpautop');
remove_filter('the_excerpt', 'wpautop');
}, 20);
// Hook adicional con prioridad 0 para asegurar que se ejecute antes que todo
add_filter('the_content', function($content) {
if (is_admin()) return $content;
global $post;
if ($post && is_thrive_architect_page($post->ID)) {
return $content; // Mantener wpautop para Thrive
}
// Para páginas normales: desactiva wpautop (TODOS los usuarios)
remove_filter('the_content', 'wpautop');
remove_filter('the_excerpt', 'wpautop');
return $content;
}, 0);
// ============================================
// HOOK ADICIONAL: wp_insert_post_data (REFUERZO)
// ============================================
add_filter('wp_insert_post_data', function($data, $postarr) {
// Solo para admins y si NO es Thrive
if (!current_user_can('unfiltered_html')) return $data;
if (isset($postarr['ID']) && is_thrive_architect_page($postarr['ID'])) return $data;
// Guarda el contenido exactamente como viene
if (isset($postarr['content']) && !empty($postarr['content'])) {
$data['post_content'] = $postarr['content'];
$data['post_content_filtered'] = '';
}
return $data;
}, 99, 2);
// ============================================
// OPTIMIZACIÓN: REMOVER CSS DE BLOQUES
// ============================================
add_action('wp_enqueue_scripts', function() {
global $post;
if ($post && is_thrive_architect_page($post->ID)) {
return;
}
wp_dequeue_style('wp-block-library');
wp_dequeue_style('wp-block-library-theme');
wp_dequeue_style('wc-blocks-style');
wp_dequeue_style('global-styles');
wp_dequeue_style('classic-theme-styles');
}, 100);
// ============================================
// COLUMNA EN LISTADO DE PÁGINAS
// ============================================
add_filter('manage_pages_columns', function($columns) {
$new_columns = [];
foreach ($columns as $key => $value) {
$new_columns[$key] = $value;
if ($key === 'title') {
$new_columns['page_editor_type'] = '🔧 Editor';
}
}
return $new_columns;
});
add_action('manage_pages_custom_column', function($column, $post_id) {
if ($column === 'page_editor_type') {
if (is_thrive_architect_page($post_id)) {
echo '<span style="color: #00a32a; font-weight: bold;">🎨 Thrive</span>';
} else {
echo '<span style="color: #2271b1;">📝 HTML Raw</span>';
}
}
}, 10, 2);
// ============================================
// NOTIFICACIONES EN ADMIN
// ============================================
add_action('admin_notices', function() {
global $post, $pagenow;
if (!in_array($pagenow, ['post.php', 'post-new.php'])) return;
if (!$post) return;
if (is_thrive_architect_page($post->ID)) {
echo '<div class="notice notice-success">';
echo '<p><strong>🎨 Thrive Architect</strong> - Esta página no será afectada por HTML Raw Mode.</p>';
echo '</div>';
} else {
$screen = get_current_screen();
if ($screen && !$screen->is_block_editor()) {
echo '<div class="notice notice-info">';
echo '<p><strong>📝 Modo HTML Raw</strong> - Usa la pestaña <strong>"Texto"</strong> para pegar HTML/CSS/JS sin restricciones. El contenido se verá igual para TODOS los visitantes.</p>';
echo '</div>';
}
}
});
add_action('admin_notices', function() {
$screen = get_current_screen();
if ($screen->id !== 'dashboard') return;
if (!is_plugin_active('classic-editor/classic-editor.php')) {
echo '<div class="notice notice-warning is-dismissible">';
echo '<p><strong>⚠️ HTML Raw Mode:</strong> Se recomienda instalar <strong>"Classic Editor"</strong> para deshabilitar bloques.</p>';
echo '<p><a href="' . admin_url('plugin-install.php?s=classic+editor&tab=search&type=term') . '" class="button button-primary">Instalar Classic Editor</a></p>';
echo '</div>';
}
});
// ============================================
// SCRIPT ADMIN: Destacar pestaña TEXTO
// ============================================
add_action('admin_head', function() {
global $post;
if (!$post || !current_user_can('unfiltered_html')) return;
if (is_thrive_architect_page($post->ID)) return;
?>
<style>
#content-html {
background: #2271b1 !important;
color: white !important;
font-weight: bold !important;
}
</style>
<?php
});
// ============================================
// PROTECCIÓN EXTRA PARA THRIVE
// ============================================
add_action('admin_init', function() {
if (isset($_GET['tve']) || isset($_GET['tcbf']) || isset($_GET['tar_edit_mode'])) {
// Estamos en el editor de Thrive, no modificar nada
return;
}
});

View File

@@ -0,0 +1,8 @@
<?php
// Disable WP site health test for automatic updates
// This plugin was added by Installatron because Installatron is handling upgrading of this application
function my_filter_site_status_tests($tests) {
unset($tests['async']['background_updates']);
return $tests;
}
add_filter('site_status_tests', 'my_filter_site_status_tests');

View File

@@ -0,0 +1,591 @@
<?php
/*
Plugin Name: Perfmatters MU
Plugin URI: https://perfmatters.io/
Description: Perfmatters is a lightweight performance plugin developed to speed up your WordPress site.
Version: 2.1.4
Author: forgemedia
Author URI: https://forgemedia.io/
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: perfmatters
Domain Path: /languages
*/
add_filter('option_active_plugins', 'perfmatters_mu_disable_plugins', 1);
function perfmatters_mu_disable_plugins($plugins) {
//admin check
if(is_admin()) {
return $plugins;
}
//only filter GET requests
if((!isset($_SERVER['REQUEST_METHOD']) || $_SERVER['REQUEST_METHOD'] !== 'GET') && !isset($_GET['perfmatters'])) {
return $plugins;
}
//dont filter if its a rest or ajax request
if((defined('REST_REQUEST') && REST_REQUEST) || (defined('WP_CLI') && WP_CLI) || (function_exists('wp_is_json_request') && wp_is_json_request()) || wp_doing_ajax() || wp_doing_cron()) {
return $plugins;
}
//manual wp-json check
if(stripos(trailingslashit($_SERVER['REQUEST_URI']), '/wp-json/') !== false) {
return $plugins;
}
//manual ajax check
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
return $plugins;
}
//base plugin active check
if(is_array($plugins) && !in_array('perfmatters/perfmatters.php', $plugins)) {
return $plugins;
}
//make sure script manager is enabled
$perfmatters_options = get_option('perfmatters_options');
if(empty($perfmatters_options['assets']['script_manager'])) {
return $plugins;
}
//make sure MU is enabled
$pmsm_settings = get_option('perfmatters_script_manager_settings');
if(empty($pmsm_settings['mu_mode'])) {
return $plugins;
}
//wp login check
$perfmatters_options = get_option('perfmatters_options');
if((!empty($GLOBALS['pagenow']) && $GLOBALS['pagenow'] == 'wp-login.php') || (!empty($perfmatters_options['login_url']) && !empty($GLOBALS['_SERVER']['REQUEST_URI']) && trim($GLOBALS['_SERVER']['REQUEST_URI'], '/') == $perfmatters_options['login_url'])) {
return $plugins;
}
//script manager is being viewed
if(isset($_GET['perfmatters'])) {
//store active plugins for script manager UI in case they get disabled completely
global $pmsm_active_plugins;
$pmsm_active_plugins = $plugins;
//don't filter plugins if script manager is up
return $plugins;
}
if(isset($_GET['perfmattersoff'])) {
return $plugins;
}
//testing mode check
if(!empty($pmsm_settings['testing_mode'])) {
require_once(wp_normalize_path(ABSPATH) . 'wp-includes/pluggable.php');
if(!function_exists('wp_get_current_user') || !current_user_can('manage_options')) {
return $plugins;
}
}
//check for manual override
if(!empty($_GET['mu_mode']) && $_GET['mu_mode'] == 'off') {
return $plugins;
}
//make sure mu hasn't run already
global $mu_run_flag;
global $mu_plugins;
if($mu_run_flag) {
return $mu_plugins;
}
//get script manager configuration
$pmsm = get_option('perfmatters_script_manager');
//we have some plugins that are disabled
if(!empty($pmsm['disabled']['plugins'])) {
//attempt to get post id
$currentID = perfmatters_mu_get_current_ID();
//echo $currentID;
//assign disable/enable arrays
$disabled = $pmsm['disabled']['plugins'];
$enabled = !empty($pmsm['enabled']['plugins']) ? $pmsm['enabled']['plugins'] : '';
//loop through disabled plugins
foreach($disabled as $handle => $data) {
//current plugin disable is set
if(!empty($data['everywhere'])
|| (!empty($data['current']) && in_array($currentID, $data['current']))
|| pmsm_mu_check_post_types($data, $currentID)
|| pmsm_mu_check_user_status($data)
|| pmsm_mu_check_device_type($data)
|| (!empty($data['regex']) && preg_match($data['regex'], home_url(add_query_arg(array(), $_SERVER['REQUEST_URI']))))
) {
if(!empty($enabled[$handle])) {
//enable current url check
if(!empty($enabled[$handle]['current']) && in_array($currentID, $enabled[$handle]['current'])) {
continue;
}
//user status check
if(pmsm_mu_check_user_status($enabled[$handle])) {
continue;
}
//device type check
if(pmsm_mu_check_device_type($enabled[$handle])) {
continue;
}
//enable regex
if(!empty($enabled[$handle]['regex'])) {
if(preg_match($enabled[$handle]['regex'], home_url(add_query_arg(array(), $_SERVER['REQUEST_URI'])))) {
continue;
}
}
//home page as post type
if(pmsm_mu_check_post_types($enabled[$handle], $currentID)) {
continue;
}
}
//remove plugin from list
$m_array = preg_grep('/^' . $handle . '.*/', $plugins);
$single_array = array();
if(!empty($m_array) && is_array($m_array)) {
if(count($m_array) > 1) {
$single_array = preg_grep('/' . $handle . '\.php/', $m_array);
}
if(!empty($single_array)) {
unset($plugins[key($single_array)]);
}
else {
unset($plugins[key($m_array)]);
}
}
}
}
}
$mu_run_flag = true;
$mu_plugins = $plugins;
return $plugins;
}
//remove our filter after plugins have loaded
function perfmatters_mu_remove_filters() {
remove_filter('option_active_plugins', 'perfmatters_mu_disable_plugins', 1, 1);
}
add_action('plugins_loaded', 'perfmatters_mu_remove_filters', 1);
//attempt to get the current id for mu mode
function perfmatters_mu_get_current_ID() {
//load necessary parts for url_to_postid
if(!defined('LOGGED_IN_COOKIE')) {
wp_cookie_constants();
}
require_once(wp_normalize_path(ABSPATH) . 'wp-includes/pluggable.php');
global $wp_rewrite;
global $wp;
$wp_rewrite = new WP_Rewrite();
$wp = new WP();
//attempt to get post id from url
$currentID = (int) perfmatters_url_to_postid(home_url($_SERVER['REQUEST_URI']));
//id wasn't found
if($currentID === 0) {
//check for home url match
//$request = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . strtok($_SERVER['REQUEST_URI']);
$request = (isset($_SERVER['HTTPS']) ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
if(trailingslashit(home_url()) !== trailingslashit($request)) {
$currentID = '';
}
}
//clean up
unset($wp_rewrite);
unset($wp);
return $currentID;
}
//check if current post type is set in option
function pmsm_mu_check_post_types($option, $currentID = '') {
if($currentID === 0) {
if(get_option('show_on_front') == 'page' && !empty($option['post_types']) && in_array('page', $option['post_types'])) {
return true;
}
}
elseif(!empty($currentID)) {
//grab post details
$post = get_post($currentID);
//post type enable check
if(!empty($post->post_type) && !empty($option['post_types']) && in_array($post->post_type, $option['post_types'])) {
return true;
}
}
return false;
}
//check if current user status is set
function pmsm_mu_check_user_status($option) {
if(!empty($option['user_status'])) {
$status = is_user_logged_in();
if(($status && $option['user_status'] == 'loggedin') || (!$status && $option['user_status'] == 'loggedout')) {
return true;
}
}
return false;
}
//check if current device type is set
function pmsm_mu_check_device_type($option) {
if(!empty($option['device_type'])) {
$mobile = wp_is_mobile();
if(($mobile && $option['device_type'] == 'mobile') || (!$mobile && $option['device_type'] == 'desktop')) {
return true;
}
}
return false;
}
//custom url_to_postid() replacement - modified from https://gist.github.com/Webcreations907/ce5b77565dfb9a208738
function perfmatters_url_to_postid($url) {
if ( isset( $_GET['post'] ) && ! empty( $_GET['post'] ) && is_numeric( $_GET['post'] ) ) {
return $_GET['post'];
}
// First, check to see if there is a 'p=N' or 'page_id=N' to match against
// added post to match, even though it's above
if ( preg_match( '#[?&](p|post|page_id|attachment_id)=(\d+)#', $url, $values ) ) {
$id = absint( $values[2] );
if ( $id ) {
return $id;
}
}
// Check to see if we are using rewrite rules
$rewrite = get_option('rewrite_rules');
global $wp_rewrite;
//$rewrite = $wp_rewrite->wp_rewrite_rules();
// Not using rewrite rules, and 'p=N' and 'page_id=N' methods failed, so we're out of options
if ( empty( $rewrite ) ) {
if ( isset( $_GET ) && ! empty( $_GET ) ) {
/************************************************************************
* ADDED: Trys checks URL for ?posttype=postname
*************************************************************************/
// Assign $url to $tempURL just incase. :)
$tempUrl = $url;
// Get rid of the #anchor
$url_split = explode( '#', $tempUrl );
$tempUrl = $url_split[0];
// Get rid of URL ?query=string
$url_query = explode( '&', $tempUrl );
$tempUrl = $url_query[0];
// Get rid of ? mark
$url_query = explode( '?', $tempUrl);
if(isset($url_query[1]) && !empty($url_query[1]) && strpos( $url_query[1], '=' )){
$url_query = explode( '=', $url_query[1] );
if(isset($url_query[0]) && isset($url_query[1])){
$args = array(
'name' => $url_query[1],
'post_type' => $url_query[0],
'showposts' => 1,
);
if ( $post = get_posts( $args ) ) {
return $post[0]->ID;
}
}
}
/************************************************************************
* END ADD
*************************************************************************/
// Add custom rules for non-rewrite URLs
foreach ( $GLOBALS['wp_post_types'] as $key => $value ) {
if ( isset( $_GET[ $key ] ) && ! empty( $_GET[ $key ] ) ) {
$args = array(
'name' => $_GET[ $key ],
'post_type' => $key,
'showposts' => 1,
);
if ( $post = get_posts( $args ) ) {
return $post[0]->ID;
}
}
}
}
}
// Get rid of the #anchor
$url_split = explode( '#', $url );
$url = $url_split[0];
// Get rid of URL ?query=string
$url_query = explode( '?', $url );
$url = $url_query[0];
// Add 'www.' if it is absent and should be there
if ( false !== strpos( home_url(), '://www.' ) && false === strpos( $url, '://www.' ) ) {
$url = str_replace( '://', '://www.', $url );
}
// Strip 'www.' if it is present and shouldn't be
if ( false === strpos( home_url(), '://www.' ) ) {
$url = str_replace( '://www.', '://', $url );
}
// Strip 'index.php/' if we're not using path info permalinks
if ( isset( $wp_rewrite ) && ! $wp_rewrite->using_index_permalinks() ) {
$url = str_replace( 'index.php/', '', $url );
}
if ( false !== strpos( $url, home_url() ) ) {
// Chop off http://domain.com
$url = str_replace( home_url(), '', $url );
} else {
// Chop off /path/to/blog
$home_path = parse_url( home_url() );
$home_path = isset( $home_path['path'] ) ? $home_path['path'] : '';
$url = str_replace( $home_path, '', $url );
}
// Trim leading and lagging slashes
$url = trim( $url, '/' );
$request = $url;
if ( empty( $request ) && ( ! isset( $_GET ) || empty( $_GET ) ) ) {
return get_option( 'page_on_front' );
}
// Look for matches.
$request_match = $request;
foreach ( (array) $rewrite as $match => $query ) {
// If the requesting file is the anchor of the match, prepend it
// to the path info.
if ( ! empty( $url ) && ( $url != $request ) && ( strpos( $match, $url ) === 0 ) ) {
$request_match = $url . '/' . $request;
}
if ( preg_match( "!^$match!", $request_match, $matches ) ) {
if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
// This is a verbose page match, let's check to be sure about it.
$page = get_page_by_path( $matches[ $varmatch[1] ] );
if ( ! $page ) {
continue;
}
$post_status_obj = get_post_status_object( $page->post_status );
if (is_object($post_status_obj) && ! $post_status_obj->public && ! $post_status_obj->protected
&& ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
continue;
}
}
// Got a match.
// Trim the query of everything up to the '?'.
$query = preg_replace( "!^.+\?!", '', $query );
// Substitute the substring matches into the query.
$query = addslashes( WP_MatchesMapRegex::apply( $query, $matches ) );
// Filter out non-public query vars
global $wp;
parse_str( $query, $query_vars );
$query = array();
foreach ( (array) $query_vars as $key => $value ) {
if ( in_array( $key, $wp->public_query_vars ) ) {
$query[ $key ] = $value;
}
}
/************************************************************************
* ADDED: $GLOBALS['wp_post_types'] doesn't seem to have custom postypes
* Trying below to find posttypes in $rewrite rules
*************************************************************************/
// PostType Array
$custom_post_type = false;
$post_types = array();
foreach ($rewrite as $key => $value) {
if(!is_string($value)) {
continue;
}
if(preg_match('/post_type=([^&]+)/i', $value, $matched)){
if(isset($matched[1]) && !in_array($matched[1], $post_types)){
$post_types[] = $matched[1];
}
}
}
foreach ((array) $query_vars as $key => $value) {
if(in_array($key, $post_types)){
$custom_post_type = true;
$query['post_type'] = $key;
$query['postname'] = $value;
}
}
/************************************************************************
* END ADD
*************************************************************************/
// Taken from class-wp.php
if(!empty($GLOBALS['wp_post_types'])) {
foreach ( $GLOBALS['wp_post_types'] as $post_type => $t ) {
if ( $t->query_var ) {
$post_type_query_vars[ $t->query_var ] = $post_type;
}
}
}
foreach ( $wp->public_query_vars as $wpvar ) {
if ( isset( $wp->extra_query_vars[ $wpvar ] ) ) {
$query[ $wpvar ] = $wp->extra_query_vars[ $wpvar ];
} elseif ( isset( $_POST[ $wpvar ] ) ) {
$query[ $wpvar ] = $_POST[ $wpvar ];
} elseif ( isset( $_GET[ $wpvar ] ) ) {
$query[ $wpvar ] = $_GET[ $wpvar ];
} elseif ( isset( $query_vars[ $wpvar ] ) ) {
$query[ $wpvar ] = $query_vars[ $wpvar ];
}
if ( ! empty( $query[ $wpvar ] ) ) {
if ( ! is_array( $query[ $wpvar ] ) ) {
$query[ $wpvar ] = (string) $query[ $wpvar ];
} else {
foreach ( $query[ $wpvar ] as $vkey => $v ) {
if ( ! is_object( $v ) ) {
$query[ $wpvar ][ $vkey ] = (string) $v;
}
}
}
if ( isset( $post_type_query_vars[ $wpvar ] ) ) {
$query['post_type'] = $post_type_query_vars[ $wpvar ];
$query['name'] = $query[ $wpvar ];
}
}
}
// Do the query
if ( isset( $query['pagename'] ) && ! empty( $query['pagename'] ) ) {
$args = array(
'name' => $query['pagename'],
'post_type' => array('post','page'), // Added post for custom permalink eg postname
'showposts' => 1,
);
if ( $post = get_posts( $args ) ) {
return $post[0]->ID;
}
}
$query = new WP_Query( $query );
if ( ! empty( $query->posts ) && $query->is_singular ) {
return $query->post->ID;
} else {
/************************************************************************
* Added:
* $query->is_singular seems to not be set on custom post types, trying
* below. Made it this far without return, worth a try? :)
*************************************************************************/
if(!empty( $query->posts ) && isset($query->post->ID) && $custom_post_type == true){
return $query->post->ID;
}
/************************************************************************
* Will match posttype when query_var => true, will not work with
* custom query_var set ie query_var => 'acme_books'.
*************************************************************************/
if(isset($post_types)) {
foreach($rewrite as $key => $value) {
if(!is_string($value)) {
continue;
}
if(preg_match('/\?([^&]+)=([^&]+)/i', $value, $matched)) {
if(isset($matched[1]) && !in_array($matched[1], $post_types) && array_key_exists($matched[1], $query_vars)) {
$post_types[] = $matched[1];
$args = array(
'name' => $query_vars[$matched[1]],
'post_type' => $matched[1],
'showposts' => 1,
);
if($post = get_posts($args)) {
return $post[0]->ID;
}
}
elseif(isset($matched[1]) && in_array($matched[1], $post_types) && !empty($query_vars['name'])) {
$args = array(
'name' => $query_vars['name'],
'post_type' => $matched[1],
'showposts' => 1,
);
if($post = get_posts($args)) {
return $post[0]->ID;
}
}
}
}
}
/************************************************************************
* END ADD
*************************************************************************/
return 0;
}
}
}
return 0;
}