$adthrive_options[ $status_type ]['timestamp'],
$status_type => $adthrive_options[ $status_type ]['content'],
);
} else {
$error = "{$status_type} not set in adthrive_options";
}
break;
case 'cls':
if ( isset( $adthrive_options['cls-deployments'] ) ) {
$return = $adthrive_options['cls-deployments']['content'];
} else {
$error = 'cls-deployments not set in adthrive_options';
}
break;
}
} else {
$error = 'adthrive_options not set';
}
if ( isset( $error ) ) {
print wp_json_encode( array( 'error' => $error ) );
} else {
print wp_json_encode( $return );
}
exit();
}
}
/**
* AJAX method to get terms with the matched search query for the specified taxonomy
*/
public function ajax_terms() {
if ( isset( $_GET['query'] ) ) {
$query = sanitize_text_field( wp_unslash( $_GET['query'] ) );
}
if ( isset( $_GET['taxonomy'] ) ) {
$taxonomy = sanitize_text_field( wp_unslash( $_GET['taxonomy'] ) );
}
wp_send_json( $this->get_term_selectize( $taxonomy, $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', true );
$disable_content_ads = get_post_meta( get_the_ID(), 'adthrive_ads_disable_content_ads', true );
$disable_auto_insert_videos = get_post_meta( get_the_ID(), 'adthrive_ads_disable_auto_insert_videos', true );
$re_enable_ads_on = get_post_meta( get_the_ID(), 'adthrive_ads_re_enable_ads_on', true );
$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 ( ! $re_enable_ads_on || false === trim( $re_enable_ads_on ) || $re_enable_ads_on > time() ) {
if ( $disable ) {
$classes[] = 'adthrive-disable-all';
}
if ( $disable_content_ads || in_array( 'noads', $tag_names, true ) ) {
$classes[] = 'adthrive-disable-content';
}
if ( $disable_auto_insert_videos || 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;
}
/**
* Adds Content Specific Video Playlist category classes to the body based on the plugin settings
*
* @param string|array $classes One or more classes to add to the class list.
*/
public function adthrive_cat_class( $classes ) {
if ( is_singular() ) {
global $post;
$categories = get_the_category( $post->ID );
$category_names = is_array( $categories ) ? array_map( array( $this, 'pluck_name' ), $categories ) : array();
if ( 'on' === \AdThrive_Ads\Options::get( 'content_specific_playlists' ) ) {
$category_body_classes = is_array( $categories ) ? array_map( array( $this, 'pluck_body_class' ), $categories ) : array();
$classes = array_merge( $classes, $category_body_classes );
}
}
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 the object nicename
*
* @param object $obj An object with a nicename property
*
* @return string Adthrive class name formatted for use in the body tag
*/
private function pluck_body_class( $obj ) {
return 'adthrive-cat-' . $obj->category_nicename;
}
/**
* 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,
);
}
/**
* Enqueue plugin admin styles on the post/page edit screens so the
* WP 7.0 :checked override (see PE-1120) applies to the post meta box,
* not just the global options page.
*
* @param string $hook The current admin page hook.
*/
public function enqueue_post_meta_styles( $hook ) {
if ( 'post.php' !== $hook && 'post-new.php' !== $hook ) {
return;
}
$screen = get_current_screen();
if ( ! $screen || ! in_array( $screen->post_type, self::OBJECT_TYPES, true ) ) {
return;
}
wp_enqueue_style(
'adthrive-ads',
plugins_url( 'css/adthrive-ads.min.css', ADTHRIVE_ADS_FILE ),
false,
ADTHRIVE_ADS_VERSION
);
}
/**
* Add fields to the options metabox for page and posts
*/
public function all_objects() {
$post_meta = new_cmb2_box(
array(
'id' => 'adthrive_ads_object_metabox',
'title' => __( 'Raptive Ads', 'adthrive_ads' ),
'object_types' => self::OBJECT_TYPES,
)
);
$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',
)
);
}
if ( \AdThrive_Ads\Options::get( 'disable_admin_ads' ) === 'on' ) {
$post_meta->add_field(
array(
'name' => __( 'Enable ads when previewing post', 'adthrive_ads' ),
'desc' => __( 'Enable all ads when previewing a post or customizing a theme in WordPress Admin', 'adthrive_ads' ),
'id' => 'adthrive_ads_enable_admin_ads',
'type' => 'checkbox',
)
);
} else {
$post_meta->add_field(
array(
'name' => __( 'Disable ads when previewing post', 'adthrive_ads' ),
'desc' => __( 'Disable all ads when previewing a post or customizing a theme in WordPress Admin', 'adthrive_ads' ),
'id' => 'adthrive_ads_disable_admin_ads',
'type' => 'checkbox',
)
);
}
}
/**
* Add fields to the options metabox for the plugin settings.
*
* @param CMB $cmb A CMB metabox instance
*/
public function add_options( $cmb ) {
$cmb->add_field(
array(
'name' => __( 'Site Id', 'adthrive_ads' ),
'desc' => __( 'Add your Raptive 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 Raptive 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',
'default_cb' => array( $this, 'cls_checkbox_default' ),
)
);
$cmb->add_field(
array(
'name' => 'Disable ads within WordPress Admin',
'desc' => 'Disable all ads when previewing a post or customizing a theme in WordPress Admin. Recommended when using post or page builders.',
'id' => 'disable_admin_ads',
'type' => 'checkbox',
)
);
return $cmb;
}
/**
* Returns true unless the checkbox was explicitly unchecked.
* Note: Working with the CMB2 checkbox is odd. This function attempts to:
* 1. Default the checkbox to 'on'
* 2. If the `adthrive_ads` options are stored in the database, look for the `cls_optimization`
* option in they array.
* 3. If the `cls_optimization` option is not stored, that means a user explicitly disabled the
* option so don't force it to true.
*/
public function cls_checkbox_default( $field_args, $field ) {
$cls_optimization = 'on';
$adthrive_options = get_option( $field->object_id, false );
if ( $adthrive_options ) {
if ( isset( $adthrive_options['cls_optimization'] ) ) {
$cls_optimization = $adthrive_options['cls_optimization'];
} else {
$cls_optimization = null;
}
}
return isset( $cls_optimization ) ? true : false;
}
/**
* 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;
}
/**
* Check if the user is within admin
*
* True if
* - user is editing a post/page
* - user is customizing a theme
* - user is previewing an unpublished post/page
* - user is viewing a published post/page while logged into WP and has higher roles than subscriber & customer
*
* @return boolean
*/
public function is_admin() {
$is_admin = false;
if ( is_admin() ) {
// User is in the admin.
$is_admin = true;
} elseif ( is_customize_preview() ) {
// User is customizing a theme.
$is_admin = true;
} elseif ( is_preview() ) {
// User is previewing an unpublished post/page.
$is_admin = true;
} elseif ( is_user_logged_in() ) {
// User is logged into WP. Check if user has an edit capability ( all roles beyond Subscriber ).
if ( current_user_can( 'edit_posts' ) ) {
$is_admin = true;
}
}
return $is_admin;
}
/**
* Check if admin ads are disabled
*
* @return boolean
*/
public function admin_ads_disabled() {
// Check site level settings.
$disable_site_admin_ads = \AdThrive_Ads\Options::get( 'disable_admin_ads' ) === 'on';
// Check page/post level settings if it's overriding site level settings.
if ( is_singular( self::OBJECT_TYPES ) ) {
if ( $disable_site_admin_ads ) {
$enable_post_admin_ads = get_post_meta( get_the_ID(), 'adthrive_ads_enable_admin_ads', true ) === 'on';
return ! $enable_post_admin_ads;
} else {
$disable_post_admin_ads = get_post_meta( get_the_ID(), 'adthrive_ads_disable_admin_ads', true ) === 'on';
return $disable_post_admin_ads;
}
}
return $disable_site_admin_ads;
}
/**
* Add header scripts for ads.
*/
public function head_scripts() {
if ( $this->is_admin() && $this->admin_ads_disabled() ) {
// Don't load ads if the user is in the admin and admin ads are disabled.
return;
}
$this->ad_head();
$this->adthrive_preload();
}
/**
* Add the AdThrive ads script
*/
private 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( array() );
if ( 'on' === $cls_optimization ) {
$cls_file_service = $this->get_cls_file_service();
$cls_data = $cls_file_service->parse_cls_deployment();
$data = array_merge( $data, $cls_data );
$site_ads = new \AdThrive_Ads\SiteAds();
$data['site_js'] = $site_ads->get_site_js();
$data['site_css'] = $cls_file_service->get_option_value( 'site_css' );
$disable_all = in_array( 'adthrive-disable-all', $body_classes, true );
if ( ! empty( $data['site_js'] ) ) {
$decoded_data = json_decode( $data['site_js'] );
if ( $this->has_essential_site_ads_keys( $decoded_data ) ) {
require 'partials/insertion-includes.php';
add_action(
'wp_head',
function () use ( $data, $cls_file_service ) {
$cls_file_service->insert_cls_file( 'comscore-loader', $data );
},
100
);
add_action(
'wp_head',
function () use ( $data, $cls_file_service ) {
$cls_file_service->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, $cls_file_service ) {
$cls_file_service->insert_cls_file( 'cls-header-insertion', $data );
},
101
);
}
}
}
}
add_action(
'wp_footer',
function () use ( $data, $cls_file_service ) {
$cls_file_service->insert_cls_file( 'cls-insertion', $data );
$this->check_cls_insertion();
},
1
);
} else {
require 'partials/sync-error.php';
}
}
}
require 'partials/ads.php';
}
}
/**
* Adthrive Preload hook - adds dns prefetch and preconnect elements to adthrive resources
*/
private function adthrive_preload() {
echo '';
echo '';
echo '';
}
/**
* Returns true if all expected siteAds keys exist: siteId, siteName, adOptions, breakpoints, adUnits
* If these keys are not present, there was an issue syncing the siteAds data, and we shouldnt load any CLS
*/
private function has_essential_site_ads_keys( $site_ads_object ) {
return ( null !== $site_ads_object && isset( $site_ads_object->siteId ) && isset( $site_ads_object->siteName ) && isset( $site_ads_object->adOptions ) && isset( $site_ads_object->breakpoints ) && isset( $site_ads_object->adUnits ) );
}
/**
* Check if cls insertion script tag has been inserted to page, if not set injectedFromPlugin to false
*/
private function check_cls_insertion() {
echo '';
}
/**
* Get the CLS file service instance.
*/
private function get_cls_file_service() {
if ( null === $this->cls_file_service ) {
$this->cls_file_service = new Cls_File_Service();
}
return $this->cls_file_service;
}
/**
* Gets terms and displays them as options
*
* @param String $taxonomy Taxonomy terms to retrieve. Default is category.
* @param String $search Optional. get_terms optional arguments
*
* @return array An array of options that matches the CMB2 options array
*/
public function get_term_selectize( $taxonomy = 'category', $search = '' ) {
$terms = (array) get_terms(
array(
'taxonomy' => $taxonomy,
'search' => $search,
'number' => 100,
)
);
return is_array( $terms ) ? array_map( array( $this, 'get_selectize' ), $terms ) : array();
}
}