get_term_selectize( $taxonomy, array( 'search' => $query ) ) );
}
/**
* Adds classes to disable ads based on the plugin settings
*
* @param string|array $classes One or more classes to add to the class list.
*/
public function body_class( $classes ) {
if ( is_singular() ) {
global $post;
$disable = get_post_meta( get_the_ID(), 'adthrive_ads_disable' );
$disable_content_ads = get_post_meta( get_the_ID(), 'adthrive_ads_disable_content_ads' );
$disable_auto_insert_videos = get_post_meta( get_the_ID(), 'adthrive_ads_disable_auto_insert_videos' );
$re_enable_ads_on = get_post_meta( get_the_ID(), 'adthrive_ads_re_enable_ads_on' );
$disabled_categories = \AdThrive_Ads\Options::get( 'disabled_categories' );
$disabled_tags = \AdThrive_Ads\Options::get( 'disabled_tags' );
$categories = get_the_category( $post->ID );
$tags = get_the_tags( $post->ID );
$category_names = is_array( $categories ) ? array_map( array( $this, 'pluck_name' ), $categories ) : array();
$tag_names = is_array( $tags ) ? array_map( array( $this, 'pluck_name' ), $tags ) : array();
if ( ! isset( $re_enable_ads_on[0] ) || false === trim( $re_enable_ads_on[0] ) || $re_enable_ads_on[0] > time() ) {
if ( isset( $disable[0] ) ) {
$classes[] = 'adthrive-disable-all';
}
if ( isset( $disable_content_ads[0] ) || in_array( 'noads', $tag_names, true ) ) {
$classes[] = 'adthrive-disable-content';
}
if ( isset( $disable_auto_insert_videos[0] ) || in_array( 'noads', $tag_names, true ) ) {
$classes[] = 'adthrive-disable-video';
}
}
if ( is_array( $disabled_categories ) && array_intersect( $disabled_categories, $category_names ) ) {
$classes[] = 'adthrive-disable-all';
} elseif ( is_array( $disabled_tags ) && array_intersect( $disabled_tags, $tag_names ) ) {
$classes[] = 'adthrive-disable-all';
}
} elseif ( is_404() ) {
$classes[] = 'adthrive-disable-all';
}
return $classes;
}
/**
* Gets the object name
*
* @param object $obj An object with a name property
*
* @return string The object name
*/
private function pluck_name( $obj ) {
return $obj->name;
}
/**
* Gets just the object name property
*
* @param object $obj An object with a name property
*
* @return string An object with just a name property
*/
private function get_selectize( $obj ) {
return array(
'text' => $obj->name,
'value' => $obj->name,
);
}
/**
* Add fields to the options metabox
*/
public function all_objects() {
$post_meta = new_cmb2_box( array(
'id' => 'adthrive_ads_object_metabox',
'title' => __( 'AdThrive Ads', 'adthrive_ads' ),
'object_types' => array( 'page', 'post' ),
) );
$post_meta->add_field( array(
'name' => __( 'Disable all ads', 'adthrive_ads' ),
'id' => 'adthrive_ads_disable',
'type' => 'checkbox',
) );
$post_meta->add_field( array(
'name' => __( 'Disable content ads', 'adthrive_ads' ),
'id' => 'adthrive_ads_disable_content_ads',
'type' => 'checkbox',
) );
$post_meta->add_field( array(
'name' => __( 'Disable auto-insert video players', 'adthrive_ads' ),
'id' => 'adthrive_ads_disable_auto_insert_videos',
'type' => 'checkbox',
) );
$post_meta->add_field( array(
'name' => __( 'Re-enable ads on', 'adthrive_ads' ),
'desc' => __( 'All ads on this post will be enabled on the specified date', 'adthrive_ads' ),
'id' => 'adthrive_ads_re_enable_ads_on',
'type' => 'text_date_timestamp',
) );
if ( \AdThrive_Ads\Options::get( 'disable_video_metadata' ) === 'on' ) {
$post_meta->add_field( array(
'name' => __( 'Enable Video Metadata', 'adthrive_ads' ),
'desc' => __( 'Enable adding metadata to video player on this post', 'adthrive_ads' ),
'id' => 'adthrive_ads_enable_metadata',
'type' => 'checkbox',
) );
} else {
$post_meta->add_field( array(
'name' => __( 'Disable Video Metadata', 'adthrive_ads' ),
'desc' => __( 'Disable adding metadata to video player on this post', 'adthrive_ads' ),
'id' => 'adthrive_ads_disable_metadata',
'type' => 'checkbox',
) );
}
}
/**
* Add fields to the options metabox
*
* @param CMB $cmb A CMB metabox instance
*/
public function add_options( $cmb ) {
$cmb->add_field( array(
'name' => __( 'Site Id', 'adthrive_ads' ),
'desc' => __( 'Add your AdThrive Site ID', 'adthrive_ads' ),
'id' => 'site_id',
'type' => 'text',
'attributes' => array(
'required' => 'required',
'pattern' => '[0-9a-f]{24}',
'title' => 'The site id needs to match the one provided by AdThrive exactly',
),
) );
$cmb->add_field( array(
'name' => 'Disabled for Categories',
'desc' => 'Disable ads for the selected categories.',
'id' => 'disabled_categories',
'type' => 'text',
'escape_cb' => array( $this, 'selectize_escape' ),
'sanitization_cb' => array( $this, 'selectize_sanitize' ),
) );
$cmb->add_field( array(
'name' => 'Disabled for Tags',
'desc' => 'Disable ads for the selected tags.',
'id' => 'disabled_tags',
'type' => 'text',
'escape_cb' => array( $this, 'selectize_escape' ),
'sanitization_cb' => array( $this, 'selectize_sanitize' ),
) );
$cmb->add_field( array(
'name' => 'Disable Video Metadata',
'desc' => 'Disable adding metadata to video players. Caution: This is a site-wide change. Only choose if metadata is being loaded another way.',
'id' => 'disable_video_metadata',
'type' => 'checkbox',
) );
$cmb->add_field( array(
'name' => 'CLS Optimization',
'desc' => "Enable solution to reduce ad-related CLS
Clear your site's cache after saving this setting to apply the update across your site. Get more details on CLS optimization here.",
'id' => 'cls_optimization',
'type' => 'checkbox',
) );
return $cmb;
}
/**
* Called for checkbox to properly default to true
*/
public function sanitize_checkbox( $value ) {
return is_null( $value ) ? 0 : $value;
}
/**
* Convert a selectize field array value to string
*
* @param mixed $value The actual field value.
* @return String Field value converted to a string
*/
public function selectize_escape( $value ) {
if ( is_string( $value ) ) {
return $value;
}
return ! empty( $value ) ? implode( ',', $value ) : null;
}
/**
* Convert a selectize field value to array
*
* @param mixed $value The actual field value.
* @return array Field value converted to an array
*/
public function selectize_sanitize( $value ) {
if ( is_array( $value ) ) {
return $value;
}
return ! empty( $value ) ? explode( ',', $value ) : null;
}
/**
* Add the AdThrive ads script
*/
public function ad_head() {
$data['site_id'] = \AdThrive_Ads\Options::get( 'site_id' );
$cls_optimization = \AdThrive_Ads\Options::get( 'cls_optimization' );
// if cls_optimization is false in the plugin, cls could still be on in ads min, so we set this here
$data['plugin_debug'] = isset( $_GET['plugin_debug'] ) && 'true' === sanitize_text_field( wp_unslash( $_GET['plugin_debug'] ) ) ? 'true' : 'false';
$thrive_architect_enabled = isset( $_GET['tve'] ) && sanitize_key( $_GET['tve'] ) === 'true';
if ( isset( $_SERVER['REQUEST_URI'] ) ) {
$request_uri = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) );
$widget_preview_active = strpos( $request_uri, 'wp-admin/widgets.php' ) !== false;
} else {
$widget_preview_active = false;
}
if ( isset( $data['site_id'] ) && preg_match( '/[0-9a-f]{24}/i', $data['site_id'] ) && ! $thrive_architect_enabled && ! $widget_preview_active ) {
$body_classes = $this->body_class( [] );
if ( 'on' === $cls_optimization ) {
$cls_data = $this->parse_cls_deployment();
$data = array_merge( $data, $cls_data );
$data['site_js'] = $this->get_file_content( 'site.js' );
$data['site_css'] = $this->get_file_content( 'site.css' );
$disable_all = in_array( 'adthrive-disable-all', $body_classes, true );
if ( ! empty( $data['site_js'] ) ) {
require 'partials/insertion-includes.php';
$decoded_data = json_decode( $data['site_js'] );
add_action('wp_head', function() use ( $data ) {
$this->insert_cls_file( 'cls-disable-ads', $data );
}, 100 );
if ( ! $disable_all && null !== $decoded_data && isset( $decoded_data->adUnits ) ) {
$adunits = $decoded_data->adUnits;
foreach ( $adunits as $adunit ) {
if ( 'Header' === $adunit->location && isset( $adunit->dynamic ) ) {
if ( ! isset( $adunit->dynamic->spacing ) ) {
$adunit->dynamic->spacing = 0;
}
if ( ! isset( $adunit->dynamic->max ) ) {
$adunit->dynamic->max = 0;
} else {
$adunit->dynamic->max = (int) floor( $adunit->dynamic->max );
}
if ( ! isset( $adunit->sequence ) ) {
$adunit->sequence = 1;
}
if ( true === $adunit->dynamic->enabled && 1 === $adunit->dynamic->max && 0 === $adunit->dynamic->spacing && 1 === $adunit->sequence ) {
add_action('wp_head', function() use ( $data ) {
$this->insert_cls_file( 'cls-header-insertion', $data );
}, 101 );
}
}
}
}
add_action('wp_footer', function() use ( $data ) {
$this->insert_cls_file( 'cls-insertion', $data );
$this->check_cls_insertion();
}, 1 );
}
}
require 'partials/ads.php';
}
}
/**
* Adthrive Preload hook - adds dns prefetch and preconnect elements to adthrive resources
*/
public function adthrive_preload() {
echo '';
echo '';
echo '';
}
/**
* Check if cls insertion script tag has been inserted to page, if not set injectedFromPlugin to false
*/
private function check_cls_insertion() {
$cls = "'cls-'";
// phpcs:disable
echo '';
// phpcs:enable
}
/**
* Returns hash value specified from the url params
*/
public function get_remote_cls_hash() {
return isset( $_GET['plugin_remote_cls'] ) ? sanitize_text_field( wp_unslash( $_GET['plugin_remote_cls'] ) ) : '';
}
/**
* Get cls file endpoint url for the hash. If no hash specified, then return empty string
*/
public function get_remote_cls_file_url( $filename, $data ) {
$remote_cls_hash = $this->get_remote_cls_hash();
if ( '' !== $remote_cls_hash ) {
return 'https://ads.adthrive.com/builds/core/' . $remote_cls_hash . '/js/cls/' . $filename . '.min.js?ts=' . strval( time() );
}
return '';
}
/**
* Inserts cls file content to script tag
* If debug options are enabled, makes request to remote url to fetch cls files.
*/
public function insert_cls_file( $filename, $data ) {
// phpcs:disable
$remote_cls_file_url = $this->get_remote_cls_file_url( $filename, $data );
if ( '' !== $remote_cls_file_url ) {
echo "";
} else {
$cls_content = $this->get_cls_file( $filename, $data );
if ( '' !== $cls_content['branch'] ) {
echo "";
}
// phpcs:enable
}
}
/**
* Get cls insertion file for the hash, if file for the hash is not found, return stable version
*/
public function get_cls_file( $filename, $data ) {
if ( isset( $data['cls_branch'] ) ) {
if ( isset( $data['cls_bucket'] ) && 'prod' !== $data['cls_bucket'] ) {
$file_content = $this->get_file_content( 'js/insertion/min/' . $filename . '.' . $data['cls_branch'] . '.js' );
if ( $file_content ) {
return array(
'branch' => $data['cls_branch'],
'bucket' => $data['cls_bucket'],
'content' => $file_content,
);
}
}
$stable_file_content = $this->get_file_content( 'js/insertion/min/' . $filename . '.stable.js' );
if ( $stable_file_content ) {
return array(
'branch' => $data['cls_branch'],
'bucket' => $data['cls_bucket'],
'content' => $stable_file_content,
);
}
}
return array(
'branch' => '',
'bucket' => '',
'content' => '',
);
}
/**
* Parser CLS deployment file from file system and return deployment info
*/
private function parse_cls_deployment() {
$output = array();
$deploy_str = $this->get_file_content( 'cls-deployments.js' );
if ( $deploy_str && strlen( $deploy_str ) > 1 ) {
$cls_deployment = json_decode( $deploy_str );
$output['cls_branch'] = $cls_deployment->stable;
$output['cls_bucket'] = 'prod';
if ( isset( $cls_deployment->test ) ) {
$output['cls_branch'] = $cls_deployment->test;
$output['cls_bucket'] = 'feature';
}
$cls_hash = $this->get_remote_cls_hash();
if ( strlen( $cls_hash ) > 0 ) {
$output['cls_branch'] = $cls_hash;
$output['cls_bucket'] = 'debug';
}
}
return $output;
}
/**
* Gets terms and displays them as options
*
* @param String $taxonomy Taxonomy terms to retrieve. Default is category.
* @param String|array $args Optional. get_terms optional arguments
* @return array An array of options that matches the CMB2 options array
*/
public function get_term_selectize( $taxonomy = 'category', $args = array() ) {
$args['taxonomy'] = $taxonomy;
$args = wp_parse_args( $args, array(
'taxonomy' => 'category',
'number' => 100,
) );
$taxonomy = $args['taxonomy'];
$terms = (array) get_terms( $taxonomy, $args );
return is_array( $terms ) ? array_map( array( $this, 'get_selectize' ), $terms ) : array();
}
/**
* Get the local file content
*/
private function get_file_content( $filename ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
if ( \WP_Filesystem() ) {
global $wp_filesystem;
return $wp_filesystem->get_contents( ADTHRIVE_ADS_PATH . $filename );
}
return false;
}
/**
* Get and save the latest site js and css file
*/
private function save_site_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() );
$filename = ADTHRIVE_ADS_PATH . 'site.js';
$css_filename = ADTHRIVE_ADS_PATH . 'site.css';
// use a transient to store the etag?
$response = wp_remote_get( $remote );
$successful_saves = array();
if ( is_wp_error( $response ) ) {
$successful_saves['site_ads_json'] = $response;
}
$response_text = wp_remote_retrieve_body( $response );
if ( is_array( $response ) ) {
if ( \WP_Filesystem() ) {
global $wp_filesystem;
$successful_saves['site_ads_json'] = $wp_filesystem->put_contents( $filename, $response_text, FS_CHMOD_FILE );
$css_content = $this->get_remote_file( 'https://ads.adthrive.com/sites/' . $site_id . '/ads.min.css?ts=' . strval( time() ) );
if ( is_wp_error( $css_content ) ) {
$successful_saves['css_content'] = $css_content;
} else {
$successful_saves['css_content'] = $wp_filesystem->put_contents( $css_filename, $css_content, FS_CHMOD_FILE );
}
} else {
$successful_saves['site_ads_json'] = new \WP_Error( 'NO_FILESYSTEM', 'WP_Filesystem not available' );
}
}
return $successful_saves;
}
/**
* Makes request to remote url and returns content
*/
private function get_remote_file( $url ) {
$response = wp_remote_get( $url );
$response_text = wp_remote_retrieve_body( $response );
if ( is_array( $response ) ) {
return $response_text;
}
return $response;
}
}