registered['jquery'] ) ) { $script = $scripts->registered['jquery']; if ( $script->deps ) { $script->deps = array_diff( $script->deps, [ 'jquery-migrate' ] ); } } } ); } if ( admbud_get_option( 'admbud_qs_remove_feed_links', '0' ) === '1' ) { remove_action( 'wp_head', 'feed_links', 2 ); remove_action( 'wp_head', 'feed_links_extra', 3 ); } if ( admbud_get_option( 'admbud_qs_remove_rsd', '0' ) === '1' ) { remove_action( 'wp_head', 'rsd_link' ); } if ( admbud_get_option( 'admbud_qs_remove_wlw', '0' ) === '1' ) { remove_action( 'wp_head', 'wlwmanifest_link' ); } if ( admbud_get_option( 'admbud_qs_remove_shortlink', '0' ) === '1' ) { remove_action( 'wp_head', 'wp_shortlink_wp_head' ); remove_action( 'template_redirect', 'wp_shortlink_header', 11 ); } if ( admbud_get_option( 'admbud_qs_remove_restapi_link', '0' ) === '1' ) { remove_action( 'wp_head', 'rest_output_link_wp_head' ); remove_action( 'template_redirect', 'rest_output_link_header', 11 ); } if ( admbud_get_option( 'admbud_qs_disable_embeds', '0' ) === '1' ) { remove_action( 'wp_head', 'wp_oembed_add_discovery_links' ); remove_action( 'wp_head', 'wp_oembed_add_host_js' ); remove_filter( 'pre_oembed_result', 'wp_filter_pre_oembed_result', 10 ); add_filter( 'embed_oembed_discover', '__return_false' ); add_filter( 'tiny_mce_plugins', static function ( $plugins ) { return array_diff( $plugins, [ 'wpembed' ] ); } ); add_action( 'wp_footer', static function () { wp_deregister_script( 'wp-embed' ); } ); } // -- Security ---------------------------------------------------------- if ( admbud_get_option( 'admbud_qs_disable_xmlrpc', '0' ) === '1' ) { add_filter( 'xmlrpc_enabled', '__return_false' ); add_filter( 'xmlrpc_methods', '__return_empty_array' ); add_filter( 'wp_xmlrpc_server_class','__return_false' ); } if ( admbud_get_option( 'admbud_qs_disable_rest_api', '0' ) === '1' ) { add_filter( 'rest_authentication_errors', static function( $result ) { if ( ! empty( $result ) ) { return $result; } if ( ! is_user_logged_in() ) { return new \WP_Error( 'rest_not_logged_in', __( 'REST API requests require authentication.', 'admin-buddy' ), [ 'status' => 401 ] ); } return $result; } ); } if ( admbud_get_option( 'admbud_qs_remove_version', '0' ) === '1' ) { remove_action( 'wp_head', 'wp_generator' ); add_filter( 'the_generator', '__return_empty_string' ); } // -- Content ----------------------------------------------------------- if ( admbud_get_option( 'admbud_qs_disable_feeds', '0' ) === '1' ) { add_action( 'do_feed', [ $this, 'redirect_feed' ], 1 ); add_action( 'do_feed_rdf', [ $this, 'redirect_feed' ], 1 ); add_action( 'do_feed_rss', [ $this, 'redirect_feed' ], 1 ); add_action( 'do_feed_rss2', [ $this, 'redirect_feed' ], 1 ); add_action( 'do_feed_atom', [ $this, 'redirect_feed' ], 1 ); } if ( admbud_get_option( 'admbud_qs_disable_self_ping', '0' ) === '1' ) { add_action( 'pre_ping', static function( &$links ) { $home = home_url(); foreach ( $links as $l => $link ) { if ( str_starts_with( $link, $home ) ) { unset( $links[ $l ] ); } } } ); } if ( admbud_get_option( 'admbud_qs_disable_comments_default', '0' ) === '1' ) { add_filter( 'wp_insert_post_data', static function( $data ) { if ( isset( $data['comment_status'] ) && $data['comment_status'] === 'open' ) { // Only override for new posts (no ID yet). if ( empty( $data['ID'] ) ) { $data['comment_status'] = 'closed'; } } return $data; } ); } // -- Admin ------------------------------------------------------------- if ( admbud_get_option( 'admbud_qs_duplicate_post', '0' ) === '1' ) { // Hook into row actions for all public post types. add_filter( 'post_row_actions', [ $this, 'add_duplicate_action' ], 10, 2 ); add_filter( 'page_row_actions', [ $this, 'add_duplicate_action' ], 10, 2 ); add_action( 'admin_action_ab_duplicate_post', [ $this, 'handle_duplicate' ] ); } if ( admbud_get_option( 'admbud_qs_user_last_seen', '0' ) === '1' ) { // Record timestamp on every login. add_action( 'wp_login', [ $this, 'record_last_seen' ], 10, 2 ); // Users list table column. add_filter( 'manage_users_columns', [ $this, 'add_last_seen_column' ] ); add_filter( 'manage_users_custom_column', [ $this, 'render_last_seen_column' ], 10, 3 ); add_filter( 'manage_users_sortable_columns', [ $this, 'sortable_last_seen_column' ] ); add_action( 'pre_get_users', [ $this, 'sort_by_last_seen' ] ); } // -- SVG uploads ------------------------------------------------------- if ( admbud_get_option( 'admbud_qs_allow_svg', '0' ) === '1' ) { $allowed_roles = array_filter( explode( ',', admbud_get_option( 'admbud_qs_allow_svg_roles', admbud_get_option( 'admbud_qs_svg_roles', 'administrator' ) ) ) ); // Allow SVG mime type - role-gated via the $user param. add_filter( 'upload_mimes', function ( $mimes, $user ) use ( $allowed_roles ) { $user_obj = $user ? ( is_object( $user ) ? $user : get_user_by( 'id', $user ) ) : wp_get_current_user(); if ( ! $user_obj ) { return $mimes; } foreach ( (array) $user_obj->roles as $role ) { if ( in_array( $role, $allowed_roles, true ) ) { $mimes['svg'] = 'image/svg+xml'; $mimes['svgz'] = 'image/svg+xml'; return $mimes; } } return $mimes; }, 10, 2 ); // Sanitise SVG content on upload - reuses SvgLibrary::sanitise_svg(). add_filter( 'wp_handle_upload_prefilter', [ $this, 'sanitise_svg_on_upload' ] ); } // -- Admin Bar: Frontend ------------------------------------------------ if ( admbud_get_option( 'admbud_qs_hide_adminbar_frontend', '0' ) === '1' ) { $fe_roles = array_filter( explode( ',', get_option( 'admbud_qs_hide_adminbar_frontend_roles', 'administrator' ) ) ); $fe_hide = false; if ( is_user_logged_in() ) { $user = wp_get_current_user(); foreach ( (array) $user->roles as $role ) { if ( in_array( $role, $fe_roles, true ) ) { $fe_hide = true; break; } } } add_filter( 'show_admin_bar', function ( $show ) use ( $fe_hide ) { return $fe_hide ? false : $show; } ); // Show floating "back to admin" icon on frontend so user can return. // Skip inside the Bricks builder - its UI is served from a frontend // URL but we don't want our floating link overlapping Bricks' own controls. if ( $fe_hide && ! is_admin() && ! self::is_bricks_builder_request() ) { add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_floating_admin_link_style' ] ); add_action( 'wp_footer', [ $this, 'render_floating_admin_link' ], 999 ); } } // -- Admin Bar: hide specific Admin Buddy pills ------------------------ // Pills are registered with known IDs by other modules: // - ab-checklist-indicator: Checklist (class-checklist.php, priority 1000) // - ab-noindex-indicator: class-adminbar.php (priority 999) // // Our removal hook runs at 10000 so it's after every known add-hook but // before class-menu-customiser.php's 999999 capture-for-UI pass (so hidden // pills don't land in the Menu Customiser's node list either). // // The AB settings topbar pills (rendered by class-settings.php render()) // are unaffected — those aren't admin bar nodes. $this->maybe_hide_adminbar_pill( 'admbud_qs_hide_adminbar_checklist', 'ab-checklist-indicator', 10000 ); $this->maybe_hide_adminbar_pill( 'admbud_qs_hide_adminbar_noindex', 'ab-noindex-indicator', 10000 ); // -- Admin Bar: Backend ------------------------------------------------- if ( admbud_get_option( 'admbud_qs_hide_adminbar_backend', '0' ) === '1' ) { $be_roles = array_filter( explode( ',', get_option( 'admbud_qs_hide_adminbar_backend_roles', 'administrator' ) ) ); $be_hide = false; if ( is_user_logged_in() ) { $user = wp_get_current_user(); foreach ( (array) $user->roles as $role ) { if ( in_array( $role, $be_roles, true ) ) { $be_hide = true; break; } } } if ( $be_hide ) { add_action( 'admin_enqueue_scripts', function () { // body.admin-bar offset cancellation: WP keeps the // admin-bar body class when the bar is CSS-hidden, so the // slide-panel would otherwise start 32px below a toolbar // that no longer exists. wp_add_inline_style( 'admbud-icon-inject', '#wpadminbar{display:none!important}' . 'html.wp-toolbar{padding-top:0!important;margin-top:0!important}' . '#wpbody{padding-top:0!important}' . '#adminmenuwrap{margin-top:0!important}' . '#adminmenuback,#adminmenuwrap{top:0!important}' . '.admin-bar .ab-topbar{top:0!important}' . '.ab-frame{min-height:calc(100vh - var(--ab-topbar-height))!important}' . 'body.admin-bar .ab-slide-panel,body.admin-bar .ab-backdrop{top:0;height:100%}' ); } ); } } // -- Collapse Sidebar by Default ---------------------------------------- if ( admbud_get_option( 'admbud_qs_collapse_menu', '0' ) === '1' ) { $cm_roles = array_filter( explode( ',', get_option( 'admbud_qs_collapse_menu_roles', 'administrator' ) ) ); add_filter( 'admin_body_class', function ( $classes ) use ( $cm_roles ) { $user = wp_get_current_user(); if ( ! $user->exists() ) { return $classes; } foreach ( (array) $user->roles as $role ) { if ( in_array( $role, $cm_roles, true ) ) { // Only add folded if user hasn't manually expanded (check user setting). // WP stores mfold=o (open) or mfold=f (folded) in user settings. // We force folded as default; user can still toggle. if ( strpos( $classes, 'folded' ) === false ) { $classes .= ' folded'; } break; } } return $classes; } ); } // -- Sidebar User Menu -------------------------------------------------- if ( admbud_get_option( 'admbud_qs_sidebar_user_menu', '0' ) === '1' ) { $um_roles = array_filter( explode( ',', get_option( 'admbud_qs_sidebar_user_menu_roles', 'administrator' ) ) ); $um_show = false; if ( is_user_logged_in() ) { $user = wp_get_current_user(); foreach ( (array) $user->roles as $role ) { if ( in_array( $role, $um_roles, true ) ) { $um_show = true; break; } } } if ( $um_show ) { add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_sidebar_user_menu_assets' ] ); // Render via the `adminmenu` action - fires inside