init
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* WordAds Admin.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* The standard set of admin pages for the user if Jetpack is installed
|
||||
*/
|
||||
class WordAds_Admin {
|
||||
|
||||
/**
|
||||
* WordAds_Admin Constructor.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( current_user_can( 'manage_options' ) && isset( $_GET['ads_debug'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
WordAds_API::update_wordads_status_from_api();
|
||||
add_action( 'admin_notices', array( $this, 'debug_output' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the API connection debug
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public function debug_output() {
|
||||
global $wordads, $wordads_status_response;
|
||||
$response = $wordads_status_response;
|
||||
if ( empty( $response ) ) {
|
||||
$response = 'No response from API :(';
|
||||
} else {
|
||||
$response = print_r( $response, 1 ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
|
||||
}
|
||||
|
||||
$status = $wordads->option( 'wordads_approved' ) ?
|
||||
array(
|
||||
'color' => 'green',
|
||||
'approved' => 'Yes',
|
||||
) :
|
||||
array(
|
||||
'color' => 'red',
|
||||
'approved' => 'No',
|
||||
);
|
||||
|
||||
$type = $wordads->option( 'wordads_approved' ) ? 'updated' : 'error';
|
||||
$message = sprintf(
|
||||
wp_kses(
|
||||
/* Translators: %1$s is the status color, %2$s is the status, %3$s is the response */
|
||||
__( '<p>Status: <span style="color:%1$s;">%2$s</span></p><pre>%3$s</pre>', 'jetpack' ),
|
||||
array(
|
||||
'p' => array(),
|
||||
'span' => array(
|
||||
'style' => array(),
|
||||
),
|
||||
'pre' => array(),
|
||||
)
|
||||
),
|
||||
esc_attr( $status['color'] ),
|
||||
esc_html( $status ),
|
||||
esc_html( $response )
|
||||
);
|
||||
|
||||
wp_admin_notice(
|
||||
$message,
|
||||
array(
|
||||
'type' => $type,
|
||||
'dismissible' => true,
|
||||
'paragraph_wrap' => false,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
global $wordads_admin;
|
||||
$wordads_admin = new WordAds_Admin();
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* The WordAds API.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Status;
|
||||
|
||||
/**
|
||||
* Methods for accessing data through the WPCOM REST API
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
class WordAds_API {
|
||||
|
||||
/**
|
||||
* Get the site's WordAds status
|
||||
*
|
||||
* @return array|WP_Error Array of site status values, or WP_Error if no response from the API.
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public static function get_wordads_status() {
|
||||
global $wordads_status_response;
|
||||
|
||||
// If the site is not connected, we can put it in a safe "house ad" mode.
|
||||
if ( ( new Status() )->is_offline_mode() ) {
|
||||
return array(
|
||||
'approved' => true,
|
||||
'active' => true,
|
||||
'house' => true,
|
||||
'unsafe' => false,
|
||||
);
|
||||
}
|
||||
|
||||
// Fetch the status from WPCOM endpoint.
|
||||
$endpoint = sprintf( '/sites/%d/wordads/status', Jetpack::get_option( 'id' ) );
|
||||
$response = Client::wpcom_json_api_request_as_blog( $endpoint );
|
||||
$wordads_status_response = $response;
|
||||
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return new WP_Error( 'api_error', __( 'Error connecting to API.', 'jetpack' ), $response );
|
||||
}
|
||||
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ) );
|
||||
|
||||
return array(
|
||||
'approved' => (bool) $body->approved,
|
||||
'active' => (bool) $body->active,
|
||||
'house' => (bool) $body->house,
|
||||
'unsafe' => (bool) $body->unsafe,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab WordAds status from WP.com API and store as option
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public static function update_wordads_status_from_api() {
|
||||
$status = self::get_wordads_status();
|
||||
|
||||
if ( ! is_wp_error( $status ) ) {
|
||||
|
||||
// Convert boolean options to string first to work around update_option not setting the option if the value is false.
|
||||
// This sets the option to either '1' if true or '' if false.
|
||||
update_option( 'wordads_approved', (string) $status['approved'], true );
|
||||
update_option( 'wordads_active', (string) $status['active'], true );
|
||||
update_option( 'wordads_house', (string) $status['house'], true );
|
||||
update_option( 'wordads_unsafe', (string) $status['unsafe'], true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ads.txt content needed to run WordAds.
|
||||
*
|
||||
* @return array string contents of the ads.txt file.
|
||||
*
|
||||
* @since 6.1.0
|
||||
*/
|
||||
public static function get_wordads_ads_txt() {
|
||||
global $wordads_status_response;
|
||||
|
||||
$endpoint = sprintf( '/sites/%d/wordads/ads-txt', Jetpack::get_option( 'id' ) );
|
||||
$response = Client::wpcom_json_api_request_as_blog( $endpoint );
|
||||
$wordads_status_response = $response;
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return new WP_Error( 'api_error', __( 'Error connecting to API.', 'jetpack' ), $response );
|
||||
}
|
||||
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ) );
|
||||
$ads_txt = str_replace( '\\n', PHP_EOL, $body->adstxt );
|
||||
|
||||
return $ads_txt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* A utility class that provides functionality for manipulating arrays.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* WordAds_Array_Utils Class.
|
||||
*/
|
||||
final class WordAds_Array_Utils {
|
||||
|
||||
/**
|
||||
* Converts a (potentially nested) array to a JavaScript object.
|
||||
*
|
||||
* Note: JS code strings should be prefixed with 'js:'.
|
||||
*
|
||||
* @param array $value The array to convert to a JavaScript object.
|
||||
* @param bool $in_list True if we are processing an inner list (non-associative array).
|
||||
*
|
||||
* @return string String representation of the JavaScript object
|
||||
*/
|
||||
public static function array_to_js_object( array $value, bool $in_list = false ): string {
|
||||
$properties = array();
|
||||
|
||||
foreach ( $value as $k => $v ) {
|
||||
// Don't set property key for values from non-associative array.
|
||||
$property_key = $in_list ? '' : "'$k': ";
|
||||
|
||||
if ( is_array( $v ) ) {
|
||||
// Check for empty array.
|
||||
if ( array() === $v ) {
|
||||
$properties[] = "'$k': []";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this is a list and not an associative array.
|
||||
if ( array_keys( $v ) === range( 0, count( $v ) - 1 ) ) {
|
||||
// Apply recursively.
|
||||
$properties[] = $property_key . '[ ' . self::array_to_js_object( $v, true ) . ' ]';
|
||||
} else {
|
||||
// Apply recursively.
|
||||
$properties[] = $property_key . self::array_to_js_object( $v );
|
||||
}
|
||||
} elseif ( is_string( $v ) && strpos( $v, 'js:' ) === 0 ) {
|
||||
// JS code. Strip the 'js:' prefix.
|
||||
$properties[] = $property_key . substr( $v, 3 );
|
||||
} elseif ( is_string( $v ) ) {
|
||||
$properties[] = $property_key . "'" . addcslashes( $v, "'" ) . "'";
|
||||
} elseif ( is_bool( $v ) ) {
|
||||
$properties[] = $property_key . ( $v ? 'true' : 'false' );
|
||||
} elseif ( $v === null ) {
|
||||
$properties[] = $property_key . 'null';
|
||||
} else {
|
||||
$properties[] = $property_key . $v;
|
||||
}
|
||||
}
|
||||
|
||||
$output = implode( ', ', $properties );
|
||||
|
||||
if ( ! $in_list ) {
|
||||
$output = '{ ' . $output . ' }';
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
/**
|
||||
* CCPA Class
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Assets;
|
||||
|
||||
/**
|
||||
* Class WordAds_California_Privacy
|
||||
*
|
||||
* Implementation of [California Consumer Privacy Act] (https://leginfo.legislature.ca.gov/faces/codes_displayText.xhtml?lawCode=CIV&division=3.&title=1.81.5.&part=4.&chapter=&article=) as applicable to WordAds.
|
||||
* Includes:
|
||||
* - Do Not Sell or Share My Personal Information shortcode and widget.
|
||||
* - Modal notice to toggle opt-in/opt-out.
|
||||
* - Cookie handling. Implements IAB usprivacy cookie specifications.
|
||||
* - Client side geo-detection of California visitors by IP address. Avoids issues with page caching.
|
||||
*/
|
||||
class WordAds_California_Privacy {
|
||||
|
||||
/**
|
||||
* Initializes required scripts and shortcode.
|
||||
*/
|
||||
public static function init() {
|
||||
// Initialize shortcode.
|
||||
add_shortcode( 'ccpa-do-not-sell-link', array( __CLASS__, 'do_not_sell_link_shortcode' ) );
|
||||
add_shortcode( 'privacy-do-not-sell-link', array( __CLASS__, 'do_not_sell_link_shortcode' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue required CCPA JavaScript on the frontend.
|
||||
*/
|
||||
public static function enqueue_scripts() {
|
||||
wp_enqueue_script(
|
||||
'wordads_ccpa',
|
||||
Assets::get_file_url_for_environment(
|
||||
'_inc/build/wordads/js/wordads-ccpa.min.js',
|
||||
'modules/wordads/js/wordads-ccpa.js'
|
||||
),
|
||||
array(),
|
||||
JETPACK__VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
'wordads_ccpa',
|
||||
'ccpaSettings',
|
||||
array(
|
||||
'defaultOptInCookieString' => esc_html( self::get_optin_cookie_string() ),
|
||||
'defaultOptOutCookieString' => esc_html( self::get_optout_cookie_string() ),
|
||||
'ccpaCssUrl' => esc_url( Assets::get_file_url_for_environment( '/css/wordads-ccpa.min.css', '/css/wordads-ccpa.css' ) . '?ver=' . JETPACK__VERSION ),
|
||||
'ajaxUrl' => esc_url( admin_url( 'admin-ajax.php' ) ),
|
||||
'ajaxNonce' => wp_create_nonce( 'ccpa_optout' ),
|
||||
'forceApplies' => wp_json_encode( is_user_logged_in() && current_user_can( 'manage_options' ) ),
|
||||
'strings' => array(
|
||||
'pleaseWait' => esc_html__( 'Please Wait', 'jetpack' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes handlers for admin AJAX.
|
||||
*/
|
||||
public static function init_ajax_actions() {
|
||||
add_action( 'wp_ajax_privacy_optout', array( __CLASS__, 'handle_optout_request' ) );
|
||||
add_action( 'wp_ajax_nopriv_privacy_optout', array( __CLASS__, 'handle_optout_request' ) );
|
||||
|
||||
add_action( 'wp_ajax_privacy_optout_markup', array( __CLASS__, 'handle_optout_markup' ) );
|
||||
add_action( 'wp_ajax_nopriv_privacy_optout_markup', array( __CLASS__, 'handle_optout_markup' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs [privacy-do-not-sell-link] shortcode markup.
|
||||
*
|
||||
* @return string The generated shortcode markup.
|
||||
*/
|
||||
public static function do_not_sell_link_shortcode() {
|
||||
|
||||
// If in the customizer always display the link.
|
||||
if ( is_customize_preview() ) {
|
||||
return '<a href="#" class="ccpa-do-not-sell">' . self::get_optout_link_text() . '</a>';
|
||||
}
|
||||
|
||||
// Load required scripts if the shortcode/widget is loaded on the page.
|
||||
self::enqueue_scripts();
|
||||
|
||||
return '<a href="#" class="ccpa-do-not-sell" style="display: none;">' . self::get_optout_link_text() . '</a>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text used to link to the opt-out page. By law must read 'Do Not Sell or Share My Personal Information'.
|
||||
*
|
||||
* @return mixed|string|void The text of the opt-out link.
|
||||
*/
|
||||
private static function get_optout_link_text() {
|
||||
return __( 'Do Not Sell or Share My Personal Information', 'jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the value of the opt-out cookie.
|
||||
* Format matches spec of [IAB U.S. Privacy String](https://github.com/InteractiveAdvertisingBureau/USPrivacy/blob/master/CCPA/US%20Privacy%20String.md).
|
||||
*
|
||||
* @param bool $optout True if setting an opt-out cookie.
|
||||
*
|
||||
* @return string The value to be stored in the opt-out cookie.
|
||||
*/
|
||||
private static function build_iab_privacy_string( $optout ) {
|
||||
$values = array(
|
||||
'1', // Specification version.
|
||||
'Y', // Explicit notice to opt-out provided.
|
||||
$optout ? 'Y' : 'N', // Opt-out of data sale.
|
||||
'N', // Signatory to IAB Limited Service Provider Agreement.
|
||||
);
|
||||
|
||||
return implode( $values );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name to be used for the opt-out cookie.
|
||||
* Name matches spec of [IAB U.S. Privacy String](https://github.com/InteractiveAdvertisingBureau/USPrivacy/blob/master/CCPA/US%20Privacy%20String.md).
|
||||
*
|
||||
* @return string The name of the opt-out cookie.
|
||||
*/
|
||||
private static function get_cookie_name() {
|
||||
return 'usprivacy';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the domain to be used for the opt-out cookie.
|
||||
* Use the site's custom domain, or if the site has a wordpress.com subdomain, use .wordpress.com to share the cookie.
|
||||
*
|
||||
* @return string The domain to set for the opt-out cookie.
|
||||
*/
|
||||
public static function get_cookie_domain() {
|
||||
$host = 'localhost';
|
||||
|
||||
if ( isset( $_SERVER['HTTP_HOST'] ) ) {
|
||||
$host = filter_var( wp_unslash( $_SERVER['HTTP_HOST'] ) );
|
||||
}
|
||||
|
||||
return '.wordpress.com' === substr( $host, -strlen( '.wordpress.com' ) ) ? '.wordpress.com' : '.' . $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value to be used when an opt-out cookie is set.
|
||||
*
|
||||
* @return string The value to store in the opt-out cookie.
|
||||
*/
|
||||
private static function get_optout_cookie_string() {
|
||||
return self::build_iab_privacy_string( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value to be used when an opt-in cookie is set.
|
||||
*
|
||||
* @return string The value to store in the opt-in cookie.
|
||||
*/
|
||||
private static function get_optin_cookie_string() {
|
||||
return self::build_iab_privacy_string( false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a cookie in the HTTP response to opt-out visitors from data sales.
|
||||
*
|
||||
* @return bool True if the cookie could be set.
|
||||
*/
|
||||
private static function set_optout_cookie() {
|
||||
return setcookie( self::get_cookie_name(), self::get_optout_cookie_string(), time() + ( 5 * YEAR_IN_SECONDS ), '/', self::get_cookie_domain(), is_ssl(), false ); // phpcs:ignore Jetpack.Functions.SetCookie -- Want this accessible.
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a cookie in the HTTP response to opt-in visitors from data sales.
|
||||
*
|
||||
* @return bool True if the cookie could be set.
|
||||
*/
|
||||
private static function set_optin_cookie() {
|
||||
return setcookie( self::get_cookie_name(), self::get_optin_cookie_string(), time() + YEAR_IN_SECONDS, '/', self::get_cookie_domain(), is_ssl(), false ); // phpcs:ignore Jetpack.Functions.SetCookie -- Want this accessible.
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for opt-in/opt-out AJAX request.
|
||||
*/
|
||||
public static function handle_optout_request() {
|
||||
check_ajax_referer( 'ccpa_optout', 'security' );
|
||||
|
||||
$optout = isset( $_POST['optout'] ) && 'true' === $_POST['optout'];
|
||||
$optout ? self::set_optout_cookie() : self::set_optin_cookie();
|
||||
|
||||
wp_send_json_success( $optout );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for modal popup notice markup.
|
||||
*/
|
||||
public static function handle_optout_markup() {
|
||||
check_ajax_referer( 'ccpa_optout', 'security' );
|
||||
|
||||
header( 'Content-Type: text/html; charset=utf-8' );
|
||||
$policy_url = get_option( 'wordads_ccpa_privacy_policy_url' );
|
||||
|
||||
$default_disclosure = sprintf(
|
||||
'<p>%s</p>
|
||||
<p>%s</p>
|
||||
<p><strong>%s</strong></p>
|
||||
<p>%s</p>
|
||||
<p>%s</p>
|
||||
<p>%s</p>',
|
||||
esc_html__( 'If you are a resident of certain US states, you have the right to opt out of the "sale" of your "personal information" under your state\'s privacy laws.', 'jetpack' ),
|
||||
esc_html__( 'This site operates an ads program in partnership with third-party vendors who help place ads. Advertising cookies enable these ads partners to serve ads, to personalize those ads based on information like visits to this site and other sites on the internet, and to understand how users engage with those ads. Cookies collect certain information as part of the ads program, and we provide the following categories of information to third-party advertising partners: online identifiers and internet or other network or device activity (such as unique identifiers, cookie information, and IP address), and geolocation data (approximate location information from your IP address). This type of sharing with ads partners may be considered a "sale" of personal information under your state\'s privacy laws.', 'jetpack' ),
|
||||
esc_html__( 'We never share information that identifies you personally, like your name or email address, as part of the advertising program.', 'jetpack' ),
|
||||
esc_html__( 'If you\'d prefer not to see ads that are personalized based on information from your visits to this site, you can opt-out by toggling the "Do Not Sell or Share My Personal Information" switch below to the On position.', 'jetpack' ),
|
||||
esc_html__( 'This opt-out is managed through cookies, so if you delete cookies, your browser is set to delete cookies automatically after a certain length of time, or if you visit this site with a different browser, you\'ll need to make this selection again.', 'jetpack' ),
|
||||
esc_html__( 'After you opt-out you may still see ads, including personalized ones, on this site and other sites - they just won\'t be personalized based on information from your visits to this site.', 'jetpack' )
|
||||
);
|
||||
|
||||
/**
|
||||
* Filter on the default CCPA disclosure text.
|
||||
*
|
||||
* @see https://jetpack.com/support/ads/
|
||||
*
|
||||
* @module wordads
|
||||
*
|
||||
* @since 8.7.0
|
||||
*
|
||||
* @param string Default CCPA disclosure for WordAds.
|
||||
*/
|
||||
$disclosure = apply_filters( 'wordads_ccpa_disclosure', $default_disclosure );
|
||||
?>
|
||||
<div id="ccpa-modal" class="cleanslate">
|
||||
<div class="components-modal__screen-overlay">
|
||||
<div tabindex="0"></div>
|
||||
<div role="dialog" aria-labelledby="dialog_label" aria-modal="true" class="components-modal__frame">
|
||||
<div class="components-modal__content ccpa-settings">
|
||||
<div class="components-modal__header">
|
||||
<div class="components-modal__header-heading-container">
|
||||
<h1 id="dialog_label" class="components-modal__header-heading"><?php esc_html_e( 'Do Not Sell or Share My Personal Information', 'jetpack' ); ?></h1>
|
||||
</div>
|
||||
<button type="button" aria-label="<?php esc_html_e( 'Close dialog', 'jetpack' ); ?>" class="components-button components-icon-button">
|
||||
<svg aria-hidden="true" role="img" focusable="false" class="dashicon dashicons-no-alt" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<path d="M14.95 6.46L11.41 10l3.54 3.54-1.41 1.41L10 11.42l-3.53 3.53-1.42-1.42L8.58 10 5.05 6.47l1.42-1.42L10 8.58l3.54-3.53z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="ccpa-settings__intro-txt"><?php echo wp_kses( $disclosure, wp_kses_allowed_html( 'post' ) ); ?></div>
|
||||
<div class="components-modal__footer">
|
||||
<div role="form" class="ccpa-setting">
|
||||
<label>
|
||||
<span class="ccpa-setting__header"><?php esc_html_e( 'Do Not Sell or Share My Personal Information', 'jetpack' ); ?></span>
|
||||
<span class="ccpa-setting__toggle components-form-toggle">
|
||||
<input id="ccpa-opt-out" class="components-form-toggle__input opt-out" type="checkbox" value="false" autofocus />
|
||||
<span class="components-form-toggle__track"></span>
|
||||
<span class="components-form-toggle__thumb"></span>
|
||||
<svg class="components-form-toggle__on" width="2" height="6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2 6" role="img" aria-hidden="true" focusable="false"><path d="M0 0h2v6H0z"></path></svg>
|
||||
<svg class="components-form-toggle__off" width="6" height="6" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 6 6" role="img" aria-hidden="true" focusable="false"><path d="M3 1.5c.8 0 1.5.7 1.5 1.5S3.8 4.5 3 4.5 1.5 3.8 1.5 3 2.2 1.5 3 1.5M3 0C1.3 0 0 1.3 0 3s1.3 3 3 3 3-1.3 3-3-1.3-3-3-3z"></path></svg>
|
||||
</span>
|
||||
<span class="ccpa-setting__toggle-text ccpa-setting__toggle-text-off"><?php esc_html_e( 'Off', 'jetpack' ); ?></span>
|
||||
<span class="ccpa-setting__toggle-text ccpa-setting__toggle-text-on"><?php esc_html_e( 'On', 'jetpack' ); ?></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="components-modal__footer-bottom">
|
||||
<button class="components-button is-button is-primary"><?php esc_html_e( 'Close', 'jetpack' ); ?></button>
|
||||
<?php
|
||||
if ( $policy_url ) {
|
||||
printf(
|
||||
'<a href="%s" class="ccpa-privacy">%s</a>',
|
||||
esc_url( $policy_url ),
|
||||
esc_html__( 'View Privacy Policy', 'jetpack' )
|
||||
);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
wp_die();
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* CCPA Do Not Sell Widget
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WordAds_Ccpa_Do_Not_Sell_Link_Widget
|
||||
*/
|
||||
class WordAds_Ccpa_Do_Not_Sell_Link_Widget extends WP_Widget {
|
||||
|
||||
/**
|
||||
* WordAds_Ccpa_Do_Not_Sell_Link_Widget constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'wordads_ccpa_do_not_sell_link_widget',
|
||||
/** This filter is documented in modules/widgets/facebook-likebox.php */
|
||||
apply_filters( 'jetpack_widget_name', __( 'Do Not Sell Link (US Privacy)', 'jetpack' ) ),
|
||||
array(
|
||||
'description' => __( 'Inserts "Do Not Sell or Share My Personal Information" link required by some US states to opt-out of targeted advertising', 'jetpack' ),
|
||||
'customize_selective_refresh' => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Widget outputter.
|
||||
*
|
||||
* @param array $args Widget args.
|
||||
* @param array $instance Widget instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo do_shortcode( '[privacy-do-not-sell-link]' );
|
||||
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
}
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* WordAds Consent Management Provider
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Assets;
|
||||
|
||||
/**
|
||||
* Class WordAds_Consent_Management_Provider
|
||||
*
|
||||
* This is an integration with the GDPR Consent Management Provider
|
||||
* to comply with GDPR requirements for privacy and transparency related to advertising.
|
||||
*/
|
||||
class WordAds_Consent_Management_Provider {
|
||||
|
||||
/**
|
||||
* IAB specified cookie name for storing the consent string.
|
||||
*/
|
||||
const COOKIE_NAME = 'euconsent-v2';
|
||||
|
||||
/**
|
||||
* Initializes loading of the frontend framework.
|
||||
*/
|
||||
public static function init() {
|
||||
// Prevent Cookies & Consent banner from displaying when the CMP is active.
|
||||
add_filter( 'jetpack_disable_eu_cookie_law_widget', '__return_true' );
|
||||
add_filter( 'jetpack_disable_cookie_consent_block', '__return_true' );
|
||||
|
||||
// Enqueue scripts.
|
||||
add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_frontend_scripts' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handlers for fetching purposes and vendor data and setting the cookie serverside.
|
||||
*
|
||||
* Serverside cookie used so that the expiration can be longer than one week.
|
||||
* This function is called from: /mu-plugins/wordads-ajax.php to ensure they run on all
|
||||
* requests including admin requests.
|
||||
*/
|
||||
public static function init_ajax_actions() {
|
||||
add_action( 'wp_ajax_gdpr_set_consent', array( __CLASS__, 'handle_set_consent_request' ) );
|
||||
add_action( 'wp_ajax_nopriv_gdpr_set_consent', array( __CLASS__, 'handle_set_consent_request' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for setting consent cookie AJAX request.
|
||||
*/
|
||||
public static function handle_set_consent_request() {
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||
if ( ! isset( $_POST['consent'] ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
// TODO: Is there better sanitizing we can do here?
|
||||
$consent = trim( wp_unslash( $_POST['consent'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
|
||||
setcookie( self::COOKIE_NAME, $consent, time() + YEAR_IN_SECONDS, '/', self::get_cookie_domain(), is_ssl(), false ); // phpcs:ignore Jetpack.Functions.SetCookie -- Client side CMP needs to be able to read this value.
|
||||
|
||||
wp_send_json_success( true );
|
||||
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues the main frontend Javascript.
|
||||
*/
|
||||
public static function enqueue_frontend_scripts() {
|
||||
Assets::register_script(
|
||||
'cmp_script_loader',
|
||||
'_inc/build/wordads/js/cmp-loader.min.js',
|
||||
JETPACK__PLUGIN_FILE,
|
||||
array(
|
||||
'nonmin_path' => 'modules/wordads/js/cmp-loader.js',
|
||||
'dependencies' => array(),
|
||||
'enqueue' => true,
|
||||
'version' => JETPACK__VERSION,
|
||||
)
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'cmp_config_script',
|
||||
esc_url( self::get_config_url() ),
|
||||
array( 'cmp_script_loader' ),
|
||||
JETPACK__VERSION,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value to be used when an opt-in cookie is set.
|
||||
*
|
||||
* @return string The value to store in the opt-in cookie.
|
||||
*/
|
||||
private static function get_config_url() {
|
||||
return sprintf(
|
||||
'https://public-api.wordpress.com/wpcom/v2/sites/%1$d/cmp/configuration/%2$s/?_jsonp=a8c_cmp_callback',
|
||||
(int) Jetpack_Options::get_option( 'id' ),
|
||||
strtolower( get_locale() ) // Defaults to en_US not en.
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the domain to be used for the opt-out cookie.
|
||||
* Use the site's custom domain, or if the site has a wordpress.com subdomain, use .wordpress.com to share the cookie.
|
||||
*
|
||||
* @return string The domain to set for the opt-out cookie.
|
||||
*/
|
||||
public static function get_cookie_domain() {
|
||||
$host = 'localhost';
|
||||
|
||||
if ( isset( $_SERVER['HTTP_HOST'] ) ) {
|
||||
$host = filter_var( wp_unslash( $_SERVER['HTTP_HOST'] ) );
|
||||
}
|
||||
|
||||
return '.wordpress.com' === substr( $host, -strlen( '.wordpress.com' ) ) ? '.wordpress.com' : '.' . $host;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* WordAds cron tasks.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* WordAds cron tasks
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
class WordAds_Cron {
|
||||
|
||||
/**
|
||||
* Add the actions the cron tasks will use
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'wordads_cron_status', array( $this, 'update_wordads_status' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registered scheduled events on activation
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public static function activate() {
|
||||
wp_schedule_event( time(), 'daily', 'wordads_cron_status' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear scheduled hooks on deactivation
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public static function deactivate() {
|
||||
wp_clear_scheduled_hook( 'wordads_cron_status' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Grab WordAds status from WP.com API
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public static function update_wordads_status() {
|
||||
WordAds_API::update_wordads_status_from_api();
|
||||
}
|
||||
}
|
||||
|
||||
global $wordads_cron;
|
||||
$wordads_cron = new WordAds_Cron();
|
||||
@@ -0,0 +1,325 @@
|
||||
<?php
|
||||
/**
|
||||
* WordAds Param Class file.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Status;
|
||||
|
||||
/**
|
||||
* Class WordAds_Params
|
||||
*
|
||||
* Sets parameters for WordAds.
|
||||
*/
|
||||
class WordAds_Params {
|
||||
/**
|
||||
* WordAds options
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $options;
|
||||
|
||||
/**
|
||||
* Current URL
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
public $url;
|
||||
|
||||
/**
|
||||
* Is this site served by CloudFlare?
|
||||
*
|
||||
* @access public
|
||||
* @var bool
|
||||
*/
|
||||
public $cloudflare;
|
||||
|
||||
/**
|
||||
* Jetpack Blog ID
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
public $blog_id;
|
||||
|
||||
/**
|
||||
* Determine if the current User Agent is a mobile device
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $mobile_device;
|
||||
|
||||
/**
|
||||
* WordAds targeting tags
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $targeting_tags;
|
||||
|
||||
/**
|
||||
* Type of page that is being loaded
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $page_type;
|
||||
|
||||
/**
|
||||
* Page type code for IPW config
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $page_type_ipw;
|
||||
|
||||
/**
|
||||
* Is this an AMP request?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $is_amp;
|
||||
|
||||
/**
|
||||
* Setup parameters for serving the ads
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public function __construct() {
|
||||
// WordAds setting => default.
|
||||
$settings = array(
|
||||
'wordads_approved' => false,
|
||||
'wordads_active' => false,
|
||||
'wordads_house' => true,
|
||||
'wordads_unsafe' => false,
|
||||
'enable_header_ad' => true,
|
||||
'wordads_second_belowpost' => true,
|
||||
'wordads_inline_enabled' => true,
|
||||
'wordads_bottom_sticky_enabled' => false,
|
||||
'wordads_sidebar_sticky_right_enabled' => false,
|
||||
'wordads_display_front_page' => true,
|
||||
'wordads_display_post' => true,
|
||||
'wordads_display_page' => true,
|
||||
'wordads_display_archive' => true,
|
||||
'wordads_custom_adstxt' => '',
|
||||
'wordads_custom_adstxt_enabled' => false,
|
||||
'wordads_ccpa_enabled' => false,
|
||||
'wordads_ccpa_privacy_policy_url' => get_option( 'wp_page_for_privacy_policy' ) ? get_permalink( (int) get_option( 'wp_page_for_privacy_policy' ) ) : '',
|
||||
'wordads_cmp_enabled' => false,
|
||||
);
|
||||
|
||||
// Grab settings, or set as default if it doesn't exist.
|
||||
$this->options = array();
|
||||
|
||||
foreach ( $settings as $setting => $default ) {
|
||||
$option = get_option( $setting, null );
|
||||
|
||||
if ( $option === null ) {
|
||||
|
||||
// Handle retroactively setting wordads_custom_adstxt_enabled to true if custom ads.txt content is already entered.
|
||||
if ( 'wordads_custom_adstxt_enabled' === $setting ) {
|
||||
$default = get_option( 'wordads_custom_adstxt' ) !== '';
|
||||
}
|
||||
|
||||
// Convert boolean options to string first to work around update_option not setting the option if the value is false.
|
||||
// This sets the option to either '1' if true or '' if false.
|
||||
update_option( $setting, (string) $default, true );
|
||||
|
||||
$option = $default;
|
||||
}
|
||||
|
||||
$this->options[ $setting ] = is_bool( $default ) ? (bool) $option : $option;
|
||||
}
|
||||
|
||||
$this->url = esc_url_raw( ( is_ssl() ? 'https' : 'http' ) . '://' . ( isset( $_SERVER['HTTP_HOST'] ) ? wp_unslash( $_SERVER['HTTP_HOST'] ) : 'localhost' ) . ( isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '' ) );
|
||||
if ( str_contains( $this->url, '?' ) && ! isset( $_GET['p'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
$this->url = substr( $this->url, 0, strpos( $this->url, '?' ) );
|
||||
}
|
||||
|
||||
$this->cloudflare = self::is_cloudflare();
|
||||
$this->blog_id = Jetpack::get_option( 'id', 0 );
|
||||
$this->mobile_device = jetpack_is_mobile( 'any', true );
|
||||
$this->targeting_tags = array(
|
||||
'WordAds' => 1,
|
||||
'BlogId' => ( new Status() )->is_offline_mode() ? 0 : Jetpack_Options::get_option( 'id' ),
|
||||
'Domain' => esc_js( wp_parse_url( home_url(), PHP_URL_HOST ) ),
|
||||
'PageURL' => esc_js( $this->url ),
|
||||
'LangId' => str_contains( get_bloginfo( 'language' ), 'en' ) ? 1 : 0, // TODO something else?
|
||||
'AdSafe' => 1, // TODO.
|
||||
);
|
||||
$this->is_amp = function_exists( 'amp_is_request' ) && amp_is_request();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this a mobile device?
|
||||
*
|
||||
* @return boolean true if the user is browsing on a mobile device (iPad not included)
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public function is_mobile() {
|
||||
return ! empty( $this->mobile_device );
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this site served by CloudFlare?
|
||||
*
|
||||
* @return boolean true if site is being served via CloudFlare
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public static function is_cloudflare() {
|
||||
if (
|
||||
defined( 'WORDADS_CLOUDFLARE' )
|
||||
|| isset( $_SERVER['HTTP_CF_CONNECTING_IP'] )
|
||||
|| isset( $_SERVER['HTTP_CF_IPCOUNTRY'] )
|
||||
|| isset( $_SERVER['HTTP_CF_VISITOR'] )
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this an iOS device?
|
||||
*
|
||||
* @return boolean true if user is browsing in iOS device
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public function is_ios() {
|
||||
return in_array( $this->get_device(), array( 'ipad', 'iphone', 'ipod' ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user's device (see user-agent.php) or 'desktop'
|
||||
*
|
||||
* @return string user device
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public function get_device() {
|
||||
global $agent_info;
|
||||
|
||||
if ( ! empty( $this->mobile_device ) ) {
|
||||
return $this->mobile_device;
|
||||
}
|
||||
|
||||
if ( $agent_info->is_ipad() ) {
|
||||
return 'ipad';
|
||||
}
|
||||
|
||||
return 'desktop';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get page type.
|
||||
*
|
||||
* @return string The type of page that is being loaded
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public function get_page_type() {
|
||||
if ( ! empty( $this->page_type ) ) {
|
||||
return $this->page_type;
|
||||
}
|
||||
|
||||
if ( self::is_static_home() ) {
|
||||
$this->page_type = 'static_home';
|
||||
} elseif ( is_home() ) {
|
||||
$this->page_type = 'home';
|
||||
} elseif ( is_page() ) {
|
||||
$this->page_type = 'page';
|
||||
} elseif ( is_single() ) {
|
||||
$this->page_type = 'post';
|
||||
} elseif ( is_search() ) {
|
||||
$this->page_type = 'search';
|
||||
} elseif ( is_category() ) {
|
||||
$this->page_type = 'category';
|
||||
} elseif ( is_archive() ) {
|
||||
$this->page_type = 'archive';
|
||||
} else {
|
||||
$this->page_type = 'wtf';
|
||||
}
|
||||
|
||||
return $this->page_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IPW code.
|
||||
*
|
||||
* @return int The page type code for ipw config
|
||||
*
|
||||
* @since 5.6.0
|
||||
*/
|
||||
public function get_page_type_ipw() {
|
||||
if ( ! empty( $this->page_type_ipw ) ) {
|
||||
return $this->page_type_ipw;
|
||||
}
|
||||
|
||||
$page_type_ipw = 6;
|
||||
if ( self::is_static_home() || is_home() || is_front_page() ) {
|
||||
$page_type_ipw = 0;
|
||||
} elseif ( is_page() ) {
|
||||
$page_type_ipw = 2;
|
||||
} elseif ( is_singular() ) {
|
||||
$page_type_ipw = 1;
|
||||
} elseif ( is_search() ) {
|
||||
$page_type_ipw = 4;
|
||||
} elseif ( is_category() || is_tag() || is_archive() || is_author() ) {
|
||||
$page_type_ipw = 3;
|
||||
} elseif ( is_404() ) {
|
||||
$page_type_ipw = 5;
|
||||
}
|
||||
|
||||
$this->page_type_ipw = $page_type_ipw;
|
||||
return $page_type_ipw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if page is static home
|
||||
*
|
||||
* @return boolean true if page is static home
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public static function is_static_home() {
|
||||
return is_front_page() &&
|
||||
'page' === get_option( 'show_on_front' ) &&
|
||||
get_option( 'page_on_front' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Logic for if we should show an ad
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public function should_show() {
|
||||
global $wp_query;
|
||||
if ( ( is_front_page() || is_home() ) && ! $this->options['wordads_display_front_page'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_single() && ! $this->options['wordads_display_post'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_page() && ! $this->options['wordads_display_page'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ( is_archive() || is_search() ) && ! $this->options['wordads_display_archive'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_single() || ( is_page() && ! is_home() ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO this would be a good place for allowing the user to specify.
|
||||
if ( ( is_home() || is_archive() || is_search() ) && 0 === $wp_query->current_post ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Wordads shortcode.
|
||||
*
|
||||
* Examples:
|
||||
* [wordads]
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WordAds_Shortcode
|
||||
*
|
||||
* Handles the [wordads] shortcode.
|
||||
*/
|
||||
class WordAds_Shortcode {
|
||||
|
||||
/**
|
||||
* Register our shortcode and enqueue necessary files.
|
||||
*/
|
||||
public static function init() {
|
||||
global $wordads;
|
||||
|
||||
if ( empty( $wordads ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
add_shortcode( 'wordads', array( self::class, 'handle_wordads_shortcode' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Our [wordads] shortcode.
|
||||
* Prints a WordAds Ad.
|
||||
*
|
||||
* @return string HTML for WordAds shortcode.
|
||||
*/
|
||||
public static function handle_wordads_shortcode() {
|
||||
global $wordads;
|
||||
|
||||
if ( empty( $wordads ) ) {
|
||||
return '<div>' . __( 'The WordAds module is not active', 'jetpack' ) . '</div>';
|
||||
}
|
||||
|
||||
$html = '<div class="jetpack-wordad" itemscope itemtype="https://schema.org/WPAdBlock"></div>';
|
||||
|
||||
return $wordads->insert_inline_ad( $html );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
/**
|
||||
* Widget for adding ads to a sidebar.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
/**
|
||||
* Widget for inserting an ad into your sidebar
|
||||
*
|
||||
* @since 4.5.0
|
||||
*/
|
||||
class WordAds_Sidebar_Widget extends WP_Widget {
|
||||
|
||||
/**
|
||||
* Allowed tags.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private static $allowed_tags = array( 'mrec', 'wideskyscraper', 'leaderboard' );
|
||||
|
||||
/**
|
||||
* Mapping array of widget sizes with the WordAds_Smart formats.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private static $sizes_x_smart_format = array(
|
||||
'300x250' => 'sidebar_widget_mediumrectangle',
|
||||
'728x90' => 'sidebar_widget_leaderboard',
|
||||
'160x600' => 'sidebar_widget_wideskyscraper',
|
||||
);
|
||||
|
||||
/**
|
||||
* Number of widgets.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $num_widgets = 0;
|
||||
|
||||
/**
|
||||
* WordAds_Sidebar_Widget constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
'wordads_sidebar_widget',
|
||||
/** This filter is documented in modules/widgets/facebook-likebox.php */
|
||||
apply_filters( 'jetpack_widget_name', 'Ads' ),
|
||||
array(
|
||||
'description' => __( 'Insert an ad unit wherever you can place a widget.', 'jetpack' ),
|
||||
'customize_selective_refresh' => true,
|
||||
)
|
||||
);
|
||||
|
||||
add_filter( 'widget_types_to_hide_from_legacy_widget_block', array( $this, 'hide_widget_in_block_editor' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the Ad widget from the Legacy Widget block
|
||||
*
|
||||
* @param array $widget_types List of widgets that are currently removed from the Legacy Widget block.
|
||||
*
|
||||
* @return array $widget_types New list of widgets that will be removed.
|
||||
*/
|
||||
public function hide_widget_in_block_editor( $widget_types ) {
|
||||
$widget_types[] = 'wordads_sidebar_widget';
|
||||
return $widget_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Widget outputter.
|
||||
*
|
||||
* @param array $args Widget args.
|
||||
* @param array $instance The Widget instance.
|
||||
*
|
||||
* @return bool|void
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
global $wordads;
|
||||
if ( $wordads->should_bail() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $instance['unit'] ) ) {
|
||||
$instance['unit'] = 'mrec';
|
||||
}
|
||||
|
||||
++self::$num_widgets;
|
||||
$width = WordAds::$ad_tag_ids[ $instance['unit'] ]['width'];
|
||||
$height = WordAds::$ad_tag_ids[ $instance['unit'] ]['height'];
|
||||
$unit_id = 1 === self::$num_widgets ? 3 : self::$num_widgets + 3; // 2nd belowpost is '4'
|
||||
$section_id = 0 === $wordads->params->blog_id ?
|
||||
WORDADS_API_TEST_ID :
|
||||
$wordads->params->blog_id . $unit_id;
|
||||
|
||||
$smart_format = self::$sizes_x_smart_format[ "{$width}x{$height}" ];
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
$is_watl_enabled = isset( $_GET['wordads-logging'] ) && isset( $_GET[ $smart_format ] ) && 'true' === $_GET[ $smart_format ];
|
||||
|
||||
// Get the widget snippet.
|
||||
$widget_snippet = $this->get_widget_snippet( $instance, $section_id, $height, $width );
|
||||
|
||||
// Render the IPW or house ad if WATL is disabled.
|
||||
if ( ! $is_watl_enabled ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $widget_snippet;
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove linebreaks and sanitize.
|
||||
$tag = esc_js( str_replace( array( "\n", "\t", "\r" ), '', $widget_snippet ) );
|
||||
|
||||
// Add the fallback to be processed by WATL.
|
||||
$fallback_snippet = <<<HTML
|
||||
<script type="text/javascript">
|
||||
var sas_fallback = sas_fallback || [];
|
||||
sas_fallback.push(
|
||||
{ tag: "$tag", type: '$smart_format' }
|
||||
);
|
||||
</script>
|
||||
HTML;
|
||||
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $fallback_snippet . $wordads::get_watl_ad_html_tag( $smart_format );
|
||||
}
|
||||
|
||||
/**
|
||||
* The widget snippet.
|
||||
*
|
||||
* @param array $instance The widget instance.
|
||||
* @param string $section_id The section id.
|
||||
* @param int $height The ad height.
|
||||
* @param int $width The ad width.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_widget_snippet( $instance, $section_id, $height, $width ) {
|
||||
global $wordads;
|
||||
|
||||
if ( $wordads->option( 'wordads_house', true ) ) {
|
||||
$unit = 'mrec';
|
||||
if ( 'leaderboard' === $instance['unit'] && ! $this->params->mobile_device ) {
|
||||
$unit = 'leaderboard';
|
||||
} elseif ( 'wideskyscraper' === $instance['unit'] ) {
|
||||
$unit = 'widesky';
|
||||
}
|
||||
|
||||
$snippet = $wordads->get_house_ad( $unit );
|
||||
} else {
|
||||
return $wordads->get_ad_snippet( $section_id, $height, $width, 'widget' );
|
||||
}
|
||||
|
||||
$about = __( 'Advertisements', 'jetpack' );
|
||||
$unit = esc_attr( $instance['unit'] );
|
||||
|
||||
return <<<HTML
|
||||
<div class="wpcnt">
|
||||
<div class="wpa">
|
||||
<span class="wpa-about">$about</span>
|
||||
<div class="u $unit">
|
||||
$snippet
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
HTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* The widget settings form.
|
||||
*
|
||||
* @param array $instance Widget instance.
|
||||
*
|
||||
* @return string|void
|
||||
*/
|
||||
public function form( $instance ) {
|
||||
// ad unit type.
|
||||
if ( isset( $instance['unit'] ) ) {
|
||||
$unit = $instance['unit'];
|
||||
} else {
|
||||
$unit = 'mrec';
|
||||
}
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr( $this->get_field_id( 'unit' ) ); ?>"><?php esc_html_e( 'Tag Dimensions:', 'jetpack' ); ?></label>
|
||||
<select class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'unit' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'unit' ) ); ?>">
|
||||
<?php
|
||||
foreach ( WordAds::$ad_tag_ids as $ad_unit => $properties ) {
|
||||
if ( ! in_array( $ad_unit, self::$allowed_tags, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$splits = explode( '_', $properties['tag'] );
|
||||
$unit_pretty = "{$splits[0]} {$splits[1]}";
|
||||
$selected = selected( $ad_unit, $unit, false );
|
||||
echo "<option value='", esc_attr( $ad_unit ), "' ", esc_attr( $selected ), '>', esc_html( $unit_pretty ), '</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* The Widget updater.
|
||||
*
|
||||
* @param array $new_instance The revised instance.
|
||||
* @param array $old_instance Original instance.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function update( $new_instance, $old_instance ) {
|
||||
$instance = $old_instance;
|
||||
|
||||
if ( in_array( $new_instance['unit'], self::$allowed_tags, true ) ) {
|
||||
$instance['unit'] = $new_instance['unit'];
|
||||
} else {
|
||||
$instance['unit'] = 'mrec';
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
<?php
|
||||
/**
|
||||
* An implementation for ads served through Equativ Smart Ad Server.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Assets;
|
||||
|
||||
// phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedScript
|
||||
|
||||
require_once WORDADS_ROOT . '/php/class-wordads-array-utils.php';
|
||||
|
||||
/**
|
||||
* Contains all the implementation details for Smart ads
|
||||
*/
|
||||
class WordAds_Smart {
|
||||
|
||||
/**
|
||||
* The single instance of the class.
|
||||
*
|
||||
* @var WordAds_Smart
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* The parameters for WordAds.
|
||||
*
|
||||
* @var WordAds_Params
|
||||
*/
|
||||
private $params;
|
||||
|
||||
/**
|
||||
* Has Smart asset been enqueued?
|
||||
*
|
||||
* @var bool True if Smart asset has been enqueued.
|
||||
*/
|
||||
private $is_asset_enqueued = false;
|
||||
|
||||
/**
|
||||
* Supported formats.
|
||||
* sidebar_widget formats represents the legacy Jetpack sidebar widget.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $formats = array(
|
||||
'top' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'inline' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'belowpost' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'bottom_sticky' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'sidebar_sticky_right' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'gutenberg_rectangle' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'gutenberg_leaderboard' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'gutenberg_mobile_leaderboard' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'gutenberg_skyscraper' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'sidebar_widget_mediumrectangle' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'sidebar_widget_leaderboard' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'sidebar_widget_wideskyscraper' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
'shortcode' => array(
|
||||
'enabled' => false,
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
*/
|
||||
private function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Main Class Instance.
|
||||
*
|
||||
* Ensures only one instance of WordAds_Smart is loaded or can be loaded.
|
||||
*
|
||||
* @return WordAds_Smart
|
||||
*/
|
||||
public static function instance(): self {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the ads.
|
||||
*
|
||||
* @param WordAds_Params $params Object containing WordAds settings.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init( WordAds_Params $params ) {
|
||||
$this->params = $params;
|
||||
|
||||
$this->enable_formats();
|
||||
$this->override_formats_from_query_string();
|
||||
|
||||
if ( $this->has_any_format_enabled() ) {
|
||||
$this->insert_ads();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue any front-end CSS and JS.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_assets() {
|
||||
|
||||
if ( $this->is_asset_enqueued ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'wp_head', array( $this, 'insert_config' ) );
|
||||
|
||||
Assets::register_script(
|
||||
'adflow_script_loader',
|
||||
'_inc/build/wordads/js/adflow-loader.min.js',
|
||||
JETPACK__PLUGIN_FILE,
|
||||
array(
|
||||
'nonmin_path' => 'modules/wordads/js/adflow-loader.js',
|
||||
'dependencies' => array(),
|
||||
'enqueue' => true,
|
||||
'version' => JETPACK__VERSION,
|
||||
)
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'adflow_config',
|
||||
esc_url( $this->get_config_url() ),
|
||||
array( 'adflow_script_loader' ),
|
||||
JETPACK__VERSION,
|
||||
false
|
||||
);
|
||||
|
||||
$this->is_asset_enqueued = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts ad tags on the page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function insert_ads() {
|
||||
if ( $this->params->is_amp ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't run on not found pages.
|
||||
if ( is_404() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the resource hints.
|
||||
add_filter( 'wp_resource_hints', array( $this, 'resource_hints' ), 10, 2 );
|
||||
|
||||
// Enqueue JS assets.
|
||||
$this->enqueue_assets();
|
||||
|
||||
$is_static_front_page = is_front_page() && 'page' === get_option( 'show_on_front' );
|
||||
|
||||
if ( ! ( $is_static_front_page || is_home() ) ) {
|
||||
if ( $this->formats['inline']['enabled'] ) {
|
||||
add_filter(
|
||||
'the_content',
|
||||
array( $this, 'insert_inline_marker' ),
|
||||
10
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->formats['bottom_sticky']['enabled'] ) {
|
||||
// Disable IPW slot.
|
||||
add_filter( 'wordads_iponweb_bottom_sticky_ad_disable', '__return_true', 10 );
|
||||
}
|
||||
|
||||
if ( $this->formats['sidebar_sticky_right']['enabled'] ) {
|
||||
// Disable IPW slot.
|
||||
add_filter( 'wordads_iponweb_sidebar_sticky_right_ad_disable', '__return_true', 10 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts JS configuration used by watl.js.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function insert_config() {
|
||||
global $post;
|
||||
|
||||
$config = array(
|
||||
'post_id' => ( $post instanceof WP_Post ) && is_singular( 'post' ) ? $post->ID : null,
|
||||
'origin' => 'jetpack',
|
||||
'theme' => get_stylesheet(),
|
||||
'target' => $this->target_keywords(),
|
||||
) + $this->formats;
|
||||
|
||||
// Do conversion.
|
||||
$js_config = WordAds_Array_Utils::array_to_js_object( $config );
|
||||
|
||||
// Output script.
|
||||
wp_print_inline_script_tag( "var wa_smart = $js_config; wa_smart.cmd = [];" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the Smart resource hints.
|
||||
*
|
||||
* @param array $hints Domains for hinting.
|
||||
* @param string $relation_type Resource type.
|
||||
*
|
||||
* @return array Domains for hinting.
|
||||
*/
|
||||
public function resource_hints( $hints, $relation_type ) {
|
||||
if ( 'dns-prefetch' === $relation_type ) {
|
||||
$hints[] = '//af.pubmine.com';
|
||||
}
|
||||
|
||||
return $hints;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL to a JSONP endpoint with configuration data.
|
||||
*
|
||||
* @return string The URL.
|
||||
*/
|
||||
private function get_config_url(): string {
|
||||
return sprintf(
|
||||
'https://public-api.wordpress.com/wpcom/v2/sites/%1$d/adflow/conf/?_jsonp=a8c_adflow_callback',
|
||||
$this->params->blog_id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Places marker at the end of the content so inline can identify the post content container.
|
||||
*
|
||||
* @param string|null $content The post content.
|
||||
* @return string|null The post content with the marker appended.
|
||||
*/
|
||||
public function insert_inline_marker( ?string $content ): ?string {
|
||||
if ( null === $content ) {
|
||||
return null;
|
||||
}
|
||||
$inline_ad_marker = '<span id="wordads-inline-marker" style="display: none;"></span>';
|
||||
|
||||
// Append the ad to the post content.
|
||||
return $content . $inline_ad_marker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a formatted list of target keywords.
|
||||
*
|
||||
* @return string Formatted list of target keywords.
|
||||
*/
|
||||
private function target_keywords(): string {
|
||||
$target_keywords = array_merge(
|
||||
$this->get_blog_keywords(),
|
||||
$this->get_language_keywords()
|
||||
);
|
||||
|
||||
return implode( ';', $target_keywords );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a formatted list of blog keywords.
|
||||
*
|
||||
* @return array The list of blog keywords.
|
||||
*/
|
||||
private function get_blog_keywords(): array {
|
||||
return array( 'wp_blog_id=' . $this->params->blog_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the site language formatted as a keyword.
|
||||
*
|
||||
* @return array The language as a keyword.
|
||||
*/
|
||||
private function get_language_keywords(): array {
|
||||
return array( 'language=' . explode( '-', get_locale() )[0] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable formats by post types and the display options.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function enable_formats(): void {
|
||||
$this->formats['top']['enabled'] = $this->params->options['enable_header_ad'];
|
||||
$this->formats['inline']['enabled'] = is_singular( 'post' ) && $this->params->options['wordads_inline_enabled'];
|
||||
$this->formats['belowpost']['enabled'] = $this->params->should_show();
|
||||
$this->formats['bottom_sticky']['enabled'] = $this->params->options['wordads_bottom_sticky_enabled'];
|
||||
$this->formats['sidebar_sticky_right']['enabled'] = $this->params->options['wordads_sidebar_sticky_right_enabled'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow format enabled override from query string, eg. ?inline=true.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function override_formats_from_query_string(): void {
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( ! isset( $_GET['wordads-logging'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $this->formats as $format_type => $_ ) {
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_GET[ $format_type ] ) && 'true' === $_GET[ $format_type ] ) {
|
||||
$this->formats[ $format_type ]['enabled'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if has any format enabled.
|
||||
*
|
||||
* @return bool True if enabled, false otherwise.
|
||||
*/
|
||||
private function has_any_format_enabled(): bool {
|
||||
return in_array( true, array_column( $this->formats, 'enabled' ), true );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Amazon Network.
|
||||
*
|
||||
* @package automattic/jetpack
|
||||
*/
|
||||
|
||||
// stub.
|
||||
Reference in New Issue
Block a user