HEX
Server: Apache/2.4.68 (Debian)
System: Linux as-cs-widget-demo-us-central1 6.1.0-44-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.164-1 (2026-03-09) x86_64
User: root (0)
PHP: 8.2.32
Disabled: NONE
Upload Files
File: /var/www/kevin-demo/wp-content/plugins/adthrive-ads/components/ads/class-scheduled.php
<?php
/**
 * Ads Main Class
 *
 * @package AdThrive Ads
 */

namespace AdThrive_Ads\Components\Ads;

/**
 * Class for scheduled events
 */
class Scheduled {

	/**
	 * Add hooks
	 */
	public function setup() {
		add_action( 'init', array( $this, 'init' ) );

		add_action( 'adthrive_cls_daily_event', array( $this, 'sync_cls_data' ) );

		add_action( 'adthrive_site_daily_event', array( $this, 'sync_site_ads_data' ) );

		add_action( 'upgrader_process_complete', array( $this, 'plugin_upgraded' ), 10, 2 );

		add_filter( 'adthrive_ads_updated', array( $this, 'options_updated' ), 10, 2 );
	}

	/**
	 * Init hook - check for parameter to update cls insertion file
	 */
	public function init() {
		$cls_optimization = \AdThrive_Ads\Options::get( 'cls_optimization' );

		if ( 'on' === $cls_optimization ) {
			$query_param_value = isset( $_GET['clsFileReset'] ) ? sanitize_text_field( wp_unslash( $_GET['clsFileReset'] ) ) : '';

			if ( 'true' === $query_param_value ) {
				$this->cls_file_reset();
			}
		}

		if ( isset( $_GET['atFileReset'] ) && 'true' === sanitize_text_field( wp_unslash( $_GET['atFileReset'] ) ) && $this->should_save_site_ads() ) {
			$this->site_ads_files_reset();
		}
	}

	/**
	 * Resets cls files and echoes the results
	 */
	public function cls_file_reset() {
		header( 'Content-Type: application/json' );
		try {
			$output = array();
			$error = array();
			$output['status'] = 'success';
			$output['message'] = 'Saved all files';
			$output['version'] = ADTHRIVE_ADS_VERSION;
			$output['result'] = $this->sync_cls_data();
			echo wp_json_encode( $output );
			exit();
		} catch ( \Exception $e ) {
			http_response_code( 500 );
			$output = array(
				'status' => 'error',
				'message' => $e->getMessage(),
				'errors' => array( $e ),
			);
			echo wp_json_encode( $output );
			exit();
		}
	}

	/**
	 * Resets site ads files and echoes the results
	 */
	public function site_ads_files_reset() {
		header( 'Content-Type: application/json' );
		try {
			$save_result = $this->save_site_ads_files();

			$output = array();

			$output['status'] = 'success';
			$output['message'] = 'Saved all files';
			$output['version'] = ADTHRIVE_ADS_VERSION;
			$output['errors'] = array();

			foreach ( $save_result as $k => $k_value ) {
				if ( is_wp_error( $k_value ) ) {
					$output['status'] = 'error';
					$output['message'] = 'Failed to save one or more files';
					$output[ $k ] = $k_value->get_error_message();
					$output['errors'][] = $k_value;
				} elseif ( false === $k_value ) {
					$output['status'] = 'error';
					$output[ $k ] = 'Failed to save file';
					$output['message'] = 'Failed to save one or more files';
					$output['errors'][] = array( 'message' => 'Failed to save ' . $k );
				} else {
					$output[ $k ] = 'Saved file';
				}
			}

			if ( 'error' === $output['status'] ) {
				http_response_code( 500 );
			}
			echo wp_json_encode( $output );

			exit();
		} catch ( \Exception $e ) {
			http_response_code( 500 );
			$output = array(
				'status' => 'error',
				'message' => $e->getMessage(),
				'errors' => array( $e ),
			);
			echo wp_json_encode( $output );
			exit();
		}
	}

	/**
	 * Returns if publisher needs site js saved
	 */
	public function should_save_site_ads() {
		$cls_optimization = \AdThrive_Ads\Options::get( 'cls_optimization' );
		$amp_stories = \AdThrive_Ads\Options::get( 'amp_stories' );
		return 'on' === $cls_optimization || 'on' === $amp_stories;
	}

