<?php
|
if (!defined('ABSPATH')) {
|
exit; // Exit if accessed directly
|
}
|
|
/**
|
* WordPress Cleanup and Optimization Functions
|
*
|
* Removes unnecessary WordPress features, optimizes performance,
|
* and improves security by removing potential attack vectors.
|
*/
|
|
/*******************************************************************************
|
BLOCK EDITOR & STYLES CLEANUP
|
*******************************************************************************/
|
|
/**
|
* Remove WordPress block editor styles and scripts
|
* Cleans up unnecessary block-related assets for custom themes
|
*/
|
function jvbRemoveBlockAssets(): void
|
{
|
if (is_admin()) {
|
return;
|
}
|
|
// Remove global WordPress styles
|
$global_styles = [
|
'global-styles',
|
'dashicons',
|
'core-block-supports'
|
];
|
|
foreach ($global_styles as $style) {
|
wp_dequeue_style($style);
|
}
|
|
// Remove all block-specific styles
|
global $wp_styles;
|
foreach ($wp_styles->queue as $handle) {
|
if (str_starts_with($handle, 'wp-block-')) {
|
wp_dequeue_style($handle);
|
}
|
}
|
|
// Remove block-specific scripts and modules
|
if (!is_admin()) {
|
wp_deregister_script('heartbeat');
|
}
|
wp_dequeue_script('wp-block-template-skip-link');
|
|
// Remove WordPress 6.5+ script modules
|
wp_dequeue_script_module('@wordpress/interactivity');
|
wp_deregister_script_module('@wordpress/interactivity');
|
wp_dequeue_script_module('@wordpress/block-library/navigation/view');
|
wp_deregister_script_module('@wordpress/block-library/navigation/view');
|
|
// Remove block template skip link
|
remove_action('wp_footer', 'the_block_template_skip_link');
|
|
// Remove third-party styles
|
wp_deregister_style('akismet-widget-style-inline-css');
|
}
|
add_action('wp_enqueue_scripts', 'jvbRemoveBlockAssets', 999);
|
|
/*******************************************************************************
|
WORDPRESS HEAD CLEANUP
|
*******************************************************************************/
|
|
/**
|
* Remove unnecessary WordPress head elements
|
* Cleans up HTML head for better performance and security
|
*/
|
function jvbCleanWordPressHead(): void
|
{
|
// Remove version info and meta tags
|
remove_action('wp_head', 'wp_generator');
|
remove_action('wp_head', 'rsd_link');
|
remove_action('wp_head', 'wlwmanifest_link');
|
remove_action('wp_head', 'wp_shortlink_wp_head');
|
|
// Remove emoji support
|
remove_action('wp_head', 'print_emoji_detection_script', 7);
|
remove_action('wp_print_styles', 'print_emoji_styles');
|
|
// Remove REST API and oEmbed discovery links
|
remove_action('wp_head', 'rest_output_link_wp_head');
|
remove_action('template_redirect', 'rest_output_link_header', 11);
|
remove_action('wp_head', 'wp_oembed_add_discovery_links');
|
remove_action('wp_head', 'wp_oembed_add_host_js');
|
}
|
add_action('init', 'jvbCleanWordPressHead');
|
|
/*******************************************************************************
|
SECURITY OPTIMIZATIONS
|
*******************************************************************************/
|
|
/**
|
* Apply security hardening measures
|
* Removes version info, disables XML-RPC, and hardens WordPress
|
*/
|
function jvbSecurityOptimizations(): void
|
{
|
// Hide WordPress version from scripts and styles
|
add_filter('style_loader_src', 'jvbRemoveVersionFromUrl', 9999);
|
add_filter('script_loader_src', 'jvbRemoveVersionFromUrl', 9999);
|
|
// Disable XML-RPC (often targeted by attackers)
|
add_filter('xmlrpc_enabled', '__return_false');
|
|
// Remove security headers that reveal info
|
add_filter('wp_headers', 'jvbRemovePingbackHeader');
|
|
// Remove WordPress version from admin footer
|
add_filter('update_footer', '__return_empty_string', 11);
|
|
// Block user enumeration
|
add_action('init', 'jvbBlockUserEnumeration');
|
add_filter('rest_endpoints', 'jvbDisableUserEndpoints');
|
add_filter('author_rewrite_rules', '__return_empty_array');
|
|
// Disable file editing in admin (if not already set)
|
if (!defined('DISALLOW_FILE_EDIT')) {
|
define('DISALLOW_FILE_EDIT', true);
|
}
|
|
// Shorten password reset expiration (15 minutes)
|
add_filter('password_reset_expiration', function() {
|
return 900;
|
});
|
}
|
add_action('init', 'jvbSecurityOptimizations');
|
|
/**
|
* Remove version query strings from static assets
|
*/
|
function jvbRemoveVersionFromUrl(string $src): string
|
{
|
return strpos($src, 'ver=') ? remove_query_arg('ver', $src) : $src;
|
}
|
|
/**
|
* Remove X-Pingback header
|
*/
|
function jvbRemovePingbackHeader(array $headers): array
|
{
|
unset($headers['X-Pingback']);
|
return $headers;
|
}
|
|
/**
|
* Block user enumeration attempts
|
* Prevents discovery of usernames via URL manipulation
|
*/
|
function jvbBlockUserEnumeration(): void
|
{
|
// Block ?author queries and author archives
|
if (!is_admin() && (isset($_GET['author']) || is_author())) {
|
wp_redirect(home_url(), 301);
|
exit;
|
}
|
}
|
|
/**
|
* Remove user endpoints from REST API
|
* Prevents user enumeration via REST API
|
*/
|
function jvbDisableUserEndpoints(array $endpoints): array
|
{
|
$user_endpoints = [
|
'/wp/v2/users',
|
'/wp/v2/users/(?P<id>[\d]+)'
|
];
|
|
foreach ($user_endpoints as $endpoint) {
|
if (isset($endpoints[$endpoint])) {
|
unset($endpoints[$endpoint]);
|
}
|
}
|
|
return $endpoints;
|
}
|
|
/*******************************************************************************
|
CONTENT MANAGEMENT
|
*******************************************************************************/
|
|
/**
|
* Clean up attachments when posts are deleted
|
* Automatically removes associated media to prevent orphaned files
|
*/
|
function jvbCleanupPostDeletion(int $post_id): void
|
{
|
// Delete attached media
|
$attachments = get_attached_media('', $post_id);
|
foreach ($attachments as $attachment) {
|
wp_delete_attachment($attachment->ID, true);
|
}
|
|
// Delete custom meta attachments
|
$meta_fields = [
|
BASE . 'image',
|
BASE . 'gallery'
|
];
|
|
//TODO: Dynamically use MetaManager to get any image or gallery fields
|
foreach ($meta_fields as $meta_key) {
|
$meta_value = get_post_meta($post_id, $meta_key, true);
|
|
if (empty($meta_value)) {
|
continue;
|
}
|
|
// Handle comma-separated IDs
|
$attachment_ids = str_contains($meta_value, ',')
|
? explode(',', $meta_value)
|
: [$meta_value];
|
|
foreach ($attachment_ids as $attachment_id) {
|
if (is_numeric($attachment_id)) {
|
wp_delete_attachment((int)$attachment_id, true);
|
}
|
}
|
}
|
}
|
add_action('before_delete_post', 'jvbCleanupPostDeletion');
|
|
/*******************************************************************************
|
THEME CUSTOMIZATION
|
*******************************************************************************/
|
|
/**
|
* Clean up body classes for simpler CSS targeting
|
* Removes WordPress defaults and adds only relevant classes
|
*/
|
function jvbBodyClasses(array $classes): array
|
{
|
// Start with empty array - only add what we need
|
$clean_classes = [];
|
|
// Add contextual classes
|
if (is_front_page()) {
|
$clean_classes[] = 'home';
|
}
|
|
if (function_exists('jvbIsDirectory') && jvbIsDirectory()) {
|
$clean_classes[] = 'is-directory';
|
} elseif (is_tax()) {
|
$clean_classes[] = str_replace(BASE, '', get_queried_object()->taxonomy);
|
} elseif (is_singular() && !is_singular('page')) {
|
$clean_classes[] = str_replace(BASE, '', get_queried_object()->post_type);
|
} elseif (is_post_type_archive()) {
|
$clean_classes[] = str_replace(BASE, '', get_queried_object()->name);
|
}
|
|
return $clean_classes;
|
}
|
add_filter('body_class', 'jvbBodyClasses');
|