Commit inicial - WordPress Análisis de Precios Unitarios

- WordPress core y plugins
- Tema Twenty Twenty-Four configurado
- Plugin allow-unfiltered-html.php simplificado
- .gitignore configurado para excluir wp-config.php y uploads

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2025-11-03 21:04:30 -06:00
commit a22573bf0b
24068 changed files with 4993111 additions and 0 deletions

View File

@@ -0,0 +1,329 @@
<?php
/**
* The class provides utility functions related to check condition related to plugin.
*
* @package AdvancedAds
* @author Advanced Ads <info@wpadvancedads.com>
* @since 1.47.0
*/
namespace AdvancedAds\Utilities;
use Advanced_Ads;
use AdvancedAds\Framework\Utilities\Params;
defined( 'ABSPATH' ) || exit;
/**
* Conditional.
*/
class Conditional {
/**
* Check if the author of the ad can use unfiltered_html.
*
* @param int $author_id User ID of the ad author.
*
* @return bool
*/
public static function can_author_unfiltered_html( $author_id ): bool {
if ( defined( 'DISALLOW_UNFILTERED_HTML' ) && DISALLOW_UNFILTERED_HTML ) {
return false;
}
$unfiltered_allowed = user_can( $author_id, 'unfiltered_html' );
if ( $unfiltered_allowed || ! is_multisite() ) {
return $unfiltered_allowed;
}
$options = Advanced_Ads::get_instance()->options();
if ( ! isset( $options['allow-unfiltered-html'] ) ) {
$options['allow-unfiltered-html'] = [];
}
$allowed_roles = $options['allow-unfiltered-html'];
$user = get_user_by( 'id', $author_id );
if ( ! $user ) {
// In case the author was removed from the site.
$user = wp_get_current_user();
}
return ! empty( array_intersect( $user->roles, $allowed_roles ) );
}
/**
* Checks if the current request is an AJAX request.
* It can be a request to `admin-ajax.php` or to `ajax-handler.php`.
*
* @return bool
*/
public static function doing_ajax(): bool {
return wp_doing_ajax() || 'XMLHttpRequest' === Params::server( 'HTTP_X_REQUESTED_WITH' );
}
/**
* Determines whether the current request is an autosave
*
* @return bool
*/
public static function doing_autosave(): bool {
return defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE;
}
/**
* Check if we have cache enabled on site
*
* @return bool
*/
public static function has_cache_plugins(): bool {
return ( defined( 'WP_CACHE' ) && WP_CACHE ) // General cache constant.
|| defined( 'W3TC' ) // W3 Total Cache.
|| function_exists( 'wp_super_cache_text_domain' ) // WP Super Cache.
|| defined( 'WP_ROCKET_SLUG' ) // WP Rocket.
|| defined( 'WPFC_WP_CONTENT_DIR' ) // WP Fastest Cache.
|| class_exists( 'HyperCache', false ) // Hyper Cache.
|| defined( 'CE_CACHE_DIR' ); // Cache Enabler.
}
/**
* Check if the current screen uses a search or filter.
*
* @return bool
*/
public static function has_filter_or_search(): bool {
$ad_params = [ 's', 'adtype', 'adsize', 'adgroup', 'addate', 'ad_author', 'ad_debugmode', 'ad_displayonce', 'ad_privacyignore' ];
$group_params = [ 's', 'group_type' ];
$placement_params = [ 's', 'placement-type' ];
$params = array_merge( $ad_params, $group_params, $placement_params );
foreach ( $params as $param ) {
if ( ! empty( Params::get( $param ) ) ) {
return true;
}
}
return false;
}
/**
* Check if the current user has a role on this site.
*
* @return bool
*/
public static function has_user_role_on_site(): bool {
return in_array(
get_current_blog_id(),
wp_list_pluck( get_blogs_of_user( get_current_user_id() ), 'userblog_id' ),
true
);
}
/**
* Is entity allowed
*
* @param string $entity Entity to check.
*
* @return boolean
*/
public static function is_entity_allowed( $entity ): bool {
if ( empty( $entity ) || ! in_array( $entity, [ 'ad', 'group', 'placement' ], true ) ) {
return false;
}
return true;
}
/**
* Check if ads are disabled.
*
* @return bool
*/
public static function is_ad_disabled(): bool {
return defined( 'ADVADS_ADS_DISABLED' ) && ADVADS_ADS_DISABLED;
}
/**
* Check if any add-on is activated
*
* @return bool true if there is any add-on activated
*/
public static function is_any_addon_activated(): bool {
return has_action( 'advanced-ads-loaded' );
}
/**
* Check if the current page is an AMP page.
*
* @return bool
*/
public static function is_amp(): bool {
return function_exists( 'advads_is_amp' ) && advads_is_amp();
}
/**
* Check if the current user agent is given or a bot
*
* @return bool
*/
public static function is_ua_bot(): bool {
// show ads on AMP version also for bots in order to allow Google (and maybe others) to cache the page.
if ( self::is_amp() ) {
return false;
}
$user_agent = Params::server( 'HTTP_USER_AGENT', '' );
if ( empty( $user_agent ) ) {
return true;
}
// Make sure delimiters in regex are escaped.
$bots = implode( '|', Data::get_bots() );
$bots = preg_replace( '/(.*?)(?<!\\\)' . preg_quote( '/', '/' ) . '(.*?)/', '$1\\/$2', $bots );
return preg_match( sprintf( '/%s/i', $bots ), wp_unslash( $user_agent ) );
}
/**
* Returns true if a REST request has an Advanced Ads endpoint.
*
* @return bool
*/
public static function is_gutenberg_writing_request(): bool {
global $wp;
$rest_route = $wp->query_vars['rest_route'] ?? '';
$is_writing = in_array( Params::server( 'REQUEST_METHOD' ), [ 'POST', 'PUT' ], true );
$is_gutenberg = mb_strpos( $rest_route, '/wp/v2/posts' ) !== false || mb_strpos( $rest_route, '/wp/v2/pages' ) !== false;
return $is_gutenberg && $is_writing;
}
/**
* Check if php execution is globally forbidden
*
* @return bool
*/
public static function is_php_allowed(): bool {
return ! ( defined( 'ADVANCED_ADS_DISALLOW_PHP' ) && ADVANCED_ADS_DISALLOW_PHP )
&& ! ( defined( 'DISALLOW_FILE_EDIT' ) && DISALLOW_FILE_EDIT );
}
/**
* Returns true if the request is a non-legacy REST API request.
*
* TODO: replace this function once core WP function is available: https://core.trac.wordpress.org/ticket/42061.
*
* @return bool
*/
public static function is_rest_request() {
$request = Params::server( 'REQUEST_URI' );
if ( empty( $request ) ) {
return false;
}
return false !== strpos( $request, trailingslashit( rest_get_url_prefix() ) );
}
/**
* Check if we are on desired screen.
*
* @param array|string $screen_id Screen id.
*
* @return bool
*/
public static function is_screen( $screen_id ): bool {
static $advads_current_screen;
if ( ! is_admin() ) {
return false;
}
if ( null === $advads_current_screen ) {
$advads_current_screen = get_current_screen()->id;
$advads_current_screen = explode( '_page_', $advads_current_screen );
$advads_current_screen = array_pop( $advads_current_screen );
$advads_current_screen = str_replace( 'advanced-ads-', '', $advads_current_screen );
}
return is_array( $screen_id )
? in_array( $advads_current_screen, $screen_id, true )
: $advads_current_screen === $screen_id;
}
/**
* Check if the current screen belongs to Advanced Ads
*
* @return bool
*/
public static function is_screen_advanced_ads(): bool {
if ( ! function_exists( 'get_current_screen' ) ) {
return false;
}
$screen = get_current_screen();
if ( ! isset( $screen->id ) ) {
return false;
}
return in_array( $screen->id, Data::get_admin_screen_ids(), true );
}
/**
* Returns whether the current user has the specified capability.
*
* @param string $capability Capability name.
*
* @return bool
*/
public static function user_can( $capability = 'manage_options' ): bool {
// Admins can do everything.
if ( current_user_can( 'manage_options' ) ) {
return true;
}
return current_user_can(
apply_filters( 'advanced-ads-capability', $capability )
);
}
/**
* Returns the capability needed to perform an action
*
* @param string $capability A capability to check, can be internal to Advanced Ads.
*
* @return string
*/
public static function user_cap( $capability = 'manage_options' ) {
// Admins can do everything.
if ( current_user_can( 'manage_options' ) ) {
return 'manage_options';
}
return apply_filters( 'advanced-ads-capability', $capability );
}
/**
* Check if the user can subscribe to a notice.
*
* @param string $notice Notice ID.
*
* @return bool
*/
public static function user_can_subscribe( $notice ) {
$current_user = wp_get_current_user();
// Early bail!!
if ( empty( $current_user->ID ) || empty( $current_user->user_email ) ) {
return false;
}
$subscribed_notices = get_user_meta( $current_user->ID, 'advanced-ads-subscribed', true );
if ( ! is_array( $subscribed_notices ) ) {
$subscribed_notices = [];
}
// secureserver.net email address belong to GoDaddy (?) and have very, very low open rates. Seems like only temporary setup.
return ( ! isset( $subscribed_notices[ $notice ] ) && is_email( $current_user->user_email ) && false === strpos( $current_user->user_email, 'secureserver.net' ) )
? true : false;
}
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* Utilities Content Injection.
*
* @package AdvancedAds
* @author Advanced Ads <info@wpadvancedads.com>
* @since 1.50.0
*/
namespace AdvancedAds\Utilities;
defined( 'ABSPATH' ) || exit;
/**
* Utilities Content Injection.
*/
class Content_Injection {
/**
* Get html tags for content injection
*
* @since 1.3.5
*
* @return array Tags that can be used for content injection
*/
public static function get_tags(): array {
$headline_tags = apply_filters( 'advanced-ads-headlines-for-ad-injection', [ 'h2', 'h3', 'h4' ] );
$headline_tags = '&lt;' . implode( '&gt;, &lt;', $headline_tags ) . '&gt;';
$tags = apply_filters(
'advanced-ads-tags-for-injection',
[
/* translators: %s is an html tag. */
'p' => sprintf( __( 'paragraph (%s)', 'advanced-ads' ), '&lt;p&gt;' ),
/* translators: %s is an html tag. */
'pwithoutimg' => sprintf( __( 'paragraph without image (%s)', 'advanced-ads' ), '&lt;p&gt;' ),
/* translators: %s is an html tag. */
'h2' => sprintf( __( 'headline 2 (%s)', 'advanced-ads' ), '&lt;h2&gt;' ),
/* translators: %s is an html tag. */
'h3' => sprintf( __( 'headline 3 (%s)', 'advanced-ads' ), '&lt;h3&gt;' ),
/* translators: %s is an html tag. */
'h4' => sprintf( __( 'headline 4 (%s)', 'advanced-ads' ), '&lt;h4&gt;' ),
/* translators: %s is an html tag. */
'headlines' => sprintf( __( 'any headline (%s)', 'advanced-ads' ), $headline_tags ),
/* translators: %s is an html tag. */
'img' => sprintf( __( 'image (%s)', 'advanced-ads' ), '&lt;img&gt;' ),
/* translators: %s is an html tag. */
'table' => sprintf( __( 'table (%s)', 'advanced-ads' ), '&lt;table&gt;' ),
/* translators: %s is an html tag. */
'li' => sprintf( __( 'list item (%s)', 'advanced-ads' ), '&lt;li&gt;' ),
/* translators: %s is an html tag. */
'blockquote' => sprintf( __( 'quote (%s)', 'advanced-ads' ), '&lt;blockquote&gt;' ),
/* translators: %s is an html tag. */
'iframe' => sprintf( __( 'iframe (%s)', 'advanced-ads' ), '&lt;iframe&gt;' ),
/* translators: %s is an html tag. */
'div' => sprintf( __( 'container (%s)', 'advanced-ads' ), '&lt;div&gt;' ),
'anyelement' => __( 'any element', 'advanced-ads' ),
'custom' => _x( 'custom', 'for the "custom" content placement option', 'advanced-ads' ),
]
);
return $tags;
}
}

View File

@@ -0,0 +1,441 @@
<?php
/**
* The class provides utility functions for retrieving and managing plugin data and choices.
*
* @package AdvancedAds
* @author Advanced Ads <info@wpadvancedads.com>
* @since 1.47.0
*/
namespace AdvancedAds\Utilities;
use WP_Role;
use AdvancedAds\Framework\Utilities\HTML;
use AdvancedAds\Framework\Utilities\Str;
defined( 'ABSPATH' ) || exit;
/**
* Data and Choices.
*/
class Data {
/**
* Get the list of all add-ons.
*
* @return array
*/
public static function get_addons(): array {
static $advads_addons = null;
if ( null === $advads_addons ) {
$advads_addons = [];
if ( ! function_exists( 'get_plugins' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$plugins = \get_plugins();
$allowed = [
'advanced-ads-pro',
'advanced-ads-responsive',
'advanced-ads-gam',
'advanced-ads-layer',
'advanced-ads-selling',
'advanced-ads-sticky',
'advanced-ads-tracking',
'slider-ads',
];
foreach ( $plugins as $plugin_file => $plugin_data ) {
$slug = $plugin_data['TextDomain'];
if ( ! in_array( $slug, $allowed, true ) ) {
continue;
}
$name = str_replace( [ ' ', 'Advanced Ads ' ], '', $plugin_data['Name'] );
$advads_addons[ $slug ] = [
'id' => str_replace( 'advanced-ads-', '', $slug ),
'name' => $name,
'version' => $plugin_data['Version'] ?? '0.0.1',
'path' => $plugin_file,
'options_slug' => $slug,
'uri' => $plugin_data['PluginURI'] ?? 'https://wpadvancedads.com',
];
}
}
return $advads_addons;
}
/**
* Get the admin screen ids.
*
* @return array
*/
public static function get_admin_screen_ids(): array {
return apply_filters(
'advanced-ads-dashboard-screens',
[
'advanced_ads',
'edit-advanced_ads',
'edit-advanced_ads_plcmnt',
'toplevel_page_advanced-ads',
'admin_page_advanced-ads-debug',
'admin_page_advanced-ads-import-export',
'advanced-ads_page_advanced-ads-groups',
'advanced-ads_page_advanced-ads-placements',
'advanced-ads_page_advanced-ads-settings',
'advanced-ads_page_advanced-ads-tools',
]
);
}
/**
* Get ad ids
*
* @return array
*/
public static function get_ads_ids(): array {
static $ad_ids = null;
if ( null !== $ad_ids ) {
return $ad_ids;
}
$ad_ids = wp_advads_get_ads_dropdown();
$ad_ids = array_keys( $ad_ids );
return $ad_ids;
}
/**
* Get the array of known bots.
*
* @param bool $filter Whether to apply filters.
*
* @return array
*/
public static function get_bots( $filter = true ) {
// List of bots and crawlers to exclude from ad impressions.
$bots = [
'bot',
'spider',
'crawler',
'scraper',
'parser',
'008',
'Accoona-AI-Agent',
'ADmantX',
'alexa',
'appie',
'Apple-PubSub',
'Arachmo',
'Ask Jeeves',
'avira\.com',
'B-l-i-t-z-B-O-T',
'boitho\.com-dc',
'BUbiNG',
'Cerberian Drtrs',
'Charlotte',
'cosmos',
'Covario IDS',
'curl',
'Datanyze',
'DataparkSearch',
'Dataprovider\.com',
'DDG-Android',
'Ecosia',
'expo9',
'facebookexternalhit',
'Feedfetcher-Google',
'FindLinks',
'Firefly',
'froogle',
'Genieo',
'heritrix',
'Holmes',
'htdig',
'https://developers\.google\.com',
'ia_archiver',
'ichiro',
'igdeSpyder',
'InfoSeek',
'inktomi',
'Kraken',
'L\.webis',
'Larbin',
'Linguee',
'LinkWalker',
'looksmart',
'lwp-trivial',
'mabontland',
'Mnogosearch',
'mogimogi',
'Morning Paper',
'MVAClient',
'NationalDirectory',
'NetResearchServer',
'NewsGator',
'NG-Search',
'Nusearch',
'NutchCVS',
'Nymesis',
'oegp',
'Orbiter',
'Peew',
'Pompos',
'PostPost',
'proximic',
'PycURL',
'Qseero',
'rabaz',
'Radian6',
'Reeder',
'savetheworldheritage',
'SBIder',
'Scooter',
'ScoutJet',
'Scrubby',
'SearchSight',
'semanticdiscovery',
'Sensis',
'ShopWiki',
'silk',
'Snappy',
'Spade',
'Sqworm',
'StackRambler',
'TechnoratiSnoop',
'TECNOSEEK',
'Teoma',
'Thumbnail\.CZ',
'TinEye',
'truwoGPS',
'updated',
'Vagabondo',
'voltron',
'Vortex',
'voyager',
'VYU2',
'WebBug',
'webcollage',
'WebIndex',
'Websquash\.com',
'WeSEE:Ads',
'wf84',
'Wget',
'WomlpeFactory',
'WordPress',
'yacy',
'Yahoo! Slurp',
'Yahoo! Slurp China',
'YahooSeeker',
'YahooSeeker-Testing',
'YandexBot',
'YandexMedia',
'YandexBlogs',
'YandexNews',
'YandexCalendar',
'YandexImages',
'Yeti',
'yoogliFetchAgent',
'Zao',
'ZyBorg',
'okhttp',
'ips-agent',
'ltx71',
'Optimizer',
'Daum',
'Qwantify',
];
return (array) ( $filter ? apply_filters( 'advanced-ads-bots', $bots ) : $bots );
}
/**
* Get the roles that are allowed to edit ads.
*
* @return array
*/
public static function get_filtered_roles_by_cap(): array {
return array_filter(
wp_roles()->role_objects,
static function ( WP_Role $role ) {
return $role->has_cap( 'advanced_ads_edit_ads' );
}
);
}
/**
* Render items dropdown html.
*
* @param array $args Arguments for the dropdown.
*
* @return void
*/
public static function items_dropdown( $args = [] ): void {
$items = self::items_for_select();
$attrs = [
'id' => $args['id'] ?? 'advads-items-select',
'name' => $args['name'] ?? 'advads-items-select',
'class' => $args['class'] ?? 'advads-items-select',
];
?>
<select <?php echo HTML::build_attributes( $attrs ); // phpcs:ignore ?>>
<option value=""><?php esc_html_e( '--empty--', 'advanced-ads' ); ?></option>
<?php if ( isset( $items['ads'] ) ) : ?>
<optgroup label="<?php esc_html_e( 'Ads', 'advanced-ads' ); ?>">
<?php foreach ( $items['ads'] as $ad_id => $ad_title ) : ?>
<option value="<?php echo esc_attr( $ad_id ); ?>"><?php echo esc_html( $ad_title ); ?></option>
<?php endforeach; ?>
</optgroup>
<?php endif; ?>
<?php if ( isset( $items['groups'] ) ) : ?>
<optgroup label="<?php esc_html_e( 'Ad Groups', 'advanced-ads' ); ?>">
<?php foreach ( $items['groups'] as $group_id => $group_title ) : ?>
<option value="<?php echo esc_attr( $group_id ); ?>"><?php echo esc_html( $group_title ); ?></option>
<?php endforeach; ?>
</optgroup>
<?php endif; ?>
<?php if ( isset( $items['placements'] ) ) : ?>
<optgroup label="<?php esc_html_e( 'Placements', 'advanced-ads' ); ?>">
<?php foreach ( $items['placements'] as $placement_id => $placement_title ) : ?>
<option value="<?php echo esc_attr( $placement_id ); ?>"><?php echo esc_html( $placement_title ); ?></option>
<?php endforeach; ?>
</optgroup>
<?php endif; ?>
</select>
<?php
}
/**
* Get items for item select field
*
* @param array $args Arguments for the dropdown.
*
* @return array
*/
public static function items_for_select( $args = [] ): array {
$select = [];
$args = wp_parse_args(
$args,
[
'ads' => true,
'groups' => true,
'placements' => true,
]
);
if ( $args['ads'] ) {
$ads = wp_advads_get_ads_dropdown();
foreach ( $ads as $ad_id => $ad_title ) {
$select['ads'][ 'ad_' . $ad_id ] = $ad_title;
}
}
if ( $args['groups'] ) {
$groups = wp_advads_get_groups_dropdown();
foreach ( $groups as $group_id => $group_title ) {
$select['groups'][ 'group_' . $group_id ] = $group_title;
}
}
if ( $args['placements'] ) {
$placements = wp_advads_get_placements_dropdown();
foreach ( $placements as $placement_id => $placement_title ) {
$select['placements'][ 'placement_' . $placement_id ] = $placement_title;
}
}
return $select;
}
/**
* Get the correct support URL: wp.org for free users and website for those with any add-on installed
*
* @param string $utm add UTM parameter to the link leading to https://wpadvancedads.com, if given.
*
* @return string URL.
*/
public static function support_url( $utm = '' ) {
$utm = empty( $utm ) ? '?utm_source=advanced-ads&utm_medium=link&utm_campaign=support' : $utm;
$url = 'https://wpadvancedads.com/support/' . $utm . '-free-user';
if ( Conditional::is_any_addon_activated() ) {
$url = 'https://wpadvancedads.com/support/' . $utm . '-with-addons';
}
return $url;
}
/**
* Show feed from wpadvancedads.com
*
* @return void
*/
public static function display_rss_feed(): void {
$cache_key = 'advads_feed_posts_v2';
$cache = get_transient( $cache_key );
// Check for cached content.
$cached_content = get_transient( $cache_key );
if ( false !== $cached_content ) {
echo $cached_content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
return;
}
// Generate feed data.
$content = self::generate_adsense_data();
// Cache the content if it's valid.
if ( ! empty( $content ) ) {
set_transient( $cache_key, $content, 2 * HOUR_IN_SECONDS );
}
echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* Get feed from wpadvancedads.com
*
* @return bool|string HTML content.
*/
private static function generate_adsense_data() {
// Get AdSense data.
$adsense_obj = \AdSense_Report_Data::get_data_from_options( 'domain' );
$adsense_num = $adsense_obj->get_sums()['28days'] ?? 0;
$currency = $adsense_obj->get_currency() ?? '';
// Define thresholds and campaigns.
$feed_id = '1';
$campaign = 'dashboard';
$adsense_num = 1500;
$valid_currencies = [ 'EUR', 'USD', 'GBP', 'CHF' ];
if ( $adsense_num > 1000 && in_array( $currency, $valid_currencies, true ) ) {
$feed_id = '8361';
$campaign = 'dashboard-adsense-motors';
} elseif ( $adsense_num > 100 && in_array( $currency, $valid_currencies, true ) ) {
$feed_id = '8364';
$campaign = 'dashboard-adsense';
}
$url = sprintf( 'https://wpadvancedads.com/wp-json/wp/v2/posts?categories=%s&per_page=3', $feed_id );
$response = wp_remote_get( $url );
if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
return false;
}
$rss_posts = json_decode( wp_remote_retrieve_body( $response ), true );
ob_start();
include ADVADS_ABSPATH . 'views/admin/widgets/rss-posts.php';
$content = ob_get_clean();
return $content;
}
}

View File

@@ -0,0 +1,82 @@
<?php
/**
* Utilities Sanitize.
*
* @package AdvancedAds
* @author Advanced Ads <info@wpadvancedads.com>
* @since 1.50.0
*/
namespace AdvancedAds\Utilities;
defined( 'ABSPATH' ) || exit;
/**
* Utilities Sanitize.
*/
class Sanitize {
/**
* Sanitize the frontend prefix to result in valid HTML classes.
* See https://www.w3.org/TR/selectors-3/#grammar for valid tokens.
*
* @param string $prefix The HTML class to sanitize.
* @param string $fallback The fallback if the class is invalid.
*
* @return string
*/
public static function frontend_prefix( $prefix, $fallback = '' ): string {
$prefix = sanitize_html_class( $prefix );
$nonascii = '[^\0-\177]';
$unicode = '\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?';
$escape = sprintf( '%s|\\[^\n\r\f0-9a-f]', $unicode );
$nmstart = sprintf( '[_a-z]|%s|%s', $nonascii, $escape );
$nmchar = sprintf( '[_a-z0-9-]|%s|%s', $nonascii, $escape );
if ( ! preg_match( sprintf( '/-?(?:%s)(?:%s)*/i', $nmstart, $nmchar ), $prefix, $matches ) ) {
return $fallback;
}
return $matches[0];
}
/**
* Sanitize email list
*
* @param string $emails List of addresses to sanitize.
*
* @return string
*/
public static function email_addresses( $emails ): string {
// Early bail!!
if ( ! is_string( $emails ) || empty( $emails ) ) {
return '';
}
$emails = stripslashes( $emails );
$emails = explode( ',', $emails );
$emails = array_map( 'sanitize_email', $emails );
$emails = array_filter( $emails );
return implode( ',', $emails );
}
/**
* Sanitize Google Analytics UID
*
* @param string $ids Google Analytics UID.
*
* @return string
*/
public static function analytics_uid( $ids ): string {
$ids = explode( ',', $ids );
$ids = array_map(
function ( $ga_id ) {
return trim( $ga_id, ' /][)(#' );
},
$ids
);
$ids = array_filter( $ids );
return implode( ', ', $ids );
}
}

View File

@@ -0,0 +1,96 @@
<?php
/**
* The class is responsible to allow split testing websites based on their URL.
*
* @package AdvancedAds
* @author Advanced Ads <info@wpadvancedads.com>
* @since 1.50.0
*/
namespace AdvancedAds\Utilities;
use Advanced_Ads;
use AdvancedAds\Framework\Utilities\Params;
defined( 'ABSPATH' ) || exit;
/**
* Utilities Testing.
*/
class Testing {
/**
* Show stuff to new users only.
*
* @param integer $timestamp time after which to show whatever.
* @param string $group optional group.
*
* @return bool true if user enabled after given timestamp.
*/
public static function show_to_new_users( $timestamp, $group = 'a' ) {
return self::get_group_by_url( null, $group ) && self::is_new_user( $timestamp );
}
/**
* Check if user started after a given date
*
* @param integer $timestamp time stamp.
*
* @return bool true if user is added after timestamp.
*/
public static function is_new_user( $timestamp = 0 ) {
// Allow admins to see version for new users in any case.
if ( Conditional::user_can( 'advanced_ads_manage_options' ) && Params::request( 'advads-ignore-timestamp' ) ) {
return true;
}
$timestamp = absint( $timestamp );
$options = Advanced_Ads::get_instance()->internal_options();
$installed = isset( $options['installed'] ) ? $options['installed'] : 0;
return $installed >= $timestamp;
}
/**
* Create a random group
*
* @param string $url optional parameter.
* @param string $ex group.
*
* @return bool
*/
public static function get_group_by_url( $url = '', $ex = 'a' ) {
$url = self::get_short_url( $url );
$code = (int) substr( md5( $url ), - 1 );
switch ( $ex ) {
case 'b':
return ( $code & 2 ) >> 1; // returns 1 or 0.
case 'c':
return ( $code & 4 ) >> 2; // returns 1 or 0.
case 'd':
return ( $code & 8 ) >> 3; // returns 1 or 0.
default:
return $code & 1; // returns 1 or 0.
}
}
/**
* Get short version of home_url() by removing protocol, www and slash
*
* @param string $url URL to be shortened.
*
* @return string
*/
public static function get_short_url( $url = '' ) {
$url = empty( $url ) ? home_url() : $url;
// Strip protocols.
if ( preg_match( '/^(\w[\w\d]*:\/\/)?(www\.)?(.*)$/', trim( $url ), $matches ) ) {
$url = $matches[3];
}
// Strip slashes.
return trim( $url, '/' );
}
}

View File

@@ -0,0 +1,100 @@
<?php
/**
* The class provides utility functions related to Validation.
*
* @package AdvancedAds
* @author Advanced Ads <info@wpadvancedads.com>
* @since 1.48.2
*/
namespace AdvancedAds\Utilities;
use DOMDocument;
use AdvancedAds\Abstracts\Ad;
defined( 'ABSPATH' ) || exit;
/**
* Validation.
*/
class Validation {
/**
* Check if an ad is valid for 'Post Content' placement
*
* @param Ad $ad Ad instance.
*
* @see Regex source: http://stackoverflow.com/questions/17852537/preg-replace-only-specific-part-of-string
*
* @return string|bool If not valid string with errors, otherwise empty string
*/
public static function is_valid_ad_dom( Ad $ad ) {
$ad_content = $ad->get_content() ?? '';
if ( ! extension_loaded( 'dom' ) || ! $ad_content ) {
return false;
}
$wp_charset = get_bloginfo( 'charset' );
$ad_dom = new DOMDocument( '1.0', $wp_charset );
$libxml_previous_state = libxml_use_internal_errors( true );
libxml_clear_errors();
$ad_content = preg_replace( '#(document.write.+)</(.*)#', '$1<\/$2', $ad_content );
$ad_dom->loadHtml( '<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wp_charset . '" /><body>' . $ad_content );
$errors = '';
foreach ( libxml_get_errors() as $error ) {
if ( stripos( $error->message, 'htmlParseEntityRef:' ) || preg_match( '/tag \S+ invalid/i', $error->message ) ) {
continue;
}
$errors .= print_r( $error, true ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
}
libxml_use_internal_errors( $libxml_previous_state );
return $errors;
}
/**
* Check if the current URL is HTTPS, but the ad code contains HTTP.
*
* @param Ad $ad Ad instance.
*
* @return bool false/string
*/
public static function is_ad_https( Ad $ad ) {
if (
$ad &&
is_ssl() &&
$ad->is_type( [ 'plain', 'content' ] ) &&
// Find img, iframe, script. '\\\\' denotes a single backslash.
preg_match( '#\ssrc=\\\\?[\'"]http:\\\\?/\\\\?/#i', $ad->get_content() )
) {
return __( 'Your website is using HTTPS, but the ad code contains HTTP and might not work.', 'advanced-ads' );
}
return false;
}
/**
* Check post and nonce while saving post to reduce complexity.
*
* @param int $post_id Post ID.
* @param object $post Post object.
*
* @return boolean
*/
public static function check_save_post( $post_id, $post ): bool {
if ( empty( $post_id ) || empty( $post ) || ! is_a( $post, 'WP_Post' ) ) {
return false;
}
// Dont' save meta boxes for revisions or autosaves.
if ( Conditional::doing_autosave() || is_int( wp_is_post_revision( $post ) ) || is_int( wp_is_post_autosave( $post ) ) ) {
return false;
}
return true;
}
}

View File

@@ -0,0 +1,470 @@
<?php
/**
* The class provides utility functions related to WordPress.
*
* @package AdvancedAds
* @author Advanced Ads <info@wpadvancedads.com>
* @since 1.47.0
*/
namespace AdvancedAds\Utilities;
use DateTimeZone;
use AdvancedAds\Constants;
use AdvancedAds\Admin\Upgrades;
use AdvancedAds\Framework\Utilities\Str;
use AdvancedAds\Framework\Utilities\Params;
defined( 'ABSPATH' ) || exit;
/**
* Utilities WordPress.
*/
class WordPress {
/**
* Debug function
*
* @return void
*/
public static function dd(): void {
echo '<pre>';
foreach ( func_get_args() as $arg ) {
print_r( $arg ); // phpcs:ignore
}
echo '</pre>';
die();
}
/**
* Function to calculate percentage
*
* @param int $part Part of total.
* @param int $total Total value.
*
* @return string
*/
public static function calculate_percentage( $part, $total ): string {
$percentage = ( $part / $total ) * 100;
return number_format( $percentage, 2 ) . '%';
}
/**
* Get the current action selected from the bulk actions dropdown.
*
* @return string|false The action name or False if no action was selected
*/
public static function current_action() {
$action = Params::request( 'action' );
if ( '-1' !== $action ) {
return sanitize_key( $action );
}
$action = Params::request( 'action2' );
if ( '-1' !== $action ) {
return sanitize_key( $action );
}
return false;
}
/**
* Get count of ads
*
* @param string $status Status need count for.
*
* @return int
*/
public static function get_count_ads( $status = 'any' ): int {
$counts = (array) wp_count_posts( Constants::POST_TYPE_AD );
if ( 'any' === $status ) {
return array_sum( $counts );
}
return $counts[ $status ] ?? 0;
}
/**
* Get site domain
*
* @param string $part Part of domain.
*
* @return string
*/
public static function get_site_domain( $part = 'host' ): string {
$domain = wp_parse_url( home_url( '/' ), PHP_URL_HOST );
if ( 'name' === $part ) {
$domain = explode( '.', $domain );
$domain = count( $domain ) > 2 ? $domain[1] : $domain[0];
}
return $domain;
}
/**
* Get SVG content as string
*
* @param string $file File name.
* @param string $folder Folder name if not default.
*
* @return string
*/
public static function get_svg( $file, $folder = '/assets/img/' ): string {
$file_path = \untrailingslashit( ADVADS_ABSPATH ) . $folder . $file;
if ( file_exists( $file_path ) ) {
ob_start();
include $file_path;
return ob_get_clean();
}
return '';
}
/**
* Retrieves the timezone of the site as a DateTimeZone object.
*
* @return DateTimeZone
*/
public static function get_timezone(): DateTimeZone {
static $advads_timezone;
// Early bail!!
if ( null !== $advads_timezone ) {
return $advads_timezone;
}
if ( function_exists( 'wp_timezone' ) ) {
$advads_timezone = wp_timezone();
return $advads_timezone;
}
$date_time_zone = new DateTimeZone( self::get_timezone_string() );
return $date_time_zone;
}
/**
* Retrieves the timezone of the site as a string.
*
* @return string
*/
public static function get_timezone_string(): string {
$timezone_string = get_option( 'timezone_string' );
if ( $timezone_string ) {
return $timezone_string;
}
$offset = (float) get_option( 'gmt_offset' );
$hours = (int) $offset;
$minutes = ( $offset - $hours );
$sign = ( $offset < 0 ) ? '-' : '+';
$abs_hour = abs( $hours );
$abs_mins = abs( $minutes * 60 );
return sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );
}
/**
* Get literal expression of timezone.
*
* @return string Human readable timezone name.
*/
public static function get_timezone_name(): string {
$time_zone = self::get_timezone()->getName();
if ( 'UTC' === $time_zone ) {
return 'UTC+0';
}
if ( 0 === strpos( $time_zone, '+' ) || 0 === strpos( $time_zone, '-' ) ) {
return 'UTC' . $time_zone;
}
/* translators: timezone name */
return sprintf( __( 'time of %s', 'advanced-ads' ), $time_zone );
}
/**
* Render icon of the type.
*
* @param string $icon Icon url.
*
* @return void
*/
public static function render_icon( $icon ): void {
printf( '<img src="%s" width="50" height="50" />', esc_url( $icon ) );
}
/**
* Applies image loading optimization attributes to an image HTML tag based on WordPress version.
*
* @param string $img HTML image tag.
* @param string $context Image context.
*
* @return string Updated HTML image tag with loading optimization attributes.
*/
public static function img_tag_add_loading_attr( $img, $context ) {
if ( is_array( $context ) ) {
$context = end( $context );
}
// Check if the current WordPress version is compatible.
if ( is_wp_version_compatible( '6.3' ) ) {
return wp_img_tag_add_loading_optimization_attrs( $img, $context );
}
return wp_img_tag_add_loading_attr( $img, $context ); // phpcs:ignore WordPress.WP.DeprecatedFunctions.wp_img_tag_add_loading_attrFound
}
/**
* Improve WP_Query performance
*
* @param array $args Query arguments.
*
* @return array
*/
public static function improve_wp_query( $args ): array {
$args['no_found_rows'] = true;
$args['update_post_meta_cache'] = false;
$args['update_post_term_cache'] = false;
return $args;
}
/**
* Clean variables using sanitize_text_field. Arrays are cleaned recursively.
* Non-scalar values are ignored.
*
* @param string|array $data Data to sanitize.
*
* @return string|array
*/
public static function sanitize_clean( $data ) {
if ( is_array( $data ) ) {
return array_map( __CLASS__ . '::sanitize_clean', $data );
}
return is_scalar( $data ) ? sanitize_text_field( $data ) : $data;
}
/**
* Sanitize conditions
*
* @param array $conditions Conditions to sanitize.
*
* @return array
*/
public static function sanitize_conditions( $conditions ): array {
foreach ( $conditions as $index => $condition ) {
if ( isset( $condition['operator'] ) && in_array( $condition['operator'], [ 'match', 'match_not' ], true ) ) {
continue;
}
// skip paginated_post from value check.
if ( isset( $condition['type'] ) && 'paginated_post' === $condition['type'] ) {
continue;
}
if ( empty( $condition['value'] ) ) {
unset( $conditions[ $index ] );
}
}
return $conditions;
}
/**
* Check if the current user is a bot prepopulating the cache
* Ads should be loaded for the bot, because they should show up on the cached site
*
* @return bool
*/
public static function is_cache_bot(): bool {
$user_agent = Params::server( 'HTTP_USER_AGENT', '' );
if ( '' !== $user_agent ) {
$current = sanitize_text_field( wp_unslash( $user_agent ) );
// WP Rocket.
if ( Str::contains( 'wprocketbot', $current ) ) {
return true;
}
// WP Super Cache.
$wp_useragent = apply_filters( 'http_headers_useragent', 'WordPress/' . get_bloginfo( 'version' ) . '; ' . get_bloginfo( 'url' ) );
if ( $current === $wp_useragent ) {
return true;
}
// LiteSpeed Cache: `lscache_runner` and `lscache_walker` user agents.
if ( Str::contains( 'lscache_', $current ) ) {
return true;
}
}
return false;
}
/**
* Unserializes data only if it was serialized.
*
* @link https://patchstack.com/articles/unauthenticated-php-object-injection-in-flatsome-theme-3-17-5/
*
* @param string $data Data that might be unserialized.
*
* @return mixed Unserialized data can be any type.
*/
public static function maybe_unserialize( $data ) {
if ( is_serialized( $data ) ) { // Don't attempt to unserialize data that wasn't serialized going in.
return @unserialize( trim( $data ), [ 'allowed_classes' => false ] ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
}
return $data;
}
/**
* Renders a setting view.
*
* @param array $args {
* An array of arguments.
*
* @type string $view The path to the view file to be included.
* }
*
* @return void
*/
public static function render_setting_view( $args ): void {
include $args['view'];
}
/**
* Create a wrapper for a single option line
*
* @param string $id internal id of the option wrapper.
* @param string $title label of the option.
* @param string $content content of the option or full path to template file or custom flag to show a pre-defined information.
* @param string $description description of the option.
*/
public static function render_option( $id, $title, $content, $description = '' ) {
/**
* This filter allows to extend the class dynamically by add-ons
* this would allow add-ons to dynamically hide/show only attributes belonging to them, practically not used now
*/
$class = apply_filters( 'advanced-ads-option-class', $id );
?>
<div class="advads-option advads-option-<?php echo esc_attr( $class ); ?>">
<span><?php echo esc_html( $title ); ?></span>
<div>
<?php
if ( 'is_pro_pitch' === $content ) { // phpcs:ignore
// Skip this step and place an upgrade link below the description if there is one.
} elseif ( strlen( $content ) < 500 && file_exists( $content ) ) { // Check length of the string because too long content can break `file_exists`.
include $content;
} else {
// phpcs:ignore
echo $content; // could include various HTML elements.
}
?>
<?php
if ( $description ) :
// phpcs:ignore
echo '<p class="description">' . $description . '</p>'; // could include various HTML elements.
endif;
// place an upgrade link below the description if there is one.
if ( 'is_pro_pitch' === $content ) {
Upgrades::pro_feature_link( 'upgrade-pro-' . $id );
}
?>
</div>
</div>
<?php
}
/**
* Show a note about a deprecated feature and link to the appropriate page in our manual
*
* @param string $feature simple string to indicate the deprecated feature. Will be added to the UTM campaign attribute.
*/
public static function show_deprecated_notice( $feature = '' ) {
$url = 'https://wpadvancedads.com/manual/deprecated-features/';
if ( '' !== $feature ) {
$url .= '#utm_source=advanced-ads&utm_medium=link&utm_campaign=deprecated-' . sanitize_title_for_query( $feature );
}
echo '<br/><br/><span class="advads-notice-inline advads-error">';
printf(
/* translators: %1$s is the opening link tag, %2$s is closing link tag */
esc_html__( 'This feature is deprecated. Please find the removal schedule %1$shere%2$s', 'advanced-ads' ),
'<a href="' . esc_url( $url ) . '" target="_blank">',
'</a>'
);
echo '</span>';
}
/**
* Sort visitor and display condition arrays alphabetically by their label.
*
* @param array $a array to be compared.
* @param array $b array to be compared.
*
* @return mixed
*/
public static function sort_array_by_label( $a, $b ) {
if ( ! isset( $a['label'] ) || ! isset( $b['label'] ) ) {
return;
}
return strcmp( strtolower( $a['label'] ), strtolower( $b['label'] ) );
}
/**
* Render a manual link
*
* @param string $url target URL.
* @param string $utm_campaign utm_campaign value to attach to the URL.
* @param string $title link text.
*
* @return void
*/
public static function manual_link( $url, $utm_campaign, $title = '' ) {
$title = ! empty( $title ) ? $title : __( 'Manual', 'advanced-ads' );
$url = add_query_arg(
[
'utm_source' => 'advanced-ads',
'utm_medium' => 'link',
'utm_campaign' => $utm_campaign,
],
$url
);
include ADVADS_ABSPATH . 'views/admin/manual-link.php';
}
/**
* Get installed plugins.
*
* @return array
*/
public static function get_wp_plugins(): array {
wp_cache_delete( 'plugins', 'plugins' );
if ( ! function_exists( 'get_plugins' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
$normalized = [];
$plugins = \get_plugins();
foreach ( $plugins as $plugin_file => $plugin_data ) {
$normalized[ $plugin_data['TextDomain'] ] = [
'file' => $plugin_file,
'version' => $plugin_data['Version'] ?? '0.0.1',
];
}
return $normalized;
}
}

View File

@@ -0,0 +1,4 @@
<?php
/**
* Silence is golden.
*/