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' ] ); add_action( 'admin_footer', [ $this, 'render_sidebar_user_menu' ] ); } } } /** * Inline CSS + JS for the sidebar user-menu widget. Registered on * admin_enqueue_scripts so the inline rules attach to the global * admbud-icon-inject handle before head/footer print. The HTML * itself is rendered later via render_sidebar_user_menu() on admin_footer. */ public function enqueue_sidebar_user_menu_assets(): void { $css = 'li#ab-sidebar-account{display:block!important;list-style:none!important;margin:0!important;padding:0!important;background:transparent!important;line-height:1.3!important;}' . 'li#ab-sidebar-account::before,li#ab-sidebar-account::after{content:none!important;}' . 'li#ab-sidebar-account,li#ab-sidebar-account:hover,li#ab-sidebar-account:focus,li#ab-sidebar-account a,li#ab-sidebar-account a:hover,li#ab-sidebar-account a:focus,li#ab-sidebar-account a:active{background:transparent!important;background-color:transparent!important;box-shadow:none!important;}' . '#ab-sidebar-user-menu{display:flex!important;align-items:center!important;flex-direction:row!important;flex-wrap:nowrap!important;gap:6px;padding:8px 10px!important;border-bottom:1px solid rgba(255,255,255,0.08);min-height:44px;}' . '.ab-sidebar-user__profile{display:flex!important;flex-direction:row!important;align-items:center!important;flex-wrap:nowrap!important;gap:8px;flex:1 1 auto;min-width:0;padding:2px 0!important;}' . '#ab-sidebar-user-menu .ab-sidebar-user__avatar,.ab-sidebar-user__avatar{width:28px!important;height:28px!important;border-radius:50%!important;flex-shrink:0!important;margin:0!important;padding:0!important;max-width:none!important;display:inline-block!important;}' . '.ab-sidebar-user__info{display:flex!important;flex-direction:column!important;min-width:0;line-height:1.3;}' . '.ab-sidebar-user__name{font-size:12px!important;font-weight:600!important;line-height:1.3!important;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}' . '.ab-sidebar-user__role{font-size:10px!important;font-weight:400!important;line-height:1.3!important;opacity:0.6;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}' . '#ab-sidebar-user-menu .ab-sidebar-user__logout{display:flex!important;align-items:center!important;justify-content:center!important;width:28px!important;height:28px!important;flex-shrink:0!important;padding:0!important;margin:0!important;}' . '#ab-sidebar-site-link{position:relative;border-bottom:1px solid rgba(255,255,255,0.08);padding:4px 10px!important;background:transparent!important;}' . '.ab-sidebar-site__home{display:flex!important;flex-direction:row!important;align-items:center!important;flex-wrap:nowrap!important;gap:8px;padding:6px 0!important;text-decoration:none!important;background:transparent!important;box-shadow:none!important;min-width:0;}' . '.ab-sidebar-site__title{flex:1 1 auto;min-width:0;font-size:13px;font-weight:600;line-height:1.3;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}' . '.ab-sidebar-site__caret{flex-shrink:0;margin-left:auto;opacity:0.5;}' . '.ab-sidebar-site__home:hover .ab-sidebar-site__caret{opacity:1;}' . '.ab-sidebar-site__favicon{display:none;width:22px;height:22px;border-radius:3px;flex-shrink:0;}' . '.ab-sidebar-site__submenu{list-style:none;margin:0;padding:5px 0;position:absolute;left:100%;top:0;min-width:200px;background:#1d2327;box-shadow:0 2px 8px rgba(0,0,0,0.35);z-index:9999;display:none;}' . '#ab-sidebar-site-link:hover .ab-sidebar-site__submenu,#ab-sidebar-site-link:focus-within .ab-sidebar-site__submenu{display:block;}' . '.ab-sidebar-site__submenu li{margin:0;}' . '.ab-sidebar-site__submenu a{display:block;padding:6px 14px;font-size:13px;line-height:1.4;color:#c3c4c7!important;text-decoration:none;white-space:nowrap;}' . '.ab-sidebar-site__submenu a:hover,.ab-sidebar-site__submenu a:focus{background:#2271b1;color:#fff!important;}' . '.folded #ab-sidebar-user-menu{flex-direction:column!important;padding:6px 0!important;gap:4px!important;min-height:0!important;}' . '.folded .ab-sidebar-user__profile{flex-direction:column!important;justify-content:center!important;padding:0!important;}' . '.folded .ab-sidebar-user__info{display:none!important;}' . '.folded #ab-sidebar-user-menu .ab-sidebar-user__avatar,.folded .ab-sidebar-user__avatar{width:24px!important;height:24px!important;}' . '.folded #ab-sidebar-user-menu .ab-sidebar-user__logout{width:100%!important;justify-content:center!important;}' . '.folded #ab-sidebar-site-link.no-favicon{display:none!important;}' . '.folded #ab-sidebar-site-link{padding:6px 0!important;}' . '.folded .ab-sidebar-site__home{justify-content:center!important;padding:2px 0!important;}' . '.folded .ab-sidebar-site__title,.folded .ab-sidebar-site__caret{display:none!important;}' . '.folded .ab-sidebar-site__favicon{display:inline-block!important;}'; wp_add_inline_style( 'admbud-icon-inject', $css ); // Move the rendered