remove_wlwmanifest_link();
$this->remove_rsd_link();
$this->remove_shortlink();
$this->disable_self_pingbacks();
}
public function disable_embeds() {
add_action('init', [$this, 'disable_embed'], 9999);
}
public function disable_embed() {
global $wp;
if (isset($wp->public_query_vars) && is_array($wp->public_query_vars)) {
$wp->public_query_vars = array_diff($wp->public_query_vars, ['embed']);
}
add_filter('embed_oembed_discover', '__return_false');
remove_action('wp_head', 'wp_oembed_add_discovery_links');
remove_action('wp_head', 'wp_oembed_add_host_js');
remove_filter('oembed_dataparse', 'wp_filter_oembed_result', 10);
remove_filter('pre_oembed_result', 'wp_filter_pre_oembed_result', 10);
add_filter('tiny_mce_plugins', [$this, 'disableEmbedsTinyMCE']);
add_filter('rewrite_rules_array', [$this, 'disableEmbedsRewrites']);
}
public function disableEmbedsTinyMCE($plugins) {
return is_array($plugins) ? array_diff($plugins, ['wpembed']) : $plugins;
}
public function disableEmbedsRewrites($rules) {
if (is_array($rules)) {
foreach ($rules as $rule => $rewrite) {
if (false !== strpos($rewrite, 'embed=true')) {
unset($rules[$rule]);
}
}
}
return $rules;
}
public function disable_xmlrpc() {
add_filter('xmlrpc_enabled', '__return_false');
add_filter('pings_open', '__return_false', 9999);
add_filter('pre_update_option_enable_xmlrpc', '__return_false');
add_filter('pre_option_enable_xmlrpc', '__return_zero');
add_filter('wp_headers', [$this, 'remove_xpingback']);
add_action('init', [$this, 'intercept_xmlrpc_header']);
}
public function remove_xpingback($headers) {
unset($headers['X-Pingback'], $headers['x-pingback']);
return $headers;
}
public function intercept_xmlrpc_header() {
if (!isset($_SERVER['SCRIPT_FILENAME'])) {
return;
}
if ('xmlrpc.php' !== basename($_SERVER['SCRIPT_FILENAME'])) {
return;
}
$header = 'HTTP/1.1 403 Forbidden';
header($header);
echo esc_html($header);
exit;
}
public function remove_jquery_migrate() {
add_filter('wp_default_scripts', [$this, 'jquery_migrate']);
}
public function jquery_migrate(&$scripts) {
if (!is_admin()) {
$scripts->remove('jquery');
$scripts->add('jquery', false, ['jquery-core']);
}
}
public function remove_wp_version() {
remove_action('wp_head', 'wp_generator');
add_filter('the_generator', '__return_empty_string');
}
public function remove_wlwmanifest_link() {
remove_action('wp_head', 'wlwmanifest_link');
}
public function remove_rsd_link() {
remove_action('wp_head', 'rsd_link');
}
public function remove_shortlink() {
remove_action('wp_head', 'wp_shortlink_wp_head');
remove_action('template_redirect', 'wp_shortlink_header', 11, 0);
}
public function disable_rss_feeds() {
add_action('template_redirect', [$this, 'rss_feed'], 1);
remove_action('wp_head', 'feed_links', 2);
remove_action('wp_head', 'feed_links_extra', 3);
}
public function rss_feed() {
if (!is_feed() || is_404()) {
return;
}
if (isset($_GET['feed'])) {
wp_safe_redirect(esc_url_raw(remove_query_arg('feed')), 301);
exit;
}
if (get_query_var('feed') !== 'old') {
set_query_var('feed', '');
}
redirect_canonical();
wp_die(sprintf(esc_html__("No feed available, please visit the homepage!", 'wp-extra'), esc_url(home_url('/'))));
}
public function disable_self_pingbacks() {
add_action('pre_ping', [$this, 'self_pingbacks']);
}
public function self_pingbacks(&$links) {
$home = get_option('home');
foreach ($links as $l => $link) {
if (strpos($link, $home) === 0) {
unset($links[$l]);
}
}
}
public function block_user_enumeration() {
if (!is_admin()) {
// Block query string ?author=N for non-logged-in visitors
if (isset($_REQUEST['author']) && (is_numeric($_REQUEST['author']) || '' !== $_REQUEST['author'])) {
wp_safe_redirect(home_url(), 301);
exit;
}
// Hide REST API user list from unauthorized visitors
add_filter('rest_endpoints', [$this, 'filter_rest_user_endpoints']);
}
}
public function filter_rest_user_endpoints($endpoints) {
if (!is_user_logged_in()) {
if (isset($endpoints['/wp/v2/users'])) {
unset($endpoints['/wp/v2/users']);
}
if (isset($endpoints['/wp/v2/users/(?P[\d]+)'])) {
unset($endpoints['/wp/v2/users/(?P[\d]+)']);
}
}
return $endpoints;
}
public function security_headers() {
add_filter('wp_headers', [$this, 'send_security_headers']);
}
public function send_security_headers($headers) {
if (!is_admin()) {
$headers['X-Frame-Options'] = 'SAMEORIGIN';
$headers['X-Content-Type-Options'] = 'nosniff';
$headers['Referrer-Policy'] = 'strict-origin-when-cross-origin';
$headers['Permissions-Policy'] = 'camera=(), microphone=(), geolocation=()';
}
return $headers;
}
public function themeplugin_edits() {
add_filter('map_meta_cap', [$this, 'disable_file_editor_caps'], 10, 2);
if (!defined('DISALLOW_FILE_EDIT')) {
define('DISALLOW_FILE_EDIT', true);
}
}
public function disable_file_editor_caps($caps, $cap) {
if (in_array($cap, ['edit_themes', 'edit_plugins', 'edit_files'], true)) {
$caps[] = 'do_not_allow';
}
return $caps;
}
public function core_updates() {
add_filter('auto_update_core', '__return_false');
add_filter('automatic_updater_disabled', '__return_true');
}
public function http_request() {
add_filter('pre_http_request', [$this, 'pass_reject_request'], 10, 3);
}
public function pass_reject_request($preempt, $parsed_args, $url) {
$value = Helper::get_option('http_request', '');
$blocked_domains = array_filter(array_map('trim', explode("\n", $value)));
foreach ($blocked_domains as $domain) {
if (strpos($url, $domain) !== false) {
return new \WP_Error('http_request_block', esc_html__('Blocked by WP EXtra', 'wp-extra'));
}
}
return $preempt;
}
public function disable_rest_api() {
add_filter('rest_authentication_errors', [$this, 'restAuthenticationErrors'], 20);
}
public function restAuthenticationErrors($result) {
if (!empty($result)) {
return $result;
}
$rest_route = isset($GLOBALS['wp']->query_vars['rest_route']) ? $GLOBALS['wp']->query_vars['rest_route'] : '';
$exceptions = apply_filters('wpex_rest_api_exceptions', [
'contact-form-7',
'wordfence',
'elementor',
'woocommerce',
'fluentform',
'wpforms'
]);
foreach ($exceptions as $exception) {
if (!empty($rest_route) && strpos($rest_route, $exception) !== false) {
return $result;
}
}
$disabled = false;
$disableOption = Helper::get_option('disable_rest_api', '');
$disableOptions = is_array($disableOption) ? $disableOption : [$disableOption];
if (in_array('non_admins', $disableOptions, true) && !current_user_can('manage_options')) {
$disabled = true;
} elseif (in_array('logged_out', $disableOptions, true) && !is_user_logged_in()) {
$disabled = true;
}
if ($disabled) {
return new \WP_Error('rest_authentication_error', __('Sorry, you do not have permission to make REST API requests.', 'wp-extra'), ['status' => 401]);
}
return $result;
}
public function remove_rest_api_links() {
remove_action('xmlrpc_rsd_apis', 'rest_output_rsd');
remove_action('wp_head', 'rest_output_link_wp_head');
remove_action('template_redirect', 'rest_output_link_header', 11, 0);
}
public function disable_heartbeat() {
add_action('init', [$this, 'disableHeartbeat'], 1);
}
public function disableHeartbeat() {
if (is_admin()) {
global $pagenow;
if (!empty($pagenow)) {
if ($pagenow === 'admin.php' && !empty($_GET['page'])) {
$exceptions = [
'gf_edit_forms',
'gf_entries',
'gf_settings'
];
if (in_array($_GET['page'], $exceptions, true)) {
return;
}
}
if ($pagenow === 'site-health.php') {
return;
}
}
}
$setting = Helper::get_option('disable_heartbeat');
if ($setting) {
if ($setting === 'everywhere') {
$this->replaceHearbeat();
} elseif ($setting === 'allow_posts') {
global $pagenow;
if ($pagenow !== 'post.php' && $pagenow !== 'post-new.php') {
$this->replaceHearbeat();
}
}
}
}
private function replaceHearbeat() {
wp_deregister_script('heartbeat');
if (is_admin() && Helper::get_option('disable_heartbeat')) {
wp_register_script('heartbeat', plugins_url('/assets/js/heartbeat.min.js', WPEX_FILE));
wp_enqueue_script('heartbeat', plugins_url('/assets/js/heartbeat.min.js', WPEX_FILE));
}
}
public function heartbeat_frequency() {
add_filter('heartbeat_settings', [$this, 'heartbeatFrequency']);
}
public function heartbeatFrequency($settings) {
$freq = Helper::get_option('heartbeat_frequency');
if ($freq) {
$settings['interval'] = intval($freq);
}
return $settings;
}
public function remove_blocks() {
add_filter('allowed_block_types_all', [$this, 'remove_default_blocks']);
add_filter('allowed_block_types', [$this, 'remove_default_blocks']);
}
public function remove_default_blocks($allowed_blocks) {
if (!class_exists('\WP_Block_Type_Registry')) {
return $allowed_blocks;
}
$registered_blocks = \WP_Block_Type_Registry::get_instance()->get_all_registered();
$filtered_blocks = [];
foreach ($registered_blocks as $block) {
if (strpos($block->name, 'core/') === false) {
if (!class_exists('WooCommerce') || strpos($block->name, 'woocommerce/') === false) {
$filtered_blocks[] = $block->name;
}
}
}
return $filtered_blocks;
}
}