	/**
	 * Get deployment json from remote location
	 */
	public function get_deployment_json() {
		$remote = 'https://ads.adthrive.com/api/v1/core/cms/experiments?ts=' . strval( time() );
		return $this->get_remote_file( $remote );
	}

	/**
	 * Update Deployment json and cls files
	 */
	public function sync_cls_data() {
		$cls_optimization = \AdThrive_Ads\Options::get( 'cls_optimization' );

		if ( 'on' === $cls_optimization ) {
			$status = array();
			$deployment_str = $this->get_deployment_json();
			if ( $deployment_str && strlen( $deployment_str ) > 1 ) {
				try {
					$deployment = $this->parse_deployment_json( $deployment_str );
					if ( isset( $deployment['stable'] ) ) {
						$this->delete_cls_files( false );
						if ( isset( $deployment['test'] ) ) {
							$status[ $deployment['test'] ] = $this->get_cls_files( $deployment['test'], false );
						}
						$status[ $deployment['stable'] ] = $this->get_cls_files( $deployment['stable'], true );
						$deployment['updated_at'] = time();

						$status['deployment'] = $deployment;
						\AdThrive_Ads\Options::save_to_option( 'cls-deployments', $deployment );
					}
				} catch ( \Exception $e ) {
					$status['error'] = $e->getMessage();
				}
			} else {
				$status['error'] = 'Failed to retrieve data from deployment json endpoint.';
			}
			if ( isset( $status['error'] ) ) {
				$status['error_at'] = time();
				\AdThrive_Ads\Options::save_to_option( 'cls-error', $status );
			}
			return $status;
		}
	}

	/**
	 * Parse deployment json and return object
	 */
	public function parse_deployment_json( $deployment_str ) {
		$site_id = \AdThrive_Ads\Options::get( 'site_id' );
		$deployment = array();
		$feature_hashes = array();
		$deploy_json = json_decode( $deployment_str );
		if ( isset( $deploy_json->values ) ) {
			foreach ( $deploy_json->values as $feature_branch ) {
				$feature_hashes[] = $feature_branch->test;
				foreach ( $feature_branch->sites as $site ) {
					if ( $site === $site_id ) {
						$deployment['test'] = $feature_branch->test;
						break;
					}
				}
			}
			$deployment['stable'] = $deploy_json->stable;
		}
		$deployment['feature_hashes'] = $feature_hashes;
		return $deployment;
	}

	/**
	 * Get CLS insertion files for given hash
	 */
	public function get_cls_files( $hash, $is_stable ) {
		$base_url = 'https://ads.adthrive.com/builds/core/' . $hash . '/js/cls/';
		$status = array();
		$status['insertion'] = \AdThrive_Ads\Options::save_to_option( 'cls-insertion.' . ( $is_stable ? 'stable' : $hash ), $this->get_remote_file( $base_url . 'cls-insertion.min.js' ) );
		$status['header-insertion'] = \AdThrive_Ads\Options::save_to_option( 'cls-header-insertion.' . ( $is_stable ? 'stable' : $hash ), $this->get_remote_file( $base_url . 'cls-header-insertion.min.js' ) );
		$status['disable-ads'] = \AdThrive_Ads\Options::save_to_option( 'cls-disable-ads.' . ( $is_stable ? 'stable' : $hash ), $this->get_remote_file( $base_url . 'cls-disable-ads.min.js' ) );
		$status['comscore-loader'] = \AdThrive_Ads\Options::save_to_option( 'comscore-loader.' . ( $is_stable ? 'stable' : $hash ), $this->get_remote_file( $base_url . 'comscore-loader.min.js' ) );
		return $status;
	}

	/**
	 * Make request to remote location and return content
	 */
	public function get_remote_file( $remote ) {
		$response = wp_remote_get( $remote );
		if ( is_wp_error( $response ) ) {
			return '';
		}
		return wp_remote_retrieve_body( $response );
	}

