Remove Google Fonts
Performance - Remove Google Fonts
add_filter( 'elementor/frontend/print_google_fonts', '__return_false' );
Ensure Webfont is Loaded
Performance - Ensure Webfont is Loaded
add_filter( 'elementor_pro/custom_fonts/font_display', function( $current_value, $font_family, $data ) {
return 'swap';
}, 10, 3 );
Reduce Revisions to 3
Database - Reduce Revisions to 3
define('WP_POST_REVISIONS', 3);
Remove Screen Options
Admin - Remove Screen Options
function remove_dashboard_widgets() {
remove_action( 'welcome_panel', 'wp_welcome_panel' );
remove_meta_box( 'dashboard_right_now', 'dashboard', 'normal' );
remove_meta_box( 'dashboard_activity', 'dashboard', 'normal' );
remove_meta_box( 'dashboard_quick_press', 'dashboard', 'side' );
remove_meta_box( 'dashboard_primary', 'dashboard', 'side' );
remove_meta_box( 'dashboard_site_health', 'dashboard', 'normal' );
remove_meta_box( 'e-dashboard-overview', 'dashboard', 'normal' );
}
add_action( 'wp_dashboard_setup', 'remove_dashboard_widgets' );
Color Contrast Checker
Admin - Color Contrast Checker
// Add the Contrast Checker Menu
add_action('admin_menu', 'contrast_checker_menu');
add_action('admin_init', 'contrast_checker_settings');
function contrast_checker_menu() {
add_options_page('Contrast Checker', 'Contrast Checker', 'manage_options', 'contrast-checker', 'contrast_checker_page');
}
function contrast_checker_settings() {
add_settings_section('contrast_checker_section', 'Contrast Checker Settings', null, 'contrast-checker');
add_settings_field('background_color', 'Background Color', 'background_color_callback', 'contrast-checker', 'contrast_checker_section');
add_settings_field('text_color', 'Foreground Color', 'foreground_color_callback', 'contrast-checker', 'contrast_checker_section');
register_setting('contrast_checker_group', 'background_color');
register_setting('contrast_checker_group', 'text_color');
}
function background_color_callback() {
$background_color = get_option('background_color', '#FFFFFF');
echo '';
echo '' . esc_attr($background_color) . '';
}
function foreground_color_callback() {
$foreground_color = get_option('text_color', '#000000');
echo '';
echo '' . esc_attr($foreground_color) . '';
}
function contrast_checker_page() {
?>
Contrast Checker
What is AA?
AA compliance refers to the Web Content Accessibility Guidelines (WCAG) 2.1, which require a contrast ratio of at least 4.5:1 for normal text (minimum 16px) and 3:1 for large text (minimum 24px or 19px bold). This ensures that content is readable and accessible for individuals with moderate visual impairments.
What is AAA?
AAA compliance is the highest level of conformance in WCAG 2.1. It requires a contrast ratio of at least 7:1 for normal text (minimum 16px) and 4.5:1 for large text (minimum 24px or 19px bold). Achieving AAA compliance ensures that content is accessible to the widest range of users, including those with significant visual impairments.
= 4.5) ? 'Yes' : 'No';
$aaa_pass = ($contrast_ratio >= 7) ? 'Yes' : 'No';
$suggested_aa = adjust_foreground_color($bg_rgb, $txt_rgb, 4.5);
$suggested_aaa = adjust_foreground_color($bg_rgb, $txt_rgb, 7);
return '
Contrast Ratio: ' . round($contrast_ratio, 2) . '
AA Compliant: ' . $aa_pass . '
AAA Compliant: ' . $aaa_pass . '
Suggested Foreground Color for AA:
' . $suggested_aa . '
Suggested Foreground Color for AAA:
' . $suggested_aaa . '
';
}
function hex_to_rgb($hex) {
$hex = ltrim($hex, '#');
$r = hexdec(substr($hex, 0, 2)) / 255;
$g = hexdec(substr($hex, 2, 2)) / 255;
$b = hexdec(substr($hex, 4, 2)) / 255;
return array($r, $g, $b);
}
function rgb_to_hex($rgb) {
return sprintf("#%02x%02x%02x", round($rgb[0] * 255), round($rgb[1] * 255), round($rgb[2] * 255));
}
function luminance($rgb) {
list($r, $g, $b) = $rgb;
$r = ($r <= 0.03928) ? $r / 12.92 : pow(($r + 0.055) / 1.055, 2.4);
$g = ($g <= 0.03928) ? $g / 12.92 : pow(($g + 0.055) / 1.055, 2.4);
$b = ($b <= 0.03928) ? $b / 12.92 : pow(($b + 0.055) / 1.055, 2.4);
return 0.2126 * $r + 0.7152 * $g + 0.0722 * $b;
}
function contrast_ratio($l1, $l2) {
$lighter = max($l1, $l2);
$darker = min($l1, $l2);
return ($lighter + 0.05) / ($darker + 0.05);
}
function adjust_foreground_color($bg_rgb, $txt_rgb, $target_ratio) {
$bg_luminance = luminance($bg_rgb);
$step = 0.02; // Adjust step value for precision and performance
// Incrementally adjust the RGB values to find a compliant color
for ($i = 0; $i <= 1; $i += $step) {
$test_rgb = adjust_rgb_lightness($txt_rgb, $i);
$test_luminance = luminance($test_rgb);
if (contrast_ratio($test_luminance, $bg_luminance) >= $target_ratio) {
return rgb_to_hex($test_rgb);
}
$test_rgb = adjust_rgb_lightness($txt_rgb, -$i);
$test_luminance = luminance($test_rgb);
if (contrast_ratio($test_luminance, $bg_luminance) >= $target_ratio) {
return rgb_to_hex($test_rgb);
}
}
return "#000000"; // fallback to black if no suitable color found
}
function adjust_rgb_lightness($rgb, $adjustment) {
return array(
min(1, max(0, $rgb[0] + $adjustment)),
min(1, max(0, $rgb[1] + $adjustment)),
min(1, max(0, $rgb[2] + $adjustment))
);
}
Custom Global Colors CSS
Custom Global Colors CSS
add_action('save_post', function ($post_id, $post, $update) {
// Check if the post is an instance of Elementor's Kit
if ('elementor_library' === get_post_type($post_id) && 'kit' === get_post_meta($post_id, '_elementor_template_type', true)) {
$meta = get_post_meta($post_id, '_elementor_page_settings', true);
// Handle custom colors
if (!empty($meta['custom_colors'])) {
foreach ($meta['custom_colors'] as &$custom_color) {
// Replace the hyphens inside of titles with underscores to ensure consistency
$custom_color['_id'] = str_replace('-', '_', sanitize_title($custom_color['title']));
}
}
// Update post meta
update_post_meta($post_id, '_elementor_page_settings', $meta);
}
}, 10, 3);
Password Lock Snippets Tab
Admin - Password Lock Snippets Tab
if (!function_exists('restrict_snippets_pages')) {
function restrict_snippets_pages() {
// Check if the current user is trying to access the Snippets pages
global $pagenow;
$restricted_pages = array(
'admin.php?page=snippets',
'admin.php?page=snippet-manager',
'admin.php?page=snippet-import',
'admin.php?page=add-snippet',
'admin.php?page=import-code-snippets'
);
// Check if the current request URI contains any of the restricted pages
$is_restricted_page = false;
foreach ($restricted_pages as $restricted_page) {
if (strpos($_SERVER['REQUEST_URI'], $restricted_page) !== false) {
$is_restricted_page = true;
break;
}
}
if ($is_restricted_page) {
// Start a session if not already started
if (!session_id()) {
session_start();
}
// SET THE PASSWORD HERE !!
$required_password = '123'; // Change this to your desired password
// Check if the password has been submitted and is correct
if (isset($_POST['snippets_password']) && $_POST['snippets_password'] === $required_password) {
$_SESSION['snippets_access_granted'] = true;
}
// Check if the session variable is not set, meaning access is not granted
if (empty($_SESSION['snippets_access_granted'])) {
// Display the password form
echo ' ';
// Prevent the rest of the Snippets page from loading
exit;
}
}
}
add_action('admin_init', 'restrict_snippets_pages');
}
Password Lock Settings Tab
Admin - Password Lock Settings Tab
function restrict_settings_page() {
// Check if the current user is trying to access the Settings page
global $pagenow;
$settings_pages = array(
'options-general.php',
'options-writing.php',
'options-reading.php',
'options-discussion.php',
'options-media.php',
'options-permalink.php',
// Add more settings pages if you have plugins that add their own settings
);
if (in_array($pagenow, $settings_pages)) {
// Start a session if not already started
if (!session_id()) {
session_start();
}
// Set the password
$required_password = '123'; // Change this to your desired password
// Check if the password has been submitted and is correct
if (isset($_POST['settings_password']) && $_POST['settings_password'] === $required_password) {
$_SESSION['settings_access_granted'] = true;
}
// Check if the session variable is not set, meaning access is not granted
if (empty($_SESSION['settings_access_granted'])) {
// Display the password form
echo ' ';
// Prevent the rest of the Settings page from loading
exit;
}
}
}
add_action('admin_init', 'restrict_settings_page');
Password Lock Users Tab
Admin - Password Lock Users Tab
function restrict_users_page() {
// Check if the current user is trying to access the Users page
global $pagenow;
if ($pagenow === 'users.php' || $pagenow === 'user-new.php' || $pagenow === 'profile.php') {
// Start a session if not already started
if (!session_id()) {
session_start();
}
// Set the password
$required_password = '123'; // Change this to your desired password
// Check if the password has been submitted and is correct
if (isset($_POST['users_password']) && $_POST['users_password'] === $required_password) {
$_SESSION['users_access_granted'] = true;
}
// Check if the session variable is not set, meaning access is not granted
if (empty($_SESSION['users_access_granted'])) {
// Display the password form
echo ' ';
// Prevent the rest of the Users page from loading
exit;
}
}
}
add_action('admin_init', 'restrict_users_page');
Password Lock Plugins Tab
Admin - Password Lock Plugins Tab
function restrict_plugins_page() {
// Check if the current user is trying to access the Plugins page
global $pagenow;
if ($pagenow === 'plugins.php' || strpos($_SERVER['REQUEST_URI'], 'plugin-install.php') !== false || strpos($_SERVER['REQUEST_URI'], 'plugin-editor.php') !== false) {
// Start a session if not already started
if (!session_id()) {
session_start();
}
// SET THE PASSWORD HERE !!
$required_password = '123'; // Change this to your desired password
// Check if the password has been submitted and is correct
if (isset($_POST['plugins_password']) && $_POST['plugins_password'] === $required_password) {
$_SESSION['plugins_access_granted'] = true;
}
// Check if the session variable is not set, meaning access is not granted
if (empty($_SESSION['plugins_access_granted'])) {
// Display the password form
echo ' ';
// Prevent the rest of the Plugins page from loading
exit;
}
}
}
add_action('admin_init', 'restrict_plugins_page');
Permalinks Set
Admin - Permalinks Set
if ( ! function_exists( 'custom_set_permalink_structure_to_post_name' ) ) {
/**
* Sets the default permalink structure to 'Post Name' if it is not already set.
*
* To change the default permalink structure, update the `$desired_permalink_structure`
* variable with one of the following values:
*
* - Plain: ''
* - Day and Name: '/%year%/%monthnum%/%day%/%postname%/'
* - Month and Name: '/%year%/%monthnum%/%postname%/'
* - Numeric: '/%post_id%/'
* - Post Name: '/%postname%/'
* - Custom Structure: '/your/custom/structure/'
*/
function custom_set_permalink_structure_to_post_name() {
// Get the current permalink structure
$current_permalink_structure = get_option('permalink_structure');
// Set the desired permalink structure here
// Default is 'Post Name'
$desired_permalink_structure = '/%postname%/';
// Uncomment one of the following lines to set a different permalink structure
// Plain:
// $desired_permalink_structure = '';
// Day and Name:
// $desired_permalink_structure = '/%year%/%monthnum%/%day%/%postname%/';
// Month and Name:
// $desired_permalink_structure = '/%year%/%monthnum%/%postname%/';
// Numeric:
// $desired_permalink_structure = '/%post_id%/';
// Custom Structure:
// $desired_permalink_structure = '/your/custom/structure/';
// Check if the current structure is not already set to the desired structure
if ($current_permalink_structure != $desired_permalink_structure) {
// Update the permalink structure
update_option('permalink_structure', $desired_permalink_structure);
// Flush rewrite rules to apply the new permalink structure
flush_rewrite_rules();
}
}
add_action('admin_init', 'custom_set_permalink_structure_to_post_name');
}
Media Original and 150x150
Admin - Media Original and 150x150
function limit_image_sizes($sizes) {
// Keep only the thumbnail size
return array(
'thumbnail' => $sizes['thumbnail']
);
}
add_filter('intermediate_image_sizes_advanced', 'limit_image_sizes');
function set_thumbnail_size() {
// Set the thumbnail size to 150x150
update_option('thumbnail_size_w', 150);
update_option('thumbnail_size_h', 150);
update_option('thumbnail_crop', 1); // 1 for hard crop, 0 for soft crop
}
add_action('admin_init', 'set_thumbnail_size');
// Remove the unnecessary regenerate_thumbnails function as the thumbnail is already handled
Add Categories to Pages
Admin - Add Categories to Pages
add_action( 'init', 'add_categories_to_pages' );
/*
* Add CATEGORIES to pages
*/
function add_categories_to_pages() {
register_taxonomy_for_object_type( 'category', 'page' );
}
Purge the Cache
Admin - Purge the Cache
/*
Plugin Name: Purge Cache
Description: Adds a button to the WordPress dashboard to clear the object cache
*/
add_action( 'admin_bar_menu', 'add_purge_cache_button', 999 );
function add_purge_cache_button( $wp_admin_bar ) {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$args = array(
'id' => 'purge-cache',
'title' => 'Purge Cache',
'href' => '#',
'meta' => array( 'class' => 'purge-cache' )
);
$wp_admin_bar->add_node( $args );
}
add_action( 'admin_footer', 'add_purge_cache_script' );
function add_purge_cache_script() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
?>
Font Clamp Calculator
Admin - Font Clamp Calculator
// Function to add the calculator to the admin menu
function ft_calculator_admin_menu()
{
add_menu_page(
"Fluid Typography Calculator", // Page title
"Clamp Calculator", // Menu title
"manage_options", // Capability
"fluid-typography-calculator", // Menu slug
"ft_calculator_page" // Function that displays the page content
);
}
add_action("admin_menu", "ft_calculator_admin_menu");
// Function that generates the calculator page
function ft_calculator_page() {
// Initialize the $useRem variable at the start of the function
$useRem = false;
echo 'Fluid Typography Calculator
';
// Basic styles for the form and output
echo '';
// Initialize variables
$rootFontSize = isset($_POST["rootFontSize"]) ? $_POST["rootFontSize"] : 16;
$defaultValues = [
"h1" => [
"MinWidth" => 380,
"MinFontSize" => 29,
"MaxWidth" => 1600,
"MaxFontSize" => 68,
],
"h2" => [
"MinWidth" => 380,
"MinFontSize" => 24,
"MaxWidth" => 1600,
"MaxFontSize" => 51,
],
"h3" => [
"MinWidth" => 380,
"MinFontSize" => 20,
"MaxWidth" => 1600,
"MaxFontSize" => 38,
],
"h4" => [
"MinWidth" => 380,
"MinFontSize" => 17,
"MaxWidth" => 1600,
"MaxFontSize" => 29,
],
"h5" => [
"MinWidth" => 380,
"MinFontSize" => 14,
"MaxWidth" => 1600,
"MaxFontSize" => 22,
],
"h6" => [
"MinWidth" => 380,
"MinFontSize" => 12,
"MaxWidth" => 1600,
"MaxFontSize" => 16,
],
"body" => [
"MinWidth" => 380,
"MinFontSize" => 16,
"MaxWidth" => 1600,
"MaxFontSize" => 24,
],
"p" => [
"MinWidth" => 380,
"MinFontSize" => 16,
"MaxWidth" => 1600,
"MaxFontSize" => 24,
],
];
$cssOutput = ""; // Initialize traditional CSS output string
$cssVariablesOutput = ""; // Initialize CSS variables output string
// Check if form is submitted
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$useRem = isset($_POST["unitToggle"]) && $_POST["unitToggle"] === 'on';
// Security check using nonce
if (!isset($_POST["ft_calculator_nonce_field"]) || !wp_verify_nonce($_POST["ft_calculator_nonce_field"], "ft_calculator_action")) {
echo "Security check failed. Please try again.
";
return;
}
foreach (["h1", "h2", "h3", "h4", "h5", "h6", "body", "p"] as $tag) {
$minWidth = $_POST[$tag . "MinWidth"]; // In pixels
$minFontSizePx = $_POST[$tag . "MinFontSize"]; // In pixels or REM based on $useRem
$maxWidth = $_POST[$tag . "MaxWidth"]; // In pixels
$maxFontSizePx = $_POST[$tag . "MaxFontSize"]; // In pixels or REM based on $useRem
// Handle unit conversion
if ($useRem) {
// Convert REM to Pixels for internal calculation
$minFontSizePx *= $rootFontSize;
$maxFontSizePx *= $rootFontSize;
}
// Convert pixel values to REM for CSS generation
$minFontSize = $minFontSizePx / $rootFontSize; // In rem
$maxFontSize = $maxFontSizePx / $rootFontSize; // In rem
// Convert widths from px to vw (assuming 1rem = rootFontSize px)
$minWidthVW = $minWidth / $rootFontSize; // In vw
$maxWidthVW = $maxWidth / $rootFontSize; // In vw
// Calculate the CSS
$vwUnit =
(($maxFontSize - $minFontSize) / ($maxWidthVW - $minWidthVW)) *
100;
$constant = $minFontSize - ($vwUnit * $minWidthVW) / 100;
// Format to a maximum of 5 decimal places
$vwUnitFormatted = number_format($vwUnit, 5, ".", "");
$constantFormatted = number_format($constant, 5, ".", "");
// Add to traditional CSS output
$cssOutput .=
"{$tag} {font-size: clamp(" .
$minFontSize .
"rem, " .
$constantFormatted .
"rem + " .
$vwUnitFormatted .
"vw, " .
$maxFontSize .
"rem);}\n";
// Add to CSS variables output
$cssVariablesOutput .=
" --{$tag}-font-size: clamp(" .
$minFontSize .
"rem, " .
$constantFormatted .
"rem + " .
$vwUnitFormatted .
"vw, " .
$maxFontSize .
"rem);\n";
}
// Wrap CSS variables in a :root selector
$cssVariablesOutput = ":root {\n" . $cssVariablesOutput . "}\n";
}
// Display the form
echo '';
// Display the traditional CSS output
if (!empty($cssOutput)) {
echo "Generated CSS:
";
echo '
";
echo '';
}
// Display the CSS variables output
if (!empty($cssVariablesOutput)) {
echo "Generated CSS Variables:
";
echo '
";
echo '';
}
// JavaScript for copy to clipboard functionality and unit conversion
echo '';
echo "";
}
// Define the function for the fluid typography calculator
function fluid_typography_calculator() {
// Call the existing function to display the fluid typography calculator
ft_calculator_page();
}
// Add the shortcode
add_shortcode('Fluid_calc', 'fluid_typography_calculator');
Duplicate Pages and Posts
Admin - Duplicate Pages and Posts
function duplicate_post_as_draft() {
global $wpdb;
// Verify the nonce for security
$nonce_action = 'duplicate_post_as_draft';
$nonce_name = 'duplicate_nonce';
if (!isset($_GET[$nonce_name]) || !wp_verify_nonce($_GET[$nonce_name], $nonce_action)) {
wp_die(esc_html__('Security check failed.', 'wpturbo'));
}
// Check if the 'post' parameter is set in either GET or POST request
$post_id = filter_input(INPUT_GET, 'post', FILTER_SANITIZE_NUMBER_INT) ?: filter_input(INPUT_POST, 'post', FILTER_SANITIZE_NUMBER_INT);
if (!$post_id) {
wp_die(esc_html__('No post to duplicate has been supplied!', 'wpturbo'));
}
// Check if the post exists
$post = get_post($post_id);
if (!$post) {
wp_die(esc_html(sprintf(__('Post creation failed, could not find original post: %s', 'wpturbo'), $post_id)));
}
$current_user = wp_get_current_user();
$new_post_author = $current_user->ID;
$args = [
"comment_status" => $post->comment_status,
"ping_status" => $post->ping_status,
"post_author" => $new_post_author,
"post_content" => $post->post_content,
"post_excerpt" => $post->post_excerpt,
"post_name" => $post->post_name,
"post_parent" => $post->post_parent,
"post_password" => $post->post_password,
"post_status" => "draft",
"post_title" => $post->post_title . " (Copy)",
"post_type" => $post->post_type,
"to_ping" => $post->to_ping,
"menu_order" => $post->menu_order
];
$new_post_id = wp_insert_post($args);
$taxonomies = get_object_taxonomies($post->post_type);
foreach ($taxonomies as $taxonomy) {
$post_terms = wp_get_object_terms($post_id, $taxonomy, ["fields" => "slugs"]);
wp_set_object_terms($new_post_id, $post_terms, $taxonomy, false);
}
$post_meta_infos = $wpdb->get_results(
$wpdb->prepare("SELECT meta_key, meta_value FROM $wpdb->postmeta WHERE post_id = %d", $post_id)
);
if (count($post_meta_infos) != 0) {
foreach ($post_meta_infos as $meta_info) {
$meta_key = $meta_info->meta_key;
$meta_value = sanitize_meta($meta_info->meta_key, $meta_info->meta_value, "post");
$wpdb->insert($wpdb->postmeta, [
"post_id" => $new_post_id,
"meta_key" => $meta_key,
"meta_value" => $meta_value
]);
}
}
// Redirect to the post list screen and show a success message
$redirect_url = admin_url("edit.php?post_type=" . $post->post_type);
wp_redirect(add_query_arg("message", "101", $redirect_url));
exit();
}
add_action("admin_action_duplicate_post_as_draft", "duplicate_post_as_draft");
function duplicate_post_link($actions, $post) {
if (current_user_can('edit_posts')) {
$actions['duplicate'] = 'ID),
'duplicate_post_as_draft',
'duplicate_nonce'
) .
'" title="' . esc_attr__('Duplicar este ítem', 'wpturbo') .
'" rel="permalink">' . esc_html__('Duplicar', 'wpturbo') . '';
}
return $actions;
}
add_filter("post_row_actions", "duplicate_post_link", 10, 2);
add_filter("page_row_actions", "duplicate_post_link", 10, 2);
function apply_duplicate_post_link_to_cpts() {
$post_types = get_post_types(["public" => true], "names");
foreach ($post_types as $post_type) {
add_filter("{$post_type}_row_actions", "duplicate_post_link", 10, 2);
}
}
add_action("admin_init", "apply_duplicate_post_link_to_cpts");
function show_duplicate_admin_notice() {
if (isset($_GET['message']) && $_GET['message'] === '101') {
echo '' . esc_html('Post duplicated successfully.') . '
';
}
}
add_action('admin_notices', 'show_duplicate_admin_notice');
Infinity Scroll Media Library
Admin - Infinity Scroll Media Library
add_filter( 'media_library_infinite_scrolling', '__return_true' );
Load Woff2 directly to Media Library
Admin - Load Woff2 directly to Media Library
function custom_mime_types($mimes) {
$mimes['woff'] = 'font/woff';
$mimes['woff2'] = 'font/woff2';
return $mimes;
}
add_filter('upload_mimes', 'custom_mime_types');
Disable User Registration
Admin - Disable User Registration
// Disable user registration
add_filter('pre_option_users_can_register', '__return_zero');
Remove Comments
Admin - Remove Comments
/*
Comments in WordPress are like an open mic.
Sometimes you want to turn the mic off.
Silencing the comment section might just be your ticket to serenity.*/
function codesnippets_disable_comments() {
// Remove comment support for posts
remove_post_type_support( 'post', 'comments' );
// Remove comment support for pages
remove_post_type_support( 'page', 'comments' );
// Remove comments from the admin menu
remove_menu_page( 'edit-comments.php' );
// Redirect comment-related URLs to the homepage
add_action( 'template_redirect', 'codesnippets_disable_comments_redirect' );
}
function codesnippets_disable_comments_redirect() {
global $wp_query;
if ( is_single() || is_page() || is_attachment() ) {
if ( have_comments() || comments_open() ) {
wp_redirect( home_url(), 301 );
exit;
}
}
}
add_action( 'admin_init', 'codesnippets_disable_comments' );
Stop Lazy Load
Performance - Stop Lazy Load
add_filter( 'wp_lazy_loading_enabled', '__return_false' );
No Zoom on Mobile
No Zoom on Mobile
Es un HTML y va en head
Hide ReCAPTCHA
Hide ReCAPTCHA
Es un HTML y va en body
PixRefiner
PixRefiner
//PixRefiner v3.4
// Helper function for formatting file sizes
function formatBytes($bytes, $precision = 2) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$bytes = max($bytes, 0);
$pow = ($bytes > 0) ? floor(log($bytes) / log(1024)) : 0;
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
// Limit default WordPress sizes to thumbnail only when auto-conversion is enabled
function wpturbo_limit_image_sizes($sizes) {
if (wpturbo_get_disable_auto_conversion()) {
return $sizes;
}
return isset($sizes['thumbnail']) ? ['thumbnail' => $sizes['thumbnail']] : $sizes;return ['thumbnail' => $sizes['thumbnail']];
}
//Global override for default sizes
add_filter('intermediate_image_sizes_advanced', function($sizes) {
if (!wpturbo_get_disable_auto_conversion()) {
return ['thumbnail' => [
'width' => 150,
'height' => 150,
'crop' => true
]];
}
return $sizes;
}, 99);
add_filter('intermediate_image_sizes_advanced', 'wpturbo_limit_image_sizes');
// Set thumbnail size to 150x150
function wpturbo_set_thumbnail_size() {
update_option('thumbnail_size_w', 150);
update_option('thumbnail_size_h', 150);
update_option('thumbnail_crop', 1);
}
add_action('admin_init', 'wpturbo_set_thumbnail_size');
// Register custom sizes (up to 3 additional sizes beyond the main one)
add_action('after_setup_theme', 'wpturbo_register_custom_sizes');
function wpturbo_register_custom_sizes() {
$mode = wpturbo_get_resize_mode();
if ($mode === 'width') {
$max_values = wpturbo_get_max_widths();
$additional_values = array_slice($max_values, 1, 3);
foreach ($additional_values as $width) {
add_image_size("custom-$width", $width, 0, false);
}
} else {
$max_values = wpturbo_get_max_heights();
$additional_values = array_slice($max_values, 1, 3);
foreach ($additional_values as $height) {
add_image_size("custom-$height", 0, $height, false);
}
}
}
// Get or set max widths (default to mobile-friendly set, limit to 4)
function wpturbo_get_max_widths() {
$value = get_option('webp_max_widths', '1920,1200,600,300');
$widths = array_map('absint', array_filter(explode(',', $value)));
$widths = array_filter($widths, function($w) { return $w > 0 && $w <= 9999; });
return array_slice($widths, 0, 4);
}
// Get or set max heights (default to mobile-friendly set, limit to 4)
function wpturbo_get_max_heights() {
$value = get_option('webp_max_heights', '1080,720,480,360');
$heights = array_map('absint', array_filter(explode(',', $value)));
$heights = array_filter($heights, function($h) { return $h > 0 && $h <= 9999; });
return array_slice($heights, 0, 4);
}
// Get or set resize mode
function wpturbo_get_resize_mode() {
return get_option('webp_resize_mode', 'width');
}
// Get or set quality (0-100)
function wpturbo_get_quality() {
return (int) get_option('webp_quality', 80);
}
// Get or set batch size
function wpturbo_get_batch_size() {
return (int) get_option('webp_batch_size', 5);
}
// Get or set preserve originals
function wpturbo_get_preserve_originals() {
return (bool) get_option('webp_preserve_originals', false);
}
// Get or set disable auto-conversion on upload
function wpturbo_get_disable_auto_conversion() {
return (bool) get_option('webp_disable_auto_conversion', false);
}
// Get or set minimum size threshold in KB (default to 0, meaning no minimum)
function wpturbo_get_min_size_kb() {
return (int) get_option('webp_min_size_kb', 0);
}
// Get or set whether to use AVIF instead of WebP
function wpturbo_get_use_avif() {
return (bool) get_option('webp_use_avif', false);
}
// Get excluded image IDs
function wpturbo_get_excluded_images() {
$excluded = get_option('webp_excluded_images', []);
return is_array($excluded) ? array_map('absint', $excluded) : [];
}
// Add an image to the excluded list
function wpturbo_add_excluded_image($attachment_id) {
$attachment_id = absint($attachment_id);
$excluded = wpturbo_get_excluded_images();
if (!in_array($attachment_id, $excluded)) {
$excluded[] = $attachment_id;
update_option('webp_excluded_images', array_unique($excluded));
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Excluded image added: Attachment ID %d', 'wpturbo'), $attachment_id);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Remove an image from the excluded list
function wpturbo_remove_excluded_image($attachment_id) {
$attachment_id = absint($attachment_id);
$excluded = wpturbo_get_excluded_images();
$index = array_search($attachment_id, $excluded);
if ($index !== false) {
unset($excluded[$index]);
update_option('webp_excluded_images', array_values($excluded));
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Excluded image removed: Attachment ID %d', 'wpturbo'), $attachment_id);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Ensure MIME types are supported in .htaccess (Apache only)
function wpturbo_ensure_mime_types() {
$htaccess_file = ABSPATH . '.htaccess';
if (!file_exists($htaccess_file) || !is_writable($htaccess_file)) {
return false;
}
$content = file_get_contents($htaccess_file);
$webp_mime = "AddType image/webp .webp";
$avif_mime = "AddType image/avif .avif";
if (strpos($content, $webp_mime) === false || strpos($content, $avif_mime) === false) {
$new_content = "# BEGIN WebP Converter MIME Types\n";
if (strpos($content, $webp_mime) === false) {
$new_content .= "$webp_mime\n";
}
if (strpos($content, $avif_mime) === false) {
$new_content .= "$avif_mime\n";
}
$new_content .= "# END WebP Converter MIME Types\n";
$content .= "\n" . $new_content;
file_put_contents($htaccess_file, $content);
return true;
}
return true;
}
// Core conversion function (supports WebP or AVIF)
function wpturbo_convert_to_format($file_path, $dimension, &$log = null, $attachment_id = null, $suffix = '') {
$use_avif = wpturbo_get_use_avif();
$format = $use_avif ? 'image/avif' : 'image/webp';
$extension = $use_avif ? '.avif' : '.webp';
$path_info = pathinfo($file_path);
$new_file_path = $path_info['dirname'] . '/' . $path_info['filename'] . $suffix . $extension;
$quality = wpturbo_get_quality();
$mode = wpturbo_get_resize_mode();
if (!(extension_loaded('imagick') || extension_loaded('gd'))) {
if ($log !== null) $log[] = sprintf(__('Error: No image library (Imagick/GD) available for %s', 'wpturbo'), basename($file_path));
return false;
}
$has_avif_support = (extension_loaded('imagick') && in_array('AVIF', Imagick::queryFormats())) || (extension_loaded('gd') && function_exists('imageavif'));
if ($use_avif && !$has_avif_support) {
if ($log !== null) $log[] = sprintf(__('Error: AVIF not supported on this server for %s', 'wpturbo'), basename($file_path));
return false;
}
$editor = wp_get_image_editor($file_path);
if (is_wp_error($editor)) {
if ($log !== null) $log[] = sprintf(__('Error: Image editor failed for %s - %s', 'wpturbo'), basename($file_path), $editor->get_error_message());
return false;
}
$dimensions = $editor->get_size();
$resized = false;
if ($mode === 'width' && $dimensions['width'] > $dimension) {
$editor->resize($dimension, null, false);
$resized = true;
} elseif ($mode === 'height' && $dimensions['height'] > $dimension) {
$editor->resize(null, $dimension, false);
$resized = true;
}
$result = $editor->save($new_file_path, $format, ['quality' => $quality]);
if (is_wp_error($result)) {
if ($log !== null) $log[] = sprintf(__('Error: Conversion failed for %s - %s', 'wpturbo'), basename($file_path), $result->get_error_message());
return false;
}
if ($log !== null) {
$log[] = sprintf(
__('Converted: %s → %s %s', 'wpturbo'),
basename($file_path),
basename($new_file_path),
$resized ? sprintf(__('(resized to %dpx %s, quality %d)', 'wpturbo'), $dimension, $mode, $quality) : sprintf(__('(quality %d)', 'wpturbo'), $quality)
);
}
return $new_file_path;
}
// Handle new uploads with format conversion
add_filter('wp_handle_upload', 'wpturbo_handle_upload_convert_to_format', 10, 1);
function wpturbo_handle_upload_convert_to_format($upload) {
if (wpturbo_get_disable_auto_conversion()) {
return $upload;
}
$file_extension = strtolower(pathinfo($upload['file'], PATHINFO_EXTENSION));
$allowed_extensions = ['jpg', 'jpeg', 'png', 'webp', 'avif'];
if (!in_array($file_extension, $allowed_extensions)) {
return $upload;
}
$use_avif = wpturbo_get_use_avif();
$format = $use_avif ? 'image/avif' : 'image/webp';
$extension = $use_avif ? '.avif' : '.webp';
$file_path = $upload['file'];
$uploads_dir = dirname($file_path);
$log = get_option('webp_conversion_log', []);
// Check if uploads directory is writable
if (!is_writable($uploads_dir)) {
$log[] = sprintf(__('Error: Uploads directory %s is not writable', 'wpturbo'), $uploads_dir);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $upload;
}
$file_size_kb = filesize($file_path) / 1024;
$min_size_kb = wpturbo_get_min_size_kb();
if ($min_size_kb > 0 && $file_size_kb < $min_size_kb) {
$log[] = sprintf(__('Skipped: %s (size %s KB < %d KB)', 'wpturbo'), basename($file_path), round($file_size_kb, 2), $min_size_kb);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $upload;
}
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$attachment_id = attachment_url_to_postid($upload['url']);
$new_files = [];
$success = true;
// Get original image dimensions
$editor = wp_get_image_editor($file_path);
if (is_wp_error($editor)) {
$log[] = sprintf(__('Error: Image editor failed for %s - %s', 'wpturbo'), basename($file_path), $editor->get_error_message());
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $upload;
}
$dimensions = $editor->get_size();
$original_width = $dimensions['width'];
// Convert only for sizes smaller than or equal to original width (in width mode)
$valid_max_values = $max_values;
if ($mode === 'width') {
$valid_max_values = array_filter($max_values, function($width, $index) use ($original_width) {
// Always include the first size (original) or sizes smaller than original width
return $index === 0 || $width <= $original_width;
}, ARRAY_FILTER_USE_BOTH);
}
// Convert all valid sizes and rollback if any fail
foreach ($valid_max_values as $index => $dimension) {
$suffix = ($index === 0) ? '' : "-{$dimension}";
$new_file_path = wpturbo_convert_to_format($file_path, $dimension, $log, $attachment_id, $suffix);
if ($new_file_path) {
if ($index === 0) {
$upload['file'] = $new_file_path;
$upload['url'] = str_replace(basename($file_path), basename($new_file_path), $upload['url']);
$upload['type'] = $format;
}
$new_files[] = $new_file_path;
} else {
$success = false;
break;
}
}
// Generate thumbnail
if ($success) {
$editor = wp_get_image_editor($file_path);
if (!is_wp_error($editor)) {
$editor->resize(150, 150, true);
$thumbnail_path = dirname($file_path) . '/' . pathinfo($file_path, PATHINFO_FILENAME) . '-150x150' . $extension;
$saved = $editor->save($thumbnail_path, $format, ['quality' => wpturbo_get_quality()]);
if (!is_wp_error($saved)) {
$log[] = sprintf(__('Generated thumbnail: %s', 'wpturbo'), basename($thumbnail_path));
$new_files[] = $thumbnail_path;
} else {
$success = false;
}
} else {
$success = false;
}
}
// Rollback if any conversion failed
if (!$success) {
foreach ($new_files as $file) {
if (file_exists($file)) @unlink($file);
}
$log[] = sprintf(__('Error: Conversion failed for %s, rolling back', 'wpturbo'), basename($file_path));
$log[] = sprintf(__('Original preserved: %s', 'wpturbo'), basename($file_path));
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $upload;
}
// Update metadata only if all conversions succeeded
if ($attachment_id && !empty($new_files)) {
$metadata = wp_generate_attachment_metadata($attachment_id, $upload['file']);
if (!is_wp_error($metadata)) {
$base_name = pathinfo($file_path, PATHINFO_FILENAME);
$dirname = dirname($file_path);
// Add custom sizes
foreach ($valid_max_values as $index => $dimension) {
if ($index === 0) continue;
$size_file = "$dirname/$base_name-$dimension$extension";
if (file_exists($size_file)) {
$metadata['sizes']["custom-$dimension"] = [
'file' => "$base_name-$dimension$extension",
'width' => ($mode === 'width') ? $dimension : 0,
'height' => ($mode === 'height') ? $dimension : 0,
'mime-type' => $format
];
}
}
// Ensure thumbnail metadata is always updated
$thumbnail_file = "$dirname/$base_name-150x150$extension";
if (file_exists($thumbnail_file)) {
$metadata['sizes']['thumbnail'] = [
'file' => "$base_name-150x150$extension",
'width' => 150,
'height' => 150,
'mime-type' => $format
];
} else {
// Regenerate thumbnail if missing
$editor = wp_get_image_editor($upload['file']);
if (!is_wp_error($editor)) {
$editor->resize(150, 150, true);
$saved = $editor->save($thumbnail_file, $format, ['quality' => wpturbo_get_quality()]);
if (!is_wp_error($saved)) {
$metadata['sizes']['thumbnail'] = [
'file' => "$base_name-150x150$extension",
'width' => 150,
'height' => 150,
'mime-type' => $format
];
$log[] = sprintf(__('Regenerated missing thumbnail: %s', 'wpturbo'), basename($thumbnail_file));
}
}
}
$metadata['webp_quality'] = wpturbo_get_quality();
$metadata['pixrefiner_stamp'] = [
'format' => wpturbo_get_use_avif() ? 'avif' : 'webp',
'quality' => wpturbo_get_quality(),
'resize_mode' => wpturbo_get_resize_mode(),
'max_values' => array_values($valid_max_values), // Use valid sizes in stamp
];
update_attached_file($attachment_id, $upload['file']);
wp_update_post(['ID' => $attachment_id, 'post_mime_type' => $format]);
wp_update_attachment_metadata($attachment_id, $metadata);
if (!empty($metadata['pixrefiner_stamp'])) {
$log[] = "Stamp check for Attachment ID {$attachment_id}:";
$log[] = "Expected stamp: " . json_encode($metadata['pixrefiner_stamp']);
$log[] = "Existing stamp: none (new upload)";
}
} else {
$log[] = sprintf(__('Error: Metadata regeneration failed for %s - %s', 'wpturbo'), basename($file_path), $metadata->get_error_message());
}
}
// Delete original only if all conversions succeeded and not preserved
if ($file_extension !== ($use_avif ? 'avif' : 'webp') && file_exists($file_path) && !wpturbo_get_preserve_originals()) {
$attempts = 0;
$chmod_failed = false;
while ($attempts < 5 && file_exists($file_path)) {
if (!is_writable($file_path)) {
@chmod($file_path, 0644);
if (!is_writable($file_path)) {
if ($chmod_failed) {
$log[] = sprintf(__('Error: Cannot make %s writable after retry - skipping deletion', 'wpturbo'), basename($file_path));
break;
}
$chmod_failed = true;
}
}
if (@unlink($file_path)) {
$log[] = sprintf(__('Deleted original: %s', 'wpturbo'), basename($file_path));
break;
}
$attempts++;
sleep(1);
}
if (file_exists($file_path)) {
$log[] = sprintf(__('Error: Failed to delete original %s after 5 retries', 'wpturbo'), basename($file_path));
}
}
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $upload;
}
// Fix metadata for converted images
add_filter('wp_generate_attachment_metadata', 'wpturbo_fix_format_metadata', 10, 2);
function wpturbo_fix_format_metadata($metadata, $attachment_id) {
$use_avif = wpturbo_get_use_avif();
$extension = $use_avif ? 'avif' : 'webp';
$format = $use_avif ? 'image/avif' : 'image/webp';
$file = get_attached_file($attachment_id);
if (pathinfo($file, PATHINFO_EXTENSION) !== $extension) {
return $metadata;
}
$uploads = wp_upload_dir();
$file_path = $file;
$file_name = basename($file_path);
$dirname = dirname($file_path);
$base_name = pathinfo($file_name, PATHINFO_FILENAME);
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$metadata['file'] = str_replace($uploads['basedir'] . '/', '', $file_path);
$metadata['mime_type'] = $format;
foreach ($max_values as $index => $dimension) {
if ($index === 0) continue;
$size_file = "$dirname/$base_name-$dimension.$extension";
if (file_exists($size_file)) {
$metadata['sizes']["custom-$dimension"] = [
'file' => "$base_name-$dimension.$extension",
'width' => ($mode === 'width') ? $dimension : 0,
'height' => ($mode === 'height') ? $dimension : 0,
'mime-type' => $format
];
}
}
$thumbnail_file = "$dirname/$base_name-150x150.$extension";
if (file_exists($thumbnail_file)) {
$metadata['sizes']['thumbnail'] = [
'file' => "$base_name-150x150.$extension",
'width' => 150,
'height' => 150,
'mime-type' => $format
];
}
// ✅ Add stamp
$metadata['pixrefiner_stamp'] = [
'format' => $use_avif ? 'avif' : 'webp',
'quality' => wpturbo_get_quality(),
'resize_mode' => $mode,
'max_values' => $max_values,
];
// ✅ Log stamp
$log = get_option('webp_conversion_log', []);
$log[] = "Stamp set via metadata hook for Attachment ID {$attachment_id}:";
$log[] = "Stamp: " . json_encode($metadata['pixrefiner_stamp']);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $metadata;
}
//
function wpturbo_convert_single_image_checker($attachments) {
if (empty($attachments) || !is_array($attachments)) {
return;
}
$log = [];
foreach ($attachments as $attachment_id) {
$file_path = get_attached_file($attachment_id);
$ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
if (!file_exists($file_path) || in_array($ext, ['jpg', 'jpeg', 'png'])) {
$log[] = sprintf(__('Skipped: Missing or original format (%s) for Attachment ID %d', 'wpturbo'), $ext, $attachment_id);
continue;
}
$metadata = wp_get_attachment_metadata($attachment_id);
// Build the expected stamp from current settings
$expected_stamp = [
'format' => wpturbo_get_use_avif() ? 'avif' : 'webp',
'quality' => wpturbo_get_quality(),
'resize_mode' => wpturbo_get_resize_mode(),
'max_values' => (wpturbo_get_resize_mode() === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights(),
];
$existing_stamp = isset($metadata['pixrefiner_stamp']) ? $metadata['pixrefiner_stamp'] : null;
// 🔍 Stamp comparison log
$log[] = "Stamp check for Attachment ID {$attachment_id}:";
$log[] = "Expected stamp: " . json_encode($expected_stamp);
$log[] = "Existing stamp: " . ($existing_stamp ? json_encode($existing_stamp) : 'none');
if (!empty($existing_stamp) && $existing_stamp !== $expected_stamp && empty($_GET['force_reconvert'])) {
foreach ($expected_stamp as $key => $value) {
if (!isset($existing_stamp[$key]) || $existing_stamp[$key] !== $value) {
$log[] = "Mismatch in stamp key '$key': expected " . json_encode($value) . " but got " . json_encode($existing_stamp[$key] ?? null);
}
}
}
// ✅ If already optimized and no force reconvert
if (!empty($existing_stamp) && $existing_stamp === $expected_stamp && empty($_GET['force_reconvert'])) {
$log[] = sprintf(__('Skipped: Already optimized Attachment ID %d', 'wpturbo'), $attachment_id);
continue;
}
// 🔥 Proceed with conversion
$conversion_result = wpturbo_convert_image($file_path, $attachment_id); // <-- your custom image converter
if (!$conversion_result) {
$log[] = sprintf(__('Failed to convert Attachment ID %d.', 'wpturbo'), $attachment_id);
continue;
}
// 🛡️ If successful, update metadata with the new stamp
if (!empty($metadata)) {
$metadata['pixrefiner_stamp'] = $expected_stamp;
wp_update_attachment_metadata($attachment_id, $metadata);
}
$log[] = sprintf(__('Converted Attachment ID %d successfully.', 'wpturbo'), $attachment_id);
}
update_option('webp_conversion_log', array_slice((array)$log, -500));
return $log;
}
function wpturbo_convert_single_image() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options') || !isset($_POST['offset'])) {
wp_send_json_error(__('Permission denied or invalid offset', 'wpturbo'));
}
$offset = absint($_POST['offset']);
$batch_size = wpturbo_get_batch_size();
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$current_ext = wpturbo_get_use_avif() ? 'avif' : 'webp';
$format = wpturbo_get_use_avif() ? 'image/avif' : 'image/webp';
$current_qual = wpturbo_get_quality();
wp_raise_memory_limit('image');
set_time_limit(max(30, 10 * $batch_size));
$attachments = get_posts([
'post_type' => 'attachment',
'post_mime_type' => ['image/jpeg', 'image/png', 'image/webp', 'image/avif'],
'posts_per_page' => $batch_size,
'offset' => $offset,
'fields' => 'ids',
'post__not_in' => wpturbo_get_excluded_images(),
]);
$log = get_option('webp_conversion_log', []);
if (empty($attachments)) {
update_option('webp_conversion_complete', true);
$log[] = "" . __('Conversion Complete', 'wpturbo') . ': ' . __('No more images to process', 'wpturbo');
update_option('webp_conversion_log', array_slice((array) $log, -500));
wp_send_json_success(['complete' => true]);
}
foreach ($attachments as $attachment_id) {
$file_path = get_attached_file($attachment_id);
if (!file_exists($file_path)) continue;
// Skip if already optimized and settings match
$meta = wp_get_attachment_metadata($attachment_id);
$expected_stamp = [
'format' => $current_ext,
'quality' => $current_qual,
'resize_mode' => $mode,
'max_values' => $max_values,
];
$existing_stamp = isset($meta['pixrefiner_stamp']) ? $meta['pixrefiner_stamp'] : null;
if (!empty($existing_stamp) && $existing_stamp === $expected_stamp && empty($_GET['force_reconvert'])) {
$log[] = sprintf(__('Skipped: Already optimized Attachment ID %d', 'wpturbo'), $attachment_id);
continue;
}
$dirname = dirname($file_path);
$base_name = pathinfo($file_path, PATHINFO_FILENAME);
$ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
$new_files = [];
$success = true;
// DELETE OUTDATED or DUPLICATE SIZES FROM FILESYSTEM AND METADATA
$old_sizes = isset($meta['sizes']) ? $meta['sizes'] : [];
$main_size = $max_values[0] ?? null;
$meta['sizes'] = []; // Initialize sizes to empty to clear outdated entries
foreach ($old_sizes as $size_key => $size_data) {
if (preg_match('/custom-(\d+)/', $size_key, $m)) {
$old_dim = (int) $m[1];
$is_redundant = (
!in_array($old_dim, $max_values)
|| ($main_size && $old_dim === $main_size)
);
if ($is_redundant) {
$old_file = "$dirname/$base_name-$old_dim.$current_ext";
if (file_exists($old_file)) {
@unlink($old_file);
$log[] = sprintf(__('Deleted duplicate or outdated size: %s', 'wpturbo'), basename($old_file));
}
} else {
// Preserve valid sizes that still exist
$meta['sizes'][$size_key] = $size_data;
}
} else if ($size_key === 'thumbnail') {
// Always preserve thumbnail if it exists
$meta['sizes']['thumbnail'] = $size_data;
}
}
// Get original image dimensions
$editor = wp_get_image_editor($file_path);
if (is_wp_error($editor)) {
$log[] = sprintf(__('Error: Image editor failed for %s - %s', 'wpturbo'), basename($file_path), $editor->get_error_message());
continue;
}
$dimensions = $editor->get_size();
$original_width = $dimensions['width'];
// Filter max_values to include only sizes less than or equal to original width
$valid_max_values = $max_values;
if ($mode === 'width') {
$valid_max_values = array_filter($max_values, function($width, $index) use ($original_width) {
return $index === 0 || $width <= $original_width;
}, ARRAY_FILTER_USE_BOTH);
// Log skipped sizes for debugging
if (count($valid_max_values) < count($max_values)) {
$skipped = array_diff($max_values, $valid_max_values);
$log[] = sprintf(__('Skipped sizes %s for %s (original width %dpx)', 'wpturbo'), implode(', ', $skipped), basename($file_path), $original_width);
}
}
// GENERATE NEW SIZES
foreach ($valid_max_values as $index => $dimension) {
$suffix = ($index === 0) ? '' : "-$dimension";
$output = wpturbo_convert_to_format($file_path, $dimension, $log, $attachment_id, $suffix);
if ($output) {
if ($index === 0) {
update_attached_file($attachment_id, $output);
wp_update_post(['ID' => $attachment_id, 'post_mime_type' => $format]);
}
$new_files[] = $output;
} else {
$success = false;
break;
}
}
// GENERATE THUMBNAIL
$thumb_path = "$dirname/$base_name-150x150.$current_ext";
if (!file_exists($thumb_path)) {
$editor = wp_get_image_editor($file_path);
if (!is_wp_error($editor)) {
$editor->resize(150, 150, true);
$saved = $editor->save($thumb_path, $format, ['quality' => $current_qual]);
if (!is_wp_error($saved)) {
$new_files[] = $thumb_path;
$log[] = sprintf(__('Generated thumbnail: %s', 'wpturbo'), basename($thumb_path));
} else {
$success = false;
}
} else {
$success = false;
}
}
if (!$success) {
foreach ($new_files as $f) if (file_exists($f)) @unlink($f);
$log[] = sprintf(__('Error: Conversion failed for %s, rolled back.', 'wpturbo'), basename($file_path));
continue;
}
// UPDATE METADATA & STAMP
if (!empty($new_files)) {
$meta = wp_generate_attachment_metadata($attachment_id, $new_files[0]);
if (!is_wp_error($meta)) {
$meta['sizes'] = []; // Clear sizes again to ensure only new sizes are included
foreach ($valid_max_values as $index => $dimension) {
if ($index === 0) continue;
$size_file = "$dirname/$base_name-$dimension.$current_ext";
if (file_exists($size_file)) {
$meta['sizes']["custom-$dimension"] = [
'file' => "$base_name-$dimension.$current_ext",
'width' => ($mode === 'width') ? $dimension : 0,
'height' => ($mode === 'height') ? $dimension : 0,
'mime-type' => $format,
];
}
}
if (file_exists($thumb_path)) {
$meta['sizes']['thumbnail'] = [
'file' => "$base_name-150x150.$current_ext",
'width' => 150,
'height' => 150,
'mime-type' => $format,
];
}
$meta['webp_quality'] = $current_qual;
$meta['pixrefiner_stamp'] = $expected_stamp;
wp_update_attachment_metadata($attachment_id, $meta);
}
}
// DELETE ORIGINAL IF NOT PRESERVED
if (!wpturbo_get_preserve_originals() && file_exists($file_path) && $ext !== $current_ext) {
@unlink($file_path);
$log[] = sprintf(__('Deleted original: %s', 'wpturbo'), basename($file_path));
}
$log[] = sprintf(__('Converted Attachment ID %d successfully.', 'wpturbo'), $attachment_id);
}
update_option('webp_conversion_log', array_slice((array)$log, -500));
wp_send_json_success([
'complete' => false,
'offset' => $offset + $batch_size
]);
}
// Progress tracking via AJAX
function wpturbo_webp_conversion_status() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(__('Permission denied', 'wpturbo'));
}
$total = wp_count_posts('attachment')->inherit;
$per_page = 50; // Chunk size for pagination
$converted = 0;
$skipped = 0;
// Validate total count
if ($total < 0) {
$log = get_option('webp_conversion_log', []);
$log[] = __('Error: Invalid attachment count detected', 'wpturbo');
update_option('webp_conversion_log', array_slice((array)$log, -500));
wp_send_json_error(__('Invalid attachment count', 'wpturbo'));
}
// Count converted images in chunks
for ($offset = 0; $offset < $total; $offset += $per_page) {
$chunk_result = get_posts([
'post_type' => 'attachment',
'post_mime_type' => wpturbo_get_use_avif() ? 'image/avif' : 'image/webp',
'posts_per_page' => $per_page,
'offset' => $offset,
'fields' => 'ids',
]);
$converted += count($chunk_result);
}
// Count skipped images in chunks
for ($offset = 0; $offset < $total; $offset += $per_page) {
$chunk_result = get_posts([
'post_type' => 'attachment',
'post_mime_type' => ['image/jpeg', 'image/png'],
'posts_per_page' => $per_page,
'offset' => $offset,
'fields' => 'ids',
]);
$skipped += count($chunk_result);
}
$remaining = $total - $converted - $skipped;
$excluded_images = wpturbo_get_excluded_images();
$excluded_data = [];
foreach ($excluded_images as $id) {
$thumbnail = wp_get_attachment_image_src($id, 'thumbnail');
$excluded_data[] = [
'id' => $id,
'title' => get_the_title($id),
'thumbnail' => $thumbnail ? $thumbnail[0] : ''
];
}
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
wp_send_json([
'total' => $total,
'converted' => $converted,
'skipped' => $skipped,
'remaining' => $remaining,
'excluded' => count($excluded_images),
'excluded_images' => $excluded_data,
'log' => get_option('webp_conversion_log', []),
'complete' => get_option('webp_conversion_complete', false),
'resize_mode' => $mode,
'max_values' => implode(', ', $max_values),
'max_widths' => implode(', ', wpturbo_get_max_widths()),
'max_heights' => implode(', ', wpturbo_get_max_heights()),
'quality' => wpturbo_get_quality(),
'preserve_originals' => wpturbo_get_preserve_originals(),
'disable_auto_conversion' => wpturbo_get_disable_auto_conversion(),
'min_size_kb' => wpturbo_get_min_size_kb(),
'use_avif' => wpturbo_get_use_avif()
]);
}
// Clear log
function wpturbo_clear_log() {
if (!isset($_GET['clear_log']) || !current_user_can('manage_options')) {
return false;
}
update_option('webp_conversion_log', [__('Log cleared', 'wpturbo')]);
return true;
}
// Reset to defaults
function wpturbo_reset_defaults() {
if (!isset($_GET['reset_defaults']) || !current_user_can('manage_options')) {
return false;
}
update_option('webp_max_widths', '1920,1200,600,300');
update_option('webp_max_heights', '1080,720,480,360');
update_option('webp_resize_mode', 'width');
update_option('webp_quality', 80);
update_option('webp_batch_size', 5);
update_option('webp_preserve_originals', false);
update_option('webp_disable_auto_conversion', false);
update_option('webp_min_size_kb', 0);
update_option('webp_use_avif', false);
$log = get_option('webp_conversion_log', []);
$log[] = __('Settings reset to defaults', 'wpturbo');
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
// Set max widths
function wpturbo_set_max_widths() {
if (!isset($_GET['set_max_width']) || !current_user_can('manage_options') || !isset($_GET['max_width'])) {
return false;
}
$max_widths = sanitize_text_field($_GET['max_width']);
$width_array = array_filter(array_map('absint', explode(',', $max_widths)));
$width_array = array_filter($width_array, function($w) { return $w > 0 && $w <= 9999; });
$width_array = array_slice($width_array, 0, 4);
if (!empty($width_array)) {
update_option('webp_max_widths', implode(',', $width_array));
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Max widths set to: %spx', 'wpturbo'), implode(', ', $width_array));
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Set max heights
function wpturbo_set_max_heights() {
if (!isset($_GET['set_max_height']) || !current_user_can('manage_options') || !isset($_GET['max_height'])) {
return false;
}
$max_heights = sanitize_text_field($_GET['max_height']);
$height_array = array_filter(array_map('absint', explode(',', $max_heights)));
$height_array = array_filter($height_array, function($h) { return $h > 0 && $h <= 9999; });
$height_array = array_slice($height_array, 0, 4);
if (!empty($height_array)) {
update_option('webp_max_heights', implode(',', $height_array));
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Max heights set to: %spx', 'wpturbo'), implode(', ', $height_array));
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Set resize mode
function wpturbo_set_resize_mode() {
if (!isset($_GET['set_resize_mode']) || !current_user_can('manage_options') || !isset($_GET['resize_mode'])) {
return false;
}
$mode = sanitize_text_field($_GET['resize_mode']);
if (in_array($mode, ['width', 'height'])) {
$current_mode = get_option('webp_resize_mode', 'width');
if ($current_mode !== $mode) {
update_option('webp_resize_mode', $mode);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Resize mode set to: %s', 'wpturbo'), $mode);
update_option('webp_conversion_log', array_slice((array)$log, -500));
}
return true;
}
return false;
}
// Set quality
function wpturbo_set_quality() {
if (!isset($_GET['set_quality']) || !current_user_can('manage_options') || !isset($_GET['quality'])) {
return false;
}
$quality = absint($_GET['quality']);
if ($quality >= 0 && $quality <= 100) {
$current_quality = (int) get_option('webp_quality', 80);
if ($current_quality !== $quality) {
update_option('webp_quality', $quality);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Quality set to: %d', 'wpturbo'), $quality);
update_option('webp_conversion_log', array_slice((array)$log, -500));
}
return true;
}
return false;
}
// Set batch size
function wpturbo_set_batch_size() {
if (!isset($_GET['set_batch_size']) || !current_user_can('manage_options') || !isset($_GET['batch_size'])) {
return false;
}
$batch_size = absint($_GET['batch_size']);
if ($batch_size > 0 && $batch_size <= 50) {
update_option('webp_batch_size', $batch_size);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Batch size set to: %d', 'wpturbo'), $batch_size);
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Set preserve originals
function wpturbo_set_preserve_originals() {
if (!isset($_GET['set_preserve_originals']) || !current_user_can('manage_options') || !isset($_GET['preserve_originals'])) {
return false;
}
$preserve = rest_sanitize_boolean($_GET['preserve_originals']);
$current_preserve = wpturbo_get_preserve_originals();
if ($current_preserve !== $preserve) {
update_option('webp_preserve_originals', $preserve);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Preserve originals set to: %s', 'wpturbo'), $preserve ? __('Yes', 'wpturbo') : __('No', 'wpturbo'));
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Set disable auto-conversion on upload
function wpturbo_set_disable_auto_conversion() {
if (!isset($_GET['set_disable_auto_conversion']) || !current_user_can('manage_options') || !isset($_GET['disable_auto_conversion'])) {
return false;
}
$disable = rest_sanitize_boolean($_GET['disable_auto_conversion']);
$current_disable = wpturbo_get_disable_auto_conversion();
if ($current_disable !== $disable) {
update_option('webp_disable_auto_conversion', $disable);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Auto-conversion on upload set to: %s', 'wpturbo'), $disable ? __('Disabled', 'wpturbo') : __('Enabled', 'wpturbo'));
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Set minimum size threshold
function wpturbo_set_min_size_kb() {
if (!isset($_GET['set_min_size_kb']) || !current_user_can('manage_options') || !isset($_GET['min_size_kb'])) {
return false;
}
$min_size = absint($_GET['min_size_kb']);
if ($min_size >= 0) {
$current_min_size = wpturbo_get_min_size_kb();
if ($current_min_size !== $min_size) {
update_option('webp_min_size_kb', $min_size);
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Minimum size threshold set to: %d KB', 'wpturbo'), $min_size);
update_option('webp_conversion_log', array_slice((array)$log, -500));
}
return true;
}
return false;
}
// Set use AVIF option and ensure MIME types
function wpturbo_set_use_avif() {
if (!isset($_GET['set_use_avif']) || !current_user_can('manage_options') || !isset($_GET['use_avif'])) {
return false;
}
$use_avif = rest_sanitize_boolean($_GET['use_avif']);
$current_use_avif = wpturbo_get_use_avif();
if ($current_use_avif !== $use_avif) {
update_option('webp_use_avif', $use_avif);
wpturbo_ensure_mime_types(); // Ensure MIME types are updated
$log = get_option('webp_conversion_log', []);
$log[] = sprintf(__('Conversion format set to: %s', 'wpturbo'), $use_avif ? 'AVIF' : 'WebP');
$log[] = __('Please reconvert all images to ensure consistency after changing formats.', 'wpturbo');
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
return false;
}
// Enhanced cleanup of leftover originals and alternate formats
function wpturbo_cleanup_leftover_originals() {
if (!isset($_GET['cleanup_leftover_originals']) || !current_user_can('manage_options')) {
return false;
}
$log = get_option('webp_conversion_log', []);
$uploads_dir = wp_upload_dir()['basedir'];
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($uploads_dir));
$deleted = 0;
$failed = 0;
$preserve_originals = wpturbo_get_preserve_originals();
$use_avif = wpturbo_get_use_avif();
$current_extension = $use_avif ? 'avif' : 'webp';
$alternate_extension = $use_avif ? 'webp' : 'avif';
$attachments = get_posts([
'post_type' => 'attachment',
'posts_per_page' => -1,
'fields' => 'ids',
'post_mime_type' => ['image/jpeg', 'image/png', 'image/webp', 'image/avif'],
]);
$active_files = [];
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$excluded_images = wpturbo_get_excluded_images();
foreach ($attachments as $attachment_id) {
$file = get_attached_file($attachment_id);
$metadata = wp_get_attachment_metadata($attachment_id);
$dirname = dirname($file);
$base_name = pathinfo($file, PATHINFO_FILENAME);
if (in_array($attachment_id, $excluded_images)) {
if ($file && file_exists($file)) $active_files[$file] = true;
$possible_extensions = ['jpg', 'jpeg', 'png', 'webp', 'avif'];
foreach ($possible_extensions as $ext) {
$potential_file = "$dirname/$base_name.$ext";
if (file_exists($potential_file)) $active_files[$potential_file] = true;
}
foreach ($max_values as $index => $dimension) {
$suffix = ($index === 0) ? '' : "-{$dimension}";
foreach (['webp', 'avif'] as $ext) {
$file_path = "$dirname/$base_name$suffix.$ext";
if (file_exists($file_path)) $active_files[$file_path] = true;
}
}
$thumbnail_files = ["$dirname/$base_name-150x150.webp", "$dirname/$base_name-150x150.avif"];
foreach ($thumbnail_files as $thumbnail_file) {
if (file_exists($thumbnail_file)) $active_files[$thumbnail_file] = true;
}
if ($metadata && isset($metadata['sizes'])) {
foreach ($metadata['sizes'] as $size_data) {
$size_file = "$dirname/" . $size_data['file'];
if (file_exists($size_file)) $active_files[$size_file] = true;
}
}
continue;
}
if ($file && file_exists($file)) {
$active_files[$file] = true;
foreach ($max_values as $index => $dimension) {
$suffix = ($index === 0) ? '' : "-{$dimension}";
$current_file = "$dirname/$base_name$suffix.$current_extension";
if (file_exists($current_file)) $active_files[$current_file] = true;
}
$thumbnail_file = "$dirname/$base_name-150x150.$current_extension";
if (file_exists($thumbnail_file)) $active_files[$thumbnail_file] = true;
}
}
if (!$preserve_originals) {
foreach ($files as $file) {
if ($file->isDir()) continue;
$file_path = $file->getPathname();
$extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
if (!in_array($extension, ['webp', 'avif', 'jpg', 'jpeg', 'png'])) continue;
$relative_path = str_replace($uploads_dir . '/', '', $file_path);
$path_parts = explode('/', $relative_path);
$is_valid_path = (count($path_parts) === 1) || (count($path_parts) === 3 && is_numeric($path_parts[0]) && is_numeric($path_parts[1]));
if (!$is_valid_path || isset($active_files[$file_path])) continue;
if (in_array($extension, ['jpg', 'jpeg', 'png']) || $extension === $alternate_extension) {
$attempts = 0;
while ($attempts < 5 && file_exists($file_path)) {
if (!is_writable($file_path)) {
@chmod($file_path, 0644);
if (!is_writable($file_path)) {
$log[] = sprintf(__('Error: Cannot make %s writable - skipping deletion', 'wpturbo'), basename($file_path));
$failed++;
break;
}
}
if (@unlink($file_path)) {
$log[] = sprintf(__('Cleanup: Deleted %s', 'wpturbo'), basename($file_path));
$deleted++;
break;
}
$attempts++;
sleep(1);
}
if (file_exists($file_path)) {
$log[] = sprintf(__('Cleanup: Failed to delete %s', 'wpturbo'), basename($file_path));
$failed++;
}
}
}
}
$log[] = "" . __('Cleanup Complete', 'wpturbo') . ": " . sprintf(__('Deleted %d files, %d failed', 'wpturbo'), $deleted, $failed);
update_option('webp_conversion_log', array_slice((array)$log, -500));
foreach ($attachments as $attachment_id) {
if (in_array($attachment_id, $excluded_images)) continue;
$file_path = get_attached_file($attachment_id);
if (file_exists($file_path) && strtolower(pathinfo($file_path, PATHINFO_EXTENSION)) === $current_extension) {
$metadata = wp_get_attachment_metadata($attachment_id);
$thumbnail_file = $uploads_dir . '/' . dirname($metadata['file']) . '/' . pathinfo($file_path, PATHINFO_FILENAME) . '-150x150.' . $current_extension;
if (!file_exists($thumbnail_file)) {
$metadata = wp_generate_attachment_metadata($attachment_id, $file_path);
if (!is_wp_error($metadata)) {
wp_update_attachment_metadata($attachment_id, $metadata);
$log[] = sprintf(__('Regenerated thumbnail for %s', 'wpturbo'), basename($file_path));
}
}
}
}
$log[] = "" . __('Thumbnail Regeneration Complete', 'wpturbo') . "";
update_option('webp_conversion_log', array_slice((array)$log, -500));
return true;
}
// AJAX handlers for exclusion
add_action('wp_ajax_webp_add_excluded_image', 'wpturbo_add_excluded_image_ajax');
function wpturbo_add_excluded_image_ajax() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options') || !isset($_POST['attachment_id'])) {
wp_send_json_error(__('Permission denied or invalid attachment ID', 'wpturbo'));
}
$attachment_id = absint($_POST['attachment_id']);
if (wpturbo_add_excluded_image($attachment_id)) {
wp_send_json_success(['message' => __('Image excluded successfully', 'wpturbo')]);
} else {
wp_send_json_error(__('Image already excluded or invalid ID', 'wpturbo'));
}
}
add_action('wp_ajax_webp_remove_excluded_image', 'wpturbo_remove_excluded_image_ajax');
function wpturbo_remove_excluded_image_ajax() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options') || !isset($_POST['attachment_id'])) {
wp_send_json_error(__('Permission denied or invalid attachment ID', 'wpturbo'));
}
$attachment_id = absint($_POST['attachment_id']);
if (wpturbo_remove_excluded_image($attachment_id)) {
wp_send_json_success(['message' => __('Image removed from exclusion list', 'wpturbo')]);
} else {
wp_send_json_error(__('Image not in exclusion list', 'wpturbo'));
}
}
// Convert post content image URLs to current format
add_action('wp_ajax_convert_post_images_to_webp', 'wpturbo_convert_post_images_to_format');
function wpturbo_convert_post_images_to_format() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(__('Permission denied', 'wpturbo'));
}
$log = get_option('webp_conversion_log', []);
function add_log_entry($message) {
global $log;
$log[] = "[" . date("Y-m-d H:i:s") . "] " . $message;
update_option('webp_conversion_log', array_slice((array)$log, -500));
}
$use_avif = wpturbo_get_use_avif();
$extension = $use_avif ? 'avif' : 'webp';
add_log_entry(sprintf(__('Starting post/page/FSE-template image conversion to %s...', 'wpturbo'), $use_avif ? 'AVIF' : 'WebP'));
$public_post_types = get_post_types(['public' => true], 'names');
$fse_post_types = ['wp_template', 'wp_template_part', 'wp_block'];
$post_types = array_unique(array_merge($public_post_types, $fse_post_types));
$args = [
'post_type' => $post_types,
'posts_per_page' => -1,
'fields' => 'ids'
];
$posts = get_posts($args);
if (!$posts) {
add_log_entry(__('No posts/pages/FSE-templates found', 'wpturbo'));
wp_send_json_success(['message' => __('No posts/pages/FSE-templates found', 'wpturbo')]);
}
$upload_dir = wp_upload_dir();
$upload_baseurl = $upload_dir['baseurl'];
$upload_basedir = $upload_dir['basedir'];
$updated_count = 0;
$checked_images = 0;
foreach ($posts as $post_id) {
$content = get_post_field('post_content', $post_id);
$original_content = $content;
$content = preg_replace_callback(
'/
]+src=["\']([^"\']+\.(?:jpg|jpeg|png))["\'][^>]*>/i',
function ($matches) use (&$checked_images, $upload_baseurl, $upload_basedir, $extension) {
$original_url = $matches[1];
if (strpos($original_url, $upload_baseurl) !== 0) {
add_log_entry("Skipping
(external): {$original_url}");
return $matches[0];
}
$checked_images++;
$dirname = pathinfo($original_url, PATHINFO_DIRNAME);
$filename = pathinfo($original_url, PATHINFO_FILENAME);
$new_url = $dirname . '/' . $filename . '.' . $extension;
$scaled_url = $dirname . '/' . $filename . '-scaled.' . $extension;
$new_path = str_replace($upload_baseurl, $upload_basedir, $new_url);
$scaled_path = str_replace($upload_baseurl, $upload_basedir, $scaled_url);
if (file_exists($scaled_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $scaled_url));
return str_replace($original_url, $scaled_url, $matches[0]);
}
if (file_exists($new_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $new_url));
return str_replace($original_url, $new_url, $matches[0]);
}
$base_name = preg_replace('/(-\d+x\d+|-scaled)$/', '', $filename);
$fallback_url = $dirname . '/' . $base_name . '.' . $extension;
$fallback_scaled_url = $dirname . '/' . $base_name . '-scaled.' . $extension;
$fallback_path = str_replace($upload_baseurl, $upload_basedir, $fallback_url);
$fallback_scaled_path = str_replace($upload_baseurl, $upload_basedir, $fallback_scaled_url);
if (file_exists($fallback_scaled_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $fallback_scaled_url));
return str_replace($original_url, $fallback_scaled_url, $matches[0]);
}
if (file_exists($fallback_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $fallback_url));
return str_replace($original_url, $fallback_url, $matches[0]);
}
return $matches[0];
},
$content
);
$content = preg_replace_callback(
'/background-image\s*:\s*url\(\s*[\'"]?([^\'"]+\.(?:jpg|jpeg|png))[\'"]?\s*\)/i',
function ($matches) use (&$checked_images, $upload_baseurl, $upload_basedir, $extension) {
$original_url = $matches[1];
if (strpos($original_url, $upload_baseurl) !== 0) {
add_log_entry("Skipping BG (external): {$original_url}");
return $matches[0];
}
$checked_images++;
$dirname = pathinfo($original_url, PATHINFO_DIRNAME);
$filename = pathinfo($original_url, PATHINFO_FILENAME);
$new_url = $dirname . '/' . $filename . '.' . $extension;
$scaled_url = $dirname . '/' . $filename . '-scaled.' . $extension;
$new_path = str_replace($upload_baseurl, $upload_basedir, $new_url);
$scaled_path = str_replace($upload_baseurl, $upload_basedir, $scaled_url);
if (file_exists($scaled_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $scaled_url));
return str_replace($original_url, $scaled_url, $matches[0]);
}
if (file_exists($new_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $new_url));
return str_replace($original_url, $new_url, $matches[0]);
}
$base_name = preg_replace('/(-\d+x\d+|-scaled)$/', '', $filename);
$fallback_url = $dirname . '/' . $base_name . '.' . $extension;
$fallback_scaled_url = $dirname . '/' . $base_name . '-scaled.' . $extension;
$fallback_path = str_replace($upload_baseurl, $upload_basedir, $fallback_url);
$fallback_scaled_path = str_replace($upload_baseurl, $upload_basedir, $fallback_scaled_url);
if (file_exists($fallback_scaled_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $fallback_scaled_url));
return str_replace($original_url, $fallback_scaled_url, $matches[0]);
}
if (file_exists($fallback_path)) {
add_log_entry(sprintf(__('Replacing: %s → %s', 'wpturbo'), $original_url, $fallback_url));
return str_replace($original_url, $fallback_url, $matches[0]);
}
return $matches[0];
},
$content
);
if ($content !== $original_content) {
wp_update_post(['ID' => $post_id, 'post_content' => $content]);
$updated_count++;
}
$thumbnail_id = get_post_thumbnail_id($post_id);
if ($thumbnail_id && !in_array($thumbnail_id, wpturbo_get_excluded_images())) {
$thumbnail_path = get_attached_file($thumbnail_id);
if ($thumbnail_path && !str_ends_with($thumbnail_path, '.' . $extension)) {
$new_path = preg_replace('/\.(jpg|jpeg|png)$/i', '.' . $extension, $thumbnail_path);
if (file_exists($new_path)) {
update_attached_file($thumbnail_id, $new_path);
wp_update_post(['ID' => $thumbnail_id, 'post_mime_type' => $use_avif ? 'image/avif' : 'image/webp']);
$metadata = wp_generate_attachment_metadata($thumbnail_id, $new_path);
wp_update_attachment_metadata($thumbnail_id, $metadata);
add_log_entry(sprintf(__('Updated thumbnail: %s → %s', 'wpturbo'), basename($thumbnail_path), basename($new_path)));
}
}
}
}
add_log_entry(sprintf(__('Checked %d images (including BG), updated %d items', 'wpturbo'), $checked_images, $updated_count));
wp_send_json_success(['message' => sprintf(__('Checked %d images (including BG), updated %d items', 'wpturbo'), $checked_images, $updated_count)]);
}
// Export all media as a ZIP file
add_action('wp_ajax_webp_export_media_zip', 'wpturbo_export_media_zip');
function wpturbo_export_media_zip() {
check_ajax_referer('webp_converter_nonce', 'nonce');
if (!current_user_can('manage_options')) {
wp_send_json_error(__('Permission denied', 'wpturbo'));
}
wp_raise_memory_limit('admin');
set_time_limit(0);
$args = [
'post_type' => 'attachment',
'post_mime_type' => 'image',
'posts_per_page' => -1,
'fields' => 'ids',
];
$attachments = get_posts($args);
if (empty($attachments)) {
wp_send_json_error(__('No media files found', 'wpturbo'));
}
$temp_file = tempnam(sys_get_temp_dir(), 'webp_media_export_');
if (!$temp_file) {
wp_send_json_error(__('Failed to create temporary file', 'wpturbo'));
}
$zip = new ZipArchive();
if ($zip->open($temp_file, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
@unlink($temp_file);
wp_send_json_error(__('Failed to create ZIP archive', 'wpturbo'));
}
$upload_dir = wp_upload_dir()['basedir'];
$log = get_option('webp_conversion_log', []);
$possible_extensions = ['jpg', 'jpeg', 'png', 'webp', 'avif'];
foreach ($attachments as $attachment_id) {
$file_path = get_attached_file($attachment_id);
if (!$file_path || !file_exists($file_path)) {
$log[] = sprintf(__('Skipped: Main file not found for Attachment ID %d', 'wpturbo'), $attachment_id);
continue;
}
$dirname = dirname($file_path);
$base_name = pathinfo($file_path, PATHINFO_FILENAME);
$relative_dir = str_replace($upload_dir . '/', '', $dirname);
// Add main file
$relative_path = $relative_dir . '/' . basename($file_path);
$zip->addFile($file_path, $relative_path);
$log[] = sprintf(__('Added to ZIP: %s (Attachment ID %d)', 'wpturbo'), basename($file_path), $attachment_id);
// Add metadata sizes
$metadata = wp_get_attachment_metadata($attachment_id);
if ($metadata && isset($metadata['sizes'])) {
foreach ($metadata['sizes'] as $size => $size_data) {
$size_file = $dirname . '/' . $size_data['file'];
if (file_exists($size_file)) {
$relative_size_path = $relative_dir . '/' . $size_data['file'];
$zip->addFile($size_file, $relative_size_path);
$log[] = sprintf(__('Added to ZIP: %s (size: %s, Attachment ID %d)', 'wpturbo'), $size_data['file'], $size, $attachment_id);
}
}
}
// Add all related files with the same base name
foreach ($possible_extensions as $ext) {
// Check for base file with different extensions (e.g., image.jpg, image.png)
$related_file = "$dirname/$base_name.$ext";
if (file_exists($related_file) && $related_file !== $file_path) {
$relative_related_path = $relative_dir . '/' . "$base_name.$ext";
$zip->addFile($related_file, $relative_related_path);
$log[] = sprintf(__('Added to ZIP: Related file %s (Attachment ID %d)', 'wpturbo'), "$base_name.$ext", $attachment_id);
}
// Check for sized versions (e.g., image-500.jpg, image-150x150.png)
$pattern = "$dirname/$base_name-*.$ext";
$related_files = glob($pattern);
foreach ($related_files as $related_file) {
// Skip if already added as main file or metadata size
if ($related_file === $file_path || in_array(basename($related_file), array_column($metadata['sizes'] ?? [], 'file'))) {
continue;
}
$relative_related_path = $relative_dir . '/' . basename($related_file);
$zip->addFile($related_file, $relative_related_path);
$log[] = sprintf(__('Added to ZIP: Related size %s (Attachment ID %d)', 'wpturbo'), basename($related_file), $attachment_id);
}
}
}
$zip->close();
update_option('webp_conversion_log', array_slice((array)$log, -500));
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="media_export_' . date('Y-m-d_H-i-s') . '.zip"');
header('Content-Length: ' . filesize($temp_file));
readfile($temp_file);
flush();
@unlink($temp_file);
exit;
}
// Custom srcset to include all sizes in current format
add_filter('wp_calculate_image_srcset', 'wpturbo_custom_srcset', 10, 5);
function wpturbo_custom_srcset($sources, $size_array, $image_src, $image_meta, $attachment_id) {
if (in_array($attachment_id, wpturbo_get_excluded_images())) {
return $sources;
}
$use_avif = wpturbo_get_use_avif();
$extension = $use_avif ? '.avif' : '.webp';
$mode = wpturbo_get_resize_mode();
$max_values = ($mode === 'width') ? wpturbo_get_max_widths() : wpturbo_get_max_heights();
$upload_dir = wp_upload_dir();
$base_path = $upload_dir['basedir'] . '/' . dirname($image_meta['file']);
$base_name = pathinfo($image_meta['file'], PATHINFO_FILENAME);
$base_url = $upload_dir['baseurl'] . '/' . dirname($image_meta['file']);
foreach ($max_values as $index => $dimension) {
if ($index === 0) continue;
$file = "$base_path/$base_name-$dimension$extension";
if (file_exists($file)) {
$size_key = "custom-$dimension";
$width = ($mode === 'width') ? $dimension : (isset($image_meta['sizes'][$size_key]['width']) ? $image_meta['sizes'][$size_key]['width'] : 0);
$sources[$width] = [
'url' => "$base_url/$base_name-$dimension$extension",
'descriptor' => 'w',
'value' => $width
];
}
}
$thumbnail_file = "$base_path/$base_name-150x150$extension";
if (file_exists($thumbnail_file)) {
$sources[150] = [
'url' => "$base_url/$base_name-150x150$extension",
'descriptor' => 'w',
'value' => 150
];
}
return $sources;
}
function wpturbo_convert_single_image_stamp_check($attachment_id) {
// Your existing settings - you might already have these defined elsewhere
$use_avif = false; // or however you detect AVIF
$current_quality = 80; // your WebP/AVIF quality setting
$mode = 'width'; // resize mode: width, height, or auto
$max_values = [1920, 1200, 600, 300]; // your target sizes
// 🔥 1. Load the current metadata
$metadata = wp_get_attachment_metadata($attachment_id);
if (!$metadata) {
return; // Can't process without metadata
}
// 🔥 2. Build the expected stamp
$expected_stamp = [
'format' => $use_avif ? 'avif' : 'webp',
'quality' => $current_quality,
'resize_mode' => $mode,
'max_values' => $max_values,
];
// 🔥 3. Check existing stamp
$stamp = isset($metadata['pixrefiner_stamp']) ? $metadata['pixrefiner_stamp'] : null;
// 🔥 4. Compare — if matches and no force, skip
if ($stamp === $expected_stamp && empty($_GET['force_reconvert'])) {
return; // Already converted correctly, no need to reprocess
}
// 🔥 5. If no match — continue normal conversion
// 👉 Now here you do your actual conversion logic like:
// - Resize images
// - Generate WebP / AVIF
// - Compress
// etc.
// (This part is your existing code that does the heavy work.)
// 🔥 6. After conversion, update the stamp
$metadata['pixrefiner_stamp'] = $expected_stamp;
wp_update_attachment_metadata($attachment_id, $metadata);
}
// Admin interface
add_action('admin_menu', function() {
add_media_page(
__('PixRefiner', 'wpturbo'),
__('PixRefiner', 'wpturbo'),
'manage_options',
'webp-converter',
'wpturbo_webp_converter_page'
);
});
function wpturbo_webp_converter_page() {
wp_enqueue_media();
wp_enqueue_script('media-upload');
wp_enqueue_style('media');
if (isset($_GET['set_max_width'])) wpturbo_set_max_widths();
if (isset($_GET['set_max_height'])) wpturbo_set_max_heights();
if (isset($_GET['set_resize_mode'])) wpturbo_set_resize_mode();
if (isset($_GET['set_quality'])) wpturbo_set_quality();
if (isset($_GET['set_batch_size'])) wpturbo_set_batch_size();
if (isset($_GET['set_preserve_originals'])) wpturbo_set_preserve_originals();
if (isset($_GET['set_disable_auto_conversion'])) wpturbo_set_disable_auto_conversion();
if (isset($_GET['set_min_size_kb'])) wpturbo_set_min_size_kb();
if (isset($_GET['set_use_avif'])) wpturbo_set_use_avif();
if (isset($_GET['cleanup_leftover_originals'])) wpturbo_cleanup_leftover_originals();
if (isset($_GET['clear_log'])) wpturbo_clear_log();
if (isset($_GET['reset_defaults'])) wpturbo_reset_defaults();
$has_image_library = extension_loaded('imagick') || extension_loaded('gd');
$has_avif_support = (extension_loaded('imagick') && in_array('AVIF', Imagick::queryFormats())) || (extension_loaded('gd') && function_exists('imageavif'));
$htaccess_file = ABSPATH . '.htaccess';
// Original check kept as comment for reference:
// $mime_configured = file_exists($htaccess_file) && strpos(file_get_contents($htaccess_file), 'AddType image/webp .webp') !== false;
$mime_configured = true; // Force to true to suppress the MIME type warning
?>
1. Resize Mode:
2. Set Max Sizes:
3. Min Size for Conversion:
4. Conversion Format:
5. Preserve Originals:
6. Disable Auto-Conversion:
7. Upload:
1. Repeat:
2. Run All:
1. Repeat:
2. Convert:
3. Cleanup:
4. Fix Links:
a) Usability:
b) Backups:
c) Export Media:
d) Reset Defaults:
e) Speed:
f) Log Wait:
g) Stop Anytime:
h) AVIF Needs:
i) Old Browsers:
j) MIME Types:
k) Rollback:
' . __('Conversion started. Monitor progress in Media.', 'wpturbo') . '
' . __('Max widths updated.', 'wpturbo') . '
' . __('Max heights updated.', 'wpturbo') . '
' . __('Settings reset to defaults.', 'wpturbo') . '
' . __('Minimum size threshold updated.', 'wpturbo') . '
' . __('Conversion format updated. Please reconvert all images.', 'wpturbo') . '
✅ PixRefiner stamp patch complete.
Custom WordPress Admin Dashboard
Custom WordPress Admin Dashboard
class DocumentacionDashboard {
private $grupo_opciones = 'dashboard_docs_settings';
private $capacidad_requerida = 'manage_options';
private $grupo_cache = 'dashboard_docs';
private $expiracion_cache = 3600; // 1 hora
public function __construct() {
// Solo cargar funcionalidad de administración en el área de administración
if (is_admin()) {
add_action('admin_menu', array($this, 'agregar_pagina_configuracion'));
add_action('admin_menu', array($this, 'agregar_menu_tutoriales'), 11);
add_action('admin_bar_menu', array($this, 'agregar_menu_barra_admin'), 100);
add_action('admin_init', array($this, 'registrar_configuraciones'));
add_action('load-index.php', array($this, 'personalizar_dashboard'));
add_action('wp_dashboard_setup', array($this, 'eliminar_todos_widgets_dashboard'), 999);
add_action('admin_init', array($this, 'validar_envio_configuraciones'));
// Seguridad: Agregar cabeceras CSP para área de administración
add_action('admin_head', array($this, 'agregar_cabeceras_csp_admin'));
}
// Funcionalidad frontend: solo ocultación de barra de administración e inyección de CSS
if (!is_admin()) {
add_action('template_redirect', array($this, 'ocultar_barra_admin_en_pagina_doc'));
add_action('wp_head', array($this, 'agregar_css_frontend'));
add_action('wp_before_admin_bar_render', array($this, 'agregar_menu_barra_admin'));
// Seguridad: Agregar cabeceras CSP para páginas de documentación frontend
add_action('wp_head', array($this, 'agregar_cabeceras_csp_frontend'));
}
// Seguridad: Inicializar limitación de velocidad para cambios de configuración
add_action('init', array($this, 'inicializar_limitacion_velocidad'));
}
// Agregar página de configuración bajo el menú Configuración
public function agregar_pagina_configuracion() {
add_options_page(
__('Configuración Dashboard Personalizado', 'dashboard-docs'),
__('Dashboard personalizado', 'dashboard-docs'),
$this->capacidad_requerida,
'dashboard-documentation',
array($this, 'pagina_configuracion')
);
}
// Agregar menú Tutoriales si está habilitado
public function agregar_menu_tutoriales() {
$mostrar_menu_tutoriales = get_option('dashboard_docs_show_tutorials_menu', 0);
if (!$mostrar_menu_tutoriales || !current_user_can($this->capacidad_requerida)) {
return;
}
add_menu_page(
__('Tutoriales', 'dashboard-docs'),
__('Tutoriales', 'dashboard-docs'),
$this->capacidad_requerida,
'dashboard-tutorials',
array($this, 'renderizar_pagina_tutoriales'),
'dashicons-editor-help',
2
);
}
// Renderizar página de tutoriales (igual que el dashboard)
public function renderizar_pagina_tutoriales() {
$this->mostrar_contenido_dashboard_personalizado();
}
// Agregar menú de documentación externa a la barra de administración
public function agregar_menu_barra_admin($wp_admin_bar = null) {
$mostrar_menu_barra_admin = get_option('dashboard_docs_show_admin_bar_menu', 0);
if (!$mostrar_menu_barra_admin || !current_user_can($this->capacidad_requerida)) {
return;
}
// Obtener barra de administración si no se pasa (para frontend)
if (!$wp_admin_bar) {
global $wp_admin_bar;
}
if (!$wp_admin_bar) {
return;
}
$menus_externos = get_option('dashboard_docs_external_menus', array());
if (empty($menus_externos)) {
return;
}
// Agregar menú principal
$nombre_menu_barra_admin = get_option('dashboard_docs_admin_bar_menu_name', __('Todos los tutoriales', 'dashboard-docs'));
$wp_admin_bar->add_menu(array(
'id' => 'all-tutorials',
'title' => esc_html($nombre_menu_barra_admin),
'href' => '#',
));
// Agregar submenús
foreach ($menus_externos as $indice => $menu) {
if (!empty($menu['name']) && !empty($menu['url'])) {
$meta = array();
if (isset($menu['open_in_new_tab']) && $menu['open_in_new_tab']) {
$meta['target'] = '_blank';
$meta['rel'] = 'noopener noreferrer';
} else {
$meta['target'] = '_self';
}
$wp_admin_bar->add_menu(array(
'id' => 'tutorial-' . $indice,
'parent' => 'all-tutorials',
'title' => esc_html($menu['name']),
'href' => esc_url($menu['url']),
'meta' => $meta,
));
}
}
}
// Registrar configuraciones del plugin con validación
public function registrar_configuraciones() {
register_setting(
$this->grupo_opciones,
'dashboard_docs_page',
array(
'type' => 'integer',
'sanitize_callback' => array($this, 'sanitizar_id_pagina'),
'default' => 0
)
);
register_setting(
$this->grupo_opciones,
'dashboard_docs_hide_header',
array(
'type' => 'boolean',
'sanitize_callback' => array($this, 'sanitizar_checkbox'),
'default' => false
)
);
register_setting(
$this->grupo_opciones,
'dashboard_docs_hide_footer',
array(
'type' => 'boolean',
'sanitize_callback' => array($this, 'sanitizar_checkbox'),
'default' => false
)
);
register_setting(
$this->grupo_opciones,
'dashboard_docs_role_pages',
array(
'type' => 'array',
'sanitize_callback' => array($this, 'sanitizar_paginas_roles'),
'default' => array()
)
);
register_setting(
$this->grupo_opciones,
'dashboard_docs_show_tutorials_menu',
array(
'type' => 'boolean',
'sanitize_callback' => array($this, 'sanitizar_checkbox'),
'default' => false
)
);
register_setting(
$this->grupo_opciones,
'dashboard_docs_show_admin_bar_menu',
array(
'type' => 'boolean',
'sanitize_callback' => array($this, 'sanitizar_checkbox'),
'default' => false
)
);
register_setting(
$this->grupo_opciones,
'dashboard_docs_admin_bar_menu_name',
array(
'type' => 'string',
'sanitize_callback' => array($this, 'sanitizar_campo_texto'),
'default' => __('Todos los tutoriales', 'dashboard-docs')
)
);
register_setting(
$this->grupo_opciones,
'dashboard_docs_external_menus',
array(
'type' => 'array',
'sanitize_callback' => array($this, 'sanitizar_menus_externos'),
'default' => array()
)
);
}
// Seguridad: Validar envío de formulario de configuraciones
public function validar_envio_configuraciones() {
if (isset($_POST['submit']) && isset($_POST['option_page']) && $_POST['option_page'] === $this->grupo_opciones) {
if (!current_user_can($this->capacidad_requerida)) {
wp_die(__('No tienes permisos suficientes para acceder a esta página.', 'dashboard-docs'));
}
if (!isset($_POST['_wpnonce']) || !wp_verify_nonce($_POST['_wpnonce'], $this->grupo_opciones . '-options')) {
wp_die(__('Verificación de seguridad falló.', 'dashboard-docs'));
}
// Limpiar cache cuando las configuraciones se actualizan
$this->limpiar_cache_documentacion();
}
}
// Rendimiento: Limpiar cache de página de documentación
private function limpiar_cache_documentacion() {
// Limpiar todos los datos de la página de documentación en cache
// Respaldo para sistemas sin wp_cache_delete_group
if (function_exists('wp_cache_delete_group')) {
wp_cache_delete_group($this->grupo_cache);
}
}
// Seguridad: Sanitizar entrada de ID de página
public function sanitizar_id_pagina($entrada) {
$id_pagina = absint($entrada);
if ($id_pagina > 0) {
$pagina = get_post($id_pagina);
if (!$pagina || $pagina->post_type !== 'page') {
add_settings_error(
'dashboard_docs_page',
'invalid_page',
__('Página seleccionada inválida.', 'dashboard-docs')
);
return get_option('dashboard_docs_page', 0);
}
}
return $id_pagina;
}
// Seguridad: Sanitizar entrada de checkbox
public function sanitizar_checkbox($entrada) {
return !empty($entrada) ? 1 : 0;
}
// Seguridad: Sanitizar entrada de campo de texto
public function sanitizar_campo_texto($entrada) {
return sanitize_text_field($entrada);
}
// Seguridad: Sanitizar array de páginas de roles
public function sanitizar_paginas_roles($entrada) {
if (!is_array($entrada)) {
return array();
}
$sanitizado = array();
$roles_validos = wp_roles()->get_names();
foreach ($entrada as $rol => $id_pagina) {
// Validar que el rol existe
if (!array_key_exists($rol, $roles_validos)) {
continue;
}
// Validar ID de página
$id_pagina = absint($id_pagina);
if ($id_pagina > 0) {
$pagina = get_post($id_pagina);
if ($pagina && $pagina->post_type === 'page') {
$sanitizado[sanitize_key($rol)] = $id_pagina;
}
}
}
return $sanitizado;
}
// Seguridad: Sanitizar array de menús externos
public function sanitizar_menus_externos($entrada) {
if (!is_array($entrada)) {
return array();
}
$sanitizado = array();
foreach ($entrada as $menu) {
if (is_array($menu) && !empty($menu['name']) && !empty($menu['url'])) {
$nombre = sanitize_text_field($menu['name']);
$url = esc_url_raw($menu['url']);
$abrir_nueva_pestana = (isset($menu['open_in_new_tab']) && $menu['open_in_new_tab'] == 1) ? 1 : 0;
// Validación mejorada de URL
if (!empty($nombre) && !empty($url) && $this->validar_url_externa($url)) {
$sanitizado[] = array(
'name' => $nombre,
'url' => $url,
'open_in_new_tab' => $abrir_nueva_pestana
);
} else {
add_settings_error(
'dashboard_docs_external_menus',
'invalid_external_url',
sprintf(
__('URL inválida o insegura eliminada: %s', 'dashboard-docs'),
esc_html($menu['url'])
)
);
}
}
}
return $sanitizado;
}
// Página de configuración HTML con seguridad adecuada
public function pagina_configuracion() {
// Seguridad: Verificar capacidades de usuario
if (!current_user_can($this->capacidad_requerida)) {
wp_die(__('No tienes permisos suficientes para acceder a esta página.', 'dashboard-docs'));
}
$roles = wp_roles()->get_names();
$paginas_roles = get_option('dashboard_docs_role_pages', array());
$menus_externos = get_option('dashboard_docs_external_menus', array());
// Seguridad: Obtener páginas con verificación adecuada de estado de publicación y límite para rendimiento
$paginas = get_pages(array(
'post_status' => array('publish', 'private'),
'number' => 100 // Limitar a 100 páginas para rendimiento
));
?>
obtener_pagina_documentacion_usuario();
if ($id_pagina_seleccionada && is_page($id_pagina_seleccionada)) {
add_filter('show_admin_bar', '__return_false', 10, 1);
}
}
public function eliminar_todos_widgets_dashboard() {
$id_pagina_seleccionada = $this->obtener_pagina_documentacion_usuario();
if (!$id_pagina_seleccionada) return;
global $wp_meta_boxes;
$wp_meta_boxes['dashboard']['normal']['core'] = array();
$wp_meta_boxes['dashboard']['side']['core'] = array();
$wp_meta_boxes['dashboard']['normal']['high'] = array();
$wp_meta_boxes['dashboard']['side']['high'] = array();
}
public function mostrar_contenido_dashboard_personalizado() {
$id_pagina_seleccionada = $this->obtener_pagina_documentacion_usuario();
if (!$id_pagina_seleccionada) return;
$pagina = get_post($id_pagina_seleccionada);
if (!$pagina || $pagina->post_type !== 'page') {
echo '' . esc_html__('Página de documentación seleccionada no encontrada.', 'dashboard-docs') . '
';
return;
}
if ($pagina->post_status === 'private' && !current_user_can('read_private_pages')) {
echo '' . esc_html__('No tienes permisos para ver esta página de documentación.', 'dashboard-docs') . '
';
return;
}
$enlace_pagina = get_permalink($id_pagina_seleccionada);
if (!$enlace_pagina) {
echo '' . esc_html__('No se puede generar la URL de la página.', 'dashboard-docs') . '
';
return;
}
$ocultar_encabezado = get_option('dashboard_docs_hide_header');
$ocultar_pie = get_option('dashboard_docs_hide_footer');
$parametros_url = array();
if ($ocultar_encabezado) $parametros_url['hide_header'] = '1';
if ($ocultar_pie) $parametros_url['hide_footer'] = '1';
if (!empty($parametros_url)) {
$enlace_pagina = add_query_arg($parametros_url, $enlace_pagina);
}
?>
obtener_pagina_documentacion_usuario();
if (!$id_pagina_seleccionada) return;
add_filter('screen_options_show_screen', '__return_false');
add_action('current_screen', array($this, 'eliminar_pestanas_ayuda'));
add_action('in_admin_header', array($this, 'mostrar_contenido_dashboard_personalizado'), 100);
}
public function eliminar_pestanas_ayuda() {
$pantalla = get_current_screen();
if ($pantalla && $pantalla->id === 'dashboard') {
$pantalla->remove_help_tabs();
}
}
private function obtener_pagina_documentacion_usuario() {
$usuario_actual = wp_get_current_user();
if (!$usuario_actual || !$usuario_actual->exists()) {
return false;
}
$clave_cache = 'pagina_doc_usuario_' . $usuario_actual->ID;
$id_pagina_cache = wp_cache_get($clave_cache, $this->grupo_cache);
if ($id_pagina_cache !== false) {
return $id_pagina_cache;
}
$paginas_roles = get_option('dashboard_docs_role_pages', array());
$id_pagina = false;
foreach ($usuario_actual->roles as $rol) {
$rol = sanitize_key($rol);
if (isset($paginas_roles[$rol]) && !empty($paginas_roles[$rol])) {
$id_pagina_temp = absint($paginas_roles[$rol]);
if ($id_pagina_temp > 0) {
$pagina = get_post($id_pagina_temp);
if ($pagina && $pagina->post_type === 'page') {
$id_pagina = $id_pagina_temp;
break;
}
}
}
}
if (!$id_pagina) {
$pagina_por_defecto = absint(get_option('dashboard_docs_page', 0));
if ($pagina_por_defecto > 0) {
$pagina = get_post($pagina_por_defecto);
if ($pagina && $pagina->post_type === 'page') {
$id_pagina = $pagina_por_defecto;
}
}
}
wp_cache_set($clave_cache, $id_pagina, $this->grupo_cache, $this->expiracion_cache);
return $id_pagina;
}
public function agregar_css_frontend() {
$ocultar_encabezado = isset($_GET['hide_header']) && sanitize_text_field($_GET['hide_header']) === '1';
$ocultar_pie = isset($_GET['hide_footer']) && sanitize_text_field($_GET['hide_footer']) === '1';
if (!$ocultar_encabezado && !$ocultar_pie) {
return;
}
$id_pagina_actual = get_the_ID();
if (!$this->es_pagina_documentacion($id_pagina_actual)) {
return;
}
$css = '';
if ($ocultar_encabezado) {
$css .= 'header, .site-header, #masthead { display: none !important; }';
}
if ($ocultar_pie) {
$css .= 'footer, .site-footer, #colophon { display: none !important; }';
}
if (!empty($css)) {
echo '';
}
}
private function es_pagina_documentacion($id_pagina) {
if (!$id_pagina) {
return false;
}
$clave_cache = 'es_pagina_doc_' . $id_pagina;
$resultado_cache = wp_cache_get($clave_cache, $this->grupo_cache);
if ($resultado_cache !== false) {
return $resultado_cache;
}
$resultado = false;
$pagina_por_defecto = absint(get_option('dashboard_docs_page', 0));
if ($id_pagina === $pagina_por_defecto) {
$resultado = true;
} else {
$paginas_roles = get_option('dashboard_docs_role_pages', array());
$resultado = in_array($id_pagina, array_map('absint', $paginas_roles));
}
wp_cache_set($clave_cache, $resultado, $this->grupo_cache, $this->expiracion_cache);
return $resultado;
}
public function agregar_cabeceras_csp_admin() {
$pantalla = get_current_screen();
if ($pantalla && $pantalla->id === 'dashboard') {
echo '';
}
}
public function agregar_cabeceras_csp_frontend() {
$id_pagina_actual = get_the_ID();
if ($this->es_pagina_documentacion($id_pagina_actual)) {
echo '';
}
}
public function inicializar_limitacion_velocidad() {
if (isset($_POST['submit']) && isset($_POST['option_page']) && $_POST['option_page'] === $this->grupo_opciones) {
$id_usuario = get_current_user_id();
$clave_limite_velocidad = 'dashboard_docs_limite_velocidad_' . $id_usuario;
$intentos = get_transient($clave_limite_velocidad);
if ($intentos === false) {
set_transient($clave_limite_velocidad, 1, HOUR_IN_SECONDS);
} elseif ($intentos >= 100) {
wp_die(
esc_html__('Demasiados cambios de configuración. Por favor espera una hora antes de intentar de nuevo.', 'dashboard-docs'),
esc_html__('Límite de Velocidad Excedido', 'dashboard-docs'),
array('response' => 429)
);
} else {
set_transient($clave_limite_velocidad, $intentos + 1, HOUR_IN_SECONDS);
}
}
}
private function validar_url_externa($url) {
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return false;
}
$url_parseada = parse_url($url);
if (!in_array($url_parseada['scheme'], array('http', 'https'))) {
return false;
}
$hosts_bloqueados = array(
'localhost',
'127.0.0.1',
'::1',
'0.0.0.0',
'10.0.0.0/8',
'172.16.0.0/12',
'192.168.0.0/16'
);
foreach ($hosts_bloqueados as $host_bloqueado) {
if (strpos($url_parseada['host'], $host_bloqueado) !== false) {
return false;
}
}
return true;
}
}
// Inicializar la clase
new DocumentacionDashboard();
Borrar y Eliminar Plugin
Borrar y Eliminar Plugin
/*
Plugin Name: Desactivar y Eliminar
Description: Agrega una opción para desactivar y eliminar plugins en un solo clic.
Version: 1.2
Author: WP Simple Hacks
Author URI: https://wpsimplehacks.com
*/
// Check if we're on the plugins page or handling a plugin action
add_action('current_screen', 'dad_initialize_plugin');
add_action('admin_init', 'dad_handle_plugin_actions');
function dad_initialize_plugin() {
$screen = get_current_screen();
// Only load on plugins page
if (!$screen || $screen->id !== 'plugins') {
return;
}
// Register all plugin functionality
add_filter('bulk_actions-plugins', 'dad_add_bulk_actions');
add_filter('handle_bulk_actions-plugins', 'dad_handle_bulk_actions', 10, 3);
add_action('admin_notices', 'dad_bulk_action_admin_notice');
add_filter('plugin_action_links', 'dad_add_quick_action', 10, 4);
add_action('pre_current_active_plugins', 'dad_sort_plugins_list');
add_filter('plugin_row_meta', 'dad_add_plugin_info', 10, 2);
add_action('activated_plugin', 'dad_track_plugin_activation');
add_action('deactivated_plugin', 'dad_track_plugin_deactivation');
// Run once to check existing plugins
dad_check_existing_plugins();
}
function dad_handle_plugin_actions() {
// Only handle our specific quick action
if (isset($_GET['action']) && $_GET['action'] === 'deactivate_and_delete' && isset($_GET['plugin'])) {
dad_handle_quick_action();
}
}
function dad_add_bulk_actions($bulk_actions) {
// Security: Check if user has capability to manage plugins
if (!current_user_can('delete_plugins')) {
return $bulk_actions;
}
$bulk_actions['deactivate_and_delete'] = 'Desactivar y Eliminar';
return $bulk_actions;
}
function dad_handle_bulk_actions($redirect_to, $doaction, $plugins) {
if ($doaction !== 'deactivate_and_delete') {
return $redirect_to;
}
// Security: Check user capabilities
if (!current_user_can('delete_plugins') || !current_user_can('deactivate_plugins')) {
return $redirect_to;
}
// Security: Verify nonce
if (!isset($_REQUEST['_wpnonce']) || !wp_verify_nonce($_REQUEST['_wpnonce'], 'bulk-plugins')) {
return $redirect_to;
}
// Security: Validate and sanitize plugin list
if (!is_array($plugins) || empty($plugins)) {
return $redirect_to;
}
// Optimization: Cache plugins list to avoid multiple calls
static $valid_plugins = null;
if ($valid_plugins === null) {
$valid_plugins = array_keys(get_plugins());
}
$processed_count = 0;
foreach ($plugins as $plugin) {
// Security: Sanitize and validate plugin path
$plugin = sanitize_text_field($plugin);
// Security: Ensure plugin exists and is valid
if (!in_array($plugin, $valid_plugins, true)) {
continue;
}
// Security: Prevent self-deletion
if (plugin_basename(__FILE__) === $plugin) {
continue;
}
deactivate_plugins($plugin);
dad_track_plugin_deactivation($plugin);
delete_plugins(array($plugin));
$processed_count++;
}
$redirect_to = add_query_arg('deactivate_and_delete', $processed_count, $redirect_to);
return $redirect_to;
}
function dad_bulk_action_admin_notice() {
if (!empty($_REQUEST['deactivate_and_delete'])) {
$count = intval($_REQUEST['deactivate_and_delete']);
if ($count > 0) {
$message = sprintf(
_n(
'%d plugin desactivado y eliminado.',
'%d plugins desactivados y eliminados.',
$count,
'deactivate-and-delete'
),
$count
);
echo '' . esc_html($message) . '
';
}
}
}
function dad_add_quick_action($actions, $plugin_file, $plugin_data, $context) {
// Security: Check user capabilities
if (!current_user_can('delete_plugins') || !current_user_can('deactivate_plugins')) {
return $actions;
}
// Security: Prevent self-deletion
if (plugin_basename(__FILE__) === $plugin_file) {
return $actions;
}
if (is_plugin_active($plugin_file)) {
$url = wp_nonce_url(
admin_url('plugins.php?action=deactivate_and_delete&plugin=' . urlencode($plugin_file)),
'deactivate_and_delete_plugin_' . $plugin_file
);
$actions['deactivate_and_delete'] = sprintf(
'%s',
esc_url($url),
esc_attr("'" . esc_js(__('¿Estás seguro de que quieres desactivar y eliminar este plugin? Esta acción no se puede deshacer.', 'deactivate-and-delete')) . "'"),
esc_html__('Desactivar y Eliminar', 'deactivate-and-delete')
);
}
return $actions;
}
function dad_sort_plugins_list() {
global $wp_list_table;
if (!is_admin() || !$wp_list_table || get_current_screen()->id !== 'plugins') {
return;
}
$all_plugins = get_plugins();
$active_plugins = get_option('active_plugins', []);
// Sort plugins into active and inactive
$active = [];
$inactive = [];
foreach ($all_plugins as $plugin_file => $plugin_data) {
if (in_array($plugin_file, $active_plugins, true)) {
$active[$plugin_file] = $plugin_data;
} else {
$inactive[$plugin_file] = $plugin_data;
}
}
// Sort both arrays alphabetically by plugin name
uasort($active, function ($a, $b) {
return strcasecmp($a['Name'], $b['Name']);
});
uasort($inactive, function ($a, $b) {
return strcasecmp($a['Name'], $b['Name']);
});
// Merge sorted arrays
$sorted_plugins = $active + $inactive;
// Replace plugin list table items
$wp_list_table->items = [];
foreach ($sorted_plugins as $plugin_file => $plugin_data) {
$wp_list_table->items[$plugin_file] = $plugin_data;
}
}
function dad_track_plugin_activation($plugin) {
// Security: Validate input
if (empty($plugin) || !is_string($plugin)) {
return;
}
$plugin = sanitize_text_field($plugin);
$plugin_dates = get_option('dad_plugin_dates', []);
// Track installation date if this is the first time we see this plugin
if (!isset($plugin_dates[$plugin]['installed'])) {
$plugin_dates[$plugin]['installed'] = current_time('mysql');
}
$plugin_dates[$plugin]['activated'] = current_time('mysql');
update_option('dad_plugin_dates', $plugin_dates);
}
function dad_track_plugin_deactivation($plugin) {
// Security: Validate input
if (empty($plugin) || !is_string($plugin)) {
return;
}
$plugin = sanitize_text_field($plugin);
$plugin_dates = get_option('dad_plugin_dates', []);
// Track installation date if this is the first time we see this plugin
if (!isset($plugin_dates[$plugin]['installed'])) {
$plugin_dates[$plugin]['installed'] = current_time('mysql');
}
$plugin_dates[$plugin]['deactivated'] = current_time('mysql');
update_option('dad_plugin_dates', $plugin_dates);
}
// Check and track installation dates for existing plugins
function dad_check_existing_plugins() {
$all_plugins = get_plugins();
$plugin_dates = get_option('dad_plugin_dates', []);
$updated = false;
foreach ($all_plugins as $plugin_file => $plugin_data) {
if (!isset($plugin_dates[$plugin_file]['installed'])) {
$plugin_dates[$plugin_file]['installed'] = current_time('mysql');
$updated = true;
}
}
if ($updated) {
update_option('dad_plugin_dates', $plugin_dates);
}
}
function dad_get_plugin_size($plugin_file) {
// Optimization: Cache plugin sizes to avoid recalculation
static $size_cache = [];
if (isset($size_cache[$plugin_file])) {
return $size_cache[$plugin_file];
}
// Security: Validate input
if (empty($plugin_file) || !is_string($plugin_file)) {
return $size_cache[$plugin_file] = 0;
}
// Security: Sanitize plugin file path
$original_plugin_file = $plugin_file;
$plugin_file = sanitize_text_field($plugin_file);
// Security: Validate plugin exists
static $valid_plugins = null;
if ($valid_plugins === null) {
$valid_plugins = array_keys(get_plugins());
}
if (!in_array($plugin_file, $valid_plugins, true)) {
return $size_cache[$original_plugin_file] = 0;
}
// Security: Prevent path traversal in the plugin file name
if (strpos($plugin_file, '..') !== false) {
return $size_cache[$original_plugin_file] = 0;
}
// Get the directory name from plugin file
$plugin_dir = dirname($plugin_file);
// Debug: For understanding plugin structure
// Single file plugins: dirname() returns '.'
// Directory plugins: dirname() returns the folder name (e.g., 'akismet' for 'akismet/akismet.php')
// If it's a single file plugin (in root plugins directory)
if ($plugin_dir === '.') {
$file_path = WP_PLUGIN_DIR . '/' . $plugin_file;
if (file_exists($file_path) && is_readable($file_path)) {
return $size_cache[$original_plugin_file] = filesize($file_path);
}
return $size_cache[$original_plugin_file] = 0;
}
// For directory-based plugins
$plugin_path = WP_PLUGIN_DIR . '/' . $plugin_dir;
// Security: Ensure path is within plugin directory
$real_plugin_dir = realpath(WP_PLUGIN_DIR);
$real_plugin_path = realpath($plugin_path);
if (!$real_plugin_path || strpos($real_plugin_path, $real_plugin_dir) !== 0) {
return $size_cache[$original_plugin_file] = 0;
}
// Calculate total size for directory plugins
if (!is_dir($plugin_path) || !is_readable($plugin_path)) {
return $size_cache[$original_plugin_file] = 0;
}
$size = 0;
$file_count = 0;
$max_files = 1000; // Security: Limit number of files to prevent resource exhaustion
try {
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($plugin_path, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::LEAVES_ONLY
);
foreach ($iterator as $file) {
if ($file_count++ > $max_files) {
break; // Security: Prevent resource exhaustion
}
if ($file->isFile() && $file->isReadable()) {
$file_size = $file->getSize();
if ($file_size !== false) {
$size += $file_size;
}
}
}
} catch (Exception $e) {
// Security: Handle exceptions gracefully
return $size_cache[$original_plugin_file] = 0;
}
return $size_cache[$original_plugin_file] = $size;
}
function dad_format_file_size($bytes) {
if ($bytes === 0) {
return '0 B';
}
$units = ['B', 'KB', 'MB', 'GB'];
$i = 0;
while ($bytes >= 1024 && $i < count($units) - 1) {
$bytes /= 1024;
$i++;
}
return round($bytes, 2) . ' ' . $units[$i];
}
function dad_add_plugin_info($plugin_meta, $plugin_file) {
// Security: Validate inputs
if (!is_array($plugin_meta) || empty($plugin_file) || !is_string($plugin_file)) {
return $plugin_meta;
}
// Security: Sanitize plugin file
$plugin_file = sanitize_text_field($plugin_file);
// Get plugin dates
$plugin_dates = get_option('dad_plugin_dates', []);
$dates_info = [];
// First: Installation date
if (isset($plugin_dates[$plugin_file]['installed'])) {
$installed_date = date('j M Y g:i A', strtotime($plugin_dates[$plugin_file]['installed']));
$dates_info[] = '' . esc_html__('Instalado:', 'deactivate-and-delete') . ' ' . esc_html($installed_date);
}
// Second: Last activated date
if (isset($plugin_dates[$plugin_file]['activated'])) {
$activated_date = date('j M Y g:i A', strtotime($plugin_dates[$plugin_file]['activated']));
$dates_info[] = '' . esc_html__('Última activación:', 'deactivate-and-delete') . ' ' . esc_html($activated_date);
}
// Third: Last deactivated date
if (isset($plugin_dates[$plugin_file]['deactivated'])) {
$deactivated_date = date('j M Y g:i A', strtotime($plugin_dates[$plugin_file]['deactivated']));
$dates_info[] = '' . esc_html__('Última desactivación:', 'deactivate-and-delete') . ' ' . esc_html($deactivated_date);
}
// Last: Plugin file size
$plugin_size = dad_get_plugin_size($plugin_file);
$size_info = '' . esc_html__('Tamaño:', 'deactivate-and-delete') . ' ' . esc_html(dad_format_file_size($plugin_size));
// Add the information to plugin meta in the specified order
if (!empty($dates_info)) {
$plugin_meta[] = implode(' | ', $dates_info);
}
$plugin_meta[] = $size_info;
return $plugin_meta;
}
function dad_handle_quick_action() {
// Security: Check if this is the correct action
if (!isset($_GET['action']) || $_GET['action'] !== 'deactivate_and_delete' || !isset($_GET['plugin'])) {
return;
}
// Security: Check user capabilities
if (!current_user_can('delete_plugins') || !current_user_can('deactivate_plugins')) {
wp_die(__('Lo siento, no tienes permisos para eliminar plugins en este sitio.', 'deactivate-and-delete'));
}
// Security: Sanitize and validate plugin parameter
$plugin = sanitize_text_field($_GET['plugin']);
// Security: Verify nonce
check_admin_referer('deactivate_and_delete_plugin_' . $plugin);
// Security: Validate plugin exists
$valid_plugins = array_keys(get_plugins());
if (!in_array($plugin, $valid_plugins, true)) {
wp_die(__('El plugin especificado no es válido.', 'deactivate-and-delete'));
}
// Security: Prevent self-deletion
if (plugin_basename(__FILE__) === $plugin) {
wp_die(__('No puedes eliminar este plugin mientras está activo.', 'deactivate-and-delete'));
}
// Deactivate the plugin
deactivate_plugins($plugin);
// Track deactivation date
dad_track_plugin_deactivation($plugin);
// Delete the plugin
$result = delete_plugins(array($plugin));
// Security: Check if deletion was successful
$redirect_url = admin_url('plugins.php');
if (is_wp_error($result)) {
$redirect_url = add_query_arg('error', 'delete_failed', $redirect_url);
} else {
$redirect_url = add_query_arg('deactivate_and_delete', '1', $redirect_url);
}
wp_safe_redirect($redirect_url);
exit;
}