admin_menu_hooks = array(); } /** * Create hooks. */ public function hooks() { add_filter( 'plugin_action_links_' . ADCMDR_PLUGIN_BASENAME, array( $this, 'plugin_action_links' ) ); add_action( 'admin_menu', array( $this, 'check_admin_capabilities' ) ); add_action( 'admin_menu', array( $this, 'create_admin_menu' ) ); add_action( 'admin_head', array( $this, 'set_current_admin_menu_item' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) ); add_action( 'admin_print_styles', array( $this, 'admin_print_styles' ) ); add_action( 'admin_init', array( $this, 'register_settings' ) ); add_action( 'in_admin_header', array( $this, 'adcmdr_admin_header' ) ); add_action( 'admin_notices', array( $this, 'maybe_onboard_global' ), 11 ); add_filter( 'pre_update_option_adcmdr_addons', array( $this, 'addon_options_updated' ), 10, 2 ); add_filter( 'wp_insert_post_data', array( $this, 'modify_post_title' ), 100, 1 ); $this->admin_reports()->hooks(); $this->admin_notifications()->hooks(); AdminAdsense::instance()->hooks(); AdminOnboarding::instance()->hooks(); $duplicate = new Duplicate(); $duplicate->hooks(); add_action( 'admin_init', function () { new AdminAdPostMeta(); new AdminGroupTermMeta(); new AdminPlacementPostMeta(); } ); add_filter( 'wo_repeater_draggable_icon', function () { return Admin::sortable_handle( false ); } ); add_filter( 'wo_repeater_draggable_icon_width', function () { return 10; } ); add_filter( 'wo_repeater_sort_handle_selector', function () { return '.adcmdr-ui-sort-icon'; } ); /** * Hook fires when AdSense options are updated. */ add_action( 'update_option_adcmdr_adsense', function () { do_action( 'adcmdr_adsense_publisher_id_changed', AdSense::instance()->current_adsense_publisher_id() ); } ); } /** * Create a new WOSettings instance if necessary. * * @return WOSettings */ protected function sf() { if ( ! $this->sf ) { $this->sf = new WOSettings( AdCommander::ns() ); } return $this->sf; } /** * Create a new AdminReports instance if necessary. * * @return AdminReports */ public function admin_reports() { if ( ! $this->admin_reports ) { $this->admin_reports = new AdminReports(); } return $this->admin_reports; } /** * Create a new AdminNotifications instance if necessary. * * @return AdminNotifications */ public function admin_notifications() { if ( ! $this->admin_notifications ) { $this->admin_notifications = new AdminNotifications(); } return $this->admin_notifications; } /** * Create a new AdminGeo instance if necessary. * * @return AdminGeo */ public function admin_geo() { if ( ! $this->admin_geo && ProBridge::instance()->is_pro_loaded() ) { $this->admin_geo = new AdminGeo(); } return $this->admin_geo; } /** * Create a new AdminDashboard instance if necessary. * * @return AdminReports */ public function admin_dashboard() { if ( ! $this->admin_dashboard ) { $this->admin_dashboard = new AdminDashboard(); } return $this->admin_dashboard; } /** * Create a new AdminSupport instance if necessary. * * @return AdminSupport */ public function admin_support() { if ( ! $this->admin_support ) { $this->admin_support = new AdminSupport(); } return $this->admin_support; } /** * Create a new AdminTargeting instance if necessary. * * @return AdminTargeting */ protected function admin_targeting() { if ( ! $this->admin_targeting ) { $this->admin_targeting = new AdminTargeting(); } return $this->admin_targeting; } /** * The UI element for sorting drag-and-drop lists. * * @param bool $display Whether to display or return the handle. * * @return string */ public static function sortable_handle( $display = true ) { $allowed_html = array( 'img' => array( 'src' => array(), 'class' => array(), 'alt' => array(), ), ); // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage -- Loading image from plugin directory. $img = ''; if ( ! $display ) { return wp_kses( $img, $allowed_html ); } echo wp_kses( $img, $allowed_html ); } /** * The URL to the sortable handle * * @return string */ public static function sortable_handle_url() { return AdCommander::assets_url() . 'img/drag.png'; } /** * Add links to the plugin screen. * * @param array $links Existing links passed into this function. * * @return array */ public function plugin_action_links( $links ) { $action_links = array( array( 'title' => __( 'Settings', 'ad-commander' ), 'url' => self::settings_admin_url(), ), array( 'title' => __( 'Support', 'ad-commander' ), 'url' => self::support_admin_url(), ), ); $plugin_links = array(); foreach ( $action_links as $action_link ) { $plugin_links[ Util::ns( sanitize_title( $action_link['title'] ), '_' ) ] = '' . esc_html( $action_link['title'] ) . ''; } return array_merge( $plugin_links, $links ); } /** * Check that administrator and editor roles have the correct caps. * * @return void */ public function check_admin_capabilities() { $admins = get_role( 'administrator' ); $editors = get_role( 'editor' ); if ( ! $admins->has_cap( AdCommander::capability() ) ) { Install::add_cap( $admins ); } $allow_editors = Options::instance()->get( 'allow_editors', 'admin', true, false ); if ( $allow_editors && ! $editors->has_cap( AdCommander::capability() ) ) { Install::add_cap( $editors ); } elseif ( ! $allow_editors && $editors->has_cap( AdCommander::capability() ) ) { Install::remove_cap( $editors ); } } /** * Enqueue styles if we're on a screen that needs them. * * @return void */ public function admin_print_styles() { wp_enqueue_style( Util::ns( 'menu' ), AdCommander::assets_url() . 'css/admin_global.css', array(), AdCommander::version() ); if ( $this->is_screen() ) { $is_pro = ProBridge::instance()->is_pro_loaded(); $frontend = new Frontend(); $frontend->enqueue_or_print_styles( Util::ns( 'front' ), AdCommander::assets_url() . 'css/style.css', AdCommander::version(), false ); if ( $is_pro ) { $frontend->enqueue_or_print_styles( Util::ns( 'front-pro' ), AdCommanderPro::assets_url() . 'css/style.css', AdCommanderPro::version() ); } $this->enqueue_woadmin_styles(); wp_enqueue_style( Util::ns( 'admin' ), AdCommander::assets_url() . 'css/admin.css', array( 'woadmin' ), AdCommander::version() ); if ( ! $is_pro ) { wp_add_inline_style( Util::ns( 'admin' ), '.woadmin-form-inner input[value*="admin.php?page=ad-commander-settings&tab=adcmdr_addons"] ~ p.submit { display: none; }' ); } } } /** * Enqueue styles for jQuery UI as these are not necessarily included already. * * @return void */ protected function enqueue_jquery_ui_styles() { wp_register_style( 'jquery-ui', AdCommander::assets_url() . 'vendor/jquery-ui.min.css', array(), AdCommander::version() ); wp_enqueue_style( 'jquery-ui' ); } /** * Enqueue admin script for showing/hiding settings. * * @return string */ protected function enqueue_setting_restrict() { wp_enqueue_script( 'jquery' ); $handle = Util::ns( 'settingrestrict' ); wp_register_script( $handle, AdCommander::assets_url() . 'js/setting-restrict.js', array( 'jquery' ), AdCommander::version(), array( 'in_footer' => true ) ); wp_enqueue_script( $handle ); return $handle; } /** * Enqueue scripts if we're on a screen that needs them. * * @return void */ public function admin_enqueue_scripts() { if ( $this->is_screen() ) { wp_enqueue_script( 'jquery' ); } $admin_onboarding = AdminOnboarding::instance(); if ( $admin_onboarding->should_onboard() ) { $admin_onboarding->enqueue(); } if ( $this->is_screen( array( AdCommander::tax_group(), AdCommander::posttype_ad(), 'edit-' . AdCommander::tax_group(), 'edit-' . AdCommander::posttype_ad() ) ) ) { wp_enqueue_script( 'jquery' ); $handle = Util::ns( 'copy' ); wp_register_script( $handle, AdCommander::assets_url() . 'js/copy.js', array( 'jquery' ), AdCommander::version(), array( 'in_footer' => true ) ); wp_enqueue_script( $handle ); } if ( isset( $this->admin_menu_hooks[ self::admin_slug( 'reports' ) ] ) && $this->is_screen( $this->admin_menu_hooks[ self::admin_slug( 'reports' ) ] ) ) { $this->admin_reports()->enqueue(); } elseif ( isset( $this->admin_menu_hooks[ self::admin_slug( 'settings' ) ] ) && $this->is_screen( $this->admin_menu_hooks[ self::admin_slug( 'settings' ) ] ) ) { $settings = array( 'restricted' => array(), ); foreach ( self::settings() as $setting ) { if ( isset( $setting['sections'] ) ) { foreach ( $setting['sections'] as $section ) { if ( isset( $section['fields'] ) ) { foreach ( $section['fields'] as $field ) { if ( ! is_array( $field ) ) { continue; } if ( isset( $field['restricted'] ) ) { $settings['restricted'][] = sanitize_title( $field['restricted'] ); } } } } } } $settings['restricted'] = array_values( array_unique( $settings['restricted'] ) ); $handle = Util::ns( 'settings' ); wp_register_script( $handle, AdCommander::assets_url() . 'js/settings.js', array( 'jquery' ), AdCommander::version(), array( 'in_footer' => true ) ); wp_enqueue_script( $handle ); Util::enqueue_script_data( $handle, $settings ); AdminAdsense::instance()->admin_enqueue_scripts(); /** * Enqueue pro scripts that aren't otherwise enqueued already. */ if ( ProBridge::instance()->is_pro_loaded() ) { $this->admin_geo()->enqueue(); } } } /** * Check the current screen against an array of screen IDs. * * @param array $screen_ids Screen IDs to compare against. * * @return bool */ public function is_screen( $screen_ids = array() ) { $screen = get_current_screen(); if ( ! isset( $screen->id ) ) { return false; } if ( ! $screen_ids ) { $screen_ids = apply_filters( 'adcmdr_admin_all_screen_ids', array( 'edit-' . AdCommander::tax_group(), 'edit-' . AdCommander::posttype_ad(), 'edit-' . AdCommander::posttype_placement(), AdCommander::posttype_ad(), AdCommander::posttype_placement(), ) ); $screen_ids = array_merge( $screen_ids, apply_filters( 'adcmdr_admin_menu_hooks', array_values( $this->admin_menu_hooks ) ) ); } $screen_ids = Util::arrayify( $screen_ids ); return in_array( $screen->id, $screen_ids ); } /** * Overwrites global variables so that the correct menu items stay open. * * @return void */ public function set_current_admin_menu_item() { global $parent_file, $submenu_file, $post_type, $taxonomy; if ( $taxonomy === AdCommander::tax_group() ) { $parent_file = self::admin_slug(); $submenu_file = self::admin_group_tax_path(); } elseif ( $post_type === AdCommander::posttype_ad() ) { $parent_file = self::admin_slug(); $submenu_file = self::admin_ad_post_type_path(); } elseif ( $post_type === AdCommander::posttype_placement() ) { $parent_file = self::admin_slug(); $submenu_file = self::admin_placement_post_type_path(); } } /** * Creates an admin slug using the text domain and an optional sub string. * * @param null|string $sub Optional sub page slug. * * @return string */ public static function admin_slug( $sub = null ) { $slug = 'ad-commander'; if ( $sub ) { $slug .= '-' . sanitize_title( $sub ); } return $slug; } /** * The path to the admin page. * * @param null $sub Optional sub page. * * @return string */ public static function admin_path( $sub = null ) { return 'admin.php?page=' . self::admin_slug( $sub ); } /** * The path to AD post type. * * @return string */ public static function admin_ad_post_type_path() { return 'edit.php?post_type=' . AdCommander::posttype_ad(); } public static function admin_ad_post_type_url() { return admin_url( self::admin_ad_post_type_path() ); } /** * The path to Placement post type. * * @return string */ public static function admin_placement_post_type_path() { return 'edit.php?post_type=' . AdCommander::posttype_placement(); } public static function admin_placement_post_type_url() { return admin_url( self::admin_placement_post_type_path() ); } /** * The path to Group taxonomy. * * @return string */ public static function admin_group_tax_path() { return 'edit-tags.php?taxonomy=' . AdCommander::tax_group() . '&post_type=' . AdCommander::posttype_ad(); } public static function admin_group_tax_url() { return admin_url( self::admin_group_tax_path() ); } /** * The path to edit an ad post - or to the trash if the post is trashed. * * @param int $post_id The post ID to edit. * @param string $post_status The post status. * * @return string */ public static function edit_ad_post_url( $post_id, $post_status = 'publish' ) { if ( $post_status === 'trash' ) { return add_query_arg( array( 'post_status' => 'trash', ), self::admin_ad_post_type_path() ); } return admin_url( 'post.php?post=' . absint( $post_id ) . '&action=edit' ); } /** * URL to create a new ad. * * @return string */ public static function new_ad_post_url() { return admin_url( 'post-new.php?post_type=' . AdCommander::posttype_ad() ); } /** * URL to create a new placement. * * @return string */ public static function new_placement_post_url() { return admin_url( 'post-new.php?post_type=' . AdCommander::posttype_placement() ); } /** * The admin_url for the settings page. * * @return string */ public static function settings_admin_url( $tab = false ) { if ( ! $tab ) { return admin_url( self::admin_path( 'settings' ) ); } $sf = new WOSettings( AdCommander::ns() ); return $sf->get_tab_url( $sf->key( $tab ), self::settings_admin_url() ); } /** * The admin_url for the reports page. * * @return string */ public static function reports_admin_url() { return admin_url( self::admin_path( 'reports' ) ); } /** * The admin_url for the support page. * * @return string */ public static function support_admin_url() { return admin_url( self::admin_path( 'support' ) ); } /** * Link to the plugin manual. * * @param array $args Arguments to add to end of link. * * @return string */ public static function documentation_url( $args = array() ) { return AdCommander::public_site_url( 'documentation', $args ); } /** * Link to the latitude/longitude lookup tool * * @param array $args Arguments to add to end of link. * * @return string */ public static function latlng_url( $args = array() ) { return AdCommander::public_site_url( 'latitude-longitude-lookup', $args ); } /** * Link to a support request. * * @return string */ public static function support_public_url() { return 'https://wordpress.org/support/plugin/ad-commander/'; } /** * Link to report a security issue. * * @param array $args Arguments to add to end of link. * * @return string */ public static function security_issue_url( $args = array() ) { return self::bug_report_url(); } /** * Link to report a bug. * * @param array $args Arguments to add to end of link. * * @return string */ public static function bug_report_url( $args = array() ) { $url = AdCommander::public_site_url( 'support', $args ); $url = add_query_arg( array( 'topic' => urlencode( 'Bug report' ), ), $url ); return $url; } /** * Link to upgrade to pro. * * @param array $args Arguments to add to end of link. * * @return string */ public static function pro_upgrade_url( $args = array() ) { return AdCommander::public_site_url( 'download', $args ); } /** * Link to renew your license. * * @return string */ public static function renew_license_url() { return AdCommander::public_site_url( 'order-history/subscriptions' ); } /** * Link to get priority support. * * @param array $args Arguments to add to end of link. * * @return string */ public static function pro_support_url( $args = array() ) { return AdCommander::public_site_url( 'support', $args ); } /** * Link to get priority support. * * @param array $args Arguments to add to end of link. * * @return string */ public static function newsletter_url( $args = array() ) { return AdCommander::public_site_url( 'newsletter', $args ); } /** * Link to leave a review. * * @return string */ public static function review_url() { return 'https://wordpress.org/support/plugin/ad-commander/reviews/#new-post'; } /** * The action (for use in forms). * * @return string */ public function admin_action() { return self::settings_admin_url(); } /** * The title of the settings page * * @return string */ public function settings_title() { return __( 'Settings', 'ad-commander' ); } /** * The title of the Dashboard page * * @return string */ public function dashboard_title() { return __( 'Dashboard', 'ad-commander' ); } /** * The title of the Manage ads page * * @return string */ public function manage_ads_title() { return __( 'Manage Ads', 'ad-commander' ); } /** * The title of the Manage groups page * * @return string */ public function manage_groups_title() { return __( 'Manage Groups', 'ad-commander' ); } /** * The title of the Manage placements page * * @return string */ public function manage_placements_title() { return __( 'Manage Placements', 'ad-commander' ); } /** * The title of the Reports page * * @return string */ public function reports_title() { return __( 'Reports', 'ad-commander' ); } /** * The title of the Support page * * @return string */ public function support_title() { return __( 'Support', 'ad-commander' ); } /** * Create all of the admin pages. * Also adds the admin page hooks to an array for later use. * * @return void */ public function create_admin_menu() { $dashboard_title = self::dashboard_title(); $notification_count = $this->admin_notifications()->count(); if ( $notification_count > 0 ) { $dashboard_title .= ' ' . absint( $notification_count ) . ''; } $hook = add_menu_page( self::dashboard_title(), AdCommander::title(), AdCommander::capability(), self::admin_slug(), array( $this, 'dashboard_page' ), 'none', 30 ); $this->admin_menu_hooks[ self::admin_slug() ] = $hook; add_submenu_page( self::admin_slug(), self::dashboard_title(), $dashboard_title, AdCommander::capability(), self::admin_slug(), array( $this, 'dashboard_page' ), 1 ); add_submenu_page( self::admin_slug(), self::manage_ads_title(), self::manage_ads_title(), AdCommander::capability(), self::admin_ad_post_type_path(), '', 5 ); add_submenu_page( self::admin_slug(), self::manage_groups_title(), self::manage_groups_title(), AdCommander::capability(), self::admin_group_tax_path(), '', 10 ); add_submenu_page( self::admin_slug(), self::manage_placements_title(), self::manage_placements_title(), AdCommander::capability(), self::admin_placement_post_type_path(), '', 15 ); $hook = add_submenu_page( self::admin_slug(), self::reports_title(), self::reports_title(), AdCommander::capability(), self::admin_slug( 'reports' ), array( $this, 'reports_page' ), 20 ); $this->admin_menu_hooks[ self::admin_slug( 'reports' ) ] = $hook; $hook = add_submenu_page( self::admin_slug(), $this->settings_title(), $this->settings_title(), 'manage_options', self::admin_slug( 'settings' ), array( $this, 'settings_page' ), 50 ); $this->admin_menu_hooks[ self::admin_slug( 'settings' ) ] = $hook; $hook = add_submenu_page( self::admin_slug(), self::support_title(), self::support_title(), AdCommander::capability(), self::admin_slug( 'support' ), array( $this, 'support_page' ), 70 ); $this->admin_menu_hooks[ self::admin_slug( 'support' ) ] = $hook; } /** * The master settings array. * This array will be parsed by other functions to implement various functionality. * We shouldn't have to edit any existing functions to add new options. * Instead, we just modify this array. * * @return array */ public static function settings() { return apply_filters( 'adcmdr_settings', array( 'general' => array( 'title' => __( 'General', 'ad-commander' ), 'initialize' => array( 'render_method' => array( 'callback' => array( '\ADCmdr\Util', 'default_render_method' ) ), 'newwindow' => 1, 'rel_attributes' => array( 'sponsored' ), 'responsive_banners' => 1, 'filter_priority' => Placement::placement_priority_default(), 'disable_virtual_adstxt' => array( 'callback' => array( '\ADCmdr\AdsTxt', 'should_disable_ads_txt_on_plugin_activation' ) ), 'prefix' => Util::prefix(), ), 'sections' => array( 'general' => array( 'title' => __( 'General', 'ad-commander' ), 'fields' => array( 'render_method' => __( 'Ad & Group Rendering', 'ad-commander' ), 'ad_label' => __( 'Ad Label', 'ad-commander' ), 'prefix' => __( 'Class/ID Prefix', 'ad-commander' ), 'lazy_load_ads' => __( 'Lazy Load Ads', 'ad-commander' ), 'loading_animation' => __( 'Loading Animation', 'ad-commander' ), ), ), 'defaults' => array( 'title' => __( 'Default Banner Ad Settings', 'ad-commander' ), 'fields' => array( 'newwindow' => __( 'Link Target', 'ad-commander' ), 'rel_attributes' => __( 'Link Rel Attributes', 'ad-commander' ), 'responsive_banners' => __( 'Responsive Ad Images', 'ad-commander' ), ), ), 'disable_ads' => array( 'title' => __( 'Disable Ads', 'ad-commander' ), 'fields' => array( 'disable_all' => __( 'Disable All Ads', 'ad-commander' ), 'disable_user_roles' => __( 'Disable Ads for User Roles', 'ad-commander' ), 'bots_disable_ads' => __( 'Disable Ads for Bots', 'ad-commander' ), ), ), 'ads_txt' => array( 'title' => __( 'Virtual ads.txt', 'ad-commander' ), 'fields' => array( 'disable_virtual_adstxt' => __( 'Disable Ads.txt', 'ad-commander' ), 'ads_txt_records' => __( 'Ads.txt Records', 'ad-commander' ), ), ), 'advanced_settings' => array( 'title' => __( 'Advanced / Miscellaneous', 'ad-commander' ), 'fields' => array( 'filter_priority' => __( 'Placement Filter Priority', 'ad-commander' ), 'disable_stylesheets' => __( 'Disable Plugin Stylesheets', 'ad-commander' ), ), ), ), ), 'adsense' => array( 'title' => __( 'AdSense', 'ad-commander' ), 'sections' => array( 'adsense' => array( 'title' => __( 'AdSense Account', 'ad-commander' ), 'fields' => array( 'adsense_account' => __( 'AdSense Account', 'ad-commander' ), 'disable_adsense_account_alerts' => __( 'AdSense Alerts', 'ad-commander' ), ), ), 'auto_ads' => array( 'title' => __( 'Auto Ads', 'ad-commander' ), 'fields' => array( 'insert_adsense_head_code' => __( 'Insert AdSense Code', 'ad-commander' ), 'enable_amp_auto_ads' => __( 'AMP Auto Ads', 'ad-commander' ), ), ), 'amp_defaults' => array( 'title' => __( 'Default AMP Settings', 'ad-commander' ), 'fields' => array( 'adsense_amp_ad_mode' => __( 'AdSense AMP ads', 'ad-commander' ), ), ), ), ), 'tracking' => array( 'title' => __( 'Tracking', 'ad-commander' ), 'initialize' => array( 'enable_local_tracking' => 1, ), 'sections' => array( 'tracking_methods' => array( 'title' => __( 'Tracking Method', 'ad-commander' ), 'fields' => array( 'enable_local_tracking' => __( 'Local Tracking', 'ad-commander' ), 'disable_amp_pixel' => array( 'title' => '', 'restricted' => 'enable_local_tracking', ), 'enable_ga_tracking' => __( 'Google Analytics (GA4)', 'ad-commander' ), 'disable_amp_analytics' => array( 'title' => '', 'restricted' => 'enable_ga_tracking', ), 'ga_tracking_ids' => array( 'title' => __( 'GA Tracking IDs', 'ad-commander' ), 'restricted' => 'enable_ga_tracking', ), 'ga_anonymize_ip' => array( 'title' => __( 'GA Anonymize IP', 'ad-commander' ), 'restricted' => 'enable_ga_tracking', ), 'enable_3p_tracking' => __( 'Third-Party Tracking', 'ad-commander' ), ), ), 'disable_tracking' => array( 'title' => __( 'Disable Tracking', 'ad-commander' ), 'fields' => array( 'disable_track_impressions' => __( 'Impression Tracking', 'ad-commander' ), 'disable_track_clicks' => __( 'Click tracking', 'ad-commander' ), 'bots_disable_tracking' => __( 'Disable Tracking for Bots', 'ad-commander' ), ), ), ), ), 'targeting' => array( 'title' => __( 'Targeting', 'ad-commander' ), 'sections' => array( 'geotargeting' => array( 'title' => __( 'Geotargeting', 'ad-commander' ), 'fields' => array( 'geo_service' => __( 'Geolocation Service', 'ad-commander' ), 'maxmind_license_key' => array( 'title' => __( 'MaxMind License Key', 'ad-commander' ), 'restricted' => 'geo_service', 'restricted_val' => 'maxmind', ), 'maxmind_database_update' => array( 'title' => __( 'MaxMind Database', 'ad-commander' ), 'restricted' => 'geo_service', 'restricted_val' => 'maxmind', ), ), ), ), ), 'privacy' => array( 'title' => __( 'Consent', 'ad-commander' ), 'sections' => array( 'consent' => array( // 'title' => __( 'consent', 'ad-commander' ), 'fields' => array( 'consent_required' => __( 'Require Consent', 'ad-commander' ), 'consent_cookie_name' => array( 'title' => __( 'Consent Cookie Name', 'ad-commander' ), 'restricted' => 'consent_required', ), 'consent_cookie_value' => array( 'title' => __( 'Consent Cookie Value', 'ad-commander' ), 'restricted' => 'consent_required', ), 'consent_cookie_comparison' => array( 'title' => __( 'Cookie Comparison', 'ad-commander' ), 'restricted' => 'consent_required', ), ), ), ), ), 'admin' => array( 'title' => __( 'Admin', 'ad-commander' ), 'sections' => array( 'onboarding' => array( 'title' => __( 'Onboarding', 'ad-commander' ), 'fields' => array( 'disable_onboarding_global' => __( 'Disable Onboarding Message', 'ad-commander' ), 'disable_onboarding_ads' => __( 'Disable Ad Message', 'ad-commander' ), ), ), 'misc' => array( 'title' => __( 'Miscellaneous', 'ad-commander' ), 'fields' => array( 'disable_doc_links' => __( 'Disable Help Links', 'ad-commander' ), 'allow_editors' => __( 'Allow editors to manage', 'ad-commander' ), 'delete_data' => __( 'Delete data on deactivation', 'ad-commander' ), ), ), ), ), 'addons' => array( 'title' => __( 'Add-ons', 'ad-commander' ), 'sections' => array( 'licenses' => array( 'title' => __( 'Pro', 'ad-commander' ), 'fields' => array( 'pro_license_key' => __( 'Pro License', 'ad-commander' ), ), ), ), ), ) ); } /** * Add settings for mulsisite installations. * This is not currently in use but may be added in the future. * * @param array $settings The filtered settings array. * * @return array */ public function multisite_settings( $settings ) { if ( is_multisite() ) { /** * This is currently not in use, because adding unfiltered HTML capabilities is dangerous. * If we can find a safe way to grant this permission, we may do so in the future. */ if ( current_user_can( 'unfiltered_html' ) ) { $settings['admin']['sections']['multisite'] = array( 'title' => __( 'Multisite', 'ad-commander' ), 'fields' => array( 'allow_unfiltered_html' => __( 'Allow unfiltered HTML', 'ad-commander' ), ), ); } } return $settings; } /** * Start the wrap. * * @return void */ protected function start_wrap() { $this->sf()->start(); } /** * End the wrap. * * @return void */ protected function end_wrap() { $this->sf()->end(); } /** * Branded Ad Commander header for plugin admin pages. * * @return void */ public function adcmdr_admin_header() { if ( $this->is_screen() ) : ?>
is_pro_loaded() ) : ?>
should_onboard( 'global' ) ) { if ( ! $this->is_screen() || $this->is_screen( array( $this->admin_menu_hooks[ self::admin_slug() ], $this->admin_menu_hooks[ self::admin_slug( 'support' ) ] ) ) ) { $admin_onboarding->onboarding_notice(); } } } /** * Start the poststuff div. * * @param array $classes Classes applied to poststuff div. * * @return void */ protected function start_poststuff( $classes = array() ) { $classes = Util::arrayify( $classes ); $classes[] = Util::ns( 'poststuff' ); ?>
true ) ) { $classes = Util::arrayify( $classes ); $html = '
'; if ( ! $args['display'] ) { return wp_kses_post( $html ); } echo wp_kses_post( $html ); } /** * End the poststuff div. * * @return void */ protected function end_poststuff() { $this->end_div(); } /** * End a div. * * @param array $args An array of arguments. * * @return void|string */ protected function end_div( $args = array( 'display' => true ) ) { $html = '
'; if ( ! $args['display'] ) { return wp_kses_post( $html ); } echo wp_kses_post( $html ); } /** * Create a postbox. * * @param string $title Title of post box. * @param string $content Content in post box. * @param array $classes Classes on postbox. * * @return void */ protected function postbox( $title, $content, $classes = array() ) { $classes = Util::arrayify( $classes ); $classes[] = 'postbox'; $classes[] = Util::ns( 'postbox' ); ?>

admin_dashboard()->page(); } /** * Display the reports page. * * @return void */ public function reports_page() { $this->admin_reports()->page(); } /** * Display the support page. * * @return void */ public function support_page() { $this->admin_support()->page(); } /** * Display the settings page. * * @return void */ public function settings_page() { $this->sf()->settings_page( $this->settings_title(), self::settings_admin_url(), self::settings() ); } /** * Register settings from settings array. * * @return void */ public function register_settings() { $this->sf()->add_sections_and_settings( $this->settings(), $this ); } /** * Sanitize input by type. * * @param array $input The input to sanitize. * * @return array */ private function sanitize_by_key_type( $input ) { $output = array(); if ( $input ) { foreach ( $input as $key => $value ) { switch ( $key ) { case 'render_method': case 'adsense_account': case 'ga_tracking_ids': case 'rel_attributes': case 'geo_service': case 'maxmind_license_key': case 'maxmind_database_update': case 'ad_label_text': case 'pro_license_key': case 'disable_user_roles': case 'consent_cookie_name': case 'consent_cookie_value': case 'consent_cookie_comparison': case 'prefix': case 'adsense_amp_ad_mode': $type = 'str'; break; case 'filter_priority': case 'automatic_placement': $type = 'int'; break; case 'ads_txt_records': $type = 'textarea'; break; default: // wo_log( 'missing type for ' . $key ); $type = 'bool'; break; } $output[ $key ] = WOAdmin::sanitize_by_type( $value, $type ); } } return $output; } /** * Sanitize general group. * * @param array $input The input to sanitize. * * @return array */ public function sanitize_adcmdr_general( $input ) { Maintenance::flush_css_transients(); return $this->sanitize_by_key_type( $input ); } /** * Sanitize admin group. * * @param array $input The input to sanitize. * * @return array */ public function sanitize_adcmdr_admin( $input ) { return $this->sanitize_by_key_type( $input ); } /** * Sanitize tracking group. * * @param array $input The input to sanitize. * * @return array */ public function sanitize_adcmdr_tracking( $input ) { return $this->sanitize_by_key_type( $input ); } /** * Sanitize adsense group. * * @param array $input The input to sanitize. * * @return array */ public function sanitize_adcmdr_adsense( $input ) { return $this->sanitize_by_key_type( $input ); } /** * Sanitize privacy group. * * @param array $input The input to sanitize. * * @return array */ public function sanitize_adcmdr_privacy( $input ) { return $this->sanitize_by_key_type( $input ); } /** * Sanitize geotargeting group. * * @param array $input The input to sanitize. * * @return array */ public function sanitize_adcmdr_targeting( $input ) { return $this->sanitize_by_key_type( $input ); } /** * Sanitize add-on group. * * @param array $input The input to sanitize. * * @return array */ public function sanitize_adcmdr_addons( $input ) { return $this->sanitize_by_key_type( $input ); } /** * Create an underscored key from a string. * * @param string $key The key to convert. * * @return string */ public function _key( $key ) { return str_replace( '-', '_', $key ); } /** * Create a nonce array. * This is not an actual nonce. This array is used for creating and checking unique nonces. * * @param string $action The action.. * @param string $key The key to create the nonce string from. * * @return array */ protected function nonce( $action, $key ) { return array( 'action' => $action, 'name' => $this->nonce_string( $key ), ); } /** * Create a nonce field. * * @param array $nonce_arr A nonce array. * @param bool $referrer Whether to include the referrer field. * * @return void */ protected function nonce_field( $nonce_arr, $referrer = false ) { wp_nonce_field( $nonce_arr['action'], $nonce_arr['name'], $referrer ); } /** * Create a string for use in your nonce. * * @param string $action Action name. * * @return string */ protected function nonce_string( $action ) { return sanitize_title( Util::ns( 'n-' . $action ) ); } /** * Create an action string for use in your nonce. * * @param string $action Action name. * * @return string */ protected function action_string( $action ) { return self::_key( sanitize_title( Util::ns( $action, '_' ) ) ); } /** * Authorizes actions for non-settings pages. * Interfaces with WOAdmin to check nonce, capability, and required $_POST keys. * * @param mixed $action_key The action key to authorized. * @param array $required_post Any required post keys. * @param string|bool $capability The capability required to process this action. * * @return void */ protected function check_ajax_action( $action_key, $required_post = array(), $capability = false ) { /** * In some cases we may want 'manage_options' instead of the custom AdCommander::capability(). * This would be for anything in the Settings section. * * Other areas use the custom cap so that editors can manage ads, groups, etc., if allowed. */ if ( ! $capability ) { $capability = AdCommander::capability(); } $this->authorize_ajax_action( $this->nonce_string( $action_key ), 'security', $capability, $required_post ); } /** * Call back for settings section. * * @return void */ public function settings_callback_adcmdr_defaults() { ?>

info( sprintf( __( 'Consent management only partially works with server-side rendering. %1$sUpdate render settings.%2$s %3$s', 'ad-commander' ), '', '', Doc::doc_link( 'requiring_consent', false, __( 'Learn more', 'ad-commander' ) ) ), array( 'adcmdr-metaitem__warning' ) ); } ?>

pro_license_status(); if ( $old_license && ! in_array( $status, array( 'processing', 'pending', 'deactivated' ) ) ) { ProBridge::instance()->pro_license_deactivate( $old_license ); } ProBridge::instance()->pro_license_reset_status( true, ( $new_license ) ? true : false ); } } return $new_value; } /** * Callback for settings field. * * @return void */ public function field_adcmdr_pro_license_key() { $pro_bridge = ProBridge::instance(); if ( $pro_bridge->is_pro_loaded() ) { $id = array( $this->sf()->key( 'addons' ) => 'pro_license_key' ); $current_value = $this->sf()->get( 'pro_license_key', 'addons' ); $disabled = false; $message = null; $clr = 'neutral'; $status = $pro_bridge->pro_license_status(); if ( $current_value || $status ) { if ( $status === 'pending' || $status === 'processing' ) { $message = '' . esc_html__( 'License update is pending...', 'ad-commander' ); } elseif ( $status === 'valid' ) { $clr = 'yes'; $message = ' ' . esc_html__( 'License key active.', 'ad-commander' ); } elseif ( $status === 'expired' ) { $clr = 'no'; /* translators: %1$s: anchor tag with URL, %2$s call to action text, %3$s: close anchor tag */ $message = ' ' . sprintf( esc_html__( 'License key expired - %1$s%2$s%3$s', 'ad-commander' ), '', esc_html__( 'Renew your license', 'ad-commander' ) . ' >', '' ); } elseif ( in_array( $status, License::no_seats_license_statuses() ) ) { $clr = 'no'; /* translators: %1$s: anchor tag with URL, %2$s call to action text, %3$s: close anchor tag */ $message = ' ' . sprintf( esc_html__( 'License has no remaining activations - %1$s%2$s%3$s', 'ad-commander' ), '', esc_html__( 'Purchase a new license', 'ad-commander' ) . ' >', '' ); } elseif ( in_array( $status, License::invalid_license_statuses() ) ) { $clr = 'no'; /* translators: %1$s: response code, %2$s anchor tag with URL, %3$s call to action text, %4$s: close anchor tag */ $message = ' ' . sprintf( esc_html__( 'License key invalid (response code: %1$s) - %2$s%3$s%4$s', 'ad-commander' ), sanitize_text_field( $status ), '', esc_html__( 'Purchase a license', 'ad-commander' ) . ' >', '' ); } elseif ( $status !== 'deactivated' ) { $clr = 'no'; /* translators: %1$s: anchor tag with URL, %2$s call to action text, %3$s: close anchor tag */ $message = ' ' . sprintf( esc_html__( 'An unkonwn error occurred - Please %1$s%2$s%3$s', 'ad-commander' ), '', esc_html__( 'contact support', 'ad-commander' ) . ' >', '' ); } $pro_bridge->enqueue_pro_license_script_data( $status ); } $this->sf()->input( $id, $current_value, 'text', array( 'disabled' => $disabled ) ); if ( $message ) { $this->sf()->message( '' . $message . '' ); } } else { echo wp_kses_post( $this->get_addons() ); } } /** * Callback for settings field. * * @return void */ public function field_adcmdr_geo_service() { $id = array( $this->sf()->key( 'targeting' ) => 'geo_service' ); $current_value = null; $args = array( 'empty_text' => __( 'Select a service', 'ad-commander' ), ); $options = array( 'disabled:maxmind' => __( 'MaxMind', 'ad-commander' ), ); if ( ProBridge::instance()->is_pro_loaded() ) { $current_value = $this->sf()->get( 'geo_service', 'targeting' ); $pro_options = array(); foreach ( $options as $key => $text ) { $pro_options[ str_replace( 'disabled:', '', $key ) ] = $text; } $options = $pro_options; } else { $args['empty_text'] .= ProBridge::pro_label(); } $this->sf()->select( $id, $options, $current_value, $args ); Doc::doc_link( 'geo_targeting' ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_maxmind_license_key() { if ( ProBridge::instance()->is_pro_loaded() ) { $this->admin_geo()->field_maxmind_license_key(); } } /** * Callback for settings field. * * @return void */ public function field_adcmdr_maxmind_database_update() { if ( ProBridge::instance()->is_pro_loaded() ) { $this->admin_geo()->field_maxmind_database_update(); } } /** * Callback for settings field. * * @return void */ public function field_adcmdr_render_method() { $pro_only = array( 'clientside', 'smart' ); $render_options = array( 'serverside' => esc_html__( 'Server-side', 'ad-commander' ), 'smart' => esc_html__( 'Smart (Combination)', 'ad-commander' ), 'clientside' => esc_html__( 'Client-side Only', 'ad-commander' ), ); $options = $render_options; if ( ! ProBridge::instance()->is_pro_loaded() ) { $no_pro_options = array(); foreach ( $render_options as $key => $text ) { if ( in_array( $key, $pro_only ) ) { $no_pro_options[ 'disabled:' . $key ] = $text . ProBridge::pro_label(); } else { $no_pro_options[ $key ] = $text; } } $options = $no_pro_options; } $message = array( '' . $render_options['serverside'] . esc_html__( ':', 'ad-commander' ) . ' ' . esc_html__( 'Render ads with other page content. Not usually compatible with page caching and some targeting settings.', 'ad-commander' ), '' . $render_options['smart'] . esc_html__( ':', 'ad-commander' ) . ' ' . esc_html__( 'Client-side if group settings, targeting methods, or other settings are likely to conflict with page caching. Otherwise, uses server-side.', 'ad-commander' ), '' . $render_options['clientside'] . esc_html__( ':', 'ad-commander' ) . ' ' . esc_html__( 'Render ads after other page content loads using javascript. Circumvents page caching and works with all visitor targeting methods.', 'ad-commander' ), ); array_walk( $message, function ( &$item ) { $item = '
  • • ' . $item . '
  • '; } ); $message = ''; $id = array( $this->sf()->key( 'general' ) => 'render_method' ); $current_value = $this->sf()->get( 'render_method', 'general' ); $this->sf()->select( $id, $options, $current_value ? $current_value : array_key_first( $options ), ); Doc::doc_link( 'rendering' ); $this->sf()->message( $message ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_ad_label() { $id = array( $this->sf()->key( 'general' ) => 'ad_label' ); $this->sf()->checkbox( $id, $this->sf()->get( 'ad_label', 'general' ) ); $this->sf()->label( $id, __( 'Display ad label above ads or groups', 'ad-commander' ) ); echo wp_kses_post( '
    ' ); $id = array( $this->sf()->key( 'general' ) => 'ad_label_text' ); $this->sf()->input( $id, $this->sf()->get( 'ad_label_text', 'general', __( 'Advertisement', 'ad-commander' ) ) ); echo wp_kses_post( '
    ' ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_prefix() { $id = array( $this->sf()->key( 'general' ) => 'prefix' ); $this->sf()->input( $id, $this->sf()->get( 'prefix', 'general', Util::prefix() ) ); $this->sf()->message( __( 'Using a unique prefix may help circumvent ad blockers. Recommended length is 5-7 characters and it should contain only alpha letters.', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_loading_animation() { $id = array( $this->sf()->key( 'general' ) => 'loading_animation' ); $this->sf()->checkbox( $id, $this->sf()->get( 'loading_animation', 'general' ) ); $this->sf()->label( $id, __( 'Show loading animation before ads display', 'ad-commander' ) ); $this->sf()->message( __( 'Only applies to ads and groups loaded client-side, and only to the first ad on the page.', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_lazy_load_ads() { $id = array( $this->sf()->key( 'general' ) => 'lazy_load_ads' ); $label = __( "Don't load ads until they enter viewport", 'ad-commander' ); $current_value = 0; $disabled = true; if ( ProBridge::instance()->is_pro_loaded() ) { $current_value = $this->sf()->get( 'lazy_load_ads', 'general' ); $disabled = false; } else { $label .= ProBridge::pro_label(); } $this->sf()->checkbox( $id, $current_value, 1, array( 'disabled' => $disabled ) ); $this->sf()->label( $id, $label ); Doc::doc_link( 'lazy_load_ads' ); $message = esc_html__( 'Lazy loading ads requires smart or client-side rendering.', 'ad-commander' ); if ( ! $disabled && $current_value === 1 && Util::render_method() === 'serverside' ) { $message = '' . $message . ''; } $message .= ' ' . esc_html__( 'If tracking is enabled, impressions will track when the ad loads.', 'ad-commander' ); $this->sf()->message( $message ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_onboarding_global() { $id = array( $this->sf()->key( 'admin' ) => 'disable_onboarding_global' ); $this->sf()->checkbox( $id, $this->sf()->get( 'disable_onboarding_global', 'admin' ) ); $this->sf()->label( $id, __( 'Disable onboarding message and help links', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_onboarding_ads() { $id = array( $this->sf()->key( 'admin' ) => 'disable_onboarding_ads' ); $this->sf()->checkbox( $id, $this->sf()->get( 'disable_onboarding_ads', 'admin' ) ); $this->sf()->label( $id, __( 'Disable message that appears after new ad is published', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_doc_links() { $id = array( $this->sf()->key( 'admin' ) => 'disable_doc_links' ); $this->sf()->checkbox( $id, $this->sf()->get( 'disable_doc_links', 'admin' ) ); $this->sf()->label( $id, __( 'Disable documentation links throughout plugin', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_virtual_adstxt() { $id = array( $this->sf()->key( 'general' ) => 'disable_virtual_adstxt' ); $disabled = false; $disabled_text = ''; $current_value = $this->sf()->get( 'disable_virtual_adstxt', 'general' ); $ads_txt = new AdsTxt(); $can_generate = $ads_txt->can_generate_ads_txt( true ); if ( $can_generate === false || ( is_array( $can_generate ) && isset( $can_generate['can'] ) && $can_generate['can'] === false ) ) { if ( isset( $can_generate['message'] ) && $can_generate['message'] !== '' ) { $disabled_text = $can_generate['message']; } else { $disabled_text = __( 'Virtual ads.txt is disabled due to incompatibility with your site.', 'ad-commander' ); } $disabled = true; $current_value = 1; } elseif ( $ads_txt->alternate_file_exists() ) { $disabled_text = __( 'A physical ads.txt or one generated by another plugin already exists. We suggest disabling this setting or removing the other ads.txt.', 'ad-commander' ); } elseif ( is_array( $can_generate ) && isset( $can_generate['message'] ) && $can_generate['message'] !== '' ) { $disabled_text = $can_generate['message']; } $this->sf()->checkbox( $id, $current_value, 1, array( 'disabled' => $disabled ) ); $this->sf()->label( $id, __( 'Do not generate a virtual ads.txt', 'ad-commander' ) ); if ( $disabled_text !== '' ) { $this->info( $disabled_text, array( 'adcmdr-metaitem__warning' ) ); } } /** * Callback for settings field. * * @return void */ public function field_adcmdr_ads_txt_records() { $id = array( $this->sf()->key( 'general' ) => 'ads_txt_records' ); $this->sf()->message( __( 'One record per line. AdSense is automatically included if publisher ID is set. Add additional records here.', 'ad-commander' ) ); $ads_txt = new AdsTxt(); $output = $ads_txt->adsense_ads_txt_line(); if ( $output != '' ) { $this->sf()->message( '' . $output . '', array( 'classes' => 'adcmdr-readonly', 'element' => 'div', ) ); } $this->sf()->textarea( $id, $this->sf()->get( 'ads_txt_records', 'general' ) ); /* translators: %1$s: anchor tag with URL, %2$s text representation of URL, %3$s: close anchor tag */ $message = sprintf( __( 'You can preview your ads.txt at %1$s%2$s%3$s', 'ad-commander' ), '', site_url( 'ads.txt' ), '' ); $this->sf()->message( $message ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_newwindow() { $id = array( $this->sf()->key( 'general' ) => 'newwindow' ); $this->sf()->checkbox( $id, $this->sf()->get( 'newwindow', 'general' ) ); $this->sf()->label( $id, __( 'Open links in a new window', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_rel_attributes() { $id = array( $this->sf()->key( 'general' ) => 'rel_attributes' ); $checkboxes = array( 'sponsored' => 'rel=sponsored', 'nofollow' => 'rel=nofollow', 'noreferrer' => 'rel=noreferer', 'noopener' => 'rel=noopener', ); $this->sf()->checkgroup( $id, $checkboxes, $this->sf()->get( 'rel_attributes', 'general' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_responsive_banners() { $id = array( $this->sf()->key( 'general' ) => 'responsive_banners' ); $this->sf()->checkbox( $id, $this->sf()->get( 'responsive_banners', 'general' ) ); $this->sf()->label( $id, __( 'Include responsive styles for images in ads', 'ad-commander' ) ); /* translators: %1$s: CSS 'auto' code, %2$s, CSS '100%' code */ $message = sprintf( __( 'Images will have max-width set to %1$s and height set to %2$s. Theme styles may override this setting.', 'ad-commander' ), '100%', 'auto' ); $this->sf()->message( $message ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_filter_priority() { $id = array( $this->sf()->key( 'general' ) => 'filter_priority' ); $priority = $this->sf()->get( 'filter_priority', 'general' ); $this->sf()->input( $id, $priority ? $priority : Placement::placement_priority_default(), 'number' ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_stylesheets() { $id = array( $this->sf()->key( 'general' ) => 'disable_stylesheets' ); $this->sf()->checkbox( $id, $this->sf()->get( 'disable_stylesheets', 'general' ) ); $this->sf()->label( $id, __( 'Disable all front-end plugin stylesheets (some ads may not display correctly)', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_bots_disable_ads() { $id = array( $this->sf()->key( 'general' ) => 'bots_disable_ads' ); $this->sf()->checkbox( $id, $this->sf()->get( 'bots_disable_ads', 'general' ) ); $this->sf()->label( $id, __( 'Hide ads for suspected bots - use with caution', 'ad-commander' ) ); Doc::doc_link( 'bots' ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_all() { $id = array( $this->sf()->key( 'general' ) => 'disable_all' ); $this->sf()->checkbox( $id, $this->sf()->get( 'disable_all', 'general' ) ); $this->sf()->label( $id, __( 'Disable all ads for everyone', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_user_roles() { $roles = TargetingVisitor::parse_roles_to_values(); $id = array( $this->sf()->key( 'general' ) => 'disable_user_roles' ); $this->sf()->checkgroup( $id, $roles, $this->sf()->get( 'disable_user_roles', 'general' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_allow_editors() { $id = array( $this->sf()->key( 'admin' ) => 'allow_editors' ); $this->sf()->checkbox( $id, $this->sf()->get( 'allow_editors', 'admin' ) ); $this->sf()->label( $id, __( 'Allow editors to manage Ad Commander', 'ad-commander' ) ); $this->sf()->message( __( 'Only administrators - or those with manage_options capability - will have access to settings.', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_allow_unfiltered_html() { $id = array( $this->sf()->key( 'admin' ) => 'allow_unfiltered_html' ); $this->sf()->checkbox( $id, $this->sf()->get( 'allow_unfiltered_html', 'admin' ) ); $this->sf()->label( $id, __( 'Allow unfiltered HTML by administrators and editors', 'ad-commander' ) ); $this->sf()->message( __( 'By default, only Super Admins can add unfiltered HTML in a multisite installation.', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_delete_data() { $id = array( $this->sf()->key( 'admin' ) => 'delete_data' ); $this->sf()->checkbox( $id, $this->sf()->get( 'delete_data', 'admin' ) ); /* translators: %1$s: open span tag with class; %2$s close span tag */ $this->sf()->label( $id, sprintf( __( '%1$sDANGER:%2$s Delete all plugin data (ads, groups, stats, options, etc) when plugin deactivated', 'ad-commander' ), '', '' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_track_impressions() { $id = array( $this->sf()->key( 'tracking' ) => 'disable_track_impressions' ); $this->sf()->checkbox( $id, $this->sf()->get( 'disable_track_impressions', 'tracking' ) ); $this->sf()->label( $id, __( 'Disable impression tracking for all ads', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_track_clicks() { $id = array( $this->sf()->key( 'tracking' ) => 'disable_track_clicks' ); $this->sf()->checkbox( $id, $this->sf()->get( 'disable_track_clicks', 'tracking' ) ); $this->sf()->label( $id, __( 'Disable click tracking for all ads', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_enable_local_tracking() { $id = array( $this->sf()->key( 'tracking' ) => 'enable_local_tracking' ); $this->sf()->checkbox( $id, $this->sf()->get( 'enable_local_tracking', 'tracking' ) ); $this->sf()->label( $id, __( 'Enable local tracking', 'ad-commander' ) ); Doc::doc_link( 'tracking_methods' ); $this->sf()->message( __( 'Local tracking is required for Ad Commander reports and to expire ads at maximum impressions or clicks. If not using this features, disabling may increase performance.', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_enable_3p_tracking() { $id = array( $this->sf()->key( 'tracking' ) => 'enable_3p_tracking' ); $label = __( 'Enable 3rd-party tracking', 'ad-commander' ); $current_value = 0; $disabled = true; if ( ProBridge::instance()->is_pro_loaded() ) { $current_value = $this->sf()->get( 'enable_3p_tracking', 'tracking' ); $disabled = false; } else { $label .= ProBridge::pro_label(); } $this->sf()->checkbox( $id, $current_value, 1, array( 'disabled' => $disabled ) ); $this->sf()->label( $id, $label ); Doc::doc_link( 'third_party_tracking' ); $this->sf()->message( __( 'Third-party tracking requires implementation of custom tracking code. See help doc for more information.', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_enable_ga_tracking() { $id = array( $this->sf()->key( 'tracking' ) => 'enable_ga_tracking' ); $label = __( 'Enable Google Analytics tracking', 'ad-commander' ); $disabled = true; $current_value = 0; if ( ProBridge::instance()->is_pro_loaded() ) { $current_value = $this->sf()->get( 'enable_ga_tracking', 'tracking' ); $disabled = false; } else { $label .= ProBridge::pro_label(); } $this->sf()->checkbox( $id, $current_value, 1, array( 'disabled' => $disabled ) ); $this->sf()->label( $id, $label ); Doc::doc_link( 'tracking_methods' ); $this->sf()->message( __( 'GA tracking will send events for impression and click to Google Analytics.', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_ga_tracking_ids() { $id = array( $this->sf()->key( 'tracking' ) => 'ga_tracking_ids' ); $this->sf()->input( $id, $this->sf()->get( 'ga_tracking_ids', 'tracking' ) ); /* translators: %1$s: sample Google Analytics ID */ $this->sf()->message( sprintf( __( 'One or more GA4 property IDs where clicks and impressions should be sent. Comma separated. Example: %1$s', 'ad-commander' ), 'G-XXXXXXXXXX' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_ga_anonymize_ip() { $id = array( $this->sf()->key( 'tracking' ) => 'ga_anonymize_ip' ); $this->sf()->checkbox( $id, $this->sf()->get( 'ga_anonymize_ip', 'tracking' ) ); $this->sf()->label( $id, __( 'Tell Google Ananlytics to anonymize IPs', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_amp_analytics() { $id = array( $this->sf()->key( 'tracking' ) => 'disable_amp_analytics' ); $this->sf()->checkbox( $id, $this->sf()->get( 'disable_amp_analytics', 'tracking' ) ); $this->sf()->label( $id, __( 'Disable AMP analytics', 'ad-commander' ) ); $this->sf()->message( esc_html__( 'Used for GA impression tracking of AMP sites.', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_amp_pixel() { $id = array( $this->sf()->key( 'tracking' ) => 'disable_amp_pixel' ); $this->sf()->checkbox( $id, $this->sf()->get( 'disable_amp_pixel', 'tracking' ) ); $this->sf()->label( $id, __( 'Disable AMP pixel', 'ad-commander' ) ); $this->sf()->message( esc_html__( 'Used for local impression tracking of AMP sites.', 'ad-commander' ) ); if ( ! is_ssl() ) { $this->info( esc_html__( 'AMP pixel requires your site to use HTTPS.', 'ad-commander' ), array( 'adcmdr-metaitem__warning' ) ); } } /** * Callback for settings field. * * @return void */ public function field_adcmdr_bots_disable_tracking() { $id = array( $this->sf()->key( 'tracking' ) => 'bots_disable_tracking' ); $this->sf()->checkbox( $id, $this->sf()->get( 'bots_disable_tracking', 'tracking' ) ); $this->sf()->label( $id, __( 'Disable tracking for bots - use with caution', 'ad-commander' ) ); Doc::doc_link( 'bots' ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_adsense_account() { $pub_id = $this->sf()->get( 'adsense_account', 'adsense' ); $adsense_connected = AdminAdsense::instance()->has_access_token( $pub_id ); if ( $adsense_connected && ! $pub_id ) { AdminAdsense::instance()->revoke_access( $pub_id ); $adsense_connected = false; } ?>
    disabled>
    sf()->message( esc_html__( 'Or enter your publisher ID manually for limited functionality.', 'ad-commander' ) ); } elseif ( $adsense_connected && $pub_id ) { $adsense_api = AdminAdSense::get_adsense_api_account(); if ( isset( $adsense_api['accounts'][ $pub_id ] ) && isset( $adsense_api['accounts'][ $pub_id ]['account_details'] ) ) { $pub_label .= ' (' . '' . esc_html( $adsense_api['accounts'][ $pub_id ]['account_details']['account_name'] ) . ')'; } if ( ! Options::instance()->get( 'disable_adsense_account_alerts', 'adsense', true ) ) { $alerts = AdminNotifications::instance()->test_adsense_alerts(); if ( $alerts && ! empty( $alerts ) ) { $account_message = $this->info( ' ' . '' . esc_html__( 'View account alerts', 'ad-commander' ) . ' >', array( 'adcmdr-metaitem__warning' ), array( 'display' => false ) ); } } } $pub_label .= esc_html_x( ':', 'After publisher ID label', 'ad-commander' ); $id = array( $this->sf()->key( 'adsense' ) => 'adsense_account' ); $this->sf()->label( $id, $pub_label ); echo '
    '; $this->sf()->input( $id, $pub_id, 'text', array( 'placeholder' => 'pub-XXXXXXXXXX', 'readonly' => (bool) $adsense_connected, ) ); if ( ! $adsense_connected && $pub_id && ! AdSense::instance()->is_publisher_id_valid( $pub_id ) ) { $this->info( esc_html__( 'Your publisher ID appears to be an invalid format. It should start with pub-', 'ad-commander' ), array( 'adcmdr-metaitem__error' ) ); } echo wp_kses_post( $account_message ); ?>

    sf()->key( 'adsense' ) => 'adsense_amp_ad_mode' ); $modes = AdSense::amp_modes(); unset( $modes['site_default'] ); $disabled = ! ProBridge::instance()->is_pro_loaded(); if ( $disabled ) { $modes = Util::disable_options( $modes ); foreach ( $modes as $key => $text ) { $modes[ $key ] = $text . ProBridge::instance()->pro_label(); } } $this->sf()->radiogroup( $id, $modes, $this->sf()->get( 'adsense_amp_ad_mode', 'adsense', 'automatic' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_insert_adsense_head_code() { $id = array( $this->sf()->key( 'adsense' ) => 'insert_adsense_head_code' ); $this->sf()->checkbox( $id, $this->sf()->get( 'insert_adsense_head_code', 'adsense' ) ); $this->sf()->label( $id, __( 'Insert AdSense script in head on every page (for auto ads and site verification)', 'ad-commander' ) ); if ( Options::instance()->get( 'insert_adsense_head_code', 'adsense', true ) ) { $this->sf()->message( '' . htmlentities( AdSense::instance()->get_adsense_script_tag( false, 'pub-XXXXXXXXXX' ) ) . '' ); } } /** * Callback for settings field. * * @return void */ public function field_adcmdr_enable_amp_auto_ads() { $id = array( $this->sf()->key( 'adsense' ) => 'enable_amp_auto_ads' ); $this->sf()->checkbox( $id, $this->sf()->get( 'enable_amp_auto_ads', 'adsense' ) ); $this->sf()->label( $id, __( 'Insert AMP auto ads code on every page', 'ad-commander' ) ); if ( Options::instance()->get( 'enable_amp_auto_ads', 'adsense', true ) ) { $this->sf()->message( '' . htmlentities( Amp::instance()->get_amp_auto_ads_script_tag() ) . '' ); $this->sf()->message( '' . htmlentities( Amp::instance()->get_amp_auto_ads_element( false, 'pub-XXXXXXXXXX' ) ) . '' ); if ( ! Amp::instance()->has_amp_plugin() ) { $this->info( __( 'No AMP plugin found. View documentation for more information.', 'ad-commander' ) . ' ' . Doc::doc_link( 'amp', false ), array( 'adcmdr-metaitem__warning' ) ); } } } /** * Callback for settings field. * * @return void */ public function field_adcmdr_disable_adsense_account_alerts() { $pub_id = $this->sf()->get( 'adsense_account', 'adsense' ); $adsense_connected = AdminAdsense::instance()->has_access_token( $pub_id ); $id = array( $this->sf()->key( 'adsense' ) => 'disable_adsense_account_alerts' ); $this->sf()->checkbox( $id, $this->sf()->get( 'disable_adsense_account_alerts', 'adsense' ), 1, array( 'disabled' => ! $adsense_connected ) ); $this->sf()->label( $id, __( 'Disable AdSense connected account alerts in the Ad Commander Dashboard', 'ad-commander' ), array( 'disabled' => ! $adsense_connected ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_consent_required() { $id = array( $this->sf()->key( 'privacy' ) => 'consent_required' ); $this->sf()->checkbox( $id, $this->sf()->get( 'consent_required', 'privacy' ), 1 ); $this->sf()->label( $id, __( 'Require consent before displaying ads.', 'ad-commander' ) ); Doc::doc_link( 'requiring_consent' ); echo wp_kses_post( '
    ' ); $this->sf()->message( __( 'If enabled, this setting can be overridden by individual ads, groups, or placements.', 'ad-commander' ) ); echo wp_kses_post( '
    ' ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_consent_cookie_name() { $id = array( $this->sf()->key( 'privacy' ) => 'consent_cookie_name' ); $this->sf()->input( $id, $this->sf()->get( 'consent_cookie_name', 'privacy' ) ); /* translators: %1$s: sample Google Analytics ID */ $this->sf()->message( __( 'The name of the cookie that indicates a user has given consent.', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_consent_cookie_value() { $id = array( $this->sf()->key( 'privacy' ) => 'consent_cookie_value' ); $this->sf()->input( $id, $this->sf()->get( 'consent_cookie_value', 'privacy' ) ); /* translators: %1$s: sample Google Analytics ID */ $this->sf()->message( __( 'The cookie should have this value. Leave blank to accept any value.', 'ad-commander' ) ); } /** * Callback for settings field. * * @return void */ public function field_adcmdr_consent_cookie_comparison() { $options = array( 'equals' => __( 'Equals', 'ad-commander' ), 'contains' => __( 'Contains', 'ad-commander' ), 'equals_insensitive' => __( 'Equals (case-insensitive)', 'ad-commander' ), 'contains_insensitive' => __( 'Contains (case-insensitive)', 'ad-commander' ), ); $id = array( $this->sf()->key( 'privacy' ) => 'consent_cookie_comparison' ); $current_value = $this->sf()->get( 'consent_cookie_comparison', 'privacy' ); $this->sf()->select( $id, $options, $current_value ? $current_value : array_key_first( $options ), ); $this->sf()->message( __( 'The manner in which to check the cookie value. If the cookie value above is blank, this setting is ignored and Ad Commander will check if the cookie exists.', 'ad-commander' ) ); } /** * Create classes for use on a meta item. * * @param array $suffixes An array of suffices to append. * * @return string */ public static function metaitem_classes( $suffixes = array() ) { $classes = array( 'adcmdr-metaitem' ); if ( $suffixes && ! is_array( $suffixes ) ) { $suffixes = array( $suffixes ); } if ( $suffixes ) { foreach ( $suffixes as $suffix ) { $classes[] = 'adcmdr-metaitem--' . $suffix; } } return implode( ' ', $classes ); } /** * Interfaces with WOMeta message and adds classes. * * @param string $message The message to display. * @param array $classes Any additional classes. * @param array $args Additional arguments. * * @return string */ protected function info( $message, $classes = array(), $args = array() ) { $classes = Util::arrayify( $classes ); $classes[] = 'adcmdr-metaitem__info'; $args['classes'] = $classes; $args['element'] = 'div'; $args['inner_element'] = 'p'; return $this->sf()->wo_forms->message( $message, $args ); } /** * Display an add-on table. * * @return string */ protected function get_addons() { $html = ''; if ( ! ProBridge::instance()->is_pro_loaded() ) { $lis = array( __( 'Priority support and updates', 'ad-commander' ), __( 'Client-side and smart rendering modes (cache busting)', 'ad-commander' ), __( 'Google Analytics tracking (GA4)', 'ad-commander' ), __( 'Visitor targeting options', 'ad-commander' ), __( 'Geotargeting with MaxMind', 'ad-commander' ), __( 'Group and placement targeting options', 'ad-commander' ), __( 'Advanced automatic placement positions', 'ad-commander' ), __( 'Weighted and evenly distributed ads', 'ad-commander' ), __( 'Advanced group layouts', 'ad-commander' ), __( 'Expire ads by date or stats', 'ad-commander' ), __( 'Increased AdSense API calls', 'ad-commander' ), __( '...and more', 'ad-commander' ), ); foreach ( $lis as &$li ) { $li = ' ' . $li; } $html .= $this->start_div( Util::ns( 'addons' ), array( 'display' => false ) ) . $this->start_div( array( Util::ns( 'addon-features' ), Util::ns( 'pro-features' ) ), array( 'display' => false ) ) . Html::h3( AdCommander::title() . ' Pro' ) . Html::ul( $lis, Util::ns( 'addon' ) ) . $this->start_div( 'adcmdr-btn-group', array( 'display' => false ) ) . Html::abtn( self::pro_upgrade_url( array( 'utm_medium' => 'button' ) ), __( 'Upgrade to Pro', 'ad-commander' ) ) . Html::abtn( AdCommander::public_site_url( '', array( 'utm_medium' => 'button' ) ), 'Learn more', '_blank', true ) . $this->end_div( array( 'display' => false ) ) . $this->end_div( array( 'display' => false ) ) . $this->end_div( array( 'display' => false ) ); } if ( ! AddonBridge::instance()->is_addon_loaded( 'tools' ) ) { $lis = array( __( 'Export Ad Commander ads', 'ad-commander' ), __( 'Import Ad Commander ads from another site', 'ad-commander' ), __( 'Reset all ad statistics', 'ad-commander' ), __( 'Reset single ad statistics', 'ad-commander' ), __( 'Purge rogue statistics (deleted ads)', 'ad-commander' ), __( 'Available in the WordPress plugin directory', 'ad-commander' ), ); foreach ( $lis as &$li ) { $li = ' ' . $li; } $html .= $this->start_div( Util::ns( 'addons' ), array( 'display' => false ) ) . $this->start_div( Util::ns( 'addon-features' ), array( 'display' => false ) ) . Html::h3( __( 'Ad Commander Tools', 'ad-commander' ) ) . Html::ul( $lis, Util::ns( 'addon' ) ) . $this->start_div( 'adcmdr-btn-group', array( 'display' => false ) ) . Html::abtn( AddonBridge::addon_url( 'tools' ), __( 'Download Add-on', 'ad-commander' ) ) . $this->end_div( array( 'display' => false ) ) . $this->end_div( array( 'display' => false ) ) . $this->end_div( array( 'display' => false ) ); } if ( ! AddonBridge::instance()->is_addon_loaded( 'scrnsa' ) ) { $p = esc_html__( "Screen Stay Awake prevents your website visitor's screen from turning off. The Screen Wake Lock API is used and no visitor prompt is required.", 'ad-commander' ); $p .= '

    '; $p .= esc_html__( 'This plugin is great for recipe websites and other how-to websites where a visitor would prefer their screen stay on.', 'ad-commander' ); $html .= $this->start_div( Util::ns( 'addons' ), array( 'display' => false ) ) . $this->start_div( Util::ns( 'addon-features' ), array( 'display' => false ) ) . Html::h3( __( 'Screen Stay Awake', 'ad-commander' ) ) . Html::p( $p ) . $this->start_div( 'adcmdr-btn-group', array( 'display' => false ) ) . Html::abtn( AddonBridge::addon_url( 'scrnsa' ), __( 'Download Plugin', 'ad-commander' ) ) . $this->end_div( array( 'display' => false ) ) . $this->end_div( array( 'display' => false ) ) . $this->end_div( array( 'display' => false ) ); } if ( $html ) { $html = '
    ' . $html . '
    '; } return $html; } /** * Modify the ad or placement post title if it's blank. * * @param array $post_data The current post data. * * @return array */ public function modify_post_title( $post_data ) { if ( $post_data['post_type'] === AdCommander::posttype_ad() || $post_data['post_type'] === AdCommander::posttype_placement() ) { if ( ( ! isset( $post_data['post_title'] ) || trim( $post_data['post_title'] ) === '' ) && isset( $post_data['post_date_gmt'] ) ) { $prefix = $post_data['post_type'] === AdCommander::posttype_ad() ? esc_html__( 'Ad', 'ad-commander' ) : esc_html__( 'Placement', 'ad-commander' ); $post_data['post_title'] = $prefix . ' | ' . get_date_from_gmt( $post_data['post_date_gmt'], get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ); } } return $post_data; } }