connect = $connect; $this->settings = new AdvisorPPC_Settings(); } /** * Register hooks. * * @param AdvisorPPC_Loader $loader Hook loader. * @return void */ public function register( $loader ) { $this->settings->register( $loader ); $loader->add_action( 'admin_menu', $this, 'add_menu' ); $loader->add_action( 'admin_enqueue_scripts', $this, 'enqueue_assets' ); $loader->add_action( 'admin_notices', $this, 'render_notices' ); $loader->add_action( 'admin_post_advisorppc_clear_log', $this, 'handle_clear_log' ); $loader->add_action( 'admin_post_advisorppc_tracktor_enable', $this, 'handle_tracktor_enable' ); $loader->add_action( 'admin_post_advisorppc_detect_scan', $this, 'handle_detect_scan' ); $loader->add_action( 'admin_post_advisorppc_detect_apply', $this, 'handle_detect_apply' ); $loader->add_action( 'admin_post_advisorppc_detect_dismiss', $this, 'handle_detect_dismiss' ); $loader->add_action( 'admin_post_advisorppc_detect_undo', $this, 'handle_detect_undo' ); $loader->add_filter( 'plugin_action_links_' . plugin_basename( ADVISORPPC_PLUGIN_FILE ), $this, 'action_links' ); } /** * Add the top-level menu. * * @return void */ public function add_menu() { $this->hook_suffix = add_menu_page( __( 'AdvisorPPC', 'advisorppc' ), __( 'AdvisorPPC', 'advisorppc' ), 'manage_options', self::SLUG, array( $this, 'render_page' ), self::menu_icon(), 58 ); } /** * Read one of the shipped brand SVGs for inline output. * * Inline rather than an `` because the marks use `currentColor`: an * image-loaded SVG has no access to the host document's colour, so it would * render black on the dark admin scheme. Inlining is also one fewer request * on a screen that already loads a stylesheet. * * Returns '' rather than a placeholder when the file is missing, so a * broken asset degrades to a text-only heading instead of a broken image. * * @param string $name File stem inside assets/brand, no extension. * @param string $class Optional class attribute for the root element. * @return string Raw SVG markup, or ''. */ public static function brand_svg( $name, $class = 'advisorppc-brand-svg' ) { $name = preg_replace( '/[^a-z0-9\-]/', '', strtolower( (string) $name ) ); if ( '' === $name ) { return ''; } $path = ADVISORPPC_PLUGIN_DIR . 'assets/brand/' . $name . '.svg'; if ( ! is_readable( $path ) ) { return ''; } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- local plugin asset, not a remote fetch. $svg = file_get_contents( $path ); if ( ! is_string( $svg ) ) { return ''; } // Drop the XML prolog and any comment block; neither belongs inline. $svg = preg_replace( '/<\?xml.*?\?>/s', '', $svg ); $svg = preg_replace( '//s', '', $svg ); $svg = trim( (string) $svg ); if ( '' === $class ) { return $svg; } return preg_replace( '/