'sanitize_text_field' ]); register_setting('adpagex_settings_group', 'adpagex_debug', [ 'sanitize_callback' => function($value) { return $value === '1' ? '1' : '0'; } ]); } /** * Renders the AdPageX settings page. * */ public function render_settings_page() { $configs = get_option('adpagex_configurations', []); $active = get_option('adpagex_active_config'); // Handle settings form submission (General Settings) if ( isset($_POST['submit']) && current_user_can('manage_options') && isset($_POST['_wpnonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_wpnonce'])), 'adpagex_settings_save') ) { $api_url = isset($_POST['adpagex_api_url']) ? sanitize_text_field(wp_unslash($_POST['adpagex_api_url'])) : ''; update_option('adpagex_api_url', $api_url); update_option('adpagex_debug', isset($_POST['adpagex_debug']) ? '1' : '0'); echo '

Settings saved successfully!

'; } // Handle set active placement if ( isset($_POST['action_type']) && $_POST['action_type'] === 'set_active' && current_user_can('manage_options') && isset($_POST['_wpnonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_wpnonce'])), 'adpagex_set_active') ) { $config_id = isset($_POST['config_id']) ? sanitize_text_field(wp_unslash($_POST['config_id'])) : ''; update_option('adpagex_active_config', $config_id); $active = $config_id; $this->redirect( admin_url( 'admin.php?page=adpagex-settings&tab=general&settings-updated=true' ) ); exit; } $active_tab = isset($_GET['tab']) ? sanitize_text_field(wp_unslash($_GET['tab'])) : 'general'; // Display settings updated message if redirected if (isset($_GET['settings-updated']) && $_GET['settings-updated'] === 'true') { echo '

Settings saved successfully!

'; } $this->enqueue_admin_assets(); // Enqueue styles and scripts include ADPAGEX_DIR . 'includes/views/settings-page.php'; } /** * Displays the form for adding/editing placements. * */ public function display_form_page() { ob_start(); $config_id = isset($_GET['edit']) ? sanitize_text_field(wp_unslash($_GET['edit'])) : null; $configs = get_option('adpagex_configurations', []); $config = $config_id && isset($configs[$config_id]) ? $configs[$config_id] : []; if ($config_id && !isset($configs[$config_id])) { $this->redirect(admin_url('admin.php?page=adpagex&message=invalid_placement')); exit; } // Helper for sanitize array $sanitize_array = function($arr) { return is_array($arr) ? array_map('sanitize_text_field', wp_unslash($arr)) : []; }; // Handle form submission if ( isset($_POST['action_type'], $_POST['_wpnonce']) && $_POST['action_type'] === 'save' && wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['_wpnonce'])), 'adpagex_save_placement') ) { if (!current_user_can('manage_options')) { wp_die('Insufficient permissions'); } check_admin_referer('adpagex_save_placement'); $pubid = isset($_POST['pubid']) ? sanitize_text_field(wp_unslash($_POST['pubid'])) : ''; $styleid = isset($_POST['styleid']) ? sanitize_text_field(wp_unslash($_POST['styleid'])) : ''; $targetElement = isset($_POST['target_element']) ? sanitize_text_field(wp_unslash($_POST['target_element'])) : ''; $countKeywords = isset($_POST['countKeywords']) ? intval($_POST['countKeywords']) : 10; $countSponsoredLinks = isset($_POST['countSponsoredLinks']) ? intval($_POST['countSponsoredLinks']) : 10; $status = isset($_POST['afs_status']) ? sanitize_text_field(wp_unslash($_POST['afs_status'])) : 'enabled'; $has_error = false; if($status == 'enabled'){ if (!preg_match('/^partner-pub-\d+$/', $pubid)) { echo '

Error: Publisher ID must be in the format partner-pub-xxxxxxxxxxxxxxx.

'; $has_error = true; } if (!preg_match('/^\d+$/', $styleid)) { echo '

Error: Style ID must be a number.

'; $has_error = true; } } if (!$has_error) { $need_fetch = true; $placement_id = isset($_POST['placement_id']) ? sanitize_text_field(wp_unslash($_POST['placement_id'])) : ''; if ($placement_id && isset($configs[$placement_id])) { $existing = $configs[$placement_id]; $rewarded_cooldown_minutes = isset($_POST['rewarded_cooldown_minutes']) ? intval($_POST['rewarded_cooldown_minutes']) : 0; $rewarded_cooldown_seconds = $rewarded_cooldown_minutes * 60; $rewarded_trigger_selector = isset($_POST['rewarded_trigger_selector']) ? array_map('sanitize_text_field', wp_unslash((array)$_POST['rewarded_trigger_selector'])) : []; if ( $existing['pubid'] === $pubid && $existing['styleid'] === $styleid && $existing['target_element'] === $targetElement && $existing['countKeywords'] === $countKeywords && $existing['countSponsoredLinks'] === $countSponsoredLinks && $existing['status'] === $status && $existing['rewarded_enabled'] === (isset($_POST['rewarded_enabled']) ? sanitize_text_field(wp_unslash($_POST['rewarded_enabled'])) : '0') && $existing['rewarded_ad_unit_path'] === (isset($_POST['rewarded_ad_unit_path']) ? sanitize_text_field(wp_unslash($_POST['rewarded_ad_unit_path'])) : '') && $existing['rewarded_cooldown_seconds'] === $rewarded_cooldown_seconds && $existing['rewarded_trigger_type'] === (isset($_POST['rewarded_trigger_type']) ? sanitize_text_field(wp_unslash($_POST['rewarded_trigger_type'])) : '') && ( (isset($existing['rewarded_trigger_selector']) && $existing['rewarded_trigger_selector'] === $rewarded_trigger_selector) || (!isset($existing['rewarded_trigger_selector']) && empty($rewarded_trigger_selector)) ) && !empty($existing['script_content']) ) { $need_fetch = false; $api_script = $existing['script']; } } if ($need_fetch) { $api_script = (new AdPageX_API())->fetch_script_from_api( $pubid, $styleid, $targetElement, $countKeywords, $countSponsoredLinks, $status, [ 'rewarded_enabled' => (isset($_POST['rewarded_enabled']) ? sanitize_text_field(wp_unslash($_POST['rewarded_enabled'])) : '0'), 'rewarded_ad_unit_path' => isset($_POST['rewarded_ad_unit_path']) ? sanitize_text_field(wp_unslash($_POST['rewarded_ad_unit_path'])) : '', 'rewarded_cooldown_seconds' => $rewarded_cooldown_seconds ?? 0, 'rewarded_trigger_type' => isset($_POST['rewarded_trigger_type']) ? sanitize_text_field(wp_unslash($_POST['rewarded_trigger_type'])) : '', 'rewarded_trigger_selector' => isset($_POST['rewarded_trigger_selector']) ? array_map('sanitize_text_field', wp_unslash((array)$_POST['rewarded_trigger_selector'])) : [], ] ); if ($api_script === false) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('[ADPAGEX] API call FAILED for config_id=' . $config_id . ' pubid=' . substr($pubid, 0, 6) . '*** styleid=' . substr($styleid, 0, 4) . '***'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log } echo '

' . esc_html__( 'Error: Could not fetch script from API. Please check your Publisher ID and Style ID.', 'adpagex' ) . '

'; $api_script = ""; } else { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('[ADPAGEX] API call SUCCESS for config_id=' . $config_id . ', script length=' . strlen($api_script)); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log } } } $insertion_type = isset($_POST['insertion_type']) ? array_map('sanitize_text_field', wp_unslash((array)$_POST['insertion_type'])) : []; $show_readmore = isset($_POST['show_readmore']) ? sanitize_text_field(wp_unslash($_POST['show_readmore'])) : 'no'; $rewarded_cooldown_minutes = isset($_POST['rewarded_cooldown_minutes']) ? intval($_POST['rewarded_cooldown_minutes']) : 0; $rewarded_cooldown_seconds = $rewarded_cooldown_minutes * 60; if (!empty($api_script)) { $api_script = preg_replace( '/^\s*
<\/div>(\s*
<\/div>)?\s*/i', '', $api_script ); $api_script = preg_replace('/^\s*]*>/i', '', $api_script); $api_script = preg_replace('/<\/script>\s*$/i', '', $api_script); $js_script_content = html_entity_decode($api_script, ENT_QUOTES | ENT_HTML5, 'UTF-8'); $js_version = time(); if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log('[ADPAGEX] Script saved to DB for config_id=' . $config_id . ' (' . strlen($api_script) . ' bytes)'); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log } } else { // No new script fetched (nothing changed) — preserve existing script_content $js_script_content = (isset($existing) && !empty($existing['script_content'])) ? base64_decode($existing['script_content']) : ''; $js_version = (isset($existing) && !empty($existing['script_file_version'])) ? $existing['script_file_version'] : time(); } $new_config = [ 'name' => isset($_POST['placement_name']) ? sanitize_text_field(wp_unslash($_POST['placement_name'])) : '', 'status' => $status, 'pubid' => $pubid, 'styleid' => $styleid, 'script_content' => base64_encode($js_script_content), 'script_file' => '', 'script_file_version' => $js_version, 'location' => isset($_POST['location']) ? sanitize_text_field(wp_unslash($_POST['location'])) : '', 'position' => isset($_POST['position']) ? sanitize_text_field(wp_unslash($_POST['position'])) : '', 'alignment' => isset($_POST['alignment']) ? sanitize_text_field(wp_unslash($_POST['alignment'])) : 'default', 'enabled_on' => isset($_POST['enabled_on']) ? array_map('sanitize_text_field', wp_unslash((array)$_POST['enabled_on'])) : ['posts'], 'devices' => isset($_POST['devices']) ? array_map('sanitize_text_field', wp_unslash((array)$_POST['devices'])) : ['desktop', 'tablet', 'mobile'], 'insertion_type' => $insertion_type, 'target_element' => $targetElement, 'countKeywords' => $countKeywords, 'countSponsoredLinks' => $countSponsoredLinks, 'show_readmore' => $show_readmore, 'rewarded_enabled' => isset($_POST['rewarded_enabled']) ? sanitize_text_field(wp_unslash($_POST['rewarded_enabled'])) : '0', 'rewarded_ad_unit_path' => isset($_POST['rewarded_ad_unit_path']) ? sanitize_text_field(wp_unslash($_POST['rewarded_ad_unit_path'])) : '', 'rewarded_cooldown_seconds' => $rewarded_cooldown_seconds, 'rewarded_trigger_type' => isset($_POST['rewarded_trigger_type']) ? sanitize_text_field(wp_unslash($_POST['rewarded_trigger_type'])) : '', 'rewarded_trigger_selector' => isset($_POST['rewarded_trigger_selector']) ? array_map('sanitize_text_field', wp_unslash((array)$_POST['rewarded_trigger_selector'])) : [], ]; $configSave = $configs; if (!$placement_id) { $config_id = 'placement_' . uniqid(); $new_config['id'] = $config_id; $configSave[$config_id] = $new_config; if (count($configs) === 0) { update_option('adpagex_active_config', $config_id); } } else { $config_id = $placement_id; $new_config['id'] = $config_id; $configSave[$config_id] = $new_config; } update_option('adpagex_configurations', $configSave); $this->flush_page_cache(); if (count($configSave) === 1) { update_option('adpagex_active_config', $config_id); } ob_end_clean(); $this->redirect(admin_url('admin.php?page=adpagex&message=saved')); exit; } } else { // Convert seconds to minutes for form display $config['rewarded_cooldown_minutes'] = isset($config['rewarded_cooldown_seconds']) ? intval($config['rewarded_cooldown_seconds'] / 60) : 0; } $this->enqueue_admin_assets(); include ADPAGEX_DIR . 'includes/views/placements-form.php'; ob_end_flush(); } /** * Performs a safe redirect to a given URL. * * @param string $url The URL to redirect to. * @param int $status HTTP status code (default 302). */ public function redirect($url, $status = 302) { $url = esc_url_raw( $url ); if ( ! headers_sent() ) { wp_safe_redirect( $url, $status ); } else { // Admin page callbacks run after HTML output — JS redirect as fallback. $handle = 'adpagex-js-redirect'; wp_register_script( $handle, false, [], false, false ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters wp_add_inline_script( $handle, 'window.location.href="' . esc_js( $url ) . '";' ); wp_print_scripts( [ $handle ] ); } exit; } /** * Enqueues admin specific styles and scripts. */ private function enqueue_admin_assets() { wp_enqueue_style('wp-color-picker'); wp_enqueue_style('adpagex-admin-styles', ADPAGEX_URL . 'assets/css/admin-styles.css', [], ADPAGEX_VERSION); wp_enqueue_script('adpagex-admin-scripts', ADPAGEX_URL . 'assets/js/admin-scripts.js', ['jquery', 'wp-color-picker'], ADPAGEX_VERSION, true); } private function flush_page_cache() { if (function_exists('wp_cache_flush')) { wp_cache_flush(); } if (function_exists('rocket_clean_domain')) { rocket_clean_domain(); } if (function_exists('w3tc_flush_all')) { w3tc_flush_all(); } if (function_exists('wp_cache_clear_cache')) { wp_cache_clear_cache(); } if (class_exists('LiteSpeed_Cache_API') && method_exists('LiteSpeed_Cache_API', 'purge_all')) { LiteSpeed_Cache_API::purge_all(); } } }