- 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>
1217 lines
30 KiB
PHP
Executable File
1217 lines
30 KiB
PHP
Executable File
<?php
|
||
/**
|
||
* This class is serving as the base for various ad types and providing a foundation for defining common ad attributes and methods.
|
||
*
|
||
* @package AdvancedAds
|
||
* @author Advanced Ads <info@wpadvancedads.com>
|
||
* @since 1.48.0
|
||
*/
|
||
|
||
namespace AdvancedAds\Abstracts;
|
||
|
||
use Advanced_Ads;
|
||
use Advanced_Ads_Inline_Css;
|
||
use Advanced_Ads_Utils;
|
||
use Advanced_Ads_Visitor_Conditions;
|
||
use AdvancedAds\Traits;
|
||
use AdvancedAds\Constants;
|
||
use AdvancedAds\Frontend\Stats;
|
||
use AdvancedAds\Interfaces\Ad_Type;
|
||
use AdvancedAds\Utilities\WordPress;
|
||
use AdvancedAds\Utilities\Conditional;
|
||
use AdvancedAds\Framework\Utilities\Arr;
|
||
use AdvancedAds\Framework\Utilities\Str;
|
||
use AdvancedAds\Compatibility\Compatibility;
|
||
use AdvancedAds\Framework\Utilities\Formatting;
|
||
|
||
defined( 'ABSPATH' ) || exit;
|
||
|
||
/**
|
||
* Ad.
|
||
*/
|
||
abstract class Ad extends Data {
|
||
|
||
use Traits\Entity;
|
||
use Traits\Wrapper;
|
||
|
||
/**
|
||
* This is the object type.
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $object_type = 'ad';
|
||
|
||
/**
|
||
* The label for the ad.
|
||
*
|
||
* @var string|null
|
||
*/
|
||
private $label = null;
|
||
|
||
/**
|
||
* Hold groups within the ad
|
||
*
|
||
* @var Group[]
|
||
*/
|
||
private $groups = null;
|
||
|
||
/**
|
||
* Wrapper for the ad.
|
||
*
|
||
* @var array|null
|
||
*/
|
||
protected $wrapper = null;
|
||
|
||
/**
|
||
* Core data for this object. Name value pairs (name + default value).
|
||
*
|
||
* @var array
|
||
*/
|
||
protected $data = [
|
||
'title' => '',
|
||
'slug' => '',
|
||
'status' => false,
|
||
'author_id' => 0,
|
||
'content' => '',
|
||
'description' => '',
|
||
'width' => 0,
|
||
'height' => 0,
|
||
'visitors' => [],
|
||
'conditions' => [],
|
||
'has_weekdays' => false,
|
||
'weekdays' => [],
|
||
'type' => 'dummy',
|
||
'url' => '',
|
||
'expiry_date' => false,
|
||
'allow_php' => false,
|
||
'allow_shortcodes' => false,
|
||
'reserve_space' => false,
|
||
'debugmode' => false,
|
||
'wrapper-id' => '',
|
||
'wrapper-class' => '',
|
||
'position' => 'none',
|
||
'clearfix' => false,
|
||
'margin' => [
|
||
'top' => 0,
|
||
'right' => 0,
|
||
'bottom' => 0,
|
||
'left' => 0,
|
||
],
|
||
];
|
||
|
||
/**
|
||
* Get the ad if ID is passed, otherwise the ad is new and empty.
|
||
*
|
||
* @param Ad|WP_Post|int $ad Ad to init.
|
||
*/
|
||
public function __construct( $ad = 0 ) {
|
||
parent::__construct();
|
||
|
||
$this->set_ad_id( $ad );
|
||
$this->data_store = wp_advads_get_ad_repository();
|
||
|
||
if ( $this->get_id() > 0 ) {
|
||
$this->data_store->read( $this );
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Set the ad ID depending on what was passed.
|
||
*
|
||
* @param Ad|WP_Post|int $ad Ad instance, post instance or numeric.
|
||
*
|
||
* @return void
|
||
*/
|
||
private function set_ad_id( $ad ): void {
|
||
if ( is_numeric( $ad ) && $ad > 0 ) {
|
||
$this->set_id( $ad );
|
||
} elseif ( $ad instanceof self ) {
|
||
$this->set_id( absint( $ad->get_id() ) );
|
||
} elseif ( ! empty( $ad->ID ) ) {
|
||
$this->set_id( absint( $ad->ID ) );
|
||
} else {
|
||
$this->set_object_read( true );
|
||
}
|
||
}
|
||
|
||
/* Getter ------------------- */
|
||
|
||
/**
|
||
* Get description.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return string
|
||
*/
|
||
public function get_description( $context = 'view' ): string {
|
||
return $this->get_prop( 'description', $context );
|
||
}
|
||
|
||
/**
|
||
* Get url.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return string
|
||
*/
|
||
public function get_url( $context = 'view' ): string {
|
||
return $this->get_prop( 'url', $context );
|
||
}
|
||
|
||
/**
|
||
* Get the expiry date of the ad.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return int
|
||
*/
|
||
public function get_expiry_date( $context = 'view' ): int {
|
||
return $this->get_prop( 'expiry_date', $context );
|
||
}
|
||
|
||
/**
|
||
* Get the weekdays.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return array
|
||
*/
|
||
public function get_weekdays( $context = 'view' ): array {
|
||
return $this->get_prop( 'weekdays', $context );
|
||
}
|
||
|
||
/**
|
||
* Get the width of the ad in pixels.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return int
|
||
*/
|
||
public function get_width( $context = 'view' ): int {
|
||
return $this->get_prop( 'width', $context );
|
||
}
|
||
|
||
/**
|
||
* Get the height of the ad in pixels.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return int
|
||
*/
|
||
public function get_height( $context = 'view' ): int {
|
||
return $this->get_prop( 'height', $context );
|
||
}
|
||
|
||
/**
|
||
* Get the display conditions for the ad.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return array
|
||
*/
|
||
public function get_display_conditions( $context = 'view' ): array {
|
||
return $this->get_prop( 'conditions', $context );
|
||
}
|
||
|
||
/**
|
||
* Get the visitor conditions for the ad.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return array
|
||
*/
|
||
public function get_visitor_conditions( $context = 'view' ): array {
|
||
return array_filter(
|
||
$this->get_prop( 'visitors', $context ),
|
||
function ( $value ) {
|
||
return 'unknown' !== $value['type'];
|
||
}
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Get clearfix.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function get_clearfix( $context = 'view' ): bool {
|
||
return $this->get_prop( 'clearfix', $context );
|
||
}
|
||
|
||
/**
|
||
* Get position.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return string
|
||
*/
|
||
public function get_position( $context = 'view' ): string {
|
||
return $this->get_prop( 'position', $context );
|
||
}
|
||
|
||
/**
|
||
* Get the margin setting for the ad.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return array
|
||
*/
|
||
public function get_margin( $context = 'view' ): array {
|
||
return $this->get_prop( 'margin', $context );
|
||
}
|
||
|
||
/**
|
||
* Get the wrapper classes for the ad.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return int
|
||
*/
|
||
public function get_weight( $context = 'view' ): int {
|
||
return $this->get_prop( 'weight', $context );
|
||
}
|
||
|
||
/**
|
||
* Retrieves the number of clicks for the ad.
|
||
*
|
||
* @return int
|
||
*/
|
||
public function get_clicks(): int {
|
||
$post = get_post();
|
||
|
||
if ( isset( $post->clicks ) ) {
|
||
return absint( $post->clicks );
|
||
}
|
||
|
||
global $wpdb;
|
||
$clicks = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
||
$wpdb->prepare(
|
||
'SELECT SUM(count) FROM ' . $wpdb->prefix . 'advads_clicks WHERE ad_id = %d',
|
||
$this->get_id()
|
||
)
|
||
);
|
||
|
||
return absint( $clicks );
|
||
}
|
||
|
||
/**
|
||
* Retrieves the number of impressions for the ad.
|
||
*
|
||
* @return int
|
||
*/
|
||
public function get_impressions(): int {
|
||
$post = get_post();
|
||
|
||
if ( isset( $post->impressions ) ) {
|
||
return absint( $post->impressions );
|
||
}
|
||
|
||
global $wpdb;
|
||
|
||
$impressions = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
|
||
$wpdb->prepare(
|
||
'SELECT SUM(count) FROM ' . $wpdb->prefix . 'advads_impressions WHERE ad_id = %d',
|
||
$this->get_id()
|
||
)
|
||
);
|
||
|
||
return absint( $impressions );
|
||
}
|
||
|
||
/**
|
||
* Retrieves the number of ctr for the ad.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return int|string
|
||
*/
|
||
public function get_ctr( $context = 'view' ) {
|
||
$post = get_post();
|
||
$ctr = $post->ctr ?? 0;
|
||
|
||
if ( ! $ctr && $this->get_impressions() > 0 ) {
|
||
$ctr = $this->get_clicks() / $this->get_impressions();
|
||
}
|
||
|
||
return 'view' === $context ? number_format_i18n( 100 * $ctr, 2 ) : $ctr;
|
||
}
|
||
|
||
/* Setter ------------------- */
|
||
|
||
/**
|
||
* Set display conditions.
|
||
*
|
||
* @param string $conditions Ad conditions.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_display_conditions( $conditions ): void {
|
||
$this->set_prop( 'conditions', $conditions );
|
||
}
|
||
|
||
/**
|
||
* Set conditions.
|
||
*
|
||
* @param string $conditions Ad conditions.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_visitor_conditions( $conditions ): void {
|
||
$this->set_prop( 'visitors', $conditions );
|
||
}
|
||
|
||
/**
|
||
* Set clearfix.
|
||
*
|
||
* @param string $clearfix Ad clearfix.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_clearfix( $clearfix ): void {
|
||
$this->set_prop( 'clearfix', Formatting::string_to_bool( $clearfix ) );
|
||
}
|
||
|
||
/**
|
||
* Set position.
|
||
*
|
||
* @param string $position Ad position.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_position( $position ): void {
|
||
$this->set_prop( 'position', empty( $position ) ? 'none' : $position );
|
||
}
|
||
|
||
/**
|
||
* Set margin.
|
||
*
|
||
* @param array $margin Ad margin.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_margin( $margin ): void {
|
||
$margin = [
|
||
'top' => intval( $margin['top'] ?? 0 ),
|
||
'right' => intval( $margin['right'] ?? 0 ),
|
||
'bottom' => intval( $margin['bottom'] ?? 0 ),
|
||
'left' => intval( $margin['left'] ?? 0 ),
|
||
];
|
||
|
||
$this->set_prop( 'margin', $margin );
|
||
}
|
||
|
||
/**
|
||
* Set expiry date.
|
||
*
|
||
* @param array|string $expiry_date Ad expiry date.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_expiry_date( $expiry_date ): void {
|
||
if ( is_array( $expiry_date ) ) {
|
||
$expiry_date = $this->normalize_expiry_date( $expiry_date );
|
||
}
|
||
|
||
$this->set_prop( 'expiry_date', $expiry_date );
|
||
}
|
||
|
||
/**
|
||
* Set weekdays.
|
||
*
|
||
* @param array $weekdays Ad weekdays.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_weekdays( $weekdays ): void {
|
||
$this->set_prop( 'weekdays', $weekdays );
|
||
}
|
||
|
||
/**
|
||
* Set description.
|
||
*
|
||
* @param string $description Ad description.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_description( $description ): void {
|
||
$this->set_prop( 'description', $description );
|
||
}
|
||
|
||
/**
|
||
* Set url.
|
||
*
|
||
* @param string $url Ad url.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_url( $url ): void {
|
||
global $pagenow;
|
||
|
||
// If the tracking add-on is not active.
|
||
// If this is not the ad edit page.
|
||
if ( ! defined( 'AAT_VERSION' ) && ! in_array( $pagenow, [ 'post.php', 'post-new.php' ], true ) ) {
|
||
$placeholders = [
|
||
'[POST_ID]',
|
||
'[POST_SLUG]',
|
||
'[CAT_SLUG]',
|
||
'[AD_ID]',
|
||
];
|
||
|
||
$url = str_replace( $placeholders, '', $url );
|
||
}
|
||
|
||
$this->set_prop( 'url', trim( $url ) );
|
||
}
|
||
|
||
/**
|
||
* Set the width.
|
||
*
|
||
* @param float|string $width Total width.
|
||
*/
|
||
public function set_width( $width ) {
|
||
$this->set_prop( 'width', '' === $width ? 0 : absint( $width ) );
|
||
}
|
||
|
||
/**
|
||
* Set the height.
|
||
*
|
||
* @param float|string $height Total height.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_height( $height ): void {
|
||
$this->set_prop( 'height', '' === $height ? 0 : absint( $height ) );
|
||
}
|
||
|
||
/**
|
||
* Set if debug mode is enabled.
|
||
*
|
||
* @param bool $enabled Is Enabled.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_debugmode( $enabled ): void {
|
||
$this->set_prop( 'debugmode', Formatting::string_to_bool( $enabled ) );
|
||
}
|
||
|
||
/**
|
||
* Set if php is allowed.
|
||
*
|
||
* @param bool|string $allowed Allowed.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_allow_php( $allowed ): void {
|
||
$this->set_prop( 'allow_php', Formatting::string_to_bool( $allowed ) );
|
||
}
|
||
|
||
/**
|
||
* Set if shortcodes is allowed.
|
||
*
|
||
* @param bool|string $allowed Allowed.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_allow_shortcodes( $allowed ): void {
|
||
$this->set_prop( 'allow_shortcodes', Formatting::string_to_bool( $allowed ) );
|
||
}
|
||
|
||
/**
|
||
* Set add sizes is allowed.
|
||
*
|
||
* @param bool|string $allowed Allowed.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_reserve_space( $allowed ): void {
|
||
$this->set_prop( 'reserve_space', Formatting::string_to_bool( $allowed ) );
|
||
}
|
||
|
||
/**
|
||
* Set if has weekdays.
|
||
*
|
||
* @param bool|string $has_weekdays Has weekdays.
|
||
*
|
||
* @return void
|
||
*/
|
||
public function set_has_weekdays( $has_weekdays ): void {
|
||
$this->set_prop( 'has_weekdays', Formatting::string_to_bool( $has_weekdays ) );
|
||
}
|
||
|
||
/* Conditional ------------------- */
|
||
|
||
/**
|
||
* Check if debug mode is enabled within the ad.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function is_debug_mode( $context = 'view' ): bool {
|
||
return $this->get_prop( 'debugmode', $context );
|
||
}
|
||
|
||
/**
|
||
* Check if PHP code execution is allowed within the ad.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function is_php_allowed( $context = 'view' ): bool {
|
||
return $this->get_prop( 'allow_php', $context );
|
||
}
|
||
|
||
/**
|
||
* Check if shortcode execution is allowed within the ad.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function is_shortcode_allowed( $context = 'view' ): bool {
|
||
return $this->get_prop( 'allow_shortcodes', $context );
|
||
}
|
||
|
||
/**
|
||
* Check if has weekdays.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function has_weekdays( $context = 'view' ): bool {
|
||
return $this->get_prop( 'has_weekdays', $context );
|
||
}
|
||
|
||
/**
|
||
* Check if space is reserved.
|
||
*
|
||
* @param string $context What the value is for. Valid values are view and edit.
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function is_space_reserved( $context = 'view' ): bool {
|
||
return $this->get_prop( 'reserve_space', $context );
|
||
}
|
||
|
||
/**
|
||
* Check whether this ad is expired.
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function is_expired(): bool {
|
||
if ( $this->get_expiry_date() <= 0 || $this->get_expiry_date() > time() ) {
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Checks if the ad is placed in the header.
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function is_head_placement(): bool {
|
||
if ( null !== $this->get_parent() && $this->get_parent()->is_type( 'header' ) ) {
|
||
return true;
|
||
}
|
||
|
||
// group as head placement.
|
||
if ( 'header' === $this->get_prop( 'group_placement_context' ) ) {
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Check if the ad is a top-level ad.
|
||
*
|
||
* @return bool
|
||
*/
|
||
public function is_top_level(): bool {
|
||
return ! $this->get_parent() || is_a_placement( $this->get_parent() );
|
||
}
|
||
|
||
/**
|
||
* Determines whether the ad can be displayed.
|
||
*
|
||
* @param array $check_options check options.
|
||
*
|
||
* @return bool True if the ad can be displayed, false otherwise.
|
||
*/
|
||
public function can_display( $check_options = [] ): bool {
|
||
$check_options = wp_parse_args(
|
||
$check_options,
|
||
[
|
||
'passive_cache_busting' => false,
|
||
'ignore_debugmode' => false,
|
||
]
|
||
);
|
||
|
||
// Prevent ad to show up through wp_head, if this is not a header placement.
|
||
if ( doing_action( 'wp_head' ) && ! $this->is_head_placement() && ! Compatibility::can_inject_during_wp_head() ) {
|
||
return false;
|
||
}
|
||
|
||
// Check If the current ad is requested using a shortcode placed in the content of the current ad.
|
||
$shortcode_ad_id = $this->get_prop( 'shortcode_ad_id' );
|
||
if ( $shortcode_ad_id && absint( $shortcode_ad_id ) === $this->get_id() ) {
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Allows bypassing server side visitor conditions checks or ignoring debug mode
|
||
*
|
||
* @param array $check_options can display check options.
|
||
*/
|
||
$check_options = apply_filters( 'advanced-ads-can-display-ad-check-options', $check_options );
|
||
|
||
// Force ad display if debug mode is enabled.
|
||
if ( $this->is_debug_mode() && ! $check_options['ignore_debugmode'] ) {
|
||
return true;
|
||
}
|
||
|
||
if ( ! $check_options['passive_cache_busting'] ) {
|
||
// Don’t display ads that are not published or private for users not logged in.
|
||
if ( ! $this->is_status( 'publish' ) && ! ( $this->is_status( 'private' ) && is_user_logged_in() ) ) {
|
||
return false;
|
||
}
|
||
|
||
if ( ! $this->can_display_by_visitor() ) {
|
||
return false;
|
||
}
|
||
} elseif ( ! $this->is_status( 'publish' ) ) {
|
||
return false;
|
||
}
|
||
|
||
if ( $this->is_expired() ) {
|
||
return false;
|
||
}
|
||
|
||
$can_display = apply_filters( 'advanced-ads-can-display-ad', true, $this, $check_options );
|
||
|
||
// Add own conditions to flag output as possible or not.
|
||
return apply_filters_deprecated( 'advanced-ads-can-display', [ $can_display, $this, $check_options ], '2.0.0', 'advanced-ads-can-display-ad', 'Use advanced-ads-can-display-ad instead.' );
|
||
}
|
||
|
||
/* Additional Methods ------------------- */
|
||
|
||
/**
|
||
* Prepares the output for the group.
|
||
*
|
||
* @return string The prepared output.
|
||
*/
|
||
public function prepare_output(): string {
|
||
$ad_args = $this->get_prop( 'ad_args' ) ?? [];
|
||
$output = $this->prepare_frontend_output();
|
||
|
||
// Don’t deliver anything, if main ad content is empty.
|
||
if ( empty( $output ) ) {
|
||
return '';
|
||
}
|
||
|
||
$output_options = $this->get_prop( 'output_options' ) ?? [];
|
||
$global_output = $output_options['global_output'] ?? ! isset( $ad_args['global_output'] ) || $ad_args['global_output'];
|
||
$this->set_prop_temp( 'global_output', $global_output );
|
||
|
||
$output_options['global_output'] = $global_output;
|
||
|
||
if ( ! $this->is_head_placement() ) {
|
||
// Filter to manipulate the output before the wrapper is added.
|
||
$output = apply_filters( 'advanced-ads-output-inside-wrapper', $output, $this );
|
||
$output = $this->add_wrapper( $output, $global_output );
|
||
|
||
// Add a clearfix, if set.
|
||
if (
|
||
( $this->is_top_level() && ! empty( $ad_args['placement_clearfix'] ) )
|
||
|| $this->get_clearfix()
|
||
) {
|
||
$output .= '<br style="clear: both; display: block; float: none;"/>';
|
||
}
|
||
}
|
||
|
||
// Add the ad to the global output array.
|
||
if ( $output_options['global_output'] ) {
|
||
Stats::get()->add_entity( 'ad', $this->get_id(), $this->get_title() );
|
||
}
|
||
|
||
do_action_deprecated(
|
||
'advanced-ads-output',
|
||
[ $this, $output, $output_options ],
|
||
'2.0.0',
|
||
'advanced-ads-ad-output-ready',
|
||
'Use advanced-ads-ad-output-ready instead.'
|
||
);
|
||
|
||
return apply_filters_deprecated(
|
||
'advanced-ads-output-final',
|
||
[ $output, $this, $output_options ],
|
||
'2.0.0',
|
||
'advanced-ads-ad-output',
|
||
'Use advanced-ads-ad-output instead.'
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Get groups
|
||
*
|
||
* @return bool|array
|
||
*/
|
||
public function get_groups() {
|
||
if ( null === $this->groups ) {
|
||
$this->groups = [];
|
||
$terms = wp_get_object_terms( $this->get_id(), Constants::TAXONOMY_GROUP );
|
||
if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) {
|
||
foreach ( $terms as $term ) {
|
||
$this->groups[ $term->term_id ] = wp_advads_get_group( $term );
|
||
}
|
||
}
|
||
}
|
||
|
||
return $this->groups;
|
||
}
|
||
|
||
/**
|
||
* Get ad type object
|
||
*
|
||
* @return Ad_Type|bool
|
||
*/
|
||
public function get_type_object() {
|
||
if ( ! wp_advads_has_ad_type( $this->get_type() ) ) {
|
||
wp_advads_create_ad_type( $this->get_type() );
|
||
}
|
||
|
||
return wp_advads_get_ad_type( $this->get_type() );
|
||
}
|
||
|
||
/**
|
||
* Get ad schedule details
|
||
*
|
||
* @return array
|
||
*/
|
||
public function get_ad_schedule_details(): array {
|
||
$status_strings = [];
|
||
$html_classes = 'advads-filter-timing';
|
||
$post_start = get_post_time( 'U', true, $this->get_id() );
|
||
$expiry_date_format = get_option( 'date_format' ) . ', ' . get_option( 'time_format' );
|
||
|
||
$status_type = get_post_status( $this->get_id() );
|
||
if ( empty( $status_type ) || 'publish' === $status_type ) {
|
||
$status_type = 'published';
|
||
}
|
||
|
||
if ( $post_start > time() ) {
|
||
$status_type = 'future';
|
||
$html_classes .= ' advads-filter-future';
|
||
|
||
/* translators: %s is a date. */
|
||
$status_strings[] = sprintf( __( 'starts %s', 'advanced-ads' ), get_date_from_gmt( gmdate( 'Y-m-d H:i:s', $post_start ), $expiry_date_format ) );
|
||
}
|
||
|
||
$expiry = $this->get_expiry_date();
|
||
if ( ! empty( $expiry ) ) {
|
||
$html_classes .= ' advads-filter-any-exp-date';
|
||
$expiry_date = ( new \DateTimeImmutable( '@' . $expiry ) )->setTimezone( WordPress::get_timezone() );
|
||
$tz = ' (' . WordPress::get_timezone_name() . ')';
|
||
|
||
if ( $expiry > time() ) {
|
||
$status_type = 'expiring';
|
||
/* translators: %s is a date. */
|
||
$status_strings[] = sprintf( __( 'expires %s', 'advanced-ads' ), $expiry_date->format( $expiry_date_format ) ) . $tz;
|
||
} else {
|
||
$status_type = 'expired';
|
||
$html_classes .= ' advads-filter-expired';
|
||
|
||
/* translators: %s is a date. */
|
||
$status_strings[] = sprintf( __( 'expired %s', 'advanced-ads' ), $expiry_date->format( $expiry_date_format ) ) . $tz;
|
||
}
|
||
}
|
||
|
||
$labels = [
|
||
'published' => __( 'Published', 'advanced-ads' ),
|
||
'draft' => __( 'Draft', 'advanced-ads' ),
|
||
'trash' => __( 'Trashed', 'advanced-ads' ),
|
||
];
|
||
|
||
if ( isset( $labels[ $status_type ] ) ) {
|
||
$status_strings[] = $labels[ $status_type ];
|
||
}
|
||
|
||
return compact( 'post_start', 'status_type', 'status_strings', 'html_classes' );
|
||
}
|
||
|
||
/**
|
||
* Load a template with the information on ad expiry
|
||
*
|
||
* @return string
|
||
*/
|
||
public function get_ad_schedule_html(): string {
|
||
[
|
||
'post_start' => $post_start,
|
||
'status_type' => $status_type,
|
||
'status_strings' => $status_strings
|
||
] = $this->get_ad_schedule_details();
|
||
|
||
if ( empty( $status_strings ) ) {
|
||
return '';
|
||
}
|
||
|
||
ob_start();
|
||
include ADVADS_ABSPATH . 'views/admin/tables/ads/icon-status.php';
|
||
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* Get the post edit link
|
||
*
|
||
* @return string|null
|
||
*/
|
||
public function get_edit_link() {
|
||
return get_edit_post_link( $this->get_id(), 'other' );
|
||
}
|
||
|
||
/**
|
||
* Normalize expiry date
|
||
*
|
||
* @param array $expiry_date Expiry date.
|
||
*
|
||
* @return int
|
||
*/
|
||
private function normalize_expiry_date( $expiry_date ): int {
|
||
// Early bail!!
|
||
if ( empty( $expiry_date['enabled'] ) ) {
|
||
return 0;
|
||
}
|
||
|
||
$local_string = sprintf(
|
||
'%04d-%02d-%02d %02d:%02d:00',
|
||
absint( $expiry_date['year'] ),
|
||
absint( $expiry_date['month'] ),
|
||
absint( $expiry_date['day'] ),
|
||
absint( $expiry_date['hour'] ),
|
||
absint( $expiry_date['minute'] )
|
||
);
|
||
|
||
$local_dt = \DateTimeImmutable::createFromFormat( 'Y-m-d H:i:s', $local_string, WordPress::get_timezone() );
|
||
|
||
return $local_dt ? $local_dt->getTimestamp() : 0;
|
||
}
|
||
|
||
/**
|
||
* Process shortcodes.
|
||
*
|
||
* @param string $output Ad content.
|
||
*
|
||
* @return string
|
||
*/
|
||
protected function do_shortcode( $output ): string {
|
||
$ad_args = $this->temp_data;
|
||
$ad_args['shortcode_ad_id'] = $this->get_id();
|
||
$output = preg_replace(
|
||
'/\[(the_ad_group|the_ad_placement|the_ad) /',
|
||
'[$1 ad_args="' . rawurlencode( wp_json_encode( $ad_args ) ) . '" ',
|
||
$output
|
||
);
|
||
|
||
return do_shortcode( $output );
|
||
}
|
||
|
||
/**
|
||
* Add a wrapper arount the ad content if wrapper information are given
|
||
*
|
||
* @since 1.1.4
|
||
*
|
||
* @param string $ad_content content of the ad.
|
||
* @param bool $global_output Global output.
|
||
*
|
||
* @return string $wrapper ad within the wrapper
|
||
*/
|
||
private function add_wrapper( $ad_content = '', $global_output = false ): string {
|
||
$ad_args = $this->get_prop( 'ad_args' ) ?? [];
|
||
$label = $this->get_label();
|
||
$wrapper = $this->create_wrapper();
|
||
$wrapper_options = apply_filters( 'advanced-ads-output-wrapper-options', $wrapper, $this );
|
||
|
||
// Create another wrapper so that the label does not reduce the height of the ad wrapper.
|
||
if ( $label && ! empty( $wrapper_options['style']['height'] ) ) {
|
||
$height = [ 'style' => [ 'height' => $wrapper_options['style']['height'] ] ];
|
||
unset( $wrapper_options['style']['height'] );
|
||
$ad_content = '<div' . Advanced_Ads_Utils::build_html_attributes( $height ) . '>' . $ad_content . '</div>';
|
||
}
|
||
|
||
// Adds inline css to the wrapper.
|
||
if ( ! empty( $ad_args['inline-css'] ) && $this->is_top_level() ) {
|
||
$wrapper_options = ( new Advanced_Ads_Inline_Css() )->add_css( $wrapper_options, $ad_args['inline-css'], $global_output );
|
||
}
|
||
|
||
if (
|
||
! defined( 'ADVANCED_ADS_DISABLE_EDIT_BAR' ) &&
|
||
Conditional::user_can( 'advanced_ads_edit_ads' ) &&
|
||
$this->is_parent_placement()
|
||
) {
|
||
ob_start();
|
||
include ADVADS_ABSPATH . 'public/views/ad-edit-bar.php';
|
||
$ad_content = trim( ob_get_clean() ) . $ad_content;
|
||
$wrapper_options['data-title'][] = $this->get_tooltip_title();
|
||
}
|
||
|
||
// Ad Health Tool add class and attribute in to ads and group.
|
||
if ( Conditional::user_can( 'advanced_ads_edit_ads' ) ) {
|
||
// Add the 'highlight-wrapper' class to the ad wrapper.
|
||
if ( ! $this->is_parent_group() ) {
|
||
$wrapper_options['class'][] = wp_advads()->get_frontend_prefix() . 'highlight-wrapper';
|
||
}
|
||
}
|
||
|
||
if (
|
||
Str::is_empty( $this->get_wrapper_id() ) &&
|
||
( [] === $wrapper_options || ! Arr::accessible( $wrapper_options ) )
|
||
) {
|
||
return $label . $ad_content;
|
||
}
|
||
|
||
// Create unique id if not yet given.
|
||
if ( empty( $wrapper_options['id'] ) ) {
|
||
$wrapper_options['id'] = $this->create_wrapper_id();
|
||
}
|
||
|
||
$wrapper_element = ! empty( $this->get_prop( 'inline_wrapper_element' ) ) ? 'span' : 'div';
|
||
|
||
// Build the box.
|
||
$wrapper = '<' . $wrapper_element . Advanced_Ads_Utils::build_html_attributes( $wrapper_options ) . '>';
|
||
$wrapper .= $label;
|
||
$wrapper .= apply_filters( 'advanced-ads-output-wrapper-before-content', '', $this );
|
||
$wrapper .= $ad_content;
|
||
$wrapper .= apply_filters( 'advanced-ads-output-wrapper-after-content', '', $this );
|
||
$wrapper .= '</' . $wrapper_element . '>';
|
||
|
||
return $wrapper;
|
||
}
|
||
|
||
/**
|
||
* Creates a wrapper array for the group.
|
||
*
|
||
* @return array
|
||
*/
|
||
public function create_wrapper(): array {
|
||
// Early bail!!
|
||
if ( null !== $this->wrapper ) {
|
||
return $this->wrapper;
|
||
}
|
||
|
||
$this->wrapper = [];
|
||
|
||
if ( ! $this->is_head_placement() ) {
|
||
$position = $this->get_position();
|
||
$use_position = false;
|
||
|
||
if ( $this->is_top_level() ) {
|
||
$classes = $this->get_prop( 'ad_args.output.class' );
|
||
if ( $classes && is_array( $classes ) ) {
|
||
$this->wrapper['class'] = $classes;
|
||
}
|
||
|
||
if ( $this->is_parent_placement() && 'default' !== $this->get_parent()->get_prop( 'placement_position' ) ) {
|
||
$use_position = true;
|
||
$position = $this->get_parent()->get_prop( 'placement_position' );
|
||
}
|
||
}
|
||
|
||
$this->get_wrapper_styles( $this->wrapper, $position, $use_position );
|
||
|
||
// Add manual classes.
|
||
if ( Str::is_non_empty( $this->get_wrapper_class() ) ) {
|
||
$classes = explode( ' ', $this->get_wrapper_class() );
|
||
|
||
foreach ( $classes as $_class ) {
|
||
$this->wrapper['class'][] = sanitize_html_class( $_class );
|
||
}
|
||
}
|
||
|
||
$this->wrapper = apply_filters( 'advanced-ads-set-wrapper', $this->wrapper, $this );
|
||
if ( is_array( $this->wrapper ) && [] !== $this->wrapper && ! isset( $this->wrapper['id'] ) ) {
|
||
$this->wrapper['id'] = $this->create_wrapper_id();
|
||
}
|
||
}
|
||
|
||
return $this->wrapper;
|
||
}
|
||
|
||
/**
|
||
* Retrieves the label for the ad.
|
||
*
|
||
* @return string The label for the ad.
|
||
*/
|
||
private function get_label(): string {
|
||
if ( null === $this->label ) {
|
||
$ad_args = $this->get_prop( 'ad_args' );
|
||
$state = $ad_args['ad_label'] ?? 'default';
|
||
$label = Advanced_Ads::get_instance()->get_label( $this, $state );
|
||
|
||
$this->label = $this->is_top_level() && $label ? $label : '';
|
||
}
|
||
|
||
return $this->label;
|
||
}
|
||
|
||
/**
|
||
* Check visitor conditions
|
||
*
|
||
* @return bool $can_display true if can be displayed in frontend based on visitor settings
|
||
* @since 1.1.0
|
||
*/
|
||
private function can_display_by_visitor() {
|
||
$wp_the_query = $this->get_prop( 'wp_the_query' );
|
||
if ( $wp_the_query && ! empty( $wp_the_query['is_feed'] ) ) {
|
||
return true;
|
||
}
|
||
|
||
$conditions = $this->get_visitor_conditions();
|
||
if ( empty( $conditions ) ) {
|
||
return true;
|
||
}
|
||
|
||
$last_result = false;
|
||
$length = count( $conditions );
|
||
|
||
for ( $i = 0; $i < $length; ++$i ) {
|
||
$_condition = current( $conditions );
|
||
// Ignore OR if last result was true.
|
||
if ( $last_result && isset( $_condition['connector'] ) && 'or' === $_condition['connector'] ) {
|
||
next( $conditions );
|
||
continue;
|
||
}
|
||
|
||
$result = Advanced_Ads_Visitor_Conditions::frontend_check( $_condition, $this );
|
||
$last_result = $result;
|
||
if ( ! $result ) {
|
||
// return false only, if the next condition doesn’t have an OR operator.
|
||
$next = next( $conditions );
|
||
if ( ! isset( $next['connector'] ) || 'or' !== $next['connector'] ) {
|
||
return false;
|
||
}
|
||
} else {
|
||
next( $conditions );
|
||
}
|
||
}
|
||
|
||
// Check mobile condition.
|
||
if ( isset( $conditions['mobile'] ) ) {
|
||
switch ( $conditions['mobile'] ) {
|
||
case 'only':
|
||
if ( ! wp_is_mobile() ) {
|
||
return false;
|
||
}
|
||
break;
|
||
case 'no':
|
||
if ( wp_is_mobile() ) {
|
||
return false;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Create a random wrapper id
|
||
*
|
||
* @since 1.1.4
|
||
*
|
||
* @return string $id random id string
|
||
*/
|
||
public function create_wrapper_id(): string {
|
||
$wrapper_id = sanitize_key( $this->get_wrapper_id() );
|
||
if ( '' !== $wrapper_id ) {
|
||
return $wrapper_id;
|
||
}
|
||
|
||
return wp_advads()->get_frontend_prefix() . wp_rand();
|
||
}
|
||
|
||
/**
|
||
* Sets the wrapper styles based on the given position.
|
||
*
|
||
* @param array $wrapper The wrapper array to store the styles.
|
||
* @param string $position The position of the ad.
|
||
* @param bool $use_position Whether to use the position or not.
|
||
*
|
||
* @return void
|
||
*/
|
||
private function get_wrapper_styles( &$wrapper, $position, $use_position ): void {
|
||
// Always keep margin before handling position.
|
||
$margin = $this->get_margin();
|
||
foreach ( $margin as $key => $value ) {
|
||
if ( ! empty( $value ) ) {
|
||
$wrapper['style'][ 'margin-' . $key ] = $value . 'px';
|
||
}
|
||
}
|
||
|
||
switch ( $position ) {
|
||
case 'left':
|
||
case 'left_float':
|
||
case 'left_nofloat':
|
||
$wrapper['style']['float'] = 'left';
|
||
break;
|
||
case 'right':
|
||
case 'right_float':
|
||
case 'right_nofloat':
|
||
$wrapper['style']['float'] = 'right';
|
||
break;
|
||
case 'center':
|
||
case 'center_nofloat':
|
||
case 'center_float':
|
||
$wrapper['style']['margin-left'] = 'auto';
|
||
$wrapper['style']['margin-right'] = 'auto';
|
||
|
||
if ( empty( $this->get_width() ) || empty( $this->get_prop( 'add_wrapper_sizes' ) ) || $use_position ) {
|
||
$wrapper['style']['text-align'] = 'center';
|
||
}
|
||
break;
|
||
case 'clearfix':
|
||
$wrapper['style']['clear'] = 'both';
|
||
break;
|
||
}
|
||
|
||
if ( $this->is_space_reserved() ) {
|
||
if ( ! empty( $this->get_width() ) ) {
|
||
$wrapper['style']['width'] = $this->get_width() . 'px';
|
||
}
|
||
|
||
if ( ! empty( $this->get_height() ) ) {
|
||
$wrapper['style']['height'] = $this->get_height() . 'px';
|
||
}
|
||
}
|
||
|
||
if ( ! empty( $this->get_clearfix() ) ) {
|
||
$wrapper['style']['clear'] = 'both';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Generate the tooltip title for a placement with associated ads.
|
||
*
|
||
* @return string Tooltip title containing placement and ads name.
|
||
*/
|
||
private function get_tooltip_title(): string {
|
||
$ads = $this->is_parent_group()
|
||
? wp_list_pluck( $this->get_parent()->get_ads(), 'post_title' )
|
||
: [ $this->get_title() ];
|
||
|
||
// Construct and format the tooltip title using the placement ID and ad titles.
|
||
return sprintf(
|
||
/* translators: %1$s is a placement name, %2$s is the ads name. */
|
||
__( 'Placement name: %1$s; Ads: %2$s', 'advanced-ads' ),
|
||
esc_attr( $this->get_parent()->get_title() ),
|
||
esc_attr( $ads ? implode( ',', $ads ) : '' )
|
||
);
|
||
}
|
||
}
|