plugin_name = $plugin_name; $this->version = $version; $this->options = $options; add_action('wp_ajax_adasprso_search_categories', array($this, 'ajax_search_categories')); add_action('admin_head', array($this, 'suppress_foreign_notices')); } /** * Remove other plugins' and themes' admin notices on our settings page * so they don't clutter the interface. Our own settings errors are output * via settings_errors() inside the page template, so they are unaffected. */ public function suppress_foreign_notices() { $screen = get_current_screen(); if ( ! $screen || 'settings_page_add-as-preferred-source' !== $screen->id ) { return; } remove_all_actions( 'admin_notices' ); remove_all_actions( 'all_admin_notices' ); } /** * Register the stylesheets for the admin area. * * @since 1.0.0 */ public function enqueue_styles($hook) { // Only load on plugin settings page if ('settings_page_add-as-preferred-source' !== $hook) { return; } wp_enqueue_style('wp-color-picker'); wp_enqueue_style($this->plugin_name . '-admin', ADASPRSO_PLUGIN_URL . 'admin/css/add-as-preferred-source-admin.css', array(), $this->version, 'all'); } /** * Register the JavaScript for the admin area. * * @since 1.0.0 */ public function enqueue_scripts($hook) { // Only load on plugin settings page if ('settings_page_add-as-preferred-source' !== $hook) { return; } wp_enqueue_script('wp-color-picker'); wp_enqueue_script($this->plugin_name . '-admin', ADASPRSO_PLUGIN_URL . 'admin/js/add-as-preferred-source-admin.js', array('jquery', 'wp-color-picker'), $this->version, false); wp_localize_script($this->plugin_name . '-admin', 'adasprso_admin', array( 'ajax_url' => admin_url('admin-ajax.php'), 'nonce' => wp_create_nonce('adasprso_categories_nonce'), )); } /** * Add settings page link to plugins page * * @since 1.0.0 */ public function add_action_links($links) { $settings_link = '' . __('Settings', 'add-as-preferred-source') . ''; array_unshift($links, $settings_link); return $links; } /** * Show admin notice with settings link * * @since 1.0.0 */ public function admin_notice() { // Show notice only once $notice_dismissed = get_option('adasprso_notice_dismissed'); // Check if notice is already dismissed or if not on plugins page $current_screen = get_current_screen(); if ( $notice_dismissed || ! $current_screen || $current_screen->id !== 'plugins' ) { return; } if ( 'plugins' === $current_screen->id ) { // Auto-dismiss the notice after showing it once update_option('adasprso_notice_dismissed', true); ?>
plugin_name, array($this, 'display_settings_page') ); } /** * Display the settings page content * * @since 1.0.0 */ public function display_settings_page() { include_once ADASPRSO_PLUGIN_PATH . 'admin/partials/add-as-preferred-source-admin-display.php'; } /** * Register plugin settings * * @since 1.0.0 */ public function register_settings() { register_setting( 'adasprso_settings', 'adasprso_options', array($this, 'validate_settings') ); // General Settings Section add_settings_section( 'adasprso_general_section', __('General Settings', 'add-as-preferred-source'), array($this, 'general_section_callback'), 'adasprso_settings' ); // Banner Enabled add_settings_field( 'adasprso_enabled', __('Enable Banner', 'add-as-preferred-source'), array($this, 'enabled_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Website Name add_settings_field( 'adasprso_website_name', __('Website Name', 'add-as-preferred-source'), array($this, 'website_name_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Custom Domain add_settings_field( 'adasprso_custom_domain', __('Custom Domain', 'add-as-preferred-source'), array($this, 'custom_domain_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Banner Text add_settings_field( 'adasprso_banner_text', __('Banner Text', 'add-as-preferred-source'), array($this, 'banner_text_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Badge Language add_settings_field( 'adasprso_badge_language', __('Badge Language', 'add-as-preferred-source'), array($this, 'badge_language_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Badge Theme add_settings_field( 'adasprso_badge_theme', __('Badge Theme', 'add-as-preferred-source'), array($this, 'badge_theme_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Banner Position add_settings_field( 'adasprso_banner_position', __('Banner Position', 'add-as-preferred-source'), array($this, 'banner_position_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Banner Trigger add_settings_field( 'adasprso_banner_trigger', __('Display Trigger', 'add-as-preferred-source'), array($this, 'banner_trigger_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Scroll Percentage add_settings_field( 'adasprso_banner_scroll_percent', __('Scroll Percentage', 'add-as-preferred-source'), array($this, 'banner_scroll_percent_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Delay Seconds add_settings_field( 'adasprso_banner_delay_seconds', __('Delay (seconds)', 'add-as-preferred-source'), array($this, 'banner_delay_seconds_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Banner Frequency (after the visitor closes the banner) add_settings_field( 'adasprso_banner_frequency', __('After Visitor Closes Banner', 'add-as-preferred-source'), array($this, 'banner_frequency_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Dismiss Duration (days) add_settings_field( 'adasprso_banner_dismiss_days', __('Hide Duration (days)', 'add-as-preferred-source'), array($this, 'banner_dismiss_days_callback'), 'adasprso_settings', 'adasprso_general_section' ); // Color Settings Section add_settings_section( 'adasprso_color_section', __('Color Settings', 'add-as-preferred-source'), array($this, 'color_section_callback'), 'adasprso_settings' ); // Banner Background Color add_settings_field( 'adasprso_banner_bg_color', __('Banner Background Color', 'add-as-preferred-source'), array($this, 'banner_bg_color_callback'), 'adasprso_settings', 'adasprso_color_section' ); // Text Color add_settings_field( 'adasprso_text_color', __('Text Color', 'add-as-preferred-source'), array($this, 'text_color_callback'), 'adasprso_settings', 'adasprso_color_section' ); // Device Settings Section add_settings_section( 'adasprso_device_section', __('Device Settings', 'add-as-preferred-source'), array($this, 'device_section_callback'), 'adasprso_settings' ); // Show on Mobile add_settings_field( 'adasprso_show_on_mobile', __('Show on Mobile', 'add-as-preferred-source'), array($this, 'show_on_mobile_callback'), 'adasprso_settings', 'adasprso_device_section' ); // Show on Desktop add_settings_field( 'adasprso_show_on_desktop', __('Show on Desktop', 'add-as-preferred-source'), array($this, 'show_on_desktop_callback'), 'adasprso_settings', 'adasprso_device_section' ); // Display Rules Section add_settings_section( 'adasprso_display_rules_section', __('Display Rules', 'add-as-preferred-source'), array($this, 'display_rules_section_callback'), 'adasprso_settings' ); // Display On add_settings_field( 'adasprso_display_on', __('Show Banner On', 'add-as-preferred-source'), array($this, 'display_on_callback'), 'adasprso_settings', 'adasprso_display_rules_section' ); // Exclude Post / Page IDs add_settings_field( 'adasprso_exclude_post_ids', __('Exclude Post / Page IDs', 'add-as-preferred-source'), array($this, 'exclude_post_ids_callback'), 'adasprso_settings', 'adasprso_display_rules_section' ); // Exclude Categories add_settings_field( 'adasprso_exclude_categories', __('Exclude Categories', 'add-as-preferred-source'), array($this, 'exclude_categories_callback'), 'adasprso_settings', 'adasprso_display_rules_section' ); // Inline Button Settings Section add_settings_section( 'adasprso_inline_section', __('Inline Button Settings', 'add-as-preferred-source'), array($this, 'inline_section_callback'), 'adasprso_settings_inline' ); // Inline Enabled add_settings_field( 'adasprso_inline_enabled', __('Enable Inline Button', 'add-as-preferred-source'), array($this, 'inline_enabled_callback'), 'adasprso_settings_inline', 'adasprso_inline_section' ); // Inline Style add_settings_field( 'adasprso_inline_style', __('Badge Style', 'add-as-preferred-source'), array($this, 'inline_style_callback'), 'adasprso_settings_inline', 'adasprso_inline_section' ); // Inline Position add_settings_field( 'adasprso_inline_position', __('Button Position', 'add-as-preferred-source'), array($this, 'inline_position_callback'), 'adasprso_settings_inline', 'adasprso_inline_section' ); // Inline Post Types add_settings_field( 'adasprso_inline_post_types', __('Post Types', 'add-as-preferred-source'), array($this, 'inline_post_types_callback'), 'adasprso_settings_inline', 'adasprso_inline_section' ); // Inline Background Color add_settings_field( 'adasprso_inline_bg_color', __('Background Color', 'add-as-preferred-source'), array($this, 'inline_bg_color_callback'), 'adasprso_settings_inline', 'adasprso_inline_section' ); // Inline Text Color add_settings_field( 'adasprso_inline_text_color', __('Text Color', 'add-as-preferred-source'), array($this, 'inline_text_color_callback'), 'adasprso_settings_inline', 'adasprso_inline_section' ); // Inline Text (Title) add_settings_field( 'adasprso_inline_text', __('Inline Title', 'add-as-preferred-source'), array($this, 'inline_text_callback'), 'adasprso_settings_inline', 'adasprso_inline_section' ); // Inline Subtitle add_settings_field( 'adasprso_inline_subtitle', __('Inline Subtitle', 'add-as-preferred-source'), array($this, 'inline_subtitle_callback'), 'adasprso_settings_inline', 'adasprso_inline_section' ); } /** * Validate settings * * @since 1.0.0 * @param array $input The input options. * @return array The sanitized options. */ public function validate_settings($input) { $sanitized_input = array(); // No need to manually verify nonce - WordPress settings API handles this automatically // The nonce is automatically generated and verified by settings_fields() // Boolean field $sanitized_input['enabled'] = isset($input['enabled']) ? 1 : 0; // Text fields $sanitized_input['website_name'] = sanitize_text_field( isset( $input['website_name'] ) ? $input['website_name'] : '' ); $sanitized_input['banner_text'] = sanitize_text_field( isset( $input['banner_text'] ) ? $input['banner_text'] : '' ); // Custom domain — store as entered (full URL or plain domain both work) $sanitized_input['custom_domain'] = sanitize_text_field( isset( $input['custom_domain'] ) ? trim( $input['custom_domain'] ) : '' ); // Banner position $sanitized_input['banner_position'] = ( isset( $input['banner_position'] ) && 'top' === $input['banner_position'] ) ? 'top' : 'bottom'; // Banner trigger $valid_triggers = array('immediate', 'scroll', 'time'); $sanitized_input['banner_trigger'] = (isset($input['banner_trigger']) && in_array($input['banner_trigger'], $valid_triggers, true)) ? $input['banner_trigger'] : 'immediate'; // Scroll percentage (10–90) $sanitized_input['banner_scroll_percent'] = isset($input['banner_scroll_percent']) ? max(10, min(90, (int) $input['banner_scroll_percent'])) : 50; // Delay seconds (1–60) $sanitized_input['banner_delay_seconds'] = isset($input['banner_delay_seconds']) ? max(1, min(60, (int) $input['banner_delay_seconds'])) : 5; // Banner frequency — 'remember' hides via cookie after dismissal, 'always' shows on every page view $sanitized_input['banner_frequency'] = ( isset( $input['banner_frequency'] ) && 'always' === $input['banner_frequency'] ) ? 'always' : 'remember'; // Dismiss duration in days (1–365) $sanitized_input['banner_dismiss_days'] = isset($input['banner_dismiss_days']) ? max(1, min(365, (int) $input['banner_dismiss_days'])) : 7; // Color fields $sanitized_input['banner_bg_color'] = sanitize_hex_color( isset( $input['banner_bg_color'] ) ? $input['banner_bg_color'] : '' ); $sanitized_input['text_color'] = sanitize_hex_color( isset( $input['text_color'] ) ? $input['text_color'] : '' ); // Device settings $sanitized_input['show_on_mobile'] = isset($input['show_on_mobile']) ? 1 : 0; $sanitized_input['show_on_desktop'] = isset($input['show_on_desktop']) ? 1 : 0; // Display rules $valid_display_on = array('everywhere', 'posts_only', 'pages_only', 'front_page_only'); $sanitized_input['display_on'] = (isset($input['display_on']) && in_array($input['display_on'], $valid_display_on, true)) ? $input['display_on'] : 'everywhere'; // Exclude post/page IDs — keep only integers, re-join as comma string $raw_ids = isset($input['exclude_post_ids']) ? $input['exclude_post_ids'] : ''; $ids = array_filter(array_map('intval', explode(',', $raw_ids))); $sanitized_input['exclude_post_ids'] = implode(',', $ids); // Exclude categories — array of term IDs $sanitized_input['exclude_categories'] = array(); if (isset($input['exclude_categories']) && is_array($input['exclude_categories'])) { foreach ($input['exclude_categories'] as $cat_id) { $sanitized_input['exclude_categories'][] = absint($cat_id); } } // Inline settings $sanitized_input['inline_enabled'] = isset($input['inline_enabled']) ? 1 : 0; $valid_inline_styles = array('default', 'simple'); $sanitized_input['inline_style'] = ( isset( $input['inline_style'] ) && in_array( $input['inline_style'], $valid_inline_styles, true ) ) ? $input['inline_style'] : 'default'; $valid_positions = array('above', 'below', 'both'); $sanitized_input['inline_position'] = ( isset( $input['inline_position'] ) && in_array( $input['inline_position'], $valid_positions, true ) ) ? $input['inline_position'] : 'both'; // Sanitize Post Types $sanitized_input['inline_post_types'] = array(); if (isset($input['inline_post_types']) && is_array($input['inline_post_types'])) { foreach ($input['inline_post_types'] as $post_type) { if (post_type_exists($post_type)) { $sanitized_input['inline_post_types'][] = sanitize_text_field($post_type); } } } // Sanitize Colors $sanitized_input['inline_bg_color'] = sanitize_hex_color( isset( $input['inline_bg_color'] ) ? $input['inline_bg_color'] : '' ); $sanitized_input['inline_text_color'] = sanitize_hex_color( isset( $input['inline_text_color'] ) ? $input['inline_text_color'] : '' ); $sanitized_input['inline_text'] = sanitize_text_field( isset( $input['inline_text'] ) ? $input['inline_text'] : '' ); $sanitized_input['inline_subtitle'] = sanitize_text_field( isset( $input['inline_subtitle'] ) ? $input['inline_subtitle'] : '' ); $valid_badge_languages = array_keys( $this->get_available_badge_languages() ); $sanitized_input['badge_language'] = ( isset( $input['badge_language'] ) && in_array( $input['badge_language'], $valid_badge_languages, true ) ) ? $input['badge_language'] : 'auto'; $sanitized_input['badge_custom_text'] = sanitize_text_field( isset( $input['badge_custom_text'] ) ? $input['badge_custom_text'] : '' ); // Badge theme — anything other than an explicit "light" stays dark, so // installs updated from older versions keep their current badges. $sanitized_input['badge_theme'] = ( isset( $input['badge_theme'] ) && 'light' === $input['badge_theme'] ) ? 'light' : 'dark'; // Clear site caches so the updated settings take effect immediately. $this->clear_site_caches(); // Add success message add_settings_error('adasprso_options', 'settings_updated', __('Settings saved successfully!', 'add-as-preferred-source'), 'updated'); return $sanitized_input; } /** * Clear caches from popular caching plugins and the WordPress object cache. * * Runs after settings are saved so visitors see the updated banner/button * without needing a manual cache purge. */ private function clear_site_caches() { // WP Rocket if ( function_exists( 'rocket_clean_domain' ) ) { rocket_clean_domain(); } // W3 Total Cache if ( function_exists( 'w3tc_pgcache_flush' ) ) { w3tc_pgcache_flush(); } // WP Super Cache if ( function_exists( 'wp_cache_clear_cache' ) ) { wp_cache_clear_cache(); } // LiteSpeed Cache if ( class_exists( 'LiteSpeed_Cache_API' ) ) { do_action( 'litespeed_purge_all' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound } // Autoptimize if ( class_exists( 'autoptimizeCache' ) ) { autoptimizeCache::clearall(); } // WP Fastest Cache if ( isset( $GLOBALS['wp_fastest_cache'] ) && method_exists( $GLOBALS['wp_fastest_cache'], 'deleteCache' ) ) { $GLOBALS['wp_fastest_cache']->deleteCache( true ); } // Hummingbird if ( class_exists( '\Hummingbird\Core\Filesystem' ) ) { do_action( 'wphb_clear_page_cache' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound } // Cache Enabler if ( class_exists( 'Cache_Enabler' ) ) { do_action( 'cache_enabler_clear_complete_cache' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound } // SG Optimizer (SiteGround) if ( function_exists( 'sg_cachepress_purge_cache' ) ) { sg_cachepress_purge_cache(); } // Comet Cache if ( class_exists( 'comet_cache' ) ) { comet_cache::clearCache(); } // Swift Performance if ( class_exists( 'Swift_Performance_Cache' ) ) { Swift_Performance_Cache::clear_all_cache(); } // Breeze (Cloudways) if ( class_exists( 'Breeze_PurgeCache' ) ) { do_action( 'breeze_clear_all_cache' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound } } /** * General section callback * * @since 1.0.0 */ public function general_section_callback() { echo '' . esc_html__('Configure the general settings for your preferred source banner.', 'add-as-preferred-source') . '
'; } /** * Color section callback * * @since 1.0.0 */ public function color_section_callback() { echo '' . esc_html__('Customize the colors for your preferred source banner.', 'add-as-preferred-source') . '
'; } /** * Device section callback * * @since 1.0.0 */ public function device_section_callback() { echo '' . esc_html__('Choose on which devices the banner should be displayed.', 'add-as-preferred-source') . '
'; } /** * Enable callback * * @since 1.0.0 */ public function enabled_callback() { $enabled = isset($this->options['enabled']) ? $this->options['enabled'] : 0; echo ''; echo ''; } /** * Website name callback * * @since 1.0.0 */ public function website_name_callback() { $website_name = isset($this->options['website_name']) ? $this->options['website_name'] : get_bloginfo('name'); echo ''; echo '' . esc_html__('Enter your website name for the banner text.', 'add-as-preferred-source') . '
'; } /** * Custom domain callback */ public function custom_domain_callback() { $custom_domain = isset( $this->options['custom_domain'] ) ? $this->options['custom_domain'] : ''; $default_url = wp_parse_url( home_url(), PHP_URL_HOST ); echo ''; if ( empty( $custom_domain ) ) { echo '' . sprintf(
/* translators: %s: the site's hostname */
esc_html__( 'Currently using: %s. Enter a value to override.', 'add-as-preferred-source' ),
'' . esc_html( $default_url ) . ''
) . '
' . esc_html__( 'Override the URL used in the Google Preferred Source link. Leave empty to use your site\'s domain automatically.', 'add-as-preferred-source' ) . '
'; } } /** * Banner text callback * * @since 1.0.0 */ public function banner_text_callback() { $banner_text = isset($this->options['banner_text']) ? $this->options['banner_text'] : 'Add as a preferred source on Google'; echo ''; echo '' . esc_html__('Enter the text to display in the banner. Use {website_name} to include the website name.', 'add-as-preferred-source') . '
'; } /** * Banner position callback * * @since 1.0.0 */ public function banner_position_callback() { $banner_position = isset($this->options['banner_position']) ? $this->options['banner_position'] : 'bottom'; ?> options['banner_bg_color']) ? $this->options['banner_bg_color'] : '#1a1a1a'; echo ''; } /** * Text color callback * * @since 1.0.0 */ public function text_color_callback() { $text_color = isset($this->options['text_color']) ? $this->options['text_color'] : '#ffffff'; echo ''; } /** * Show on mobile callback * * @since 1.0.0 */ public function show_on_mobile_callback() { $show_on_mobile = isset($this->options['show_on_mobile']) ? $this->options['show_on_mobile'] : 1; echo ''; echo ''; } /** * Show on desktop callback * * @since 1.0.0 */ public function show_on_desktop_callback() { $show_on_desktop = isset($this->options['show_on_desktop']) ? $this->options['show_on_desktop'] : 1; echo ''; echo ''; } /** * Inline section callback */ public function inline_section_callback() { echo '' . esc_html__('Configure the inline "Add as Preferred Source" button that appears within your content.', 'add-as-preferred-source') . '
'; } /** * Inline style callback */ public function inline_style_callback() { $style = isset( $this->options['inline_style'] ) ? $this->options['inline_style'] : 'default'; ?> options['inline_enabled']) ? $this->options['inline_enabled'] : 0; echo ''; echo ''; } /** * Inline position callback */ public function inline_position_callback() { $inline_position = isset($this->options['inline_position']) ? $this->options['inline_position'] : 'both'; ?> options['inline_post_types']) ? $this->options['inline_post_types'] : array('post'); // Get all public post types $args = array( 'public' => true, '_builtin' => false ); $post_types = get_post_types($args, 'objects'); // Add built-in types $post_types['post'] = get_post_type_object('post'); $post_types['page'] = get_post_type_object('page'); echo ''; echo '' . esc_html__('Select the post types where the button should appear.', 'add-as-preferred-source') . '
'; } /** * Inline Background Color Callback */ public function inline_bg_color_callback() { $bg_color = isset($this->options['inline_bg_color']) ? $this->options['inline_bg_color'] : '#ffffff'; echo ''; } /** * Inline Text Color Callback */ public function inline_text_color_callback() { $text_color = isset($this->options['inline_text_color']) ? $this->options['inline_text_color'] : '#1c1e21'; echo ''; } /** * Inline text callback */ public function inline_text_callback() { $inline_text = isset($this->options['inline_text']) ? $this->options['inline_text'] : 'Stay connected via Google News'; echo ''; echo '' . esc_html__('The main title text.', 'add-as-preferred-source') . '
'; } /** * Inline subtitle callback */ public function inline_subtitle_callback() { $inline_subtitle = isset($this->options['inline_subtitle']) ? $this->options['inline_subtitle'] : 'Follow us for the latest travel updates and guides.'; echo ''; echo '' . esc_html__('The secondary text displayed below the title.', 'add-as-preferred-source') . '
'; } /** * Builds the badge image URL for a language code and theme. * Falls back to the English badge when the language file is missing. * * @param string|null $code Badge language code, or null for English. * @param string $theme 'dark' or 'light'. */ private function badge_image_url( $code, $theme ) { $dir = ( 'light' === $theme ) ? 'public/images/light/' : 'public/images/'; if ( $code && file_exists( ADASPRSO_PLUGIN_PATH . $dir . 'google-preferred-source-button-' . $code . '.png' ) ) { return ADASPRSO_PLUGIN_URL . $dir . 'google-preferred-source-button-' . $code . '.png'; } return ADASPRSO_PLUGIN_URL . $dir . 'google-preferred-source-button.png'; } /** * Returns the badge theme ('dark' or 'light') from a set of options. */ private function get_badge_theme( $options ) { return ( isset( $options['badge_theme'] ) && 'light' === $options['badge_theme'] ) ? 'light' : 'dark'; } /** * Returns the badge image URL to use in admin previews, based on the saved options. * * @param array $options The plugin options. * @param string|null $theme Optional theme override; defaults to the saved theme. */ public function get_preview_badge_url( $options, $theme = null ) { if ( null === $theme ) { $theme = $this->get_badge_theme( $options ); } $setting = isset( $options['badge_language'] ) ? $options['badge_language'] : 'auto'; if ( $setting === 'custom' ) { return ''; } if ( $setting === 'auto' ) { $locale_map = array( 'da' => 'da', 'da_DK' => 'da', 'de' => 'de', 'de_DE' => 'de', 'de_AT' => 'de', 'de_CH' => 'de', 'de_DE_formal' => 'de', 'es' => 'es', 'es_ES' => 'es', 'es_MX' => 'es', 'es_AR' => 'es', 'es_CL' => 'es', 'et' => 'et', 'et_EE' => 'et', 'fi' => 'fi', 'fi_FI' => 'fi', 'fr' => 'fr', 'fr_FR' => 'fr', 'fr_BE' => 'fr', 'fr_CA' => 'fr', 'fr_CH' => 'fr', 'hi' => 'hi', 'hi_IN' => 'hi', 'he' => 'iw', 'he_IL' => 'iw', 'ja' => 'ja', 'ja_JP' => 'ja', 'ko' => 'ko', 'ko_KR' => 'ko', 'nb' => 'no', 'nb_NO' => 'no', 'nn_NO' => 'no', 'pt_BR' => 'pt-br', 'ru' => 'ru', 'ru_RU' => 'ru', 'sv' => 'sv', 'sv_SE' => 'sv', 'tr' => 'tr', 'tr_TR' => 'tr', 'uk' => 'uk', 'uk_UA' => 'uk', ); $code = isset( $locale_map[ get_locale() ] ) ? $locale_map[ get_locale() ] : null; } else { $code = ( $setting === 'en' ) ? null : $setting; } return $this->badge_image_url( $code, $theme ); } /** * Returns the map of badge language codes to their display labels. */ public function get_available_badge_languages() { return array( 'auto' => __('Auto (match site language)', 'add-as-preferred-source'), 'en' => 'English', 'da' => 'Dansk', 'de' => 'Deutsch', 'es' => 'Español', 'et' => 'Eesti', 'fi' => 'Suomi', 'fr' => 'Français', 'hi' => 'हिन्दी', 'iw' => 'עברית', 'ja' => '日本語', 'ko' => '한국어', 'no' => 'Norsk', 'pt-br' => 'Português (Brasil)', 'ru' => 'Русский', 'sv' => 'Svenska', 'tr' => 'Türkçe', 'uk' => 'Українська', 'custom' => __('Custom text (my language is not listed)', 'add-as-preferred-source'), ); } /** * Badge language callback */ public function badge_language_callback() { $saved = isset( $this->options['badge_language'] ) ? $this->options['badge_language'] : 'auto'; $languages = $this->get_available_badge_languages(); $options = is_array( $this->options ) ? $this->options : array(); $custom_text = isset( $this->options['badge_custom_text'] ) ? $this->options['badge_custom_text'] : ''; $is_custom = ( $saved === 'custom' ); echo ''; printf( '%s
' . esc_html__( 'Choose which language badge to display. "Auto" detects the site language automatically and falls back to English if unavailable. If your language is not listed, select "Custom text (my language is not listed)" to enter your own button text — a custom badge will be generated with the Google logo and your text. We are adding more languages with each update — stay tuned!', 'add-as-preferred-source' ) . '
'; } /** * Badge theme callback */ public function badge_theme_callback() { $theme = $this->get_badge_theme( is_array( $this->options ) ? $this->options : array() ); ?> options['banner_trigger']) ? $this->options['banner_trigger'] : 'immediate'; ?> options['banner_scroll_percent']) ? (int) $this->options['banner_scroll_percent'] : 50; $trigger = isset($this->options['banner_trigger']) ? $this->options['banner_trigger'] : 'immediate'; $style = ( $trigger !== 'scroll' ) ? 'display:none;' : ''; echo '' . esc_html__('Show the banner after the visitor has scrolled this percentage of the page (10–90).', 'add-as-preferred-source') . '
'; echo '' . esc_html__('Show the banner after this many seconds on the page (1–60).', 'add-as-preferred-source') . '
'; echo '' . esc_html__('After a visitor closes the banner, keep it hidden for this many days (1–365).', 'add-as-preferred-source') . '
'; echo '' . esc_html__('Control exactly where the banner appears on your site.', 'add-as-preferred-source') . '
'; } /** * Display On callback */ public function display_on_callback() { $display_on = isset($this->options['display_on']) ? $this->options['display_on'] : 'everywhere'; ?> options['exclude_post_ids']) ? $this->options['exclude_post_ids'] : ''; echo ''; echo '' . esc_html__('Enter comma-separated post or page IDs where the banner should never appear.', 'add-as-preferred-source') . '
'; } /** * Exclude Categories callback — renders a lightweight custom tag-search widget (no external library). */ public function exclude_categories_callback() { $excluded = isset($this->options['exclude_categories']) ? array_map('intval', (array) $this->options['exclude_categories']) : array(); // Pre-load labels for already-selected categories only (typically a very small set). $preloaded = array(); if (!empty($excluded)) { $terms = get_terms(array( 'taxonomy' => 'category', 'include' => $excluded, 'hide_empty' => false, )); if (!is_wp_error($terms)) { foreach ($terms as $t) { $preloaded[$t->term_id] = $t->name . ' (' . $t->count . ')'; } } } echo '' . esc_html__('Search and select categories where the banner should not appear.', 'add-as-preferred-source') . '
'; } /** * AJAX handler — returns up to 20 categories matching a search string. */ public function ajax_search_categories() { check_ajax_referer('adasprso_categories_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error('unauthorized'); } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce already verified above $search = isset($_GET['q']) ? sanitize_text_field(wp_unslash($_GET['q'])) : ''; $terms = get_terms(array( 'taxonomy' => 'category', 'search' => $search, 'number' => 20, 'hide_empty' => false, )); $results = array(); if (!is_wp_error($terms)) { foreach ($terms as $term) { $results[] = array( 'id' => $term->term_id, 'text' => $term->name . ' (' . $term->count . ')', ); } } wp_send_json(array('results' => $results)); } }