	/**
	 * Delete existing cls files, if delete_all is true, it will delete all fines under insertion/min, otherwise keep stable files
	 */
	public function delete_cls_files( $delete_all ) {
		require_once ABSPATH . 'wp-admin/includes/file.php';

		if ( \WP_Filesystem() ) {
			global $wp_filesystem;

			if ( $wp_filesystem->is_file( 'cls-deployments.js' ) ) {
				$wp_filesystem->delete( 'cls-deployments.js' );
			}
			if ( $wp_filesystem->is_file( 'cls-error.js' ) ) {
				$wp_filesystem->delete( 'cls-error.js' );
			}

			$cls_files = list_files( ADTHRIVE_ADS_PATH . 'js/insertion/min' );
			foreach ( $cls_files as $cls_file ) {
				if ( $wp_filesystem->is_file( $cls_file ) && ( ! preg_match( '/stable.js$/', $cls_file ) || $delete_all ) ) {
					$wp_filesystem->delete( $cls_file );
				}
			}
		}

		\AdThrive_Ads\Options::remove_option( 'cls-deployments' );
		\AdThrive_Ads\Options::remove_option( 'cls-error' );
		$options = get_option( 'adthrive_options' );
		foreach ( $options as $k => $option ) {
			if ( false !== strpos( $k, 'cls' ) ) {
				if ( ! preg_match( '/stable$/', $k ) || $delete_all ) {
					\AdThrive_Ads\Options::remove_option( $k );
				}
			}
		}
	}

	/**
	 * Save site js if publisher should
	 */
	public function sync_site_ads_data() {
		if ( $this->should_save_site_ads() ) {
			$this->save_site_ads_files();
		}
	}

	/**
	 * Get and save the latest site js and css file
	 */
	private function save_site_ads_files() {
		require_once ABSPATH . 'wp-admin/includes/file.php';
		global $wp;
		$site_id = \AdThrive_Ads\Options::get( 'site_id' );
		$remote = "https://ads.adthrive.com/api/v1/siteAds/$site_id?ts=" . strval( time() );

		$successful_saves = array();

		$response = wp_remote_get( $remote );
		if ( is_wp_error( $response ) ) {
			$successful_saves['site_ads_json'] = $response;
		} else {
			$response_text = wp_remote_retrieve_body( $response );

			if ( is_array( $response ) ) {
				$successful_saves['site_ads_json'] = \AdThrive_Ads\Options::save_to_option( 'site_js', $response_text );
			}
		}

		$css_response = wp_remote_get( 'https://ads.adthrive.com/sites/' . $site_id . '/ads.min.css?ts=' . strval( time() ) );
		if ( is_wp_error( $css_response ) ) {
			$successful_saves['css_content'] = $response;
		} else {
			$css_response_text = wp_remote_retrieve_body( $css_response );
			$successful_saves['css_content'] = \AdThrive_Ads\Options::save_to_option( 'site_css', $css_response_text );
		}

		return $successful_saves;
	}

	/**
	 * Delete the site js and css file
	 */
	private function delete_site_ads_files() {
		require_once ABSPATH . 'wp-admin/includes/file.php';
		if ( \WP_Filesystem() ) {
			global $wp_filesystem;
			$filename = ADTHRIVE_ADS_PATH . 'site.js';
			$css_filename = ADTHRIVE_ADS_PATH . 'site.css';

			if ( $wp_filesystem->is_file( $filename ) ) {
				$wp_filesystem->delete( $filename );
			}
			if ( $wp_filesystem->is_file( $css_filename ) ) {
				$wp_filesystem->delete( $css_filename );
			}
		}

		\AdThrive_Ads\Options::remove_option( 'site_js' );
		\AdThrive_Ads\Options::remove_option( 'site_css' );
	}

	/**
	 * Called when the adthrive_ads option is updated
	 */
	public function options_updated( $old_value, $value ) {
		if ( isset( $value['cls_optimization'] ) && 'on' === $value['cls_optimization'] ) {
			$this->sync_cls_data();
			$this->sync_site_ads_data();
		} else {
			$this->delete_cls_files( true );
			$this->delete_site_ads_files();
		}
	}

	/**
	 * Deployment json and cls files need to be updated when plugin is upgraded
	 */
	public function plugin_upgraded( $upgrader_object, $options ) {
		$current_plugin_path_name = plugin_basename( ADTHRIVE_ADS_FILE );

		if ( 'update' === $options['action'] && 'plugin' === $options['type'] && isset( $options['plugins'] ) ) {
			foreach ( $options['plugins'] as $each_plugin ) {
				if ( $each_plugin === $current_plugin_path_name ) {
					$cls_optimization = \AdThrive_Ads\Options::get( 'cls_optimization' );

					if ( 'on' === $cls_optimization ) {
						$this->sync_cls_data();
					}
					$this->sync_site_ads_data();
				}
			}
		}
	}
}