' . \esc_html__( 'Mails', '0-day-analytics' ) . ''; array_unshift( $links, $settings_link ); } if ( ( Settings::get_option( 'snippets_module_enabled' ) ) ) { $settings_link = '' . \esc_html__( 'Snippets', '0-day-analytics' ) . ''; array_unshift( $links, $settings_link ); } if ( ( Settings::get_option( 'requests_module_enabled' ) ) ) { $settings_link = '' . \esc_html__( 'Requests', '0-day-analytics' ) . ''; array_unshift( $links, $settings_link ); } if ( ( Settings::get_option( 'tables_module_enabled' ) ) ) { $settings_link = '' . \esc_html__( 'Tables', '0-day-analytics' ) . ''; array_unshift( $links, $settings_link ); } if ( ( Settings::get_option( 'transients_module_enabled' ) ) ) { $settings_link = '' . \esc_html__( 'Transients', '0-day-analytics' ) . ''; array_unshift( $links, $settings_link ); } if ( ( Settings::get_option( 'cron_module_enabled' ) ) ) { $settings_link = '' . \esc_html__( 'Cron Jobs', '0-day-analytics' ) . ''; array_unshift( $links, $settings_link ); } if ( ( Settings::get_option( 'rest_api_module_enabled' ) ) ) { $settings_link = '' . \esc_html__( 'REST API', '0-day-analytics' ) . ''; array_unshift( $links, $settings_link ); } if ( ( Settings::get_option( 'file_editor_module_enabled' ) ) ) { $settings_link = '' . \esc_html__( 'File Editor', '0-day-analytics' ) . ''; array_unshift( $links, $settings_link ); } if ( ( Settings::get_option( 'fatals_module_enabled' ) ) ) { $settings_link = '' . \esc_html__( 'PHP Errors View', '0-day-analytics' ) . ''; array_unshift( $links, $settings_link ); } $settings_link = '' . \esc_html__( 'Error Logs', '0-day-analytics' ) . ''; array_unshift( $links, $settings_link ); } return $links; } /** * Add meta to plugin details * * Add options to plugin meta line * * @param string $links - Current links. * @param string $file - File in use. * * @return array Links, now with settings added. * * @since 1.8.4 */ public static function plugin_meta( $links, $file ) { if ( false !== strpos( $file, 'advanced-analytics.php' ) ) { $links = array_merge( $links, array( '' . \esc_html__( 'Support', '0-day-analytics' ) . '', ) ); } return $links; } /** * Remove all non plugin notices from our plugin pages. * * @since 1.8.4 */ public static function hide_unrelated_notices(): void { // Bail if we're not on our screen or page. if ( ! WP_Helper::is_admin_page() ) { return; } self::remove_unrelated_actions( 'user_admin_notices' ); self::remove_unrelated_actions( 'admin_notices' ); self::remove_unrelated_actions( 'all_admin_notices' ); self::remove_unrelated_actions( 'network_admin_notices' ); } /** * Remove all notices from our plugin pages based on the provided action hook. * * @param string $action The name of the action hook. Expected values: 'user_admin_notices', 'admin_notices', 'all_admin_notices', 'network_admin_notices'. * * @since 1.8.4 */ public static function remove_unrelated_actions( $action ) { global $wp_filter; if ( ! isset( $wp_filter[ $action ] ) || empty( $wp_filter[ $action ]->callbacks ) || ! is_array( $wp_filter[ $action ]->callbacks ) ) { return; } foreach ( $wp_filter[ $action ]->callbacks as $priority => $hooks ) { foreach ( $hooks as $name => $arr ) { if ( ( // Cover object method callback case. is_array( $arr['function'] ) && isset( $arr['function'][0] ) && is_object( $arr['function'][0] ) && false !== strpos( ( get_class( $arr['function'][0] ) ), 'ADVAN' ) ) || ( // Cover class static method callback case. ! empty( $name ) && /* * Cast to string before comparing. * * $name is the key _wp_filter_build_unique_id() produced. Since WP 7.1 * that is (string) spl_object_id() for a closure - "2652" - and PHP * stores a decimal-integer string as an integer array key, so $name * arrives here as an int. This file declares strict_types, so strpos() * raises a TypeError instead of coercing it, and the notice hook fatals. * * The comparison itself is unaffected: an object id has never contained * the prefix, exactly as the spl_object_hash() it replaced never did, so * closures keep being treated as unrelated and removed. */ false !== strpos( (string) $name, 'ADVAN' ) ) ) { continue; } unset( $wp_filter[ $action ]->callbacks[ $priority ][ $name ] ); } } } /** * Adds a powered-by message in the footer of the page. * * Only outputs on the frontend. * * @return void * * @since 2.0.0 */ public static function powered_by() { if ( Context_Helper::is_front() ) { printf( /* Translators: Plugin link. */ \esc_html__( 'Proudly powered by %s', '0-day-analytics' ), '' . \esc_attr( ADVAN_NAME ) . '' ); } } /** * Registers a plugin redirection on activate setting. * * @return void * * @since 1.0.0 */ public static function plugin_activate() { \add_option( self::REDIRECT_OPTION_NAME, true ); } /** * Redirects the plugin to its settings page if it was just activated. * * @return void * * @since 1.0.0 */ public static function plugin_redirect() { if ( \get_option( self::REDIRECT_OPTION_NAME, false ) ) { \delete_option( self::REDIRECT_OPTION_NAME ); if ( ! isset( $_GET['activate-multi'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Redirect only, no action taken. \wp_safe_redirect( \add_query_arg( 'page', Logs_List::MENU_SLUG, \network_admin_url( 'admin.php' ) ) ); exit; } } } /** * Action for _doing_it_wrong() calls. * * @param string $function_name The function that was called. * @param string $message A message explaining what has been done incorrectly. * @param string $version The version of WordPress where the message was added. * * @return void * * @since 1.9.2.2 */ public static function action_doing_it_wrong_run( $function_name, $message, $version ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed global $wp_filter; $function_name = (string) $function_name; $message = (string) $message; if ( ! class_exists( '\QM_Collectors', false ) || ! self::is_just_in_time_for_0_day_domain( $function_name, $message ) ) { return; } $qm_collector_doing_it_wrong = \QM_Collectors::get( 'doing_it_wrong' ); $current_priority = $wp_filter['doing_it_wrong_run']->current_priority(); if ( null === $qm_collector_doing_it_wrong || false === $current_priority ) { return; } switch ( $current_priority ) { case 0: \remove_action( 'doing_it_wrong_run', array( $qm_collector_doing_it_wrong, 'action_doing_it_wrong_run' ) ); break; case 20: \add_action( 'doing_it_wrong_run', array( $qm_collector_doing_it_wrong, 'action_doing_it_wrong_run' ), 10, 3 ); break; default: break; } } /** * Filter for _doing_it_wrong() calls. * * @param bool|mixed $trigger Whether to trigger the error for _doing_it_wrong() calls. Default true. * @param string $function_name The function that was called. * @param string $message A message explaining what has been done incorrectly. * @param string $version The version of WordPress where the message was added. * * @return bool * * @since 1.9.2.2 */ public static function filter_doing_it_wrong_trigger_error( $trigger, $function_name, $message, $version ): bool { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed $trigger = (bool) $trigger; $function_name = (string) $function_name; $message = (string) $message; return self::is_just_in_time_for_0_day_domain( $function_name, $message ) ? false : $trigger; } /** * Whether it is the just_in_time_error for 0-Day-related domains. * * @param string $function_name Function name. * @param string $message Message. * * @return bool * * @since 1.9.2.2 */ public static function is_just_in_time_for_0_day_domain( string $function_name, string $message ): bool { return '_load_textdomain_just_in_time' === $function_name && strpos( $message, '' . ADVAN_TEXTDOMAIN ) !== false; } } }