Version Description
- Feature: add "Expired" and "Expiring" views to the ad overview list replacing the expiry date filter
- Improvement: use "saved" dashicon when an element was saved correctly or a process finished
- Improvement: don't report HTML5 tags or custom elements as invalid tags in custom ad content
- Improvement: optimize warnings from AdSense account and clarify that these warnings are not from Advanced Ads
- Improvement: separate
inject_in_content
code into classAdvanced_Ads_In_Content_Injector
- Improvement: update video manual display conditions
Download this release
Release Info
Developer | advancedads |
Plugin | Advanced Ads |
Version | 1.31.0 |
Comparing to | |
See all releases |
Code changes from version 1.30.5 to 1.31.0
- admin/assets/css/admin.css +21 -0
- admin/assets/js/admin-global.js +15 -5
- admin/class-advanced-ads-admin.php +6 -1
- admin/includes/class-ad-type.php +50 -26
- admin/includes/class-licenses.php +4 -2
- admin/includes/class-list-filters.php +174 -98
- admin/includes/class-meta-box.php +1 -1
- admin/views/ad-list-filters.php +0 -8
- admin/views/ad-submitbox-meta.php +0 -2
- admin/views/placements.php +3 -2
- advanced-ads.php +2 -2
- classes/ad-expiration.php +105 -0
- classes/ad.php +26 -35
- classes/ad_placements.php +1 -566
- classes/in-content-injector.php +758 -0
- classes/plugin.php +17 -9
- languages/advanced-ads.pot +119 -104
- lib/composer/autoload_classmap.php +2 -0
- lib/composer/autoload_static.php +2 -0
- modules/gadsense/admin/views/adsense-account.php +19 -5
- readme.txt +12 -2
admin/assets/css/admin.css
CHANGED
@@ -399,6 +399,16 @@ body.rtl #mapi-archived-ads { left: 78px; right:auto; }
|
|
399 |
cursor: pointer;
|
400 |
}
|
401 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
402 |
/**
|
403 |
* Connect to Google AdSense modal
|
404 |
*/
|
@@ -664,6 +674,11 @@ li:hover > .advads-help:before {
|
|
664 |
font-size: 20px;
|
665 |
vertical-align: top;
|
666 |
}
|
|
|
|
|
|
|
|
|
|
|
667 |
|
668 |
/* Inline Notifications */
|
669 |
span.advads-notice-inline {
|
@@ -685,6 +700,12 @@ span.advads-notice-inline {
|
|
685 |
.advads-idea:before {
|
686 |
content: "\f339";
|
687 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
688 |
.advads-manual:before {
|
689 |
content: "\f118";
|
690 |
}
|
399 |
cursor: pointer;
|
400 |
}
|
401 |
|
402 |
+
@media screen and (min-width: 1368px) {
|
403 |
+
#mapi-account-alerts {
|
404 |
+
float: right;
|
405 |
+
}
|
406 |
+
|
407 |
+
#mapi-account-alerts .card {
|
408 |
+
margin-top: 0;
|
409 |
+
}
|
410 |
+
}
|
411 |
+
|
412 |
/**
|
413 |
* Connect to Google AdSense modal
|
414 |
*/
|
674 |
font-size: 20px;
|
675 |
vertical-align: top;
|
676 |
}
|
677 |
+
.advads-notice-block:after {
|
678 |
+
content: "";
|
679 |
+
clear: both;
|
680 |
+
display: block;
|
681 |
+
}
|
682 |
|
683 |
/* Inline Notifications */
|
684 |
span.advads-notice-inline {
|
700 |
.advads-idea:before {
|
701 |
content: "\f339";
|
702 |
}
|
703 |
+
.advads-check:before {
|
704 |
+
content: "\f15e";
|
705 |
+
color: #1e610f;
|
706 |
+
font-size: 24px;
|
707 |
+
line-height: 20px;
|
708 |
+
}
|
709 |
.advads-manual:before {
|
710 |
content: "\f118";
|
711 |
}
|
admin/assets/js/admin-global.js
CHANGED
@@ -148,9 +148,7 @@ jQuery( document ).ready(function () {
|
|
148 |
e.preventDefault();
|
149 |
var self = jQuery( this );
|
150 |
// set cookie for 30 days
|
151 |
-
|
152 |
-
exdate.setSeconds( exdate.getSeconds() + 2592000 );
|
153 |
-
document.cookie = "advanced_ads_hide_deactivate_feedback=1; expires=" + exdate.toUTCString() + "; path=/";
|
154 |
// save if plugin should be disabled
|
155 |
var disable_plugin = self.hasClass('advanced-ads-feedback-not-deactivate') ? false : true;
|
156 |
|
@@ -194,11 +192,13 @@ jQuery( document ).ready(function () {
|
|
194 |
// show feedback message
|
195 |
jQuery( '#advanced-ads-feedback-after-submit-goodbye' ).show();
|
196 |
jQuery( '#advanced-ads-feedback-after-submit-disabling-plugin' ).show();
|
197 |
-
//
|
|
|
|
|
198 |
setTimeout(function(){
|
199 |
jQuery( '#advanced-ads-feedback-overlay' ).hide();
|
200 |
window.location.href = advads_deactivate_link_url;
|
201 |
-
},
|
202 |
});
|
203 |
// close button for feedback form
|
204 |
jQuery('#advanced-ads-feedback-overlay-close-button').on('click', function () {
|
@@ -225,6 +225,16 @@ function advads_admin_get_cookie (name) {
|
|
225 |
}
|
226 |
}
|
227 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
228 |
/**
|
229 |
* load RSS widget on dashboard page using AJAX to not block rendering the rest of the page
|
230 |
*/
|
148 |
e.preventDefault();
|
149 |
var self = jQuery( this );
|
150 |
// set cookie for 30 days
|
151 |
+
advads_store_feedback_cookie();
|
|
|
|
|
152 |
// save if plugin should be disabled
|
153 |
var disable_plugin = self.hasClass('advanced-ads-feedback-not-deactivate') ? false : true;
|
154 |
|
192 |
// show feedback message
|
193 |
jQuery( '#advanced-ads-feedback-after-submit-goodbye' ).show();
|
194 |
jQuery( '#advanced-ads-feedback-after-submit-disabling-plugin' ).show();
|
195 |
+
// set cookie for 30 days
|
196 |
+
advads_store_feedback_cookie();
|
197 |
+
// wait one second
|
198 |
setTimeout(function(){
|
199 |
jQuery( '#advanced-ads-feedback-overlay' ).hide();
|
200 |
window.location.href = advads_deactivate_link_url;
|
201 |
+
}, 1000 );
|
202 |
});
|
203 |
// close button for feedback form
|
204 |
jQuery('#advanced-ads-feedback-overlay-close-button').on('click', function () {
|
225 |
}
|
226 |
}
|
227 |
|
228 |
+
/**
|
229 |
+
* Store a cookie for 30 days
|
230 |
+
* The cookie prevents the feedback form from showing multiple times
|
231 |
+
*/
|
232 |
+
function advads_store_feedback_cookie() {
|
233 |
+
var exdate = new Date();
|
234 |
+
exdate.setSeconds( exdate.getSeconds() + 2592000 );
|
235 |
+
document.cookie = "advanced_ads_hide_deactivate_feedback=1; expires=" + exdate.toUTCString() + "; path=/";
|
236 |
+
}
|
237 |
+
|
238 |
/**
|
239 |
* load RSS widget on dashboard page using AJAX to not block rendering the rest of the page
|
240 |
*/
|
admin/class-advanced-ads-admin.php
CHANGED
@@ -456,7 +456,12 @@ class Advanced_Ads_Admin {
|
|
456 |
if ( isset( $form['advanced_ads_disable_reason'] )
|
457 |
&& 'get help' === $form['advanced_ads_disable_reason']
|
458 |
&& ! empty( $form['advanced_ads_disable_reply_email'] ) ) {
|
459 |
-
|
|
|
|
|
|
|
|
|
|
|
460 |
$current_user = wp_get_current_user();
|
461 |
$name = ( $current_user instanceof WP_User ) ? $current_user->user_nicename : '';
|
462 |
$from = $name . ' <' . $email . '>';
|
456 |
if ( isset( $form['advanced_ads_disable_reason'] )
|
457 |
&& 'get help' === $form['advanced_ads_disable_reason']
|
458 |
&& ! empty( $form['advanced_ads_disable_reply_email'] ) ) {
|
459 |
+
|
460 |
+
$email = trim( $form['advanced_ads_disable_reply_email'] );
|
461 |
+
if ( ! is_email( $email ) ) {
|
462 |
+
die();
|
463 |
+
}
|
464 |
+
|
465 |
$current_user = wp_get_current_user();
|
466 |
$name = ( $current_user instanceof WP_User ) ? $current_user->user_nicename : '';
|
467 |
$from = $name . ' <' . $email . '>';
|
admin/includes/class-ad-type.php
CHANGED
@@ -86,14 +86,9 @@ class Advanced_Ads_Admin_Ad_Type {
|
|
86 |
2
|
87 |
);
|
88 |
|
89 |
-
//
|
90 |
-
add_filter(
|
91 |
-
|
92 |
-
array(
|
93 |
-
$this,
|
94 |
-
'ad_list_request',
|
95 |
-
)
|
96 |
-
); // order ads by title, not ID.
|
97 |
add_action(
|
98 |
'all_admin_notices',
|
99 |
array(
|
@@ -239,11 +234,12 @@ class Advanced_Ads_Admin_Ad_Type {
|
|
239 |
$ad_dom->loadHtml( '<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wp_charset . '" /><body>' . $ad_content );
|
240 |
|
241 |
$errors = '';
|
242 |
-
foreach ( libxml_get_errors() as $
|
243 |
-
// continue, if there is '&' symbol, but not HTML entity.
|
244 |
-
if (
|
245 |
-
|
246 |
}
|
|
|
247 |
}
|
248 |
|
249 |
libxml_use_internal_errors( $libxml_previous_state );
|
@@ -457,25 +453,53 @@ class Advanced_Ads_Admin_Ad_Type {
|
|
457 |
*
|
458 |
* @param array $vars array with request vars.
|
459 |
*
|
460 |
-
* @return array
|
461 |
-
* @since 1.3.18
|
462 |
*/
|
463 |
public function ad_list_request( $vars ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
464 |
|
465 |
-
// order ads by title on ads list
|
466 |
-
if (
|
467 |
-
$vars
|
468 |
-
$vars,
|
469 |
-
array(
|
470 |
-
'orderby' => 'title',
|
471 |
-
'order' => 'ASC',
|
472 |
-
)
|
473 |
-
);
|
474 |
-
// set get parameters, so the column header arrow shows up correctly.
|
475 |
-
$_GET['orderby'] = $vars['orderby'];
|
476 |
-
$_GET['order'] = $vars['order'];
|
477 |
}
|
478 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
479 |
return $vars;
|
480 |
}
|
481 |
|
86 |
2
|
87 |
);
|
88 |
|
89 |
+
// order ad lists.
|
90 |
+
add_filter( 'request', array( $this, 'ad_list_request' ) );
|
91 |
+
|
|
|
|
|
|
|
|
|
|
|
92 |
add_action(
|
93 |
'all_admin_notices',
|
94 |
array(
|
234 |
$ad_dom->loadHtml( '<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wp_charset . '" /><body>' . $ad_content );
|
235 |
|
236 |
$errors = '';
|
237 |
+
foreach ( libxml_get_errors() as $error ) {
|
238 |
+
// continue, if there is '&' symbol, but not HTML entity; or if an "invalid" tag is found.
|
239 |
+
if ( stripos( $error->message, 'htmlParseEntityRef:' ) || preg_match( '/tag \S+ invalid/i', $error->message ) ) {
|
240 |
+
continue;
|
241 |
}
|
242 |
+
$errors .= print_r( $error, true );
|
243 |
}
|
244 |
|
245 |
libxml_use_internal_errors( $libxml_previous_state );
|
453 |
*
|
454 |
* @param array $vars array with request vars.
|
455 |
*
|
456 |
+
* @return array
|
|
|
457 |
*/
|
458 |
public function ad_list_request( $vars ) {
|
459 |
+
// if we shouldn't filter this return $vars array.
|
460 |
+
if (
|
461 |
+
! isset( $vars['post_type'] )
|
462 |
+
|| $vars['post_type'] !== Advanced_Ads::POST_TYPE_SLUG
|
463 |
+
|| ! is_admin()
|
464 |
+
|| wp_doing_ajax()
|
465 |
+
) {
|
466 |
+
return $vars;
|
467 |
+
}
|
468 |
|
469 |
+
// order ads by title on ads list by default
|
470 |
+
if ( empty( $vars['orderby'] ) ) {
|
471 |
+
return $this->default_ad_list_order( $vars );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
472 |
}
|
473 |
|
474 |
+
if ( $vars['orderby'] === 'expiry_date' ) {
|
475 |
+
$vars['orderby'] = 'meta_value';
|
476 |
+
$vars['meta_key'] = Advanced_Ads_Ad_Expiration::POST_META;
|
477 |
+
$vars['order'] = strtoupper( $vars['order'] ) === 'DESC' ? 'DESC' : 'ASC';
|
478 |
+
|
479 |
+
if ( isset( $_GET['addate'] ) && $_GET['addate'] === 'advads-filter-expired' ) {
|
480 |
+
$vars['post_status'] = Advanced_Ads_Ad_Expiration::POST_STATUS;
|
481 |
+
}
|
482 |
+
}
|
483 |
+
|
484 |
+
return $vars;
|
485 |
+
}
|
486 |
+
|
487 |
+
/**
|
488 |
+
* Set query vars and $_GET parameters for default ad list order.
|
489 |
+
*
|
490 |
+
* @param array $vars request args.
|
491 |
+
*
|
492 |
+
* @return array
|
493 |
+
*/
|
494 |
+
private function default_ad_list_order( $vars ) {
|
495 |
+
$vars = array_merge( $vars, array(
|
496 |
+
'orderby' => 'title',
|
497 |
+
'order' => 'ASC',
|
498 |
+
) );
|
499 |
+
// set get parameters, so the column header arrow shows up correctly.
|
500 |
+
$_GET['orderby'] = $vars['orderby'];
|
501 |
+
$_GET['order'] = $vars['order'];
|
502 |
+
|
503 |
return $vars;
|
504 |
}
|
505 |
|
admin/includes/class-licenses.php
CHANGED
@@ -167,7 +167,8 @@ class Advanced_Ads_Admin_Licenses {
|
|
167 |
|
168 |
// show license debug output if constant is set.
|
169 |
if ( defined( 'ADVANCED_ADS_SHOW_LICENSE_RESPONSE' ) ) {
|
170 |
-
return '<
|
|
|
171 |
}
|
172 |
|
173 |
/**
|
@@ -356,7 +357,8 @@ class Advanced_Ads_Admin_Licenses {
|
|
356 |
|
357 |
// show license debug output if constant is set.
|
358 |
if ( defined( 'ADVANCED_ADS_SHOW_LICENSE_RESPONSE' ) ) {
|
359 |
-
return '<
|
|
|
360 |
}
|
361 |
|
362 |
if ( is_wp_error( $response ) ) {
|
167 |
|
168 |
// show license debug output if constant is set.
|
169 |
if ( defined( 'ADVANCED_ADS_SHOW_LICENSE_RESPONSE' ) ) {
|
170 |
+
return '<p><strong>' . esc_html__( 'The license status does not change as long as ADVANCED_ADS_SHOW_LICENSE_RESPONSE is enabled in wp-config.php.', 'advanced-ads' ) . '</strong></p>' .
|
171 |
+
'<pre>' . print_r( $response, true ) . '</pre>';
|
172 |
}
|
173 |
|
174 |
/**
|
357 |
|
358 |
// show license debug output if constant is set.
|
359 |
if ( defined( 'ADVANCED_ADS_SHOW_LICENSE_RESPONSE' ) ) {
|
360 |
+
return '<p><strong>' . esc_html__( 'The license status does not change as long as ADVANCED_ADS_SHOW_LICENSE_RESPONSE is enabled in wp-config.php.', 'advanced-ads' ) . '</strong></p>' .
|
361 |
+
'<pre>' . print_r( $response, true ) . '</pre>';
|
362 |
}
|
363 |
|
364 |
if ( is_wp_error( $response ) ) {
|
admin/includes/class-list-filters.php
CHANGED
@@ -38,6 +38,7 @@ class Advanced_Ads_Ad_List_Filters {
|
|
38 |
* Ads array with ID as key
|
39 |
*
|
40 |
* @var array
|
|
|
41 |
*/
|
42 |
protected $adsbyid = array();
|
43 |
|
@@ -63,6 +64,9 @@ class Advanced_Ads_Ad_List_Filters {
|
|
63 |
add_filter( 'posts_results', array( $this, 'post_results' ), 10, 2 );
|
64 |
add_filter( 'post_limits', array( $this, 'limit_filter' ), 10, 2 );
|
65 |
}
|
|
|
|
|
|
|
66 |
}
|
67 |
|
68 |
/**
|
@@ -82,7 +86,6 @@ class Advanced_Ads_Ad_List_Filters {
|
|
82 |
$all_filters = array(
|
83 |
'all_sizes' => array(),
|
84 |
'all_types' => array(),
|
85 |
-
'all_dates' => array(),
|
86 |
'all_groups' => array(),
|
87 |
);
|
88 |
|
@@ -99,10 +102,6 @@ class Advanced_Ads_Ad_List_Filters {
|
|
99 |
$groups_to_check = $this->ads_in_groups;
|
100 |
|
101 |
foreach ( $posts as $post ) {
|
102 |
-
|
103 |
-
if ( ! isset( $this->all_ads_options[ $post->ID ] ) ) {
|
104 |
-
continue;
|
105 |
-
}
|
106 |
$ad_option = $this->all_ads_options[ $post->ID ];
|
107 |
|
108 |
/**
|
@@ -128,8 +127,7 @@ class Advanced_Ads_Ad_List_Filters {
|
|
128 |
}
|
129 |
|
130 |
if ( isset( $ad_option['type'] ) && 'adsense' === $ad_option['type'] ) {
|
131 |
-
$content
|
132 |
-
$adsense_obj = false;
|
133 |
try {
|
134 |
$adsense_obj = json_decode( $content, true );
|
135 |
} catch ( Exception $e ) {
|
@@ -145,18 +143,6 @@ class Advanced_Ads_Ad_List_Filters {
|
|
145 |
}
|
146 |
}
|
147 |
|
148 |
-
if ( isset( $ad_option['expiry_date'] ) && $ad_option['expiry_date'] ) {
|
149 |
-
if ( time() >= absint( $ad_option['expiry_date'] ) ) {
|
150 |
-
if ( ! array_key_exists( 'advads-filter-expired', $all_filters['all_dates'] ) ) {
|
151 |
-
$all_filters['all_dates']['advads-filter-expired'] = __( 'expired', 'advanced-ads' );
|
152 |
-
}
|
153 |
-
} else {
|
154 |
-
if ( ! array_key_exists( 'advads-filter-any-exp-date', $all_filters['all_dates'] ) ) {
|
155 |
-
$all_filters['all_dates']['advads-filter-any-exp-date'] = __( 'any expiry date', 'advanced-ads' );
|
156 |
-
}
|
157 |
-
}
|
158 |
-
}
|
159 |
-
|
160 |
if ( isset( $ad_option['type'] ) // could be missing for new ads that are stored only by WP auto-save.
|
161 |
&& ! array_key_exists( $ad_option['type'], $all_filters['all_types'] )
|
162 |
&& isset( $advads->ad_types[ $ad_option['type'] ] )
|
@@ -174,27 +160,34 @@ class Advanced_Ads_Ad_List_Filters {
|
|
174 |
/**
|
175 |
* Collects all ads data.
|
176 |
*
|
177 |
-
* @param
|
178 |
*/
|
179 |
public function collect_all_ads( $posts ) {
|
180 |
-
$postsbyid = array();
|
181 |
-
|
182 |
foreach ( $posts as $post ) {
|
183 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
184 |
}
|
185 |
|
186 |
-
|
187 |
-
|
188 |
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
|
195 |
$_groups = Advanced_Ads::get_ad_groups();
|
196 |
-
|
197 |
-
$groups = array();
|
198 |
|
199 |
/**
|
200 |
* It looks like there might be a third-party conflict we haven’t been able to reproduce that causes the group
|
@@ -235,13 +228,6 @@ class Advanced_Ads_Ad_List_Filters {
|
|
235 |
}
|
236 |
}
|
237 |
|
238 |
-
/**
|
239 |
-
* Store all data
|
240 |
-
*/
|
241 |
-
$this->all_ads = $posts;
|
242 |
-
$this->adsbyid = $postsbyid;
|
243 |
-
$this->all_ads_options = $options;
|
244 |
-
|
245 |
$this->all_groups = $groups;
|
246 |
}
|
247 |
|
@@ -295,11 +281,7 @@ class Advanced_Ads_Ad_List_Filters {
|
|
295 |
*/
|
296 |
public function post_results( $posts, $the_query ) {
|
297 |
// Execute only in the main query.
|
298 |
-
if ( ! $the_query->is_main_query() ) {
|
299 |
-
return $posts;
|
300 |
-
}
|
301 |
-
|
302 |
-
if ( ! function_exists( 'get_current_screen' ) ) {
|
303 |
return $posts;
|
304 |
}
|
305 |
|
@@ -310,6 +292,7 @@ class Advanced_Ads_Ad_List_Filters {
|
|
310 |
}
|
311 |
|
312 |
$this->collect_all_ads( $posts );
|
|
|
313 |
|
314 |
// the new post list.
|
315 |
if ( isset( $_REQUEST['post_status'] ) && 'trash' === $_REQUEST['post_status'] ) {
|
@@ -438,11 +421,9 @@ class Advanced_Ads_Ad_List_Filters {
|
|
438 |
$new_posts = array();
|
439 |
$the_list = $using_original ? $this->all_ads : $posts;
|
440 |
foreach ( $the_list as $post ) {
|
441 |
-
|
442 |
-
|
443 |
-
|
444 |
-
$new_posts[] = $post;
|
445 |
-
}
|
446 |
}
|
447 |
}
|
448 |
$posts = $new_posts;
|
@@ -457,27 +438,25 @@ class Advanced_Ads_Ad_List_Filters {
|
|
457 |
$new_posts = array();
|
458 |
$the_list = $using_original ? $this->all_ads : $posts;
|
459 |
foreach ( $the_list as $post ) {
|
460 |
-
|
461 |
-
|
462 |
-
if ( '
|
463 |
-
|
|
|
|
|
|
|
464 |
$content = false;
|
465 |
-
try {
|
466 |
-
$content = json_decode( $post->post_content, true );
|
467 |
-
} catch ( Exception $e ) {
|
468 |
-
$content = false;
|
469 |
-
}
|
470 |
-
if ( $content && 'responsive' === $content['unitType'] ) {
|
471 |
-
$new_posts[] = $post;
|
472 |
-
}
|
473 |
}
|
474 |
-
|
475 |
-
$width = isset( $option['width'] ) ? $option['width'] : 0;
|
476 |
-
$height = isset( $option['height'] ) ? $option['height'] : 0;
|
477 |
-
if ( $request['adsize'] === $width . 'x' . $height ) {
|
478 |
$new_posts[] = $post;
|
479 |
}
|
480 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
481 |
}
|
482 |
}
|
483 |
$posts = $new_posts;
|
@@ -485,39 +464,8 @@ class Advanced_Ads_Ad_List_Filters {
|
|
485 |
$using_original = false;
|
486 |
}
|
487 |
|
488 |
-
|
489 |
-
|
490 |
-
*/
|
491 |
-
if ( isset( $request['addate'] ) && '' !== $request['addate'] ) {
|
492 |
-
if ( 'advads-filter-any-exp-date' === urldecode( $request['addate'] ) ) {
|
493 |
-
$new_posts = array();
|
494 |
-
$the_list = $using_original ? $this->all_ads : $posts;
|
495 |
-
foreach ( $the_list as $post ) {
|
496 |
-
if ( isset( $this->all_ads_options[ $post->ID ] ) ) {
|
497 |
-
$option = $this->all_ads_options[ $post->ID ];
|
498 |
-
if ( ! empty( $option['expiry_date'] ) ) {
|
499 |
-
$new_posts[] = $post;
|
500 |
-
}
|
501 |
-
}
|
502 |
-
}
|
503 |
-
$posts = $new_posts;
|
504 |
-
$the_query->found_posts = count( $posts );
|
505 |
-
$using_original = false;
|
506 |
-
} elseif ( 'advads-filter-expired' === urldecode( $request['addate'] ) ) {
|
507 |
-
$new_posts = array();
|
508 |
-
$the_list = $using_original ? $this->all_ads : $posts;
|
509 |
-
foreach ( $the_list as $post ) {
|
510 |
-
if ( isset( $this->all_ads_options[ $post->ID ] ) ) {
|
511 |
-
$option = $this->all_ads_options[ $post->ID ];
|
512 |
-
if ( $option['expiry_date'] && time() >= $option['expiry_date'] ) {
|
513 |
-
$new_posts[] = $post;
|
514 |
-
}
|
515 |
-
}
|
516 |
-
}
|
517 |
-
$posts = $new_posts;
|
518 |
-
$the_query->found_posts = count( $posts );
|
519 |
-
$using_original = false;
|
520 |
-
}
|
521 |
}
|
522 |
|
523 |
$posts = apply_filters( 'advanced-ads-ad-list-filter', $posts, $this->all_ads_options );
|
@@ -539,4 +487,132 @@ class Advanced_Ads_Ad_List_Filters {
|
|
539 |
|
540 |
return self::$instance;
|
541 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
542 |
}
|
38 |
* Ads array with ID as key
|
39 |
*
|
40 |
* @var array
|
41 |
+
* @deprecated 1.31.0 -- we don't needs ads indexed by id, since we have all ads.
|
42 |
*/
|
43 |
protected $adsbyid = array();
|
44 |
|
64 |
add_filter( 'posts_results', array( $this, 'post_results' ), 10, 2 );
|
65 |
add_filter( 'post_limits', array( $this, 'limit_filter' ), 10, 2 );
|
66 |
}
|
67 |
+
|
68 |
+
add_filter( 'views_edit-' . Advanced_Ads::POST_TYPE_SLUG, array( $this, 'add_expired_view' ) );
|
69 |
+
add_filter( 'views_edit-' . Advanced_Ads::POST_TYPE_SLUG, array( $this, 'add_expiring_view' ) );
|
70 |
}
|
71 |
|
72 |
/**
|
86 |
$all_filters = array(
|
87 |
'all_sizes' => array(),
|
88 |
'all_types' => array(),
|
|
|
89 |
'all_groups' => array(),
|
90 |
);
|
91 |
|
102 |
$groups_to_check = $this->ads_in_groups;
|
103 |
|
104 |
foreach ( $posts as $post ) {
|
|
|
|
|
|
|
|
|
105 |
$ad_option = $this->all_ads_options[ $post->ID ];
|
106 |
|
107 |
/**
|
127 |
}
|
128 |
|
129 |
if ( isset( $ad_option['type'] ) && 'adsense' === $ad_option['type'] ) {
|
130 |
+
$content = $this->all_ads[ array_search( $post->ID, wp_list_pluck( $this->all_ads, 'ID' ), true ) ]->post_content;
|
|
|
131 |
try {
|
132 |
$adsense_obj = json_decode( $content, true );
|
133 |
} catch ( Exception $e ) {
|
143 |
}
|
144 |
}
|
145 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
146 |
if ( isset( $ad_option['type'] ) // could be missing for new ads that are stored only by WP auto-save.
|
147 |
&& ! array_key_exists( $ad_option['type'], $all_filters['all_types'] )
|
148 |
&& isset( $advads->ad_types[ $ad_option['type'] ] )
|
160 |
/**
|
161 |
* Collects all ads data.
|
162 |
*
|
163 |
+
* @param WP_Post[] $posts array of ads.
|
164 |
*/
|
165 |
public function collect_all_ads( $posts ) {
|
|
|
|
|
166 |
foreach ( $posts as $post ) {
|
167 |
+
$this->adsbyid[ $post->ID ] = $post;
|
168 |
+
$this->all_ads_options[ $post->ID ] = get_post_meta( $post->ID, 'advanced_ads_ad_options', true );
|
169 |
+
if ( empty( $this->all_ads_options[ $post->ID ] ) ) {
|
170 |
+
$this->all_ads_options[ $post->ID ] = array();
|
171 |
+
}
|
172 |
+
|
173 |
+
// convert all expiration dates.
|
174 |
+
$ad = new Advanced_Ads_Ad( $post->ID );
|
175 |
+
$expiration = new Advanced_Ads_Ad_Expiration( $ad );
|
176 |
+
$expiration->save_expiration_date( $this->all_ads_options[ $post->ID ], $ad );
|
177 |
+
$expiration->is_ad_expired();
|
178 |
}
|
179 |
|
180 |
+
$this->all_ads = $posts;
|
181 |
+
}
|
182 |
|
183 |
+
/**
|
184 |
+
* Collects all ads groups, fills the $all_groups class property.
|
185 |
+
*/
|
186 |
+
private function collect_all_groups() {
|
187 |
+
global $wpdb;
|
188 |
|
189 |
$_groups = Advanced_Ads::get_ad_groups();
|
190 |
+
$groups = array();
|
|
|
191 |
|
192 |
/**
|
193 |
* It looks like there might be a third-party conflict we haven’t been able to reproduce that causes the group
|
228 |
}
|
229 |
}
|
230 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
231 |
$this->all_groups = $groups;
|
232 |
}
|
233 |
|
281 |
*/
|
282 |
public function post_results( $posts, $the_query ) {
|
283 |
// Execute only in the main query.
|
284 |
+
if ( ! function_exists( 'get_current_screen' ) || ! $the_query->is_main_query() ) {
|
|
|
|
|
|
|
|
|
285 |
return $posts;
|
286 |
}
|
287 |
|
292 |
}
|
293 |
|
294 |
$this->collect_all_ads( $posts );
|
295 |
+
$this->collect_all_groups();
|
296 |
|
297 |
// the new post list.
|
298 |
if ( isset( $_REQUEST['post_status'] ) && 'trash' === $_REQUEST['post_status'] ) {
|
421 |
$new_posts = array();
|
422 |
$the_list = $using_original ? $this->all_ads : $posts;
|
423 |
foreach ( $the_list as $post ) {
|
424 |
+
$option = $this->all_ads_options[ $post->ID ];
|
425 |
+
if ( isset( $option['type'] ) && $request['adtype'] === $option['type'] ) {
|
426 |
+
$new_posts[] = $post;
|
|
|
|
|
427 |
}
|
428 |
}
|
429 |
$posts = $new_posts;
|
438 |
$new_posts = array();
|
439 |
$the_list = $using_original ? $this->all_ads : $posts;
|
440 |
foreach ( $the_list as $post ) {
|
441 |
+
$option = $this->all_ads_options[ $post->ID ];
|
442 |
+
if ( 'responsive' === $request['adsize'] ) {
|
443 |
+
if ( 'adsense' === $option['type'] ) {
|
444 |
+
$content = false;
|
445 |
+
try {
|
446 |
+
$content = json_decode( $post->post_content, true );
|
447 |
+
} catch ( Exception $e ) {
|
448 |
$content = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
449 |
}
|
450 |
+
if ( $content && 'responsive' === $content['unitType'] ) {
|
|
|
|
|
|
|
451 |
$new_posts[] = $post;
|
452 |
}
|
453 |
}
|
454 |
+
} else {
|
455 |
+
$width = isset( $option['width'] ) ? $option['width'] : 0;
|
456 |
+
$height = isset( $option['height'] ) ? $option['height'] : 0;
|
457 |
+
if ( $request['adsize'] === $width . 'x' . $height ) {
|
458 |
+
$new_posts[] = $post;
|
459 |
+
}
|
460 |
}
|
461 |
}
|
462 |
$posts = $new_posts;
|
464 |
$using_original = false;
|
465 |
}
|
466 |
|
467 |
+
if ( isset( $request['addate'] ) ) {
|
468 |
+
$posts = $this->filter_expired_ads( urldecode( $request['addate'] ), $using_original ? $this->all_ads : $posts );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
469 |
}
|
470 |
|
471 |
$posts = apply_filters( 'advanced-ads-ad-list-filter', $posts, $this->all_ads_options );
|
487 |
|
488 |
return self::$instance;
|
489 |
}
|
490 |
+
|
491 |
+
/**
|
492 |
+
* If there are expired ads, add an expired view.
|
493 |
+
*
|
494 |
+
* @param array $views currently available views.
|
495 |
+
*
|
496 |
+
* @return array
|
497 |
+
*/
|
498 |
+
public function add_expired_view( $views ) {
|
499 |
+
$count = $this->count_expired_ads();
|
500 |
+
if ( empty( $count ) ) {
|
501 |
+
return $views;
|
502 |
+
}
|
503 |
+
$views[ Advanced_Ads_Ad_Expiration::POST_STATUS ] = sprintf(
|
504 |
+
'<a href="%s" %s>%s <span class="count">(%d)</span></a>',
|
505 |
+
add_query_arg( array(
|
506 |
+
'post_type' => Advanced_Ads::POST_TYPE_SLUG,
|
507 |
+
'addate' => 'advads-filter-expired',
|
508 |
+
'orderby' => 'expiry_date',
|
509 |
+
'order' => 'DESC',
|
510 |
+
), 'edit.php' ),
|
511 |
+
isset( $_REQUEST['addate'] ) && $_REQUEST['addate'] === 'advads-filter-expired' ? 'class="current" aria-current="page"' : '',
|
512 |
+
esc_attr_x( 'Expired', 'Post list header for expired ads.', 'advanced-ads' ),
|
513 |
+
$count
|
514 |
+
);
|
515 |
+
|
516 |
+
return array_replace( array_intersect_key( $this->views_order(), $views ), $views );
|
517 |
+
}
|
518 |
+
|
519 |
+
/**
|
520 |
+
* Get the number of ads that have expired.
|
521 |
+
*
|
522 |
+
* @return int
|
523 |
+
*/
|
524 |
+
private function count_expired_ads() {
|
525 |
+
return ( new WP_Query( array(
|
526 |
+
'post_type' => Advanced_Ads::POST_TYPE_SLUG,
|
527 |
+
'post_status' => Advanced_Ads_Ad_Expiration::POST_STATUS,
|
528 |
+
) ) )->found_posts;
|
529 |
+
}
|
530 |
+
|
531 |
+
/**
|
532 |
+
* If there are ads with an expiration date in the future, add an expiring view.
|
533 |
+
*
|
534 |
+
* @param array $views currently available views.
|
535 |
+
*
|
536 |
+
* @return array
|
537 |
+
*/
|
538 |
+
public function add_expiring_view( $views ) {
|
539 |
+
$count = $this->count_expiring_ads();
|
540 |
+
if ( empty( $count ) ) {
|
541 |
+
return $views;
|
542 |
+
}
|
543 |
+
$views['expiring'] = sprintf(
|
544 |
+
'<a href="%s" %s>%s <span class="count">(%d)</span></a>',
|
545 |
+
add_query_arg( array(
|
546 |
+
'post_type' => Advanced_Ads::POST_TYPE_SLUG,
|
547 |
+
'addate' => 'advads-filter-expiring',
|
548 |
+
'orderby' => 'expiry_date',
|
549 |
+
'order' => 'ASC',
|
550 |
+
), 'edit.php' ),
|
551 |
+
isset( $_REQUEST['addate'] ) && $_REQUEST['addate'] === 'advads-filter-expiring' ? 'class="current" aria-current="page"' : '',
|
552 |
+
esc_attr_x( 'Expiring', 'Post list header for ads expiring in the future.', 'advanced-ads' ),
|
553 |
+
$count
|
554 |
+
);
|
555 |
+
|
556 |
+
return array_replace( array_intersect_key( $this->views_order(), $views ), $views );
|
557 |
+
}
|
558 |
+
|
559 |
+
/**
|
560 |
+
* Get the number of ads that have an expiration date in the future.
|
561 |
+
*
|
562 |
+
* @return int
|
563 |
+
*/
|
564 |
+
private function count_expiring_ads() {
|
565 |
+
return ( new WP_Query( array(
|
566 |
+
'post_type' => Advanced_Ads::POST_TYPE_SLUG,
|
567 |
+
'post_status' => 'any',
|
568 |
+
'meta_query' => array(
|
569 |
+
array(
|
570 |
+
'key' => Advanced_Ads_Ad_Expiration::POST_META,
|
571 |
+
'value' => current_time( 'mysql', true ),
|
572 |
+
'compare' => '>=',
|
573 |
+
'type' => 'DATETIME',
|
574 |
+
),
|
575 |
+
),
|
576 |
+
) ) )->found_posts;
|
577 |
+
}
|
578 |
+
|
579 |
+
/**
|
580 |
+
* Our expected order of views.
|
581 |
+
*
|
582 |
+
* @return string[]
|
583 |
+
*/
|
584 |
+
private function views_order() {
|
585 |
+
static $views_order;
|
586 |
+
if ( $views_order === null ) {
|
587 |
+
$views_order = array_flip( array( 'all', 'publish', 'future', 'expiring', Advanced_Ads_Ad_Expiration::POST_STATUS, 'draft', 'pending', 'trash' ) );
|
588 |
+
}
|
589 |
+
|
590 |
+
return $views_order;
|
591 |
+
}
|
592 |
+
|
593 |
+
/**
|
594 |
+
* Filter by expiring or expired ads.
|
595 |
+
*
|
596 |
+
* @param string $filter The current filter name, expired or expiring.
|
597 |
+
* @param WP_Post[] $posts The array of posts.
|
598 |
+
*
|
599 |
+
* @return WP_Post[]
|
600 |
+
*/
|
601 |
+
private function filter_expired_ads( $filter, $posts ) {
|
602 |
+
$now = time();
|
603 |
+
|
604 |
+
return array_filter( $posts, function( WP_Post $post ) use ( $now, $filter ) {
|
605 |
+
$option = $this->all_ads_options[ $post->ID ];
|
606 |
+
if ( empty( $option['expiry_date'] ) ) {
|
607 |
+
return false;
|
608 |
+
}
|
609 |
+
|
610 |
+
return (
|
611 |
+
// filter by ads already expired.
|
612 |
+
( $filter === 'advads-filter-expired' && $option['expiry_date'] <= $now )
|
613 |
+
// filter by ads expiring in the future.
|
614 |
+
|| ( $filter === 'advads-filter-expiring' && $option['expiry_date'] > $now )
|
615 |
+
);
|
616 |
+
} );
|
617 |
+
}
|
618 |
}
|
admin/includes/class-meta-box.php
CHANGED
@@ -218,7 +218,7 @@ class Advanced_Ads_Admin_Meta_Boxes {
|
|
218 |
$view = 'conditions/ad-display-metabox.php';
|
219 |
$hndlelinks = '<a href="#" class="advads-video-link">' . __( 'Video', 'advanced-ads' ) . '</a>';
|
220 |
$hndlelinks .= '<a href="' . ADVADS_URL . 'manual/display-conditions#utm_source=advanced-ads&utm_medium=link&utm_campaign=edit-display" target="_blank">' . __( 'Manual', 'advanced-ads' ) . '</a>';
|
221 |
-
$videomarkup = '<iframe width="420" height="315" src="https://www.youtube-nocookie.com/embed/
|
222 |
break;
|
223 |
case 'ad-visitor-box':
|
224 |
$view = 'conditions/ad-visitor-metabox.php';
|
218 |
$view = 'conditions/ad-display-metabox.php';
|
219 |
$hndlelinks = '<a href="#" class="advads-video-link">' . __( 'Video', 'advanced-ads' ) . '</a>';
|
220 |
$hndlelinks .= '<a href="' . ADVADS_URL . 'manual/display-conditions#utm_source=advanced-ads&utm_medium=link&utm_campaign=edit-display" target="_blank">' . __( 'Manual', 'advanced-ads' ) . '</a>';
|
221 |
+
$videomarkup = '<iframe width="420" height="315" src="https://www.youtube-nocookie.com/embed/VjfrRl5Qn4I?rel=0&showinfo=0" frameborder="0" allowfullscreen></iframe>';
|
222 |
break;
|
223 |
case 'ad-visitor-box':
|
224 |
$view = 'conditions/ad-visitor-metabox.php';
|
admin/views/ad-list-filters.php
CHANGED
@@ -29,14 +29,6 @@ if ( isset( $_REQUEST['post_status'] ) && 'trash' === $_REQUEST['post_status'] )
|
|
29 |
<?php endforeach; ?>
|
30 |
</select>
|
31 |
<?php endif; ?>
|
32 |
-
<?php if ( ! empty( $all_filters['all_dates'] ) ) : ?>
|
33 |
-
<select id="advads-filter-date" name="addate">
|
34 |
-
<option value="">- <?php esc_html_e( 'all ad dates', 'advanced-ads' ); ?> -</option>
|
35 |
-
<?php foreach ( $all_filters['all_dates'] as $key => $value ) : ?>
|
36 |
-
<option <?php selected( $ad_date, $key ); ?> value="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $value ); ?></option>
|
37 |
-
<?php endforeach; ?>
|
38 |
-
</select>
|
39 |
-
<?php endif; ?>
|
40 |
<?php if ( ! empty( $all_filters['all_groups'] ) ) : ?>
|
41 |
<select id="advads-filter-group" name="adgroup">
|
42 |
<option value="">- <?php esc_html_e( 'all ad groups', 'advanced-ads' ); ?> -</option>
|
29 |
<?php endforeach; ?>
|
30 |
</select>
|
31 |
<?php endif; ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
<?php if ( ! empty( $all_filters['all_groups'] ) ) : ?>
|
33 |
<select id="advads-filter-group" name="adgroup">
|
34 |
<option value="">- <?php esc_html_e( 'all ad groups', 'advanced-ads' ); ?> -</option>
|
admin/views/ad-submitbox-meta.php
CHANGED
@@ -32,7 +32,6 @@
|
|
32 |
?>
|
33 |
<fieldset class="advads-timestamp">
|
34 |
<?php
|
35 |
-
// phpcs:disable
|
36 |
printf(
|
37 |
// translators: %1$s month, %2$s day, %3$s year, %4$s hour, %5$s minute.
|
38 |
_x( '%1$s %2$s, %3$s @ %4$s %5$s', 'order of expiry date fields 1: month, 2: day, 3: year, 4: hour, 5: minute', 'advanced-ads' ),
|
@@ -42,7 +41,6 @@
|
|
42 |
$hour_field,
|
43 |
$minute_field
|
44 |
);
|
45 |
-
// phpcs:enable
|
46 |
?>
|
47 |
</fieldset>
|
48 |
(<?php echo esc_html( Advanced_Ads_Utils::get_timezone_name() ); ?>)
|
32 |
?>
|
33 |
<fieldset class="advads-timestamp">
|
34 |
<?php
|
|
|
35 |
printf(
|
36 |
// translators: %1$s month, %2$s day, %3$s year, %4$s hour, %5$s minute.
|
37 |
_x( '%1$s %2$s, %3$s @ %4$s %5$s', 'order of expiry date fields 1: month, 2: day, 3: year, 4: hour, 5: minute', 'advanced-ads' ),
|
41 |
$hour_field,
|
42 |
$minute_field
|
43 |
);
|
|
|
44 |
?>
|
45 |
</fieldset>
|
46 |
(<?php echo esc_html( Advanced_Ads_Utils::get_timezone_name() ); ?>)
|
admin/views/placements.php
CHANGED
@@ -227,8 +227,9 @@ $quick_actions['delete'] = '<a style="cursor: pointer;" class="advads-delete-tag
|
|
227 |
<?php
|
228 |
$modal_slug = esc_attr( $_placement_slug );
|
229 |
$modal_content = $advanced_options;
|
230 |
-
|
231 |
-
$
|
|
|
232 |
include ADVADS_BASE_PATH . 'admin/views/modal.php';
|
233 |
?>
|
234 |
|
227 |
<?php
|
228 |
$modal_slug = esc_attr( $_placement_slug );
|
229 |
$modal_content = $advanced_options;
|
230 |
+
// Translators: 1: "Options", 2: the name of a placement.
|
231 |
+
$modal_title = sprintf( '%1$s: %2$s', __( 'Options', 'advanced-ads' ), esc_html( $_placement['name'] ) );
|
232 |
+
$close_action = esc_html__( 'Close and save', 'advanced-ads' );
|
233 |
include ADVADS_BASE_PATH . 'admin/views/modal.php';
|
234 |
?>
|
235 |
|
advanced-ads.php
CHANGED
@@ -12,7 +12,7 @@
|
|
12 |
* Plugin Name: Advanced Ads
|
13 |
* Plugin URI: https://wpadvancedads.com
|
14 |
* Description: Manage and optimize your ads in WordPress
|
15 |
-
* Version: 1.
|
16 |
* Author: Thomas Maier, Advanced Ads GmbH
|
17 |
* Author URI: https://wpadvancedads.com
|
18 |
* Text Domain: advanced-ads
|
@@ -39,7 +39,7 @@ define( 'ADVADS_BASE_DIR', dirname( ADVADS_BASE ) ); // directory of the plugin
|
|
39 |
// general and global slug, e.g. to store options in WP.
|
40 |
define( 'ADVADS_SLUG', 'advanced-ads' );
|
41 |
define( 'ADVADS_URL', 'https://wpadvancedads.com/' );
|
42 |
-
define( 'ADVADS_VERSION', '1.
|
43 |
|
44 |
// Autoloading, modules and functions.
|
45 |
|
12 |
* Plugin Name: Advanced Ads
|
13 |
* Plugin URI: https://wpadvancedads.com
|
14 |
* Description: Manage and optimize your ads in WordPress
|
15 |
+
* Version: 1.31.0
|
16 |
* Author: Thomas Maier, Advanced Ads GmbH
|
17 |
* Author URI: https://wpadvancedads.com
|
18 |
* Text Domain: advanced-ads
|
39 |
// general and global slug, e.g. to store options in WP.
|
40 |
define( 'ADVADS_SLUG', 'advanced-ads' );
|
41 |
define( 'ADVADS_URL', 'https://wpadvancedads.com/' );
|
42 |
+
define( 'ADVADS_VERSION', '1.31.0' );
|
43 |
|
44 |
// Autoloading, modules and functions.
|
45 |
|
classes/ad-expiration.php
ADDED
@@ -0,0 +1,105 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Ad Expiration functionality.
|
5 |
+
*/
|
6 |
+
class Advanced_Ads_Ad_Expiration {
|
7 |
+
const POST_STATUS = 'advanced_ads_expired';
|
8 |
+
const POST_META = 'advanced_ads_expiration_time';
|
9 |
+
|
10 |
+
/**
|
11 |
+
* The current ad object.
|
12 |
+
*
|
13 |
+
* @var Advanced_Ads_Ad
|
14 |
+
*/
|
15 |
+
private $ad;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Inject ad object, hook to option saving.
|
19 |
+
*
|
20 |
+
* @param Advanced_Ads_Ad $ad the current ad object.
|
21 |
+
*/
|
22 |
+
public function __construct( Advanced_Ads_Ad $ad ) {
|
23 |
+
$this->ad = $ad;
|
24 |
+
|
25 |
+
add_filter( 'advanced-ads-save-options', array( $this, 'save_expiration_date' ), 10, 2 );
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Check whether this ad is expired.
|
30 |
+
*
|
31 |
+
* @return bool
|
32 |
+
*/
|
33 |
+
public function is_ad_expired() {
|
34 |
+
if ( $this->ad->expiry_date <= 0 || $this->ad->expiry_date > time() ) {
|
35 |
+
return false;
|
36 |
+
}
|
37 |
+
|
38 |
+
// if the ad is not trashed, but has a different status than expired, transition the status.
|
39 |
+
if ( ! in_array( $this->ad->status, array( self::POST_STATUS, 'trash' ), true ) ) {
|
40 |
+
$this->transition_post_status();
|
41 |
+
}
|
42 |
+
|
43 |
+
return true;
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Extract the expiration date from the options array and save it as post_meta directly.
|
48 |
+
*
|
49 |
+
* @param array $options array with all ad options.
|
50 |
+
* @param Advanced_Ads_Ad $ad the current ad object.
|
51 |
+
*
|
52 |
+
* @return array
|
53 |
+
*/
|
54 |
+
public function save_expiration_date( $options, Advanced_Ads_Ad $ad ) {
|
55 |
+
if ( empty( $options['expiry_date'] ) ) {
|
56 |
+
return $options;
|
57 |
+
}
|
58 |
+
$datetime = ( new DateTimeImmutable() )->setTimestamp( (int) $options['expiry_date'] );
|
59 |
+
update_post_meta( $ad->id, self::POST_META, $datetime->format( 'Y-m-d H:i:s' ) );
|
60 |
+
|
61 |
+
return $options;
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Transition the post form previous status to self::POST_STATUS.
|
66 |
+
* Remove kses filters before updating the post so that expiring ads don’t lose HTML or other code.
|
67 |
+
*/
|
68 |
+
private function transition_post_status() {
|
69 |
+
kses_remove_filters();
|
70 |
+
wp_update_post(
|
71 |
+
array(
|
72 |
+
'ID' => $this->ad->id,
|
73 |
+
'post_status' => self::POST_STATUS,
|
74 |
+
)
|
75 |
+
);
|
76 |
+
kses_init_filters();
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Register custom post status for expired ads.
|
81 |
+
*/
|
82 |
+
public static function register_post_status() {
|
83 |
+
register_post_status( self::POST_STATUS, array(
|
84 |
+
'label' => __( 'Expired', 'advanced-ads' ),
|
85 |
+
'private' => true,
|
86 |
+
) );
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Hook into wp_untrash_post_status, to revert ads that previously had the expired status to that status instead of draft.
|
91 |
+
*
|
92 |
+
* @param string $new_status The new status after untrashing a post.
|
93 |
+
* @param int $post_id The post id of the post to be untrashed.
|
94 |
+
* @param string $previous_status The post status before trashing.
|
95 |
+
*
|
96 |
+
* @return string
|
97 |
+
*/
|
98 |
+
public static function wp_untrash_post_status( $new_status, $post_id, $previous_status ) {
|
99 |
+
if ( $previous_status === self::POST_STATUS ) {
|
100 |
+
return $previous_status;
|
101 |
+
}
|
102 |
+
|
103 |
+
return $new_status;
|
104 |
+
}
|
105 |
+
}
|
classes/ad.php
CHANGED
@@ -159,6 +159,19 @@ class Advanced_Ads_Ad {
|
|
159 |
* @var Advanced_Ads_Inline_Css
|
160 |
*/
|
161 |
private $inline_css;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
|
163 |
/**
|
164 |
* Init ad object
|
@@ -238,7 +251,7 @@ class Advanced_Ads_Ad {
|
|
238 |
$this->description = $this->options( 'description' );
|
239 |
$this->output = $this->options( 'output' );
|
240 |
$this->status = $_data->post_status;
|
241 |
-
$this->expiry_date = $this->options( 'expiry_date' );
|
242 |
$this->is_head_placement = isset( $this->args['placement_type'] ) && 'header' === $this->args['placement_type'];
|
243 |
$this->args['is_top_level'] = ! isset( $this->args['is_top_level'] );
|
244 |
|
@@ -259,6 +272,8 @@ class Advanced_Ads_Ad {
|
|
259 |
$this->wrapper['id'] = $this->create_wrapper_id();
|
260 |
}
|
261 |
}
|
|
|
|
|
262 |
}
|
263 |
|
264 |
/**
|
@@ -444,19 +459,19 @@ class Advanced_Ads_Ad {
|
|
444 |
return false;
|
445 |
}
|
446 |
|
447 |
-
if ( ! $this->can_display_by_visitor()
|
448 |
-
return false;
|
449 |
-
}
|
450 |
-
} else {
|
451 |
-
if ( 'publish' !== $this->status || ! $this->can_display_by_expiry_date() ) {
|
452 |
return false;
|
453 |
}
|
|
|
|
|
454 |
}
|
455 |
|
456 |
-
|
457 |
-
|
|
|
458 |
|
459 |
-
|
|
|
460 |
}
|
461 |
|
462 |
/**
|
@@ -543,34 +558,10 @@ class Advanced_Ads_Ad {
|
|
543 |
*
|
544 |
* @return bool $can_display true if can be displayed in frontend based on expiry date
|
545 |
* @since 1.3.15
|
|
|
546 |
*/
|
547 |
public function can_display_by_expiry_date() {
|
548 |
-
|
549 |
-
// if expiry_date is not set, null is returned.
|
550 |
-
$ad_expiry_date = (int) $this->options( 'expiry_date' );
|
551 |
-
|
552 |
-
if ( $ad_expiry_date <= 0 || $ad_expiry_date > time() ) {
|
553 |
-
return true;
|
554 |
-
}
|
555 |
-
|
556 |
-
// set status to 'draft' if the ad is expired.
|
557 |
-
if ( 'draft' !== $this->status ) {
|
558 |
-
// removing the kses filters here so that expiring ads don’t lose HTML or other code.
|
559 |
-
kses_remove_filters();
|
560 |
-
wp_update_post(
|
561 |
-
array(
|
562 |
-
'ID' => $this->id,
|
563 |
-
'post_status' => 'draft',
|
564 |
-
)
|
565 |
-
);
|
566 |
-
kses_init_filters();
|
567 |
-
/**
|
568 |
-
* Run when an ad expires
|
569 |
-
*/
|
570 |
-
do_action( 'advanced-ads-ad-expired', $this->id, $this );
|
571 |
-
}
|
572 |
-
|
573 |
-
return false;
|
574 |
}
|
575 |
|
576 |
/**
|
159 |
* @var Advanced_Ads_Inline_Css
|
160 |
*/
|
161 |
private $inline_css;
|
162 |
+
/**
|
163 |
+
* Timestamp if ad has an expiration date.
|
164 |
+
*
|
165 |
+
* @var int
|
166 |
+
*/
|
167 |
+
public $expiry_date = 0;
|
168 |
+
|
169 |
+
/**
|
170 |
+
* The ad expiration object.
|
171 |
+
*
|
172 |
+
* @var Advanced_Ads_Ad_Expiration
|
173 |
+
*/
|
174 |
+
private $ad_expiration;
|
175 |
|
176 |
/**
|
177 |
* Init ad object
|
251 |
$this->description = $this->options( 'description' );
|
252 |
$this->output = $this->options( 'output' );
|
253 |
$this->status = $_data->post_status;
|
254 |
+
$this->expiry_date = (int) $this->options( 'expiry_date' );
|
255 |
$this->is_head_placement = isset( $this->args['placement_type'] ) && 'header' === $this->args['placement_type'];
|
256 |
$this->args['is_top_level'] = ! isset( $this->args['is_top_level'] );
|
257 |
|
272 |
$this->wrapper['id'] = $this->create_wrapper_id();
|
273 |
}
|
274 |
}
|
275 |
+
|
276 |
+
$this->ad_expiration = new Advanced_Ads_Ad_Expiration( $this );
|
277 |
}
|
278 |
|
279 |
/**
|
459 |
return false;
|
460 |
}
|
461 |
|
462 |
+
if ( ! $this->can_display_by_visitor() ) {
|
|
|
|
|
|
|
|
|
463 |
return false;
|
464 |
}
|
465 |
+
} elseif ( 'publish' !== $this->status ) {
|
466 |
+
return false;
|
467 |
}
|
468 |
|
469 |
+
if ( $this->ad_expiration->is_ad_expired() ) {
|
470 |
+
return false;
|
471 |
+
}
|
472 |
|
473 |
+
// add own conditions to flag output as possible or not.
|
474 |
+
return apply_filters( 'advanced-ads-can-display', true, $this, $check_options );
|
475 |
}
|
476 |
|
477 |
/**
|
558 |
*
|
559 |
* @return bool $can_display true if can be displayed in frontend based on expiry date
|
560 |
* @since 1.3.15
|
561 |
+
* @deprecated 1.31.0 This is an internal method and should not have been public.
|
562 |
*/
|
563 |
public function can_display_by_expiry_date() {
|
564 |
+
return $this->ad_expiration->is_ad_expired();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
565 |
}
|
566 |
|
567 |
/**
|
classes/ad_placements.php
CHANGED
@@ -460,572 +460,7 @@ class Advanced_Ads_Placements {
|
|
460 |
* @since 1.2.1
|
461 |
*/
|
462 |
public static function &inject_in_content( $placement_id, $placement_opts, &$content ) {
|
463 |
-
|
464 |
-
return $content;
|
465 |
-
}
|
466 |
-
|
467 |
-
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
468 |
-
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
|
469 |
-
|
470 |
-
// get plugin options.
|
471 |
-
$plugin_options = Advanced_Ads::get_instance()->options();
|
472 |
-
|
473 |
-
$wp_charset = get_bloginfo( 'charset' );
|
474 |
-
// parse document as DOM (fragment - having only a part of an actual post given).
|
475 |
-
|
476 |
-
$content_to_load = self::get_content_to_load( $content, $wp_charset );
|
477 |
-
if ( ! $content_to_load ) {
|
478 |
-
return $content;
|
479 |
-
}
|
480 |
-
|
481 |
-
$dom = new DOMDocument( '1.0', $wp_charset );
|
482 |
-
// may loose some fragments or add autop-like code.
|
483 |
-
libxml_use_internal_errors( true ); // avoid notices and warnings - html is most likely malformed.
|
484 |
-
|
485 |
-
$success = $dom->loadHtml( '<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wp_charset . '" /><body>' . $content_to_load );
|
486 |
-
libxml_use_internal_errors( false );
|
487 |
-
if ( true !== $success ) {
|
488 |
-
// -TODO handle cases were dom-parsing failed (at least inform user)
|
489 |
-
return $content;
|
490 |
-
}
|
491 |
-
|
492 |
-
// parse arguments.
|
493 |
-
$tag = isset( $placement_opts['tag'] ) ? $placement_opts['tag'] : 'p';
|
494 |
-
$tag = preg_replace( '/[^a-z0-9]/i', '', $tag ); // simplify tag.
|
495 |
-
/**
|
496 |
-
* Store the original tag value since $tag is changed on the fly and we might want to know the original selected
|
497 |
-
* options for some checks later.
|
498 |
-
*/
|
499 |
-
$tag_option = $tag;
|
500 |
-
|
501 |
-
// allow more complex xPath expression.
|
502 |
-
$tag = apply_filters( 'advanced-ads-placement-content-injection-xpath', $tag, $placement_opts );
|
503 |
-
|
504 |
-
/**
|
505 |
-
* Handle advanced tags.
|
506 |
-
*/
|
507 |
-
switch ( $tag_option ) {
|
508 |
-
case 'p':
|
509 |
-
// exclude paragraphs within blockquote tags
|
510 |
-
$tag = 'p[not(parent::blockquote)]';
|
511 |
-
break;
|
512 |
-
case 'pwithoutimg':
|
513 |
-
// convert option name into correct path, exclude paragraphs within blockquote tags
|
514 |
-
$tag = 'p[not(descendant::img) and not(parent::blockquote)]';
|
515 |
-
break;
|
516 |
-
case 'img':
|
517 |
-
/*
|
518 |
-
* Handle: 1) "img" tags 2) "image" block 3) "gallery" block 4) "gallery shortcode" 5) "wp_caption" shortcode
|
519 |
-
* Handle the gallery created by the block or the shortcode as one image.
|
520 |
-
* Prevent injection of ads next to images in tables.
|
521 |
-
*/
|
522 |
-
// Default shortcodes, including non-HTML5 versions.
|
523 |
-
$shortcodes = "@class and (
|
524 |
-
contains(concat(' ', normalize-space(@class), ' '), ' gallery-size') or
|
525 |
-
contains(concat(' ', normalize-space(@class), ' '), ' wp-caption ') )";
|
526 |
-
$tag = "*[self::img or self::figure or self::div[$shortcodes]]
|
527 |
-
[not(ancestor::table or ancestor::figure or ancestor::div[$shortcodes])]";
|
528 |
-
break;
|
529 |
-
// any headline. By default h2, h3, and h4
|
530 |
-
case 'headlines':
|
531 |
-
$headlines = apply_filters( 'advanced-ads-headlines-for-ad-injection', array( 'h2', 'h3', 'h4' ) );
|
532 |
-
|
533 |
-
foreach ( $headlines as &$headline ) {
|
534 |
-
$headline = 'self::' . $headline;
|
535 |
-
}
|
536 |
-
$tag = '*[' . implode( ' or ', $headlines ) . ']'; // /html/body/*[self::h2 or self::h3 or self::h4]
|
537 |
-
break;
|
538 |
-
// any HTML element that makes sense in the content
|
539 |
-
case 'anyelement':
|
540 |
-
$exclude = array(
|
541 |
-
'html',
|
542 |
-
'body',
|
543 |
-
'script',
|
544 |
-
'style',
|
545 |
-
'tr',
|
546 |
-
'td',
|
547 |
-
// Inline tags.
|
548 |
-
'a',
|
549 |
-
'abbr',
|
550 |
-
'b',
|
551 |
-
'bdo',
|
552 |
-
'br',
|
553 |
-
'button',
|
554 |
-
'cite',
|
555 |
-
'code',
|
556 |
-
'dfn',
|
557 |
-
'em',
|
558 |
-
'i',
|
559 |
-
'img',
|
560 |
-
'kbd',
|
561 |
-
'label',
|
562 |
-
'option',
|
563 |
-
'q',
|
564 |
-
'samp',
|
565 |
-
'select',
|
566 |
-
'small',
|
567 |
-
'span',
|
568 |
-
'strong',
|
569 |
-
'sub',
|
570 |
-
'sup',
|
571 |
-
'textarea',
|
572 |
-
'time',
|
573 |
-
'tt',
|
574 |
-
'var',
|
575 |
-
);
|
576 |
-
$tag = '*[not(self::' . implode( ' or self::', $exclude ) . ')]';
|
577 |
-
break;
|
578 |
-
case 'custom':
|
579 |
-
// get the path for the "custom" tag choice, use p as a fallback to prevent it from showing any ads if users left it empty
|
580 |
-
$tag = ! empty( $placement_opts['xpath'] ) ? stripslashes( $placement_opts['xpath'] ) : 'p';
|
581 |
-
break;
|
582 |
-
}
|
583 |
-
|
584 |
-
// select positions.
|
585 |
-
$xpath = new DOMXPath( $dom );
|
586 |
-
$items = $xpath->query( '/html/body/' . $tag );
|
587 |
-
|
588 |
-
$options = array(
|
589 |
-
'allowEmpty' => false, // whether the tag can be empty to be counted.
|
590 |
-
'paragraph_select_from_bottom' => isset( $placement_opts['start_from_bottom'] ) && $placement_opts['start_from_bottom'],
|
591 |
-
// only has before and after.
|
592 |
-
'before' => isset( $placement_opts['position'] ) && 'before' === $placement_opts['position'],
|
593 |
-
);
|
594 |
-
|
595 |
-
$options['paragraph_id'] = isset( $placement_opts['index'] ) ? $placement_opts['index'] : 1;
|
596 |
-
$options['paragraph_id'] = max( 1, (int) $options['paragraph_id'] );
|
597 |
-
|
598 |
-
// if there are too few items at this level test nesting.
|
599 |
-
$options['itemLimit'] = 'p' === $tag_option ? 2 : 1;
|
600 |
-
|
601 |
-
// trigger such a high item limit that all elements will be considered.
|
602 |
-
if ( ! empty( $plugin_options['content-injection-level-disabled'] ) ) {
|
603 |
-
$options['itemLimit'] = 1000;
|
604 |
-
}
|
605 |
-
|
606 |
-
// handle tags that are empty by definition or could be empty ("custom" option)
|
607 |
-
if ( in_array( $tag_option, array( 'img', 'iframe', 'custom' ), true ) ) {
|
608 |
-
$options['allowEmpty'] = true;
|
609 |
-
}
|
610 |
-
|
611 |
-
// allow hooks to change some options.
|
612 |
-
$options = apply_filters(
|
613 |
-
'advanced-ads-placement-content-injection-options',
|
614 |
-
$options,
|
615 |
-
$tag_option
|
616 |
-
);
|
617 |
-
|
618 |
-
if ( $items->length < $options['itemLimit'] ) {
|
619 |
-
$items = $xpath->query( '/html/body/*/' . $tag );
|
620 |
-
}
|
621 |
-
// try third level.
|
622 |
-
if ( $items->length < $options['itemLimit'] ) {
|
623 |
-
$items = $xpath->query( '/html/body/*/*/' . $tag );
|
624 |
-
}
|
625 |
-
// try all levels as last resort.
|
626 |
-
if ( $items->length < $options['itemLimit'] ) {
|
627 |
-
$items = $xpath->query( '//' . $tag );
|
628 |
-
}
|
629 |
-
|
630 |
-
// allow to select other elements.
|
631 |
-
$items = apply_filters( 'advanced-ads-placement-content-injection-items', $items, $xpath, $tag_option );
|
632 |
-
|
633 |
-
// filter empty tags from items.
|
634 |
-
$whitespaces = json_decode( '"\t\n\r \u00A0"' );
|
635 |
-
$paragraphs = array();
|
636 |
-
foreach ( $items as $item ) {
|
637 |
-
if ( $options['allowEmpty'] || ( isset( $item->textContent ) && trim( $item->textContent, $whitespaces ) !== '' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
|
638 |
-
$paragraphs[] = $item;
|
639 |
-
}
|
640 |
-
}
|
641 |
-
|
642 |
-
$ancestors_to_limit = self::get_ancestors_to_limit( $xpath );
|
643 |
-
$paragraphs = self::filter_by_ancestors_to_limit( $paragraphs, $ancestors_to_limit );
|
644 |
-
|
645 |
-
$options['paragraph_count'] = count( $paragraphs );
|
646 |
-
|
647 |
-
if ( $options['paragraph_count'] >= $options['paragraph_id'] ) {
|
648 |
-
$offset = $options['paragraph_select_from_bottom'] ? $options['paragraph_count'] - $options['paragraph_id'] : $options['paragraph_id'] - 1;
|
649 |
-
$offsets = apply_filters( 'advanced-ads-placement-content-offsets', array( $offset ), $options, $placement_opts, $xpath, $paragraphs, $dom );
|
650 |
-
$did_inject = false;
|
651 |
-
|
652 |
-
foreach ( $offsets as $offset ) {
|
653 |
-
|
654 |
-
// inject.
|
655 |
-
$node = apply_filters( 'advanced-ads-placement-content-injection-node', $paragraphs[ $offset ], $tag, $options['before'] );
|
656 |
-
|
657 |
-
// Prevent injection into image caption and gallery.
|
658 |
-
$parent = $node;
|
659 |
-
for ( $i = 0; $i < 4; $i++ ) {
|
660 |
-
$parent = $parent->parentNode;
|
661 |
-
if ( ! $parent instanceof DOMElement ) {
|
662 |
-
break;
|
663 |
-
}
|
664 |
-
if ( preg_match( '/\b(wp-caption|gallery-size)\b/', $parent->getAttribute( 'class' ) ) ) {
|
665 |
-
$node = $parent;
|
666 |
-
break;
|
667 |
-
}
|
668 |
-
}
|
669 |
-
|
670 |
-
// make sure that the ad is injected outside the link
|
671 |
-
if ( 'img' === $tag_option && 'a' === $node->parentNode->tagName ) {
|
672 |
-
if ( $options['before'] ) {
|
673 |
-
$node->parentNode;
|
674 |
-
} else {
|
675 |
-
// go one level deeper if inserted after to not insert the ad into the link; probably after the paragraph
|
676 |
-
$node->parentNode->parentNode;
|
677 |
-
}
|
678 |
-
}
|
679 |
-
|
680 |
-
$ad_content = Advanced_Ads_Select::get_instance()->get_ad_by_method( $placement_id, 'placement', $placement_opts );
|
681 |
-
|
682 |
-
if ( trim( $ad_content, $whitespaces ) === '' ) {
|
683 |
-
continue;
|
684 |
-
}
|
685 |
-
|
686 |
-
// phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
|
687 |
-
$ad_content = self::filter_ad_content( $ad_content, $node->tagName, $options );
|
688 |
-
|
689 |
-
// convert HTML to XML!
|
690 |
-
$ad_dom = new DOMDocument( '1.0', $wp_charset );
|
691 |
-
libxml_use_internal_errors( true );
|
692 |
-
$ad_dom->loadHtml( '<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wp_charset . '" /><body>' . $ad_content );
|
693 |
-
// log errors.
|
694 |
-
if ( defined( 'WP_DEBUG' ) && WP_DEBUG && current_user_can( 'advanced_ads_manage_options' ) ) {
|
695 |
-
foreach ( libxml_get_errors() as $_error ) {
|
696 |
-
// continue, if there is '&' symbol, but not HTML entity.
|
697 |
-
if ( false === stripos( $_error->message, 'htmlParseEntityRef:' ) ) {
|
698 |
-
Advanced_Ads::log( 'possible content injection error for placement "' . $placement_id . '": ' . print_r( $_error, true ) );
|
699 |
-
}
|
700 |
-
}
|
701 |
-
}
|
702 |
-
|
703 |
-
if ( $options['before'] ) {
|
704 |
-
$ref_node = $node;
|
705 |
-
|
706 |
-
foreach ( $ad_dom->getElementsByTagName( 'body' )->item( 0 )->childNodes as $importedNode ) {
|
707 |
-
$importedNode = $dom->importNode( $importedNode, true );
|
708 |
-
$ref_node->parentNode->insertBefore( $importedNode, $ref_node );
|
709 |
-
}
|
710 |
-
} else {
|
711 |
-
// append before next node or as last child to body.
|
712 |
-
$ref_node = $node->nextSibling;
|
713 |
-
if ( isset( $ref_node ) ) {
|
714 |
-
|
715 |
-
foreach ( $ad_dom->getElementsByTagName( 'body' )->item( 0 )->childNodes as $importedNode ) {
|
716 |
-
$importedNode = $dom->importNode( $importedNode, true );
|
717 |
-
$ref_node->parentNode->insertBefore( $importedNode, $ref_node );
|
718 |
-
}
|
719 |
-
} else {
|
720 |
-
// append to body; -TODO using here that we only select direct children of the body tag.
|
721 |
-
foreach ( $ad_dom->getElementsByTagName( 'body' )->item( 0 )->childNodes as $importedNode ) {
|
722 |
-
$importedNode = $dom->importNode( $importedNode, true );
|
723 |
-
$node->parentNode->appendChild( $importedNode );
|
724 |
-
}
|
725 |
-
}
|
726 |
-
}
|
727 |
-
|
728 |
-
libxml_use_internal_errors( false );
|
729 |
-
$did_inject = true;
|
730 |
-
}
|
731 |
-
|
732 |
-
if ( ! $did_inject ) {
|
733 |
-
return $content;
|
734 |
-
}
|
735 |
-
|
736 |
-
$content_orig = $content;
|
737 |
-
// convert to text-representation.
|
738 |
-
$content = $dom->saveHTML();
|
739 |
-
$content = self::prepare_output( $content, $content_orig );
|
740 |
-
|
741 |
-
/**
|
742 |
-
* Show a warning to ad admins in the Ad Health bar in the frontend, when
|
743 |
-
*
|
744 |
-
* * the level limitation was not disabled
|
745 |
-
* * could not inject one ad (as by use of `elseif` here)
|
746 |
-
* * but there are enough elements on the site, but just in sub-containers
|
747 |
-
*/
|
748 |
-
} elseif ( current_user_can( Advanced_Ads_Plugin::user_cap( 'advanced_ads_manage_options' ) )
|
749 |
-
&& empty( $plugin_options['content-injection-level-disabled'] ) ) {
|
750 |
-
|
751 |
-
// Check if there are more elements without limitation.
|
752 |
-
$all_items = $xpath->query( '//' . $tag );
|
753 |
-
|
754 |
-
$paragraphs = array();
|
755 |
-
foreach ( $all_items as $item ) {
|
756 |
-
if ( $options['allowEmpty'] || ( isset( $item->textContent ) && trim( $item->textContent, $whitespaces ) !== '' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
|
757 |
-
$paragraphs[] = $item;
|
758 |
-
}
|
759 |
-
}
|
760 |
-
|
761 |
-
$paragraphs = self::filter_by_ancestors_to_limit( $paragraphs, $ancestors_to_limit );
|
762 |
-
if ( $options['paragraph_id'] <= count( $paragraphs ) ) {
|
763 |
-
// Add a warning to ad health.
|
764 |
-
add_filter( 'advanced-ads-ad-health-nodes', array( 'Advanced_Ads_Placements', 'add_ad_health_node' ) );
|
765 |
-
}
|
766 |
-
}
|
767 |
-
|
768 |
-
// phpcs:enable
|
769 |
-
|
770 |
-
return $content;
|
771 |
-
}
|
772 |
-
|
773 |
-
/**
|
774 |
-
* Get content to load.
|
775 |
-
*
|
776 |
-
* @param string $content Original content.
|
777 |
-
* @param string $wp_charset blog charset.
|
778 |
-
*
|
779 |
-
* @return string $content Content to load.
|
780 |
-
*/
|
781 |
-
private static function get_content_to_load( $content, $wp_charset ) {
|
782 |
-
$plugin_options = Advanced_Ads::get_instance()->options();
|
783 |
-
|
784 |
-
// Prevent removing closing tags in scripts.
|
785 |
-
$content_to_load = preg_replace( '/<script.*?<\/script>/si', '<!--\0-->', $content );
|
786 |
-
|
787 |
-
// check which priority the wpautop filter has; might have been disabled on purpose.
|
788 |
-
$wpautop_priority = has_filter( 'the_content', 'wpautop' );
|
789 |
-
if ( $wpautop_priority && Advanced_Ads_Plugin::get_instance()->get_content_injection_priority() < $wpautop_priority ) {
|
790 |
-
$content_to_load = wpautop( $content_to_load );
|
791 |
-
}
|
792 |
-
|
793 |
-
return $content_to_load;
|
794 |
-
}
|
795 |
-
|
796 |
-
/**
|
797 |
-
* Filter ad content.
|
798 |
-
*
|
799 |
-
* @param string $ad_content Ad content.
|
800 |
-
* @param string $tag_name tar before/after the content.
|
801 |
-
* @param array $options Injection options.
|
802 |
-
*
|
803 |
-
* @return string ad content.
|
804 |
-
*/
|
805 |
-
private static function filter_ad_content( $ad_content, $tag_name, $options ) {
|
806 |
-
// Replace `</` with `<\/` in ad content when placed within `document.write()` to prevent code from breaking.
|
807 |
-
$ad_content = preg_replace( '#(document.write.+)</(.*)#', '$1<\/$2', $ad_content );
|
808 |
-
|
809 |
-
// Inject placeholder.
|
810 |
-
$id = count( self::$ads_for_placeholders );
|
811 |
-
self::$ads_for_placeholders[] = array(
|
812 |
-
'id' => $id,
|
813 |
-
'tag' => $tag_name,
|
814 |
-
'type' => $options['before'] ? 'before' : 'after',
|
815 |
-
'ad' => $ad_content,
|
816 |
-
);
|
817 |
-
|
818 |
-
return '%advads_placeholder_' . $id . '%';
|
819 |
-
}
|
820 |
-
|
821 |
-
/**
|
822 |
-
* Prepare output.
|
823 |
-
*
|
824 |
-
* @param string $content Modified content.
|
825 |
-
* @param string $content_orig Original content.
|
826 |
-
*
|
827 |
-
* @return string $content Content to output.
|
828 |
-
*/
|
829 |
-
private static function prepare_output( $content, $content_orig ) {
|
830 |
-
$plugin_options = Advanced_Ads::get_instance()->options();
|
831 |
-
|
832 |
-
$content = self::inject_ads( $content, $content_orig, self::$ads_for_placeholders );
|
833 |
-
self::$ads_for_placeholders = array();
|
834 |
-
|
835 |
-
return $content;
|
836 |
-
}
|
837 |
-
|
838 |
-
/**
|
839 |
-
* Search for ad placeholders in the `$content` to determine positions at which to inject ads.
|
840 |
-
* Given the positions, inject ads into `$content_orig.
|
841 |
-
*
|
842 |
-
* @param string $content Post content with injected ad placeholders.
|
843 |
-
* @param string $content_orig Unmodified post content.
|
844 |
-
* @param array $options Injection options.
|
845 |
-
* @param array $ads_for_placeholders Array of ads.
|
846 |
-
* Each ad contains placeholder id, before or after which tag to inject the ad, the ad content.
|
847 |
-
*
|
848 |
-
* @return string $content
|
849 |
-
*/
|
850 |
-
private static function inject_ads( $content, $content_orig, $ads_for_placeholders ) {
|
851 |
-
$self_closing_tags = array(
|
852 |
-
'area',
|
853 |
-
'base',
|
854 |
-
'basefont',
|
855 |
-
'bgsound',
|
856 |
-
'br',
|
857 |
-
'col',
|
858 |
-
'embed',
|
859 |
-
'frame',
|
860 |
-
'hr',
|
861 |
-
'img',
|
862 |
-
'input',
|
863 |
-
'keygen',
|
864 |
-
'link',
|
865 |
-
'meta',
|
866 |
-
'param',
|
867 |
-
'source',
|
868 |
-
'track',
|
869 |
-
'wbr',
|
870 |
-
);
|
871 |
-
|
872 |
-
// It is not possible to append/prepend in self closing tags.
|
873 |
-
foreach ( $ads_for_placeholders as &$ad_content ) {
|
874 |
-
if ( ( 'prepend' === $ad_content['type'] || 'append' === $ad_content['type'] )
|
875 |
-
&& in_array( $ad_content['tag'], $self_closing_tags, true ) ) {
|
876 |
-
$ad_content['type'] = 'after';
|
877 |
-
}
|
878 |
-
}
|
879 |
-
unset( $ad_content );
|
880 |
-
usort( $ads_for_placeholders, array( 'Advanced_Ads_Placements', 'sort_ads_for_placehoders' ) );
|
881 |
-
|
882 |
-
// Add tags before/after which ad placehoders were injected.
|
883 |
-
foreach ( $ads_for_placeholders as $ad_content ) {
|
884 |
-
$tag = $ad_content['tag'];
|
885 |
-
|
886 |
-
switch ( $ad_content['type'] ) {
|
887 |
-
case 'before':
|
888 |
-
case 'prepend':
|
889 |
-
$alts[] = "<${tag}[^>]*>";
|
890 |
-
break;
|
891 |
-
case 'after':
|
892 |
-
if ( in_array( $tag, $self_closing_tags, true ) ) {
|
893 |
-
$alts[] = "<${tag}[^>]*>";
|
894 |
-
} else {
|
895 |
-
$alts[] = "</${tag}>";
|
896 |
-
}
|
897 |
-
break;
|
898 |
-
case 'append':
|
899 |
-
$alts[] = "</${tag}>";
|
900 |
-
break;
|
901 |
-
}
|
902 |
-
}
|
903 |
-
$alts = array_unique( $alts );
|
904 |
-
$tag_regexp = implode( '|', $alts );
|
905 |
-
// Add ad placeholder.
|
906 |
-
$alts[] = '%advads_placeholder_(?:\d+)%';
|
907 |
-
$tag_and_placeholder_regexp = implode( '|', $alts );
|
908 |
-
|
909 |
-
preg_match_all( "#{$tag_and_placeholder_regexp}#i", $content, $tag_matches );
|
910 |
-
$count = 0;
|
911 |
-
|
912 |
-
// For each tag located before/after an ad placeholder, find its offset among the same tags.
|
913 |
-
foreach ( $tag_matches[0] as $r ) {
|
914 |
-
if ( preg_match( '/%advads_placeholder_(\d+)%/', $r, $result ) ) {
|
915 |
-
$id = $result[1];
|
916 |
-
$found_ad = false;
|
917 |
-
foreach ( $ads_for_placeholders as $n => $ad ) {
|
918 |
-
if ( (int) $ad['id'] === (int) $id ) {
|
919 |
-
$found_ad = $ad;
|
920 |
-
break;
|
921 |
-
}
|
922 |
-
}
|
923 |
-
if ( ! $found_ad ) {
|
924 |
-
continue;
|
925 |
-
}
|
926 |
-
|
927 |
-
switch ( $found_ad['type'] ) {
|
928 |
-
case 'before':
|
929 |
-
case 'append':
|
930 |
-
$ads_for_placeholders[ $n ]['offset'] = $count;
|
931 |
-
break;
|
932 |
-
case 'after':
|
933 |
-
case 'prepend':
|
934 |
-
$ads_for_placeholders[ $n ]['offset'] = $count - 1;
|
935 |
-
break;
|
936 |
-
}
|
937 |
-
} else {
|
938 |
-
$count ++;
|
939 |
-
}
|
940 |
-
}
|
941 |
-
|
942 |
-
// Find tags before/after which we need to inject ads.
|
943 |
-
preg_match_all( "#{$tag_regexp}#i", $content_orig, $orig_tag_matches, PREG_OFFSET_CAPTURE );
|
944 |
-
$new_content = '';
|
945 |
-
$pos = 0;
|
946 |
-
|
947 |
-
foreach ( $orig_tag_matches[0] as $n => $r ) {
|
948 |
-
$to_inject = array();
|
949 |
-
// Check if we need to inject an ad at this offset.
|
950 |
-
foreach ( $ads_for_placeholders as $ad ) {
|
951 |
-
if ( isset( $ad['offset'] ) && $ad['offset'] === $n ) {
|
952 |
-
$to_inject[] = $ad;
|
953 |
-
}
|
954 |
-
}
|
955 |
-
|
956 |
-
foreach ( $to_inject as $item ) {
|
957 |
-
switch ( $item['type'] ) {
|
958 |
-
case 'before':
|
959 |
-
case 'append':
|
960 |
-
$found_pos = $r[1];
|
961 |
-
break;
|
962 |
-
case 'after':
|
963 |
-
case 'prepend':
|
964 |
-
$found_pos = $r[1] + strlen( $r[0] );
|
965 |
-
break;
|
966 |
-
}
|
967 |
-
|
968 |
-
$new_content .= substr( $content_orig, $pos, $found_pos - $pos );
|
969 |
-
$pos = $found_pos;
|
970 |
-
$new_content .= $item['ad'];
|
971 |
-
}
|
972 |
-
}
|
973 |
-
$new_content .= substr( $content_orig, $pos );
|
974 |
-
|
975 |
-
return $new_content;
|
976 |
-
}
|
977 |
-
|
978 |
-
|
979 |
-
/**
|
980 |
-
* Callback function for usort() to sort ads for placeholders.
|
981 |
-
*
|
982 |
-
* @param array $first The first array to compare.
|
983 |
-
* @param array $second The second array to compare.
|
984 |
-
*
|
985 |
-
* @return int 0 if both objects equal. -1 if second array should come first, 1 otherwise.
|
986 |
-
*/
|
987 |
-
public static function sort_ads_for_placehoders( $first, $second ) {
|
988 |
-
if ( $first['type'] === $second['type'] ) {
|
989 |
-
return 0;
|
990 |
-
}
|
991 |
-
|
992 |
-
$num = array(
|
993 |
-
'before' => 1,
|
994 |
-
'prepend' => 2,
|
995 |
-
'append' => 3,
|
996 |
-
'after' => 4,
|
997 |
-
);
|
998 |
-
|
999 |
-
return $num[ $first['type'] ] > $num[ $second['type'] ] ? 1 : - 1;
|
1000 |
-
}
|
1001 |
-
|
1002 |
-
/**
|
1003 |
-
* Add a warning to 'Ad health'.
|
1004 |
-
*
|
1005 |
-
* @param array $nodes .
|
1006 |
-
*
|
1007 |
-
* @return array $nodes.
|
1008 |
-
*/
|
1009 |
-
public static function add_ad_health_node( $nodes ) {
|
1010 |
-
$nodes[] = array(
|
1011 |
-
'type' => 1,
|
1012 |
-
'data' => array(
|
1013 |
-
'parent' => 'advanced_ads_ad_health',
|
1014 |
-
'id' => 'advanced_ads_ad_health_the_content_not_enough_elements',
|
1015 |
-
'title' => sprintf(
|
1016 |
-
/* translators: %s stands for the name of the "Disable level limitation" option and automatically translated as well */
|
1017 |
-
__( 'Set <em>%s</em> to show more ads', 'advanced-ads' ),
|
1018 |
-
__( 'Disable level limitation', 'advanced-ads' )
|
1019 |
-
),
|
1020 |
-
'href' => admin_url( '/admin.php?page=advanced-ads-settings#top#general' ),
|
1021 |
-
'meta' => array(
|
1022 |
-
'class' => 'advanced_ads_ad_health_warning',
|
1023 |
-
'target' => '_blank',
|
1024 |
-
),
|
1025 |
-
),
|
1026 |
-
);
|
1027 |
-
|
1028 |
-
return $nodes;
|
1029 |
}
|
1030 |
|
1031 |
/**
|
460 |
* @since 1.2.1
|
461 |
*/
|
462 |
public static function &inject_in_content( $placement_id, $placement_opts, &$content ) {
|
463 |
+
return Advanced_Ads_In_Content_Injector::inject_in_content( $placement_id, $placement_opts, $content );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
464 |
}
|
465 |
|
466 |
/**
|
classes/in-content-injector.php
ADDED
@@ -0,0 +1,758 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Injects ads in the content based on an XPath expression.
|
4 |
+
*/
|
5 |
+
class Advanced_Ads_In_Content_Injector {
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Gather placeholders which later are replaced by the ads
|
9 |
+
*
|
10 |
+
* @var array $ads_for_placeholders
|
11 |
+
*/
|
12 |
+
private static $ads_for_placeholders = array();
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Inject ads directly into the content
|
16 |
+
*
|
17 |
+
* @param string $placement_id Id of the placement.
|
18 |
+
* @param array $placement_opts Placement options.
|
19 |
+
* @param string $content Content to inject placement into.
|
20 |
+
* @param array $options {
|
21 |
+
* Injection options.
|
22 |
+
*
|
23 |
+
* @type bool $allowEmpty Whether the tag can be empty to be counted.
|
24 |
+
* @type bool $paragraph_select_from_bottom Whether to select ads from buttom.
|
25 |
+
* @type string $position Position. Can be one of 'before', 'after', 'append', 'prepend'
|
26 |
+
* @type number $alter_nodes Whether to alter nodes, for example to prevent injecting ads into `a` tags.
|
27 |
+
* @type bool $repeat Whether to repeat the position.
|
28 |
+
* @type number $paragraph_id Paragraph Id.
|
29 |
+
* @type number $itemLimit If there are too few items at this level test nesting. Set to '-1` to prevent testing.
|
30 |
+
* }
|
31 |
+
*
|
32 |
+
* @return string $content Content with injected placement.
|
33 |
+
*/
|
34 |
+
public static function &inject_in_content( $placement_id, $placement_opts, &$content, $options = array() ) {
|
35 |
+
if ( ! extension_loaded( 'dom' ) ) {
|
36 |
+
return $content;
|
37 |
+
}
|
38 |
+
|
39 |
+
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
40 |
+
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
|
41 |
+
|
42 |
+
// parse arguments.
|
43 |
+
$tag = isset( $placement_opts['tag'] ) ? $placement_opts['tag'] : 'p';
|
44 |
+
$tag = preg_replace( '/[^a-z0-9]/i', '', $tag ); // simplify tag.
|
45 |
+
/**
|
46 |
+
* Store the original tag value since $tag is changed on the fly and we might want to know the original selected
|
47 |
+
* options for some checks later.
|
48 |
+
*/
|
49 |
+
$tag_option = $tag;
|
50 |
+
|
51 |
+
// allow more complex xPath expression.
|
52 |
+
$tag = apply_filters( 'advanced-ads-placement-content-injection-xpath', $tag, $placement_opts );
|
53 |
+
|
54 |
+
// get plugin options.
|
55 |
+
$plugin_options = Advanced_Ads::get_instance()->options();
|
56 |
+
|
57 |
+
$defaults = array(
|
58 |
+
'allowEmpty' => false,
|
59 |
+
'paragraph_select_from_bottom' => isset( $placement_opts['start_from_bottom'] ) && $placement_opts['start_from_bottom'],
|
60 |
+
'position' => isset( $placement_opts['position'] ) ? $placement_opts['position'] : 'after',
|
61 |
+
// only has before and after.
|
62 |
+
'before' => isset( $placement_opts['position'] ) && 'before' === $placement_opts['position'],
|
63 |
+
// Whether to alter nodes, for example to prevent injecting ads into `a` tags.
|
64 |
+
'alter_nodes' => true,
|
65 |
+
'repeat' => false,
|
66 |
+
);
|
67 |
+
|
68 |
+
$defaults['paragraph_id'] = isset( $placement_opts['index'] ) ? $placement_opts['index'] : 1;
|
69 |
+
$defaults['paragraph_id'] = max( 1, (int) $defaults['paragraph_id'] );
|
70 |
+
|
71 |
+
// if there are too few items at this level test nesting.
|
72 |
+
$defaults['itemLimit'] = 'p' === $tag_option ? 2 : 1;
|
73 |
+
|
74 |
+
// trigger such a high item limit that all elements will be considered.
|
75 |
+
if ( ! empty( $plugin_options['content-injection-level-disabled'] ) ) {
|
76 |
+
$defaults['itemLimit'] = 1000;
|
77 |
+
}
|
78 |
+
|
79 |
+
// handle tags that are empty by definition or could be empty ("custom" option)
|
80 |
+
if ( in_array( $tag_option, array( 'img', 'iframe', 'custom' ), true ) ) {
|
81 |
+
$defaults['allowEmpty'] = true;
|
82 |
+
}
|
83 |
+
|
84 |
+
// allow hooks to change some options.
|
85 |
+
$options = apply_filters(
|
86 |
+
'advanced-ads-placement-content-injection-options',
|
87 |
+
wp_parse_args( $options, $defaults ),
|
88 |
+
$tag_option
|
89 |
+
);
|
90 |
+
|
91 |
+
$wp_charset = get_bloginfo( 'charset' );
|
92 |
+
// parse document as DOM (fragment - having only a part of an actual post given).
|
93 |
+
|
94 |
+
$content_to_load = self::get_content_to_load( $content, $wp_charset );
|
95 |
+
if ( ! $content_to_load ) {
|
96 |
+
return $content;
|
97 |
+
}
|
98 |
+
|
99 |
+
$dom = new DOMDocument( '1.0', $wp_charset );
|
100 |
+
// may loose some fragments or add autop-like code.
|
101 |
+
$libxml_use_internal_errors = libxml_use_internal_errors( true ); // avoid notices and warnings - html is most likely malformed.
|
102 |
+
|
103 |
+
$success = $dom->loadHtml( '<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wp_charset . '" /><body>' . $content_to_load );
|
104 |
+
libxml_use_internal_errors( $libxml_use_internal_errors );
|
105 |
+
if ( true !== $success ) {
|
106 |
+
// -TODO handle cases were dom-parsing failed (at least inform user)
|
107 |
+
return $content;
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Handle advanced tags.
|
112 |
+
*/
|
113 |
+
switch ( $tag_option ) {
|
114 |
+
case 'p':
|
115 |
+
// exclude paragraphs within blockquote tags
|
116 |
+
$tag = 'p[not(parent::blockquote)]';
|
117 |
+
break;
|
118 |
+
case 'pwithoutimg':
|
119 |
+
// convert option name into correct path, exclude paragraphs within blockquote tags
|
120 |
+
$tag = 'p[not(descendant::img) and not(parent::blockquote)]';
|
121 |
+
break;
|
122 |
+
case 'img':
|
123 |
+
/*
|
124 |
+
* Handle: 1) "img" tags 2) "image" block 3) "gallery" block 4) "gallery shortcode" 5) "wp_caption" shortcode
|
125 |
+
* Handle the gallery created by the block or the shortcode as one image.
|
126 |
+
* Prevent injection of ads next to images in tables.
|
127 |
+
*/
|
128 |
+
// Default shortcodes, including non-HTML5 versions.
|
129 |
+
$shortcodes = "@class and (
|
130 |
+
contains(concat(' ', normalize-space(@class), ' '), ' gallery-size') or
|
131 |
+
contains(concat(' ', normalize-space(@class), ' '), ' wp-caption ') )";
|
132 |
+
$tag = "*[self::img or self::figure or self::div[$shortcodes]]
|
133 |
+
[not(ancestor::table or ancestor::figure or ancestor::div[$shortcodes])]";
|
134 |
+
break;
|
135 |
+
// any headline. By default h2, h3, and h4
|
136 |
+
case 'headlines':
|
137 |
+
$headlines = apply_filters( 'advanced-ads-headlines-for-ad-injection', array( 'h2', 'h3', 'h4' ) );
|
138 |
+
|
139 |
+
foreach ( $headlines as &$headline ) {
|
140 |
+
$headline = 'self::' . $headline;
|
141 |
+
}
|
142 |
+
$tag = '*[' . implode( ' or ', $headlines ) . ']'; // /html/body/*[self::h2 or self::h3 or self::h4]
|
143 |
+
break;
|
144 |
+
// any HTML element that makes sense in the content
|
145 |
+
case 'anyelement':
|
146 |
+
$exclude = array(
|
147 |
+
'html',
|
148 |
+
'body',
|
149 |
+
'script',
|
150 |
+
'style',
|
151 |
+
'tr',
|
152 |
+
'td',
|
153 |
+
// Inline tags.
|
154 |
+
'a',
|
155 |
+
'abbr',
|
156 |
+
'b',
|
157 |
+
'bdo',
|
158 |
+
'br',
|
159 |
+
'button',
|
160 |
+
'cite',
|
161 |
+
'code',
|
162 |
+
'dfn',
|
163 |
+
'em',
|
164 |
+
'i',
|
165 |
+
'img',
|
166 |
+
'kbd',
|
167 |
+
'label',
|
168 |
+
'option',
|
169 |
+
'q',
|
170 |
+
'samp',
|
171 |
+
'select',
|
172 |
+
'small',
|
173 |
+
'span',
|
174 |
+
'strong',
|
175 |
+
'sub',
|
176 |
+
'sup',
|
177 |
+
'textarea',
|
178 |
+
'time',
|
179 |
+
'tt',
|
180 |
+
'var',
|
181 |
+
);
|
182 |
+
$tag = '*[not(self::' . implode( ' or self::', $exclude ) . ')]';
|
183 |
+
break;
|
184 |
+
case 'custom':
|
185 |
+
// get the path for the "custom" tag choice, use p as a fallback to prevent it from showing any ads if users left it empty
|
186 |
+
$tag = ! empty( $placement_opts['xpath'] ) ? stripslashes( $placement_opts['xpath'] ) : 'p';
|
187 |
+
break;
|
188 |
+
}
|
189 |
+
|
190 |
+
// select positions.
|
191 |
+
$xpath = new DOMXPath( $dom );
|
192 |
+
|
193 |
+
|
194 |
+
if ( $options['itemLimit'] !== -1 ) {
|
195 |
+
$items = $xpath->query( '/html/body/' . $tag );
|
196 |
+
|
197 |
+
if ( $items->length < $options['itemLimit'] ) {
|
198 |
+
$items = $xpath->query( '/html/body/*/' . $tag );
|
199 |
+
}
|
200 |
+
// try third level.
|
201 |
+
if ( $items->length < $options['itemLimit'] ) {
|
202 |
+
$items = $xpath->query( '/html/body/*/*/' . $tag );
|
203 |
+
}
|
204 |
+
// try all levels as last resort.
|
205 |
+
if ( $items->length < $options['itemLimit'] ) {
|
206 |
+
$items = $xpath->query( '//' . $tag );
|
207 |
+
}
|
208 |
+
} else {
|
209 |
+
$items = $xpath->query( $tag );
|
210 |
+
}
|
211 |
+
|
212 |
+
// allow to select other elements.
|
213 |
+
$items = apply_filters( 'advanced-ads-placement-content-injection-items', $items, $xpath, $tag_option );
|
214 |
+
|
215 |
+
// filter empty tags from items.
|
216 |
+
$whitespaces = json_decode( '"\t\n\r \u00A0"' );
|
217 |
+
$paragraphs = array();
|
218 |
+
foreach ( $items as $item ) {
|
219 |
+
if ( $options['allowEmpty'] || ( isset( $item->textContent ) && trim( $item->textContent, $whitespaces ) !== '' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
|
220 |
+
$paragraphs[] = $item;
|
221 |
+
}
|
222 |
+
}
|
223 |
+
|
224 |
+
$ancestors_to_limit = self::get_ancestors_to_limit( $xpath );
|
225 |
+
$paragraphs = self::filter_by_ancestors_to_limit( $paragraphs, $ancestors_to_limit );
|
226 |
+
|
227 |
+
$options['paragraph_count'] = count( $paragraphs );
|
228 |
+
|
229 |
+
if ( $options['paragraph_count'] >= $options['paragraph_id'] ) {
|
230 |
+
$offset = $options['paragraph_select_from_bottom'] ? $options['paragraph_count'] - $options['paragraph_id'] : $options['paragraph_id'] - 1;
|
231 |
+
$offsets = apply_filters( 'advanced-ads-placement-content-offsets', array( $offset ), $options, $placement_opts, $xpath, $paragraphs, $dom );
|
232 |
+
$did_inject = false;
|
233 |
+
|
234 |
+
foreach ( $offsets as $offset ) {
|
235 |
+
|
236 |
+
// inject.
|
237 |
+
$node = apply_filters( 'advanced-ads-placement-content-injection-node', $paragraphs[ $offset ], $tag, $options['before'] );
|
238 |
+
|
239 |
+
if ( $options['alter_nodes'] ) {
|
240 |
+
// Prevent injection into image caption and gallery.
|
241 |
+
$parent = $node;
|
242 |
+
for ( $i = 0; $i < 4; $i++ ) {
|
243 |
+
$parent = $parent->parentNode;
|
244 |
+
if ( ! $parent instanceof DOMElement ) {
|
245 |
+
break;
|
246 |
+
}
|
247 |
+
if ( preg_match( '/\b(wp-caption|gallery-size)\b/', $parent->getAttribute( 'class' ) ) ) {
|
248 |
+
$node = $parent;
|
249 |
+
break;
|
250 |
+
}
|
251 |
+
}
|
252 |
+
|
253 |
+
// make sure that the ad is injected outside the link
|
254 |
+
if ( 'img' === $tag_option && 'a' === $node->parentNode->tagName ) {
|
255 |
+
if ( $options['before'] ) {
|
256 |
+
$node->parentNode;
|
257 |
+
} else {
|
258 |
+
// go one level deeper if inserted after to not insert the ad into the link; probably after the paragraph
|
259 |
+
$node->parentNode->parentNode;
|
260 |
+
}
|
261 |
+
}
|
262 |
+
}
|
263 |
+
|
264 |
+
$ad_content = (string) Advanced_Ads_Select::get_instance()->get_ad_by_method( $placement_id, 'placement', $placement_opts );
|
265 |
+
|
266 |
+
if ( trim( $ad_content, $whitespaces ) === '' ) {
|
267 |
+
continue;
|
268 |
+
}
|
269 |
+
|
270 |
+
// phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
|
271 |
+
$ad_content = self::filter_ad_content( $ad_content, $node->tagName, $options );
|
272 |
+
|
273 |
+
// convert HTML to XML!
|
274 |
+
$ad_dom = new DOMDocument( '1.0', $wp_charset );
|
275 |
+
$libxml_use_internal_errors = libxml_use_internal_errors( true );
|
276 |
+
$ad_dom->loadHtml( '<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wp_charset . '" /><body>' . $ad_content );
|
277 |
+
// log errors.
|
278 |
+
if ( defined( 'WP_DEBUG' ) && WP_DEBUG && current_user_can( 'advanced_ads_manage_options' ) ) {
|
279 |
+
foreach ( libxml_get_errors() as $_error ) {
|
280 |
+
// continue, if there is '&' symbol, but not HTML entity.
|
281 |
+
if ( false === stripos( $_error->message, 'htmlParseEntityRef:' ) ) {
|
282 |
+
Advanced_Ads::log( 'possible content injection error for placement "' . $placement_id . '": ' . print_r( $_error, true ) );
|
283 |
+
}
|
284 |
+
}
|
285 |
+
}
|
286 |
+
|
287 |
+
switch ( $options['position'] ) {
|
288 |
+
case 'append':
|
289 |
+
$ref_node = $node;
|
290 |
+
|
291 |
+
foreach ( $ad_dom->getElementsByTagName( 'body' )->item( 0 )->childNodes as $importedNode ) {
|
292 |
+
$importedNode = $dom->importNode( $importedNode, true );
|
293 |
+
$ref_node->appendChild( $importedNode );
|
294 |
+
}
|
295 |
+
break;
|
296 |
+
case 'prepend':
|
297 |
+
$ref_node = $node;
|
298 |
+
|
299 |
+
foreach ( $ad_dom->getElementsByTagName( 'body' )->item( 0 )->childNodes as $importedNode ) {
|
300 |
+
$importedNode = $dom->importNode( $importedNode, true );
|
301 |
+
$ref_node->insertBefore( $importedNode, $ref_node->firstChild );
|
302 |
+
}
|
303 |
+
break;
|
304 |
+
case 'before':
|
305 |
+
$ref_node = $node;
|
306 |
+
|
307 |
+
foreach ( $ad_dom->getElementsByTagName( 'body' )->item( 0 )->childNodes as $importedNode ) {
|
308 |
+
$importedNode = $dom->importNode( $importedNode, true );
|
309 |
+
$ref_node->parentNode->insertBefore( $importedNode, $ref_node );
|
310 |
+
}
|
311 |
+
break;
|
312 |
+
case 'after':
|
313 |
+
default:
|
314 |
+
// append before next node or as last child to body.
|
315 |
+
$ref_node = $node->nextSibling;
|
316 |
+
if ( isset( $ref_node ) ) {
|
317 |
+
foreach ( $ad_dom->getElementsByTagName( 'body' )->item( 0 )->childNodes as $importedNode ) {
|
318 |
+
$importedNode = $dom->importNode( $importedNode, true );
|
319 |
+
$ref_node->parentNode->insertBefore( $importedNode, $ref_node );
|
320 |
+
}
|
321 |
+
} else {
|
322 |
+
// append to body; -TODO using here that we only select direct children of the body tag.
|
323 |
+
foreach ( $ad_dom->getElementsByTagName( 'body' )->item( 0 )->childNodes as $importedNode ) {
|
324 |
+
$importedNode = $dom->importNode( $importedNode, true );
|
325 |
+
$node->parentNode->appendChild( $importedNode );
|
326 |
+
}
|
327 |
+
}
|
328 |
+
}
|
329 |
+
libxml_use_internal_errors( $libxml_use_internal_errors );
|
330 |
+
$did_inject = true;
|
331 |
+
}
|
332 |
+
|
333 |
+
if ( ! $did_inject ) {
|
334 |
+
return $content;
|
335 |
+
}
|
336 |
+
|
337 |
+
$content_orig = $content;
|
338 |
+
// convert to text-representation.
|
339 |
+
$content = $dom->saveHTML();
|
340 |
+
$content = self::prepare_output( $content, $content_orig );
|
341 |
+
|
342 |
+
/**
|
343 |
+
* Show a warning to ad admins in the Ad Health bar in the frontend, when
|
344 |
+
*
|
345 |
+
* * the level limitation was not disabled
|
346 |
+
* * could not inject one ad (as by use of `elseif` here)
|
347 |
+
* * but there are enough elements on the site, but just in sub-containers
|
348 |
+
*/
|
349 |
+
} elseif ( current_user_can( Advanced_Ads_Plugin::user_cap( 'advanced_ads_manage_options' ) )
|
350 |
+
&& $options['itemLimit'] !== -1
|
351 |
+
&& empty( $plugin_options['content-injection-level-disabled'] ) ) {
|
352 |
+
|
353 |
+
// Check if there are more elements without limitation.
|
354 |
+
$all_items = $xpath->query( '//' . $tag );
|
355 |
+
|
356 |
+
$paragraphs = array();
|
357 |
+
foreach ( $all_items as $item ) {
|
358 |
+
if ( $options['allowEmpty'] || ( isset( $item->textContent ) && trim( $item->textContent, $whitespaces ) !== '' ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
|
359 |
+
$paragraphs[] = $item;
|
360 |
+
}
|
361 |
+
}
|
362 |
+
|
363 |
+
$paragraphs = self::filter_by_ancestors_to_limit( $paragraphs, $ancestors_to_limit );
|
364 |
+
if ( $options['paragraph_id'] <= count( $paragraphs ) ) {
|
365 |
+
// Add a warning to ad health.
|
366 |
+
add_filter( 'advanced-ads-ad-health-nodes', array( 'Advanced_Ads_In_Content_Injector', 'add_ad_health_node' ) );
|
367 |
+
}
|
368 |
+
}
|
369 |
+
|
370 |
+
// phpcs:enable
|
371 |
+
|
372 |
+
return $content;
|
373 |
+
}
|
374 |
+
|
375 |
+
/**
|
376 |
+
* Get content to load.
|
377 |
+
*
|
378 |
+
* @param string $content Original content.
|
379 |
+
* @param string $wp_charset blog charset.
|
380 |
+
*
|
381 |
+
* @return string $content Content to load.
|
382 |
+
*/
|
383 |
+
private static function get_content_to_load( $content, $wp_charset ) {
|
384 |
+
// Prevent removing closing tags in scripts.
|
385 |
+
$content_to_load = preg_replace( '/<script.*?<\/script>/si', '<!--\0-->', $content );
|
386 |
+
|
387 |
+
// check which priority the wpautop filter has; might have been disabled on purpose.
|
388 |
+
$wpautop_priority = has_filter( 'the_content', 'wpautop' );
|
389 |
+
if ( $wpautop_priority && Advanced_Ads_Plugin::get_instance()->get_content_injection_priority() < $wpautop_priority ) {
|
390 |
+
$content_to_load = wpautop( $content_to_load );
|
391 |
+
}
|
392 |
+
|
393 |
+
return $content_to_load;
|
394 |
+
}
|
395 |
+
|
396 |
+
/**
|
397 |
+
* Filter ad content.
|
398 |
+
*
|
399 |
+
* @param string $ad_content Ad content.
|
400 |
+
* @param string $tag_name tar before/after the content.
|
401 |
+
* @param array $options Injection options.
|
402 |
+
*
|
403 |
+
* @return string ad content.
|
404 |
+
*/
|
405 |
+
private static function filter_ad_content( $ad_content, $tag_name, $options ) {
|
406 |
+
// Replace `</` with `<\/` in ad content when placed within `document.write()` to prevent code from breaking.
|
407 |
+
$ad_content = preg_replace( '#(document.write.+)</(.*)#', '$1<\/$2', $ad_content );
|
408 |
+
|
409 |
+
// Inject placeholder.
|
410 |
+
$id = count( self::$ads_for_placeholders );
|
411 |
+
self::$ads_for_placeholders[] = array(
|
412 |
+
'id' => $id,
|
413 |
+
'tag' => $tag_name,
|
414 |
+
'position' => $options['position'],
|
415 |
+
'ad' => $ad_content,
|
416 |
+
);
|
417 |
+
|
418 |
+
return '%advads_placeholder_' . $id . '%';
|
419 |
+
}
|
420 |
+
|
421 |
+
/**
|
422 |
+
* Prepare output.
|
423 |
+
*
|
424 |
+
* @param string $content Modified content.
|
425 |
+
* @param string $content_orig Original content.
|
426 |
+
*
|
427 |
+
* @return string $content Content to output.
|
428 |
+
*/
|
429 |
+
private static function prepare_output( $content, $content_orig ) {
|
430 |
+
$content = self::inject_ads( $content, $content_orig, self::$ads_for_placeholders );
|
431 |
+
self::$ads_for_placeholders = array();
|
432 |
+
|
433 |
+
return $content;
|
434 |
+
}
|
435 |
+
|
436 |
+
/**
|
437 |
+
* Search for ad placeholders in the `$content` to determine positions at which to inject ads.
|
438 |
+
* Given the positions, inject ads into `$content_orig.
|
439 |
+
*
|
440 |
+
* @param string $content Post content with injected ad placeholders.
|
441 |
+
* @param string $content_orig Unmodified post content.
|
442 |
+
* @param array $ads_for_placeholders Array of ads.
|
443 |
+
* Each ad contains placeholder id, before or after which tag to inject the ad, the ad content.
|
444 |
+
*
|
445 |
+
* @return string $content
|
446 |
+
*/
|
447 |
+
private static function inject_ads( $content, $content_orig, $ads_for_placeholders ) {
|
448 |
+
$self_closing_tags = array(
|
449 |
+
'area',
|
450 |
+
'base',
|
451 |
+
'basefont',
|
452 |
+
'bgsound',
|
453 |
+
'br',
|
454 |
+
'col',
|
455 |
+
'embed',
|
456 |
+
'frame',
|
457 |
+
'hr',
|
458 |
+
'img',
|
459 |
+
'input',
|
460 |
+
'keygen',
|
461 |
+
'link',
|
462 |
+
'meta',
|
463 |
+
'param',
|
464 |
+
'source',
|
465 |
+
'track',
|
466 |
+
'wbr',
|
467 |
+
);
|
468 |
+
|
469 |
+
// It is not possible to append/prepend in self closing tags.
|
470 |
+
foreach ( $ads_for_placeholders as &$ad_content ) {
|
471 |
+
if ( ( 'prepend' === $ad_content['position'] || 'append' === $ad_content['position'] )
|
472 |
+
&& in_array( $ad_content['tag'], $self_closing_tags, true ) ) {
|
473 |
+
$ad_content['position'] = 'after';
|
474 |
+
}
|
475 |
+
}
|
476 |
+
unset( $ad_content );
|
477 |
+
usort( $ads_for_placeholders, array( 'Advanced_Ads_In_Content_Injector', 'sort_ads_for_placehoders' ) );
|
478 |
+
|
479 |
+
// Add tags before/after which ad placehoders were injected.
|
480 |
+
foreach ( $ads_for_placeholders as $ad_content ) {
|
481 |
+
$tag = $ad_content['tag'];
|
482 |
+
|
483 |
+
switch ( $ad_content['position'] ) {
|
484 |
+
case 'before':
|
485 |
+
case 'prepend':
|
486 |
+
$alts[] = "<${tag}[^>]*>";
|
487 |
+
break;
|
488 |
+
case 'after':
|
489 |
+
if ( in_array( $tag, $self_closing_tags, true ) ) {
|
490 |
+
$alts[] = "<${tag}[^>]*>";
|
491 |
+
} else {
|
492 |
+
$alts[] = "</${tag}>";
|
493 |
+
}
|
494 |
+
break;
|
495 |
+
case 'append':
|
496 |
+
$alts[] = "</${tag}>";
|
497 |
+
break;
|
498 |
+
}
|
499 |
+
}
|
500 |
+
$alts = array_unique( $alts );
|
501 |
+
$tag_regexp = implode( '|', $alts );
|
502 |
+
// Add ad placeholder.
|
503 |
+
$alts[] = '%advads_placeholder_(?:\d+)%';
|
504 |
+
$tag_and_placeholder_regexp = implode( '|', $alts );
|
505 |
+
|
506 |
+
preg_match_all( "#{$tag_and_placeholder_regexp}#i", $content, $tag_matches );
|
507 |
+
$count = 0;
|
508 |
+
|
509 |
+
// For each tag located before/after an ad placeholder, find its offset among the same tags.
|
510 |
+
foreach ( $tag_matches[0] as $r ) {
|
511 |
+
if ( preg_match( '/%advads_placeholder_(\d+)%/', $r, $result ) ) {
|
512 |
+
$id = $result[1];
|
513 |
+
$found_ad = false;
|
514 |
+
foreach ( $ads_for_placeholders as $n => $ad ) {
|
515 |
+
if ( (int) $ad['id'] === (int) $id ) {
|
516 |
+
$found_ad = $ad;
|
517 |
+
break;
|
518 |
+
}
|
519 |
+
}
|
520 |
+
if ( ! $found_ad ) {
|
521 |
+
continue;
|
522 |
+
}
|
523 |
+
|
524 |
+
switch ( $found_ad['position'] ) {
|
525 |
+
case 'before':
|
526 |
+
case 'append':
|
527 |
+
$ads_for_placeholders[ $n ]['offset'] = $count;
|
528 |
+
break;
|
529 |
+
case 'after':
|
530 |
+
case 'prepend':
|
531 |
+
$ads_for_placeholders[ $n ]['offset'] = $count - 1;
|
532 |
+
break;
|
533 |
+
}
|
534 |
+
} else {
|
535 |
+
$count ++;
|
536 |
+
}
|
537 |
+
}
|
538 |
+
|
539 |
+
// Find tags before/after which we need to inject ads.
|
540 |
+
preg_match_all( "#{$tag_regexp}#i", $content_orig, $orig_tag_matches, PREG_OFFSET_CAPTURE );
|
541 |
+
$new_content = '';
|
542 |
+
$pos = 0;
|
543 |
+
|
544 |
+
foreach ( $orig_tag_matches[0] as $n => $r ) {
|
545 |
+
$to_inject = array();
|
546 |
+
// Check if we need to inject an ad at this offset.
|
547 |
+
foreach ( $ads_for_placeholders as $ad ) {
|
548 |
+
if ( isset( $ad['offset'] ) && $ad['offset'] === $n ) {
|
549 |
+
$to_inject[] = $ad;
|
550 |
+
}
|
551 |
+
}
|
552 |
+
|
553 |
+
foreach ( $to_inject as $item ) {
|
554 |
+
switch ( $item['position'] ) {
|
555 |
+
case 'before':
|
556 |
+
case 'append':
|
557 |
+
$found_pos = $r[1];
|
558 |
+
break;
|
559 |
+
case 'after':
|
560 |
+
case 'prepend':
|
561 |
+
$found_pos = $r[1] + strlen( $r[0] );
|
562 |
+
break;
|
563 |
+
}
|
564 |
+
|
565 |
+
$new_content .= substr( $content_orig, $pos, $found_pos - $pos );
|
566 |
+
$pos = $found_pos;
|
567 |
+
$new_content .= $item['ad'];
|
568 |
+
}
|
569 |
+
}
|
570 |
+
$new_content .= substr( $content_orig, $pos );
|
571 |
+
|
572 |
+
return $new_content;
|
573 |
+
}
|
574 |
+
|
575 |
+
|
576 |
+
/**
|
577 |
+
* Callback function for usort() to sort ads for placeholders.
|
578 |
+
*
|
579 |
+
* @param array $first The first array to compare.
|
580 |
+
* @param array $second The second array to compare.
|
581 |
+
*
|
582 |
+
* @return int 0 if both objects equal. -1 if second array should come first, 1 otherwise.
|
583 |
+
*/
|
584 |
+
public static function sort_ads_for_placehoders( $first, $second ) {
|
585 |
+
if ( $first['position'] === $second['position'] ) {
|
586 |
+
return 0;
|
587 |
+
}
|
588 |
+
|
589 |
+
$num = array(
|
590 |
+
'before' => 1,
|
591 |
+
'prepend' => 2,
|
592 |
+
'append' => 3,
|
593 |
+
'after' => 4,
|
594 |
+
);
|
595 |
+
|
596 |
+
return $num[ $first['position'] ] > $num[ $second['position'] ] ? 1 : - 1;
|
597 |
+
}
|
598 |
+
|
599 |
+
/**
|
600 |
+
* Add a warning to 'Ad health'.
|
601 |
+
*
|
602 |
+
* @param array $nodes .
|
603 |
+
*
|
604 |
+
* @return array $nodes.
|
605 |
+
*/
|
606 |
+
public static function add_ad_health_node( $nodes ) {
|
607 |
+
$nodes[] = array(
|
608 |
+
'type' => 1,
|
609 |
+
'data' => array(
|
610 |
+
'parent' => 'advanced_ads_ad_health',
|
611 |
+
'id' => 'advanced_ads_ad_health_the_content_not_enough_elements',
|
612 |
+
'title' => sprintf(
|
613 |
+
/* translators: %s stands for the name of the "Disable level limitation" option and automatically translated as well */
|
614 |
+
__( 'Set <em>%s</em> to show more ads', 'advanced-ads' ),
|
615 |
+
__( 'Disable level limitation', 'advanced-ads' )
|
616 |
+
),
|
617 |
+
'href' => admin_url( '/admin.php?page=advanced-ads-settings#top#general' ),
|
618 |
+
'meta' => array(
|
619 |
+
'class' => 'advanced_ads_ad_health_warning',
|
620 |
+
'target' => '_blank',
|
621 |
+
),
|
622 |
+
),
|
623 |
+
);
|
624 |
+
|
625 |
+
return $nodes;
|
626 |
+
}
|
627 |
+
|
628 |
+
/**
|
629 |
+
* Get paths of ancestors that should not contain ads.
|
630 |
+
*
|
631 |
+
* @param object $xpath DOMXPath object.
|
632 |
+
*
|
633 |
+
* @return array Paths of ancestors.
|
634 |
+
*/
|
635 |
+
private static function get_ancestors_to_limit( $xpath ) {
|
636 |
+
$query = self::get_ancestors_to_limit_query();
|
637 |
+
if ( ! $query ) {
|
638 |
+
return array();
|
639 |
+
}
|
640 |
+
|
641 |
+
$node_list = $xpath->query( $query );
|
642 |
+
$ancestors_to_limit = array();
|
643 |
+
|
644 |
+
foreach ( $node_list as $a ) {
|
645 |
+
$ancestors_to_limit[] = $a->getNodePath();
|
646 |
+
}
|
647 |
+
|
648 |
+
return $ancestors_to_limit;
|
649 |
+
}
|
650 |
+
|
651 |
+
|
652 |
+
/**
|
653 |
+
* Remove paragraphs that has ancestors that should not contain ads.
|
654 |
+
*
|
655 |
+
* @param array $paragraphs An array of `DOMNode` objects to insert ads before or after.
|
656 |
+
* @param array $ancestors_to_limit Paths of ancestor that should not contain ads.
|
657 |
+
*
|
658 |
+
* @return array $new_paragraphs An array of `DOMNode` objects to insert ads before or after.
|
659 |
+
*/
|
660 |
+
private static function filter_by_ancestors_to_limit( $paragraphs, $ancestors_to_limit ) {
|
661 |
+
$new_paragraphs = array();
|
662 |
+
|
663 |
+
foreach ( $paragraphs as $k => $paragraph ) {
|
664 |
+
foreach ( $ancestors_to_limit as $a ) {
|
665 |
+
if ( 0 === stripos( $paragraph->getNodePath(), $a ) ) {
|
666 |
+
continue 2;
|
667 |
+
}
|
668 |
+
}
|
669 |
+
|
670 |
+
$new_paragraphs[] = $paragraph;
|
671 |
+
}
|
672 |
+
|
673 |
+
return $new_paragraphs;
|
674 |
+
}
|
675 |
+
|
676 |
+
/**
|
677 |
+
* Get query to select ancestors that should not contain ads.
|
678 |
+
*
|
679 |
+
* @return string/false DOMXPath query or false.
|
680 |
+
*/
|
681 |
+
private static function get_ancestors_to_limit_query() {
|
682 |
+
/**
|
683 |
+
* TODO:
|
684 |
+
* - support `%` (rand) at the start
|
685 |
+
* - support plain text that node should contain instead of CSS selectors
|
686 |
+
* - support `prev` and `next` as `type`
|
687 |
+
*/
|
688 |
+
|
689 |
+
/**
|
690 |
+
* Filter the nodes that limit injection.
|
691 |
+
*
|
692 |
+
* @param array An array of arrays, each of which contains:
|
693 |
+
*
|
694 |
+
* @type string $type Accept: `ancestor` - limit injection inside the ancestor.
|
695 |
+
* @type string $node A "class selector" which targets one class (.) or "id selector" which targets one id (#),
|
696 |
+
* optionally with `%` at the end.
|
697 |
+
*/
|
698 |
+
$items = apply_filters(
|
699 |
+
'advanced-ads-content-injection-nodes-without-ads',
|
700 |
+
array(
|
701 |
+
array(
|
702 |
+
// a class anyone can use to prevent automatic ad injection into a specific element.
|
703 |
+
'node' => '.advads-stop-injection',
|
704 |
+
'type' => 'ancestor',
|
705 |
+
),
|
706 |
+
array(
|
707 |
+
// Product Slider for Beaver Builder by WooPack.
|
708 |
+
'node' => '.woopack-product-carousel',
|
709 |
+
'type' => 'ancestor',
|
710 |
+
),
|
711 |
+
array(
|
712 |
+
// WP Author Box Lite.
|
713 |
+
'node' => '#wpautbox-%',
|
714 |
+
'type' => 'ancestor',
|
715 |
+
),
|
716 |
+
array(
|
717 |
+
// GeoDirectory Post Slider.
|
718 |
+
'node' => '.geodir-post-slider',
|
719 |
+
'type' => 'ancestor',
|
720 |
+
),
|
721 |
+
)
|
722 |
+
);
|
723 |
+
|
724 |
+
$query = array();
|
725 |
+
foreach ( $items as $p ) {
|
726 |
+
$sel = $p['node'];
|
727 |
+
|
728 |
+
$sel_type = substr( $sel, 0, 1 );
|
729 |
+
$sel = substr( $sel, 1 );
|
730 |
+
|
731 |
+
$rand_pos = strpos( $sel, '%' );
|
732 |
+
$sel = str_replace( '%', '', $sel );
|
733 |
+
$sel = sanitize_html_class( $sel );
|
734 |
+
|
735 |
+
if ( '.' === $sel_type ) {
|
736 |
+
if ( false !== $rand_pos ) {
|
737 |
+
$query[] = "@class and contains(concat(' ', normalize-space(@class), ' '), ' $sel')";
|
738 |
+
} else {
|
739 |
+
$query[] = "@class and contains(concat(' ', normalize-space(@class), ' '), ' $sel ')";
|
740 |
+
}
|
741 |
+
}
|
742 |
+
if ( '#' === $sel_type ) {
|
743 |
+
if ( false !== $rand_pos ) {
|
744 |
+
$query[] = "@id and starts-with(@id, '$sel')";
|
745 |
+
} else {
|
746 |
+
$query[] = "@id and @id = '$sel'";
|
747 |
+
}
|
748 |
+
}
|
749 |
+
}
|
750 |
+
|
751 |
+
if ( ! $query ) {
|
752 |
+
return false;
|
753 |
+
}
|
754 |
+
|
755 |
+
return '//*[' . implode( ' or ', $query ) . ']';
|
756 |
+
}
|
757 |
+
|
758 |
+
}
|
classes/plugin.php
CHANGED
@@ -114,15 +114,13 @@ class Advanced_Ads_Plugin {
|
|
114 |
add_action( 'widgets_init', array( $this, 'widget_init' ) );
|
115 |
|
116 |
// Call action hooks for ad status changes.
|
117 |
-
add_action(
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
3
|
125 |
-
);
|
126 |
|
127 |
// load display conditions.
|
128 |
Advanced_Ads_Display_Conditions::get_instance();
|
@@ -895,6 +893,16 @@ class Advanced_Ads_Plugin {
|
|
895 |
*/
|
896 |
do_action( 'advanced-ads-ad-status-unpublished', $ad );
|
897 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
898 |
}
|
899 |
|
900 |
}
|
114 |
add_action( 'widgets_init', array( $this, 'widget_init' ) );
|
115 |
|
116 |
// Call action hooks for ad status changes.
|
117 |
+
add_action( 'transition_post_status', array( $this, 'transition_ad_status' ), 10, 3 );
|
118 |
+
|
119 |
+
// register expired post status.
|
120 |
+
Advanced_Ads_Ad_Expiration::register_post_status();
|
121 |
+
|
122 |
+
// if expired ad gets untrashed, revert it to expired status (instead of draft).
|
123 |
+
add_filter( 'wp_untrash_post_status', array( Advanced_Ads_Ad_Expiration::class, 'wp_untrash_post_status' ), 10, 3 );
|
|
|
|
|
124 |
|
125 |
// load display conditions.
|
126 |
Advanced_Ads_Display_Conditions::get_instance();
|
893 |
*/
|
894 |
do_action( 'advanced-ads-ad-status-unpublished', $ad );
|
895 |
}
|
896 |
+
|
897 |
+
if ( $old_status === 'publish' && $new_status === Advanced_Ads_Ad_Expiration::POST_STATUS ) {
|
898 |
+
/**
|
899 |
+
* Fires when an ad is expired.
|
900 |
+
*
|
901 |
+
* @param int $id
|
902 |
+
* @param Advanced_Ads_Ad $ad
|
903 |
+
*/
|
904 |
+
do_action( 'advanced-ads-ad-expired', $ad->id, $ad );
|
905 |
+
}
|
906 |
}
|
907 |
|
908 |
}
|
languages/advanced-ads.pot
CHANGED
@@ -1,15 +1,15 @@
|
|
1 |
-
# Copyright (C)
|
2 |
# This file is distributed under the same license as the Advanced Ads plugin.
|
3 |
msgid ""
|
4 |
msgstr ""
|
5 |
-
"Project-Id-Version: Advanced Ads 1.
|
6 |
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/advanced-ads/\n"
|
7 |
"Last-Translator: Thomas Maier <post@webzunft.de>\n"
|
8 |
"Language-Team: webgilde <support@wpadvancedads.com>\n"
|
9 |
"MIME-Version: 1.0\n"
|
10 |
"Content-Type: text/plain; charset=UTF-8\n"
|
11 |
"Content-Transfer-Encoding: 8bit\n"
|
12 |
-
"POT-Creation-Date:
|
13 |
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
14 |
"X-Generator: WP-CLI 2.4.0\n"
|
15 |
"X-Domain: advanced-ads\n"
|
@@ -108,7 +108,7 @@ msgstr ""
|
|
108 |
|
109 |
#. translators: %s is the URL to add a new review, https://wordpress.org/support/plugin/advanced-ads/reviews/#new-post
|
110 |
#. translators: %s is a URL.
|
111 |
-
#: admin/class-advanced-ads-admin.php:
|
112 |
#: admin/includes/class-overview-widgets.php:191
|
113 |
msgid "Thank the developer with a ★★★★★ review on <a href=\"%s\" target=\"_blank\">wordpress.org</a>"
|
114 |
msgstr ""
|
@@ -126,7 +126,7 @@ msgstr ""
|
|
126 |
#. translators: %s is a list of PHP extensions.
|
127 |
#. Translators: %s is a name of a module.
|
128 |
#: admin/includes/ad-health-notices.php:54
|
129 |
-
#: admin/views/placements.php:
|
130 |
msgid "Missing PHP extensions could cause issues. Please ask your hosting provider to enable them: %s"
|
131 |
msgstr ""
|
132 |
|
@@ -228,7 +228,6 @@ msgstr ""
|
|
228 |
msgid "%s detected."
|
229 |
msgstr ""
|
230 |
|
231 |
-
#. translators: %s is a service or plugin name.
|
232 |
#: admin/includes/ad-health-notices.php:253
|
233 |
msgid "Learn how this might impact your ad setup."
|
234 |
msgstr ""
|
@@ -312,7 +311,7 @@ msgid "Display ads with the highest ad weight first"
|
|
312 |
msgstr ""
|
313 |
|
314 |
#: admin/includes/class-ad-groups-list.php:339
|
315 |
-
#: admin/views/placements.php:
|
316 |
#: modules/import-export/classes/import.php:153
|
317 |
#: modules/import-export/classes/import.php:193
|
318 |
#: modules/import-export/classes/import.php:595
|
@@ -321,7 +320,7 @@ msgid "Edit"
|
|
321 |
msgstr ""
|
322 |
|
323 |
#: admin/includes/class-ad-groups-list.php:340
|
324 |
-
#: admin/views/placements.php:
|
325 |
msgid "Usage"
|
326 |
msgstr ""
|
327 |
|
@@ -344,99 +343,99 @@ msgstr ""
|
|
344 |
msgid "No ad group created"
|
345 |
msgstr ""
|
346 |
|
347 |
-
#: admin/includes/class-ad-type.php:
|
348 |
-
#: admin/includes/class-ad-type.php:
|
349 |
msgid "Ad Details"
|
350 |
msgstr ""
|
351 |
|
352 |
-
#: admin/includes/class-ad-type.php:
|
353 |
-
#: admin/includes/class-ad-type.php:
|
354 |
msgid "Ad Planning"
|
355 |
msgstr ""
|
356 |
|
357 |
-
#: admin/includes/class-ad-type.php:
|
358 |
-
#: admin/includes/class-ad-type.php:
|
359 |
msgid "Ad Shortcode"
|
360 |
msgstr ""
|
361 |
|
362 |
#. translators: %s is the number of ads.
|
363 |
-
#: admin/includes/class-ad-type.php:
|
364 |
msgid "%s ad updated."
|
365 |
msgid_plural "%s ads updated."
|
366 |
msgstr[0] ""
|
367 |
msgstr[1] ""
|
368 |
|
369 |
#. translators: %s is the number of ads.
|
370 |
-
#: admin/includes/class-ad-type.php:
|
371 |
msgid "%s ad not updated, somebody is editing it."
|
372 |
msgid_plural "%s ads not updated, somebody is editing them."
|
373 |
msgstr[0] ""
|
374 |
msgstr[1] ""
|
375 |
|
376 |
#. translators: %s is the number of ads.
|
377 |
-
#: admin/includes/class-ad-type.php:
|
378 |
msgid "%s ad permanently deleted."
|
379 |
msgid_plural "%s ads permanently deleted."
|
380 |
msgstr[0] ""
|
381 |
msgstr[1] ""
|
382 |
|
383 |
#. translators: %s is the number of ads.
|
384 |
-
#: admin/includes/class-ad-type.php:
|
385 |
msgid "%s ad moved to the Trash."
|
386 |
msgid_plural "%s ads moved to the Trash."
|
387 |
msgstr[0] ""
|
388 |
msgstr[1] ""
|
389 |
|
390 |
#. translators: %s is the number of ads.
|
391 |
-
#: admin/includes/class-ad-type.php:
|
392 |
msgid "%s ad restored from the Trash."
|
393 |
msgid_plural "%s ads restored from the Trash."
|
394 |
msgstr[0] ""
|
395 |
msgstr[1] ""
|
396 |
|
397 |
#. Translators: %s is the time the ad was first saved.
|
398 |
-
#: admin/includes/class-ad-type.php:
|
399 |
msgid "Ad created on %s"
|
400 |
msgstr ""
|
401 |
|
402 |
-
#: admin/includes/class-ad-type.php:
|
403 |
-
#: admin/includes/class-ad-type.php:
|
404 |
msgid "Ad updated."
|
405 |
msgstr ""
|
406 |
|
407 |
#. translators: %s: date and time of the revision
|
408 |
-
#: admin/includes/class-ad-type.php:
|
409 |
msgid "Ad restored to revision from %s"
|
410 |
msgstr ""
|
411 |
|
412 |
-
#: admin/includes/class-ad-type.php:
|
413 |
-
#: admin/includes/class-ad-type.php:
|
414 |
msgid "Ad saved."
|
415 |
msgstr ""
|
416 |
|
417 |
-
#: admin/includes/class-ad-type.php:
|
418 |
msgid "Ad submitted."
|
419 |
msgstr ""
|
420 |
|
421 |
#. translators: %1$s is a date.
|
422 |
-
#: admin/includes/class-ad-type.php:
|
423 |
msgid "Ad scheduled for: <strong>%1$s</strong>."
|
424 |
msgstr ""
|
425 |
|
426 |
#. translators: Publish box date format, see http://php.net/date.
|
427 |
-
#: admin/includes/class-ad-type.php:
|
428 |
msgid "M j, Y @ G:i"
|
429 |
msgstr ""
|
430 |
|
431 |
-
#: admin/includes/class-ad-type.php:
|
432 |
msgid "Ad draft updated."
|
433 |
msgstr ""
|
434 |
|
435 |
-
#: admin/includes/class-ad-type.php:
|
436 |
msgid "You don’t have access to ads. Please deactivate and re-enable Advanced Ads again to fix this."
|
437 |
msgstr ""
|
438 |
|
439 |
-
#: admin/includes/class-ad-type.php:
|
440 |
#: classes/frontend_checks.php:503
|
441 |
msgid "Get help"
|
442 |
msgstr ""
|
@@ -480,71 +479,78 @@ msgstr ""
|
|
480 |
msgid "Please enter a valid license key"
|
481 |
msgstr ""
|
482 |
|
483 |
-
#: admin/includes/class-licenses.php:
|
|
|
|
|
|
|
|
|
|
|
484 |
msgid "License couldn’t be activated. Please try again later."
|
485 |
msgstr ""
|
486 |
|
487 |
-
#: admin/includes/class-licenses.php:
|
488 |
msgid "This is the bundle license key."
|
489 |
msgstr ""
|
490 |
|
491 |
-
#: admin/includes/class-licenses.php:
|
492 |
msgid "This is not the correct key for this add-on."
|
493 |
msgstr ""
|
494 |
|
495 |
-
#: admin/includes/class-licenses.php:
|
496 |
msgid "There are no activations left."
|
497 |
msgstr ""
|
498 |
|
499 |
#. translators: %1$s is a starting link tag, %2$s is the closing one.
|
500 |
-
#: admin/includes/class-licenses.php:
|
501 |
msgid "You can manage activations in %1$syour account%2$s."
|
502 |
msgstr ""
|
503 |
|
504 |
#. translators: %1$s is a starting link tag, %2$s is the closing one.
|
505 |
-
#: admin/includes/class-licenses.php:
|
506 |
msgid "%1$sUpgrade%2$s for more activations."
|
507 |
msgstr ""
|
508 |
|
509 |
#. translators: %s is a string containing information about the issue.
|
510 |
-
#: admin/includes/class-licenses.php:
|
511 |
msgid "License is invalid. Reason: %s"
|
512 |
msgstr ""
|
513 |
|
514 |
#. translators: %s is a list of server information like IP address. Just keep it as is.
|
515 |
-
#: admin/includes/class-licenses.php:
|
516 |
msgid "Your request was blocked by our firewall. Please send us the following information to unblock you: %s."
|
517 |
msgstr ""
|
518 |
|
519 |
-
#: admin/includes/class-licenses.php:
|
520 |
msgid "Error while trying to disable the license. Please contact support."
|
521 |
msgstr ""
|
522 |
|
523 |
-
#: admin/includes/class-licenses.php:
|
524 |
-
#: admin/includes/class-licenses.php:
|
525 |
msgid "License couldn’t be deactivated. Please try again later."
|
526 |
msgstr ""
|
527 |
|
528 |
-
#: admin/includes/class-licenses.php:
|
529 |
msgid "Download failed. <a href=\"%s\">Click here to try another method</a>."
|
530 |
msgstr ""
|
531 |
|
532 |
-
#: admin/includes/class-licenses.php:
|
533 |
msgid "Download failed. <a href=\"%s\" target=\"_blank\">Click here to learn why</a>."
|
534 |
msgstr ""
|
535 |
|
536 |
-
#: admin/includes/class-list-filters.php:
|
537 |
#: modules/gadsense/admin/admin.php:73
|
538 |
#: modules/gadsense/admin/views/adsense-ad-parameters.php:109
|
539 |
msgid "Responsive"
|
540 |
msgstr ""
|
541 |
|
542 |
-
#: admin/includes/class-list-filters.php:
|
543 |
-
|
|
|
544 |
msgstr ""
|
545 |
|
546 |
-
#: admin/includes/class-list-filters.php:
|
547 |
-
|
|
|
548 |
msgstr ""
|
549 |
|
550 |
#: admin/includes/class-menu.php:66
|
@@ -644,14 +650,14 @@ msgstr ""
|
|
644 |
|
645 |
#: admin/includes/class-meta-box.php:104
|
646 |
#: admin/views/placements.php:184
|
647 |
-
#: admin/views/placements.php:
|
648 |
#: classes/ad-debug.php:152
|
649 |
msgid "Display Conditions"
|
650 |
msgstr ""
|
651 |
|
652 |
#: admin/includes/class-meta-box.php:112
|
653 |
#: admin/views/placements.php:193
|
654 |
-
#: admin/views/placements.php:
|
655 |
#: classes/ad-debug.php:239
|
656 |
msgid "Visitor Conditions"
|
657 |
msgstr ""
|
@@ -745,8 +751,8 @@ msgid "Create your first ad"
|
|
745 |
msgstr ""
|
746 |
|
747 |
#: admin/includes/class-overview-widgets.php:118
|
748 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
749 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
750 |
msgid "Connect to AdSense"
|
751 |
msgstr ""
|
752 |
|
@@ -957,7 +963,7 @@ msgid "Priority of content injection filter"
|
|
957 |
msgstr ""
|
958 |
|
959 |
#: admin/includes/class-settings.php:178
|
960 |
-
#: classes/
|
961 |
msgid "Disable level limitation"
|
962 |
msgstr ""
|
963 |
|
@@ -1171,7 +1177,7 @@ msgid "Update"
|
|
1171 |
msgstr ""
|
1172 |
|
1173 |
#: admin/views/ad-group-list-ads.php:20
|
1174 |
-
#: admin/views/placements.php:
|
1175 |
#: classes/ad-debug.php:118
|
1176 |
#: classes/ad-debug.php:167
|
1177 |
#: classes/ad-debug.php:169
|
@@ -1198,7 +1204,7 @@ msgstr ""
|
|
1198 |
|
1199 |
#: admin/views/ad-group-list-form-row.php:56
|
1200 |
#: admin/views/placements.php:64
|
1201 |
-
#: admin/views/placements.php:
|
1202 |
#: modules/gadsense/admin/views/adsense-ad-parameters.php:105
|
1203 |
msgid "Type"
|
1204 |
msgstr ""
|
@@ -1227,7 +1233,7 @@ msgstr ""
|
|
1227 |
|
1228 |
#: admin/views/ad-group-list-row.php:22
|
1229 |
#: admin/views/ad-info.php:7
|
1230 |
-
#: admin/views/placements.php:
|
1231 |
msgid "shortcode"
|
1232 |
msgstr ""
|
1233 |
|
@@ -1354,10 +1360,6 @@ msgid "all ad sizes"
|
|
1354 |
msgstr ""
|
1355 |
|
1356 |
#: admin/views/ad-list-filters.php:34
|
1357 |
-
msgid "all ad dates"
|
1358 |
-
msgstr ""
|
1359 |
-
|
1360 |
-
#: admin/views/ad-list-filters.php:42
|
1361 |
msgid "all ad groups"
|
1362 |
msgstr ""
|
1363 |
|
@@ -1387,7 +1389,7 @@ msgstr ""
|
|
1387 |
#: admin/views/placements-ad-label-position.php:13
|
1388 |
#: admin/views/placements-ad-label.php:9
|
1389 |
#: admin/views/placements-ad-label.php:11
|
1390 |
-
#: admin/views/placements.php:
|
1391 |
#: modules/gadsense/includes/class-network-adsense.php:321
|
1392 |
msgid "default"
|
1393 |
msgstr ""
|
@@ -1517,7 +1519,7 @@ msgid "Minute"
|
|
1517 |
msgstr ""
|
1518 |
|
1519 |
#. translators: %1$s month, %2$s day, %3$s year, %4$s hour, %5$s minute.
|
1520 |
-
#: admin/views/ad-submitbox-meta.php:
|
1521 |
msgctxt "order of expiry date fields 1: month, 2: day, 3: year, 4: hour, 5: minute"
|
1522 |
msgid "%1$s %2$s, %3$s @ %4$s %5$s"
|
1523 |
msgstr ""
|
@@ -1720,13 +1722,13 @@ msgstr ""
|
|
1720 |
|
1721 |
#: admin/views/modal.php:36
|
1722 |
#: admin/views/modal.php:37
|
1723 |
-
#: admin/views/placements.php:320
|
1724 |
#: admin/views/placements.php:321
|
|
|
1725 |
msgid "Close"
|
1726 |
msgstr ""
|
1727 |
|
1728 |
#: admin/views/modal.php:39
|
1729 |
-
#: admin/views/placements.php:
|
1730 |
msgid "Close and save"
|
1731 |
msgstr ""
|
1732 |
|
@@ -1844,7 +1846,6 @@ msgstr ""
|
|
1844 |
msgid "Adjust the placement options"
|
1845 |
msgstr ""
|
1846 |
|
1847 |
-
#. translators: %s is a URL.
|
1848 |
#: admin/views/placement-injection-top.php:21
|
1849 |
msgid "Ad not showing up? Take a look <a href=\"%s\" target=\"_blank\">here</a>"
|
1850 |
msgstr ""
|
@@ -1938,12 +1939,10 @@ msgstr ""
|
|
1938 |
msgid "Existing placement"
|
1939 |
msgstr ""
|
1940 |
|
1941 |
-
#. translators: %s is some HTML.
|
1942 |
#: admin/views/placement-injection-top.php:168
|
1943 |
msgid "Or use the shortcode %s to insert the ad into the content manually."
|
1944 |
msgstr ""
|
1945 |
|
1946 |
-
#. translators: %s is a URL.
|
1947 |
#: admin/views/placement-injection-top.php:176
|
1948 |
msgid "Learn more about your choices to display an ad in the <a href=\"%s\" target=\"_blank\">manual</a>."
|
1949 |
msgstr ""
|
@@ -1997,12 +1996,12 @@ msgid "Placements updated"
|
|
1997 |
msgstr ""
|
1998 |
|
1999 |
#: admin/views/placements.php:25
|
2000 |
-
#: admin/views/placements.php:
|
2001 |
msgid "Create a new placement"
|
2002 |
msgstr ""
|
2003 |
|
2004 |
#: admin/views/placements.php:26
|
2005 |
-
#: admin/views/placements.php:
|
2006 |
msgid "New Placement"
|
2007 |
msgstr ""
|
2008 |
|
@@ -2072,59 +2071,60 @@ msgstr ""
|
|
2072 |
msgid "A minimum amount of words between automatically injected ads."
|
2073 |
msgstr ""
|
2074 |
|
2075 |
-
|
|
|
2076 |
#: modules/import-export/views/page.php:26
|
2077 |
msgid "Options"
|
2078 |
msgstr ""
|
2079 |
|
2080 |
#. Translators: %s is the name of a placement.
|
2081 |
-
#: admin/views/placements.php:
|
2082 |
msgid "Placement type \"%s\" is missing and was reset to \"default\".<br/>Please check if the responsible add-on is activated."
|
2083 |
msgstr ""
|
2084 |
|
2085 |
-
#: admin/views/placements.php:
|
2086 |
msgid "template (PHP)"
|
2087 |
msgstr ""
|
2088 |
|
2089 |
-
#: admin/views/placements.php:
|
2090 |
msgid "Group"
|
2091 |
msgstr ""
|
2092 |
|
2093 |
-
#: admin/views/placements.php:
|
2094 |
msgid "after"
|
2095 |
msgstr ""
|
2096 |
|
2097 |
-
#: admin/views/placements.php:
|
2098 |
msgid "before"
|
2099 |
msgstr ""
|
2100 |
|
2101 |
-
#: admin/views/placements.php:
|
2102 |
msgid "position"
|
2103 |
msgstr ""
|
2104 |
|
2105 |
-
#: admin/views/placements.php:
|
2106 |
msgid "Important Notice"
|
2107 |
msgstr ""
|
2108 |
|
2109 |
#. Translators: %s is a URL.
|
2110 |
-
#: admin/views/placements.php:
|
2111 |
msgid "Tutorial: <a href=\"%s\" target=\"_blank\">How to place visible ads in the header of your website</a>."
|
2112 |
msgstr ""
|
2113 |
|
2114 |
-
#: admin/views/placements.php:
|
2115 |
msgid "show all options"
|
2116 |
msgstr ""
|
2117 |
|
2118 |
-
#: admin/views/placements.php:
|
2119 |
msgid "edit conditions"
|
2120 |
msgstr ""
|
2121 |
|
2122 |
-
#: admin/views/placements.php:
|
2123 |
msgctxt "checkbox to remove placement"
|
2124 |
msgid "delete"
|
2125 |
msgstr ""
|
2126 |
|
2127 |
-
#: admin/views/placements.php:
|
2128 |
msgid "Save Placements"
|
2129 |
msgstr ""
|
2130 |
|
@@ -2540,6 +2540,10 @@ msgstr ""
|
|
2540 |
msgid "Placement"
|
2541 |
msgstr ""
|
2542 |
|
|
|
|
|
|
|
|
|
2543 |
#. translators: %1$s is an anchor (link) opening tag, %2$s is the closing tag.
|
2544 |
#: classes/ad-health-notices.php:865
|
2545 |
#: modules/gadsense/includes/class-mapi.php:1644
|
@@ -2664,11 +2668,6 @@ msgctxt "for the \"custom\" content placement option"
|
|
2664 |
msgid "custom"
|
2665 |
msgstr ""
|
2666 |
|
2667 |
-
#. translators: %s stands for the name of the "Disable level limitation" option and automatically translated as well
|
2668 |
-
#: classes/ad_placements.php:1017
|
2669 |
-
msgid "Set <em>%s</em> to show more ads"
|
2670 |
-
msgstr ""
|
2671 |
-
|
2672 |
#: classes/ad_type_content.php:35
|
2673 |
msgid "Rich Content"
|
2674 |
msgstr ""
|
@@ -3162,6 +3161,11 @@ msgstr ""
|
|
3162 |
msgid "Closing the message"
|
3163 |
msgstr ""
|
3164 |
|
|
|
|
|
|
|
|
|
|
|
3165 |
#. translators: time zone name.
|
3166 |
#: classes/utils.php:277
|
3167 |
msgid "time of %s"
|
@@ -3465,64 +3469,75 @@ msgstr ""
|
|
3465 |
msgid "Dummy Account Id"
|
3466 |
msgstr ""
|
3467 |
|
3468 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
3469 |
msgid "AdSense warnings"
|
3470 |
msgstr ""
|
3471 |
|
3472 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3473 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3474 |
msgid "dismiss"
|
3475 |
msgstr ""
|
3476 |
|
3477 |
-
|
|
|
|
|
|
|
|
|
|
|
3478 |
msgid "Revoke API acccess"
|
3479 |
msgstr ""
|
3480 |
|
3481 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3482 |
msgid "Account holder name"
|
3483 |
msgstr ""
|
3484 |
|
3485 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3486 |
#: modules/gadsense/includes/class-ad-type-adsense.php:91
|
3487 |
msgid "The Publisher ID has an incorrect format. (must start with \"pub-\")"
|
3488 |
msgstr ""
|
3489 |
|
3490 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3491 |
msgid "Your AdSense Publisher ID <em>(pub-xxxxxxxxxxxxxx)</em>"
|
3492 |
msgstr ""
|
3493 |
|
3494 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3495 |
msgid "Yes, I have an AdSense account"
|
3496 |
msgstr ""
|
3497 |
|
3498 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3499 |
msgid "Configure everything manually"
|
3500 |
msgstr ""
|
3501 |
|
3502 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3503 |
msgid "No, I still don't have an AdSense account"
|
3504 |
msgstr ""
|
3505 |
|
3506 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3507 |
msgid "Get a free AdSense account"
|
3508 |
msgstr ""
|
3509 |
|
3510 |
#. translators: %1$s is an opening a tag, %2$s is the closing one
|
3511 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3512 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3513 |
msgid "See all %1$srecommended ad networks%2$s."
|
3514 |
msgstr ""
|
3515 |
|
3516 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3517 |
msgid "How to choose specific positions for AdSense ad units"
|
3518 |
msgstr ""
|
3519 |
|
3520 |
#. translators: %1$s is the opening link tag to our manual; %2$s is the appropriate closing link tag; %3$s is the opening link tag to our help forum; %4$s is the appropriate closing link tag
|
3521 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3522 |
msgid "Problems with AdSense? Check out the %1$smanual%2$s or %3$sask here%4$s."
|
3523 |
msgstr ""
|
3524 |
|
3525 |
-
#: modules/gadsense/admin/views/adsense-account.php:
|
3526 |
#: modules/gadsense/admin/views/external-ads-links.php:38
|
3527 |
msgid "Can not connect AdSense account. PHP version is too low."
|
3528 |
msgstr ""
|
1 |
+
# Copyright (C) 2022 Thomas Maier, Advanced Ads GmbH
|
2 |
# This file is distributed under the same license as the Advanced Ads plugin.
|
3 |
msgid ""
|
4 |
msgstr ""
|
5 |
+
"Project-Id-Version: Advanced Ads 1.31.0\n"
|
6 |
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/advanced-ads/\n"
|
7 |
"Last-Translator: Thomas Maier <post@webzunft.de>\n"
|
8 |
"Language-Team: webgilde <support@wpadvancedads.com>\n"
|
9 |
"MIME-Version: 1.0\n"
|
10 |
"Content-Type: text/plain; charset=UTF-8\n"
|
11 |
"Content-Transfer-Encoding: 8bit\n"
|
12 |
+
"POT-Creation-Date: 2022-01-25T07:06:36-06:00\n"
|
13 |
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
14 |
"X-Generator: WP-CLI 2.4.0\n"
|
15 |
"X-Domain: advanced-ads\n"
|
108 |
|
109 |
#. translators: %s is the URL to add a new review, https://wordpress.org/support/plugin/advanced-ads/reviews/#new-post
|
110 |
#. translators: %s is a URL.
|
111 |
+
#: admin/class-advanced-ads-admin.php:669
|
112 |
#: admin/includes/class-overview-widgets.php:191
|
113 |
msgid "Thank the developer with a ★★★★★ review on <a href=\"%s\" target=\"_blank\">wordpress.org</a>"
|
114 |
msgstr ""
|
126 |
#. translators: %s is a list of PHP extensions.
|
127 |
#. Translators: %s is a name of a module.
|
128 |
#: admin/includes/ad-health-notices.php:54
|
129 |
+
#: admin/views/placements.php:389
|
130 |
msgid "Missing PHP extensions could cause issues. Please ask your hosting provider to enable them: %s"
|
131 |
msgstr ""
|
132 |
|
228 |
msgid "%s detected."
|
229 |
msgstr ""
|
230 |
|
|
|
231 |
#: admin/includes/ad-health-notices.php:253
|
232 |
msgid "Learn how this might impact your ad setup."
|
233 |
msgstr ""
|
311 |
msgstr ""
|
312 |
|
313 |
#: admin/includes/class-ad-groups-list.php:339
|
314 |
+
#: admin/views/placements.php:276
|
315 |
#: modules/import-export/classes/import.php:153
|
316 |
#: modules/import-export/classes/import.php:193
|
317 |
#: modules/import-export/classes/import.php:595
|
320 |
msgstr ""
|
321 |
|
322 |
#: admin/includes/class-ad-groups-list.php:340
|
323 |
+
#: admin/views/placements.php:307
|
324 |
msgid "Usage"
|
325 |
msgstr ""
|
326 |
|
343 |
msgid "No ad group created"
|
344 |
msgstr ""
|
345 |
|
346 |
+
#: admin/includes/class-ad-type.php:265
|
347 |
+
#: admin/includes/class-ad-type.php:271
|
348 |
msgid "Ad Details"
|
349 |
msgstr ""
|
350 |
|
351 |
+
#: admin/includes/class-ad-type.php:266
|
352 |
+
#: admin/includes/class-ad-type.php:272
|
353 |
msgid "Ad Planning"
|
354 |
msgstr ""
|
355 |
|
356 |
+
#: admin/includes/class-ad-type.php:267
|
357 |
+
#: admin/includes/class-ad-type.php:273
|
358 |
msgid "Ad Shortcode"
|
359 |
msgstr ""
|
360 |
|
361 |
#. translators: %s is the number of ads.
|
362 |
+
#: admin/includes/class-ad-type.php:437
|
363 |
msgid "%s ad updated."
|
364 |
msgid_plural "%s ads updated."
|
365 |
msgstr[0] ""
|
366 |
msgstr[1] ""
|
367 |
|
368 |
#. translators: %s is the number of ads.
|
369 |
+
#: admin/includes/class-ad-type.php:439
|
370 |
msgid "%s ad not updated, somebody is editing it."
|
371 |
msgid_plural "%s ads not updated, somebody is editing them."
|
372 |
msgstr[0] ""
|
373 |
msgstr[1] ""
|
374 |
|
375 |
#. translators: %s is the number of ads.
|
376 |
+
#: admin/includes/class-ad-type.php:441
|
377 |
msgid "%s ad permanently deleted."
|
378 |
msgid_plural "%s ads permanently deleted."
|
379 |
msgstr[0] ""
|
380 |
msgstr[1] ""
|
381 |
|
382 |
#. translators: %s is the number of ads.
|
383 |
+
#: admin/includes/class-ad-type.php:443
|
384 |
msgid "%s ad moved to the Trash."
|
385 |
msgid_plural "%s ads moved to the Trash."
|
386 |
msgstr[0] ""
|
387 |
msgstr[1] ""
|
388 |
|
389 |
#. translators: %s is the number of ads.
|
390 |
+
#: admin/includes/class-ad-type.php:445
|
391 |
msgid "%s ad restored from the Trash."
|
392 |
msgid_plural "%s ads restored from the Trash."
|
393 |
msgstr[0] ""
|
394 |
msgstr[1] ""
|
395 |
|
396 |
#. Translators: %s is the time the ad was first saved.
|
397 |
+
#: admin/includes/class-ad-type.php:686
|
398 |
msgid "Ad created on %s"
|
399 |
msgstr ""
|
400 |
|
401 |
+
#: admin/includes/class-ad-type.php:878
|
402 |
+
#: admin/includes/class-ad-type.php:879
|
403 |
msgid "Ad updated."
|
404 |
msgstr ""
|
405 |
|
406 |
#. translators: %s: date and time of the revision
|
407 |
+
#: admin/includes/class-ad-type.php:880
|
408 |
msgid "Ad restored to revision from %s"
|
409 |
msgstr ""
|
410 |
|
411 |
+
#: admin/includes/class-ad-type.php:881
|
412 |
+
#: admin/includes/class-ad-type.php:882
|
413 |
msgid "Ad saved."
|
414 |
msgstr ""
|
415 |
|
416 |
+
#: admin/includes/class-ad-type.php:883
|
417 |
msgid "Ad submitted."
|
418 |
msgstr ""
|
419 |
|
420 |
#. translators: %1$s is a date.
|
421 |
+
#: admin/includes/class-ad-type.php:886
|
422 |
msgid "Ad scheduled for: <strong>%1$s</strong>."
|
423 |
msgstr ""
|
424 |
|
425 |
#. translators: Publish box date format, see http://php.net/date.
|
426 |
+
#: admin/includes/class-ad-type.php:888
|
427 |
msgid "M j, Y @ G:i"
|
428 |
msgstr ""
|
429 |
|
430 |
+
#: admin/includes/class-ad-type.php:890
|
431 |
msgid "Ad draft updated."
|
432 |
msgstr ""
|
433 |
|
434 |
+
#: admin/includes/class-ad-type.php:946
|
435 |
msgid "You don’t have access to ads. Please deactivate and re-enable Advanced Ads again to fix this."
|
436 |
msgstr ""
|
437 |
|
438 |
+
#: admin/includes/class-ad-type.php:947
|
439 |
#: classes/frontend_checks.php:503
|
440 |
msgid "Get help"
|
441 |
msgstr ""
|
479 |
msgid "Please enter a valid license key"
|
480 |
msgstr ""
|
481 |
|
482 |
+
#: admin/includes/class-licenses.php:170
|
483 |
+
#: admin/includes/class-licenses.php:360
|
484 |
+
msgid "The license status does not change as long as ADVANCED_ADS_SHOW_LICENSE_RESPONSE is enabled in wp-config.php."
|
485 |
+
msgstr ""
|
486 |
+
|
487 |
+
#: admin/includes/class-licenses.php:188
|
488 |
msgid "License couldn’t be activated. Please try again later."
|
489 |
msgstr ""
|
490 |
|
491 |
+
#: admin/includes/class-licenses.php:205
|
492 |
msgid "This is the bundle license key."
|
493 |
msgstr ""
|
494 |
|
495 |
+
#: admin/includes/class-licenses.php:206
|
496 |
msgid "This is not the correct key for this add-on."
|
497 |
msgstr ""
|
498 |
|
499 |
+
#: admin/includes/class-licenses.php:207
|
500 |
msgid "There are no activations left."
|
501 |
msgstr ""
|
502 |
|
503 |
#. translators: %1$s is a starting link tag, %2$s is the closing one.
|
504 |
+
#: admin/includes/class-licenses.php:211
|
505 |
msgid "You can manage activations in %1$syour account%2$s."
|
506 |
msgstr ""
|
507 |
|
508 |
#. translators: %1$s is a starting link tag, %2$s is the closing one.
|
509 |
+
#: admin/includes/class-licenses.php:217
|
510 |
msgid "%1$sUpgrade%2$s for more activations."
|
511 |
msgstr ""
|
512 |
|
513 |
#. translators: %s is a string containing information about the issue.
|
514 |
+
#: admin/includes/class-licenses.php:231
|
515 |
msgid "License is invalid. Reason: %s"
|
516 |
msgstr ""
|
517 |
|
518 |
#. translators: %s is a list of server information like IP address. Just keep it as is.
|
519 |
+
#: admin/includes/class-licenses.php:271
|
520 |
msgid "Your request was blocked by our firewall. Please send us the following information to unblock you: %s."
|
521 |
msgstr ""
|
522 |
|
523 |
+
#: admin/includes/class-licenses.php:333
|
524 |
msgid "Error while trying to disable the license. Please contact support."
|
525 |
msgstr ""
|
526 |
|
527 |
+
#: admin/includes/class-licenses.php:369
|
528 |
+
#: admin/includes/class-licenses.php:392
|
529 |
msgid "License couldn’t be deactivated. Please try again later."
|
530 |
msgstr ""
|
531 |
|
532 |
+
#: admin/includes/class-licenses.php:626
|
533 |
msgid "Download failed. <a href=\"%s\">Click here to try another method</a>."
|
534 |
msgstr ""
|
535 |
|
536 |
+
#: admin/includes/class-licenses.php:628
|
537 |
msgid "Download failed. <a href=\"%s\" target=\"_blank\">Click here to learn why</a>."
|
538 |
msgstr ""
|
539 |
|
540 |
+
#: admin/includes/class-list-filters.php:140
|
541 |
#: modules/gadsense/admin/admin.php:73
|
542 |
#: modules/gadsense/admin/views/adsense-ad-parameters.php:109
|
543 |
msgid "Responsive"
|
544 |
msgstr ""
|
545 |
|
546 |
+
#: admin/includes/class-list-filters.php:512
|
547 |
+
msgctxt "Post list header for expired ads."
|
548 |
+
msgid "Expired"
|
549 |
msgstr ""
|
550 |
|
551 |
+
#: admin/includes/class-list-filters.php:552
|
552 |
+
msgctxt "Post list header for ads expiring in the future."
|
553 |
+
msgid "Expiring"
|
554 |
msgstr ""
|
555 |
|
556 |
#: admin/includes/class-menu.php:66
|
650 |
|
651 |
#: admin/includes/class-meta-box.php:104
|
652 |
#: admin/views/placements.php:184
|
653 |
+
#: admin/views/placements.php:430
|
654 |
#: classes/ad-debug.php:152
|
655 |
msgid "Display Conditions"
|
656 |
msgstr ""
|
657 |
|
658 |
#: admin/includes/class-meta-box.php:112
|
659 |
#: admin/views/placements.php:193
|
660 |
+
#: admin/views/placements.php:438
|
661 |
#: classes/ad-debug.php:239
|
662 |
msgid "Visitor Conditions"
|
663 |
msgstr ""
|
751 |
msgstr ""
|
752 |
|
753 |
#: admin/includes/class-overview-widgets.php:118
|
754 |
+
#: modules/gadsense/admin/views/adsense-account.php:87
|
755 |
+
#: modules/gadsense/admin/views/adsense-account.php:109
|
756 |
msgid "Connect to AdSense"
|
757 |
msgstr ""
|
758 |
|
963 |
msgstr ""
|
964 |
|
965 |
#: admin/includes/class-settings.php:178
|
966 |
+
#: classes/in-content-injector.php:615
|
967 |
msgid "Disable level limitation"
|
968 |
msgstr ""
|
969 |
|
1177 |
msgstr ""
|
1178 |
|
1179 |
#: admin/views/ad-group-list-ads.php:20
|
1180 |
+
#: admin/views/placements.php:348
|
1181 |
#: classes/ad-debug.php:118
|
1182 |
#: classes/ad-debug.php:167
|
1183 |
#: classes/ad-debug.php:169
|
1204 |
|
1205 |
#: admin/views/ad-group-list-form-row.php:56
|
1206 |
#: admin/views/placements.php:64
|
1207 |
+
#: admin/views/placements.php:258
|
1208 |
#: modules/gadsense/admin/views/adsense-ad-parameters.php:105
|
1209 |
msgid "Type"
|
1210 |
msgstr ""
|
1233 |
|
1234 |
#: admin/views/ad-group-list-row.php:22
|
1235 |
#: admin/views/ad-info.php:7
|
1236 |
+
#: admin/views/placements.php:311
|
1237 |
msgid "shortcode"
|
1238 |
msgstr ""
|
1239 |
|
1360 |
msgstr ""
|
1361 |
|
1362 |
#: admin/views/ad-list-filters.php:34
|
|
|
|
|
|
|
|
|
1363 |
msgid "all ad groups"
|
1364 |
msgstr ""
|
1365 |
|
1389 |
#: admin/views/placements-ad-label-position.php:13
|
1390 |
#: admin/views/placements-ad-label.php:9
|
1391 |
#: admin/views/placements-ad-label.php:11
|
1392 |
+
#: admin/views/placements.php:270
|
1393 |
#: modules/gadsense/includes/class-network-adsense.php:321
|
1394 |
msgid "default"
|
1395 |
msgstr ""
|
1519 |
msgstr ""
|
1520 |
|
1521 |
#. translators: %1$s month, %2$s day, %3$s year, %4$s hour, %5$s minute.
|
1522 |
+
#: admin/views/ad-submitbox-meta.php:37
|
1523 |
msgctxt "order of expiry date fields 1: month, 2: day, 3: year, 4: hour, 5: minute"
|
1524 |
msgid "%1$s %2$s, %3$s @ %4$s %5$s"
|
1525 |
msgstr ""
|
1722 |
|
1723 |
#: admin/views/modal.php:36
|
1724 |
#: admin/views/modal.php:37
|
|
|
1725 |
#: admin/views/placements.php:321
|
1726 |
+
#: admin/views/placements.php:322
|
1727 |
msgid "Close"
|
1728 |
msgstr ""
|
1729 |
|
1730 |
#: admin/views/modal.php:39
|
1731 |
+
#: admin/views/placements.php:232
|
1732 |
msgid "Close and save"
|
1733 |
msgstr ""
|
1734 |
|
1846 |
msgid "Adjust the placement options"
|
1847 |
msgstr ""
|
1848 |
|
|
|
1849 |
#: admin/views/placement-injection-top.php:21
|
1850 |
msgid "Ad not showing up? Take a look <a href=\"%s\" target=\"_blank\">here</a>"
|
1851 |
msgstr ""
|
1939 |
msgid "Existing placement"
|
1940 |
msgstr ""
|
1941 |
|
|
|
1942 |
#: admin/views/placement-injection-top.php:168
|
1943 |
msgid "Or use the shortcode %s to insert the ad into the content manually."
|
1944 |
msgstr ""
|
1945 |
|
|
|
1946 |
#: admin/views/placement-injection-top.php:176
|
1947 |
msgid "Learn more about your choices to display an ad in the <a href=\"%s\" target=\"_blank\">manual</a>."
|
1948 |
msgstr ""
|
1996 |
msgstr ""
|
1997 |
|
1998 |
#: admin/views/placements.php:25
|
1999 |
+
#: admin/views/placements.php:466
|
2000 |
msgid "Create a new placement"
|
2001 |
msgstr ""
|
2002 |
|
2003 |
#: admin/views/placements.php:26
|
2004 |
+
#: admin/views/placements.php:468
|
2005 |
msgid "New Placement"
|
2006 |
msgstr ""
|
2007 |
|
2071 |
msgid "A minimum amount of words between automatically injected ads."
|
2072 |
msgstr ""
|
2073 |
|
2074 |
+
#. Translators: 1: "Options", 2: the name of a placement.
|
2075 |
+
#: admin/views/placements.php:231
|
2076 |
#: modules/import-export/views/page.php:26
|
2077 |
msgid "Options"
|
2078 |
msgstr ""
|
2079 |
|
2080 |
#. Translators: %s is the name of a placement.
|
2081 |
+
#: admin/views/placements.php:243
|
2082 |
msgid "Placement type \"%s\" is missing and was reset to \"default\".<br/>Please check if the responsible add-on is activated."
|
2083 |
msgstr ""
|
2084 |
|
2085 |
+
#: admin/views/placements.php:314
|
2086 |
msgid "template (PHP)"
|
2087 |
msgstr ""
|
2088 |
|
2089 |
+
#: admin/views/placements.php:349
|
2090 |
msgid "Group"
|
2091 |
msgstr ""
|
2092 |
|
2093 |
+
#: admin/views/placements.php:365
|
2094 |
msgid "after"
|
2095 |
msgstr ""
|
2096 |
|
2097 |
+
#: admin/views/placements.php:366
|
2098 |
msgid "before"
|
2099 |
msgstr ""
|
2100 |
|
2101 |
+
#: admin/views/placements.php:379
|
2102 |
msgid "position"
|
2103 |
msgstr ""
|
2104 |
|
2105 |
+
#: admin/views/placements.php:385
|
2106 |
msgid "Important Notice"
|
2107 |
msgstr ""
|
2108 |
|
2109 |
#. Translators: %s is a URL.
|
2110 |
+
#: admin/views/placements.php:408
|
2111 |
msgid "Tutorial: <a href=\"%s\" target=\"_blank\">How to place visible ads in the header of your website</a>."
|
2112 |
msgstr ""
|
2113 |
|
2114 |
+
#: admin/views/placements.php:424
|
2115 |
msgid "show all options"
|
2116 |
msgstr ""
|
2117 |
|
2118 |
+
#: admin/views/placements.php:447
|
2119 |
msgid "edit conditions"
|
2120 |
msgstr ""
|
2121 |
|
2122 |
+
#: admin/views/placements.php:457
|
2123 |
msgctxt "checkbox to remove placement"
|
2124 |
msgid "delete"
|
2125 |
msgstr ""
|
2126 |
|
2127 |
+
#: admin/views/placements.php:464
|
2128 |
msgid "Save Placements"
|
2129 |
msgstr ""
|
2130 |
|
2540 |
msgid "Placement"
|
2541 |
msgstr ""
|
2542 |
|
2543 |
+
#: classes/ad-expiration.php:84
|
2544 |
+
msgid "Expired"
|
2545 |
+
msgstr ""
|
2546 |
+
|
2547 |
#. translators: %1$s is an anchor (link) opening tag, %2$s is the closing tag.
|
2548 |
#: classes/ad-health-notices.php:865
|
2549 |
#: modules/gadsense/includes/class-mapi.php:1644
|
2668 |
msgid "custom"
|
2669 |
msgstr ""
|
2670 |
|
|
|
|
|
|
|
|
|
|
|
2671 |
#: classes/ad_type_content.php:35
|
2672 |
msgid "Rich Content"
|
2673 |
msgstr ""
|
3161 |
msgid "Closing the message"
|
3162 |
msgstr ""
|
3163 |
|
3164 |
+
#. translators: %s stands for the name of the "Disable level limitation" option and automatically translated as well
|
3165 |
+
#: classes/in-content-injector.php:614
|
3166 |
+
msgid "Set <em>%s</em> to show more ads"
|
3167 |
+
msgstr ""
|
3168 |
+
|
3169 |
#. translators: time zone name.
|
3170 |
#: classes/utils.php:277
|
3171 |
msgid "time of %s"
|
3469 |
msgid "Dummy Account Id"
|
3470 |
msgstr ""
|
3471 |
|
3472 |
+
#. translators: 1: opening anchor tag for link to adsense account 2: closing anchor tag for link to adsense account
|
3473 |
+
#: modules/gadsense/admin/views/adsense-account.php:31
|
3474 |
+
msgid "Warning from your %1$sAdSense account%2$s"
|
3475 |
+
msgstr ""
|
3476 |
+
|
3477 |
+
#. translators: 1: opening anchor tag for link to adsense account 2: closing anchor tag for link to adsense account
|
3478 |
+
#: modules/gadsense/admin/views/adsense-account.php:31
|
3479 |
msgid "AdSense warnings"
|
3480 |
msgstr ""
|
3481 |
|
3482 |
+
#: modules/gadsense/admin/views/adsense-account.php:32
|
3483 |
+
#: modules/gadsense/admin/views/adsense-account.php:78
|
3484 |
msgid "dismiss"
|
3485 |
msgstr ""
|
3486 |
|
3487 |
+
#. translators: %s: date and time of last check in the format set in wp_options
|
3488 |
+
#: modules/gadsense/admin/views/adsense-account.php:64
|
3489 |
+
msgid "last checked: %s"
|
3490 |
+
msgstr ""
|
3491 |
+
|
3492 |
+
#: modules/gadsense/admin/views/adsense-account.php:90
|
3493 |
msgid "Revoke API acccess"
|
3494 |
msgstr ""
|
3495 |
|
3496 |
+
#: modules/gadsense/admin/views/adsense-account.php:96
|
3497 |
msgid "Account holder name"
|
3498 |
msgstr ""
|
3499 |
|
3500 |
+
#: modules/gadsense/admin/views/adsense-account.php:99
|
3501 |
#: modules/gadsense/includes/class-ad-type-adsense.php:91
|
3502 |
msgid "The Publisher ID has an incorrect format. (must start with \"pub-\")"
|
3503 |
msgstr ""
|
3504 |
|
3505 |
+
#: modules/gadsense/admin/views/adsense-account.php:101
|
3506 |
msgid "Your AdSense Publisher ID <em>(pub-xxxxxxxxxxxxxx)</em>"
|
3507 |
msgstr ""
|
3508 |
|
3509 |
+
#: modules/gadsense/admin/views/adsense-account.php:108
|
3510 |
msgid "Yes, I have an AdSense account"
|
3511 |
msgstr ""
|
3512 |
|
3513 |
+
#: modules/gadsense/admin/views/adsense-account.php:110
|
3514 |
msgid "Configure everything manually"
|
3515 |
msgstr ""
|
3516 |
|
3517 |
+
#: modules/gadsense/admin/views/adsense-account.php:113
|
3518 |
msgid "No, I still don't have an AdSense account"
|
3519 |
msgstr ""
|
3520 |
|
3521 |
+
#: modules/gadsense/admin/views/adsense-account.php:114
|
3522 |
msgid "Get a free AdSense account"
|
3523 |
msgstr ""
|
3524 |
|
3525 |
#. translators: %1$s is an opening a tag, %2$s is the closing one
|
3526 |
+
#: modules/gadsense/admin/views/adsense-account.php:120
|
3527 |
+
#: modules/gadsense/admin/views/adsense-account.php:211
|
3528 |
msgid "See all %1$srecommended ad networks%2$s."
|
3529 |
msgstr ""
|
3530 |
|
3531 |
+
#: modules/gadsense/admin/views/adsense-account.php:185
|
3532 |
msgid "How to choose specific positions for AdSense ad units"
|
3533 |
msgstr ""
|
3534 |
|
3535 |
#. translators: %1$s is the opening link tag to our manual; %2$s is the appropriate closing link tag; %3$s is the opening link tag to our help forum; %4$s is the appropriate closing link tag
|
3536 |
+
#: modules/gadsense/admin/views/adsense-account.php:193
|
3537 |
msgid "Problems with AdSense? Check out the %1$smanual%2$s or %3$sask here%4$s."
|
3538 |
msgstr ""
|
3539 |
|
3540 |
+
#: modules/gadsense/admin/views/adsense-account.php:225
|
3541 |
#: modules/gadsense/admin/views/external-ads-links.php:38
|
3542 |
msgid "Can not connect AdSense account. PHP version is too low."
|
3543 |
msgstr ""
|
lib/composer/autoload_classmap.php
CHANGED
@@ -12,6 +12,7 @@ return array(
|
|
12 |
'Advanced_Ads_Ad' => $baseDir . '/classes/ad.php',
|
13 |
'Advanced_Ads_Ad_Ajax_Callbacks' => $baseDir . '/classes/ad_ajax_callbacks.php',
|
14 |
'Advanced_Ads_Ad_Debug' => $baseDir . '/classes/ad-debug.php',
|
|
|
15 |
'Advanced_Ads_Ad_Health_Notices' => $baseDir . '/classes/ad-health-notices.php',
|
16 |
'Advanced_Ads_Ad_List_Filters' => $baseDir . '/admin/includes/class-list-filters.php',
|
17 |
'Advanced_Ads_Ad_Network' => $baseDir . '/admin/includes/class-ad-network.php',
|
@@ -41,6 +42,7 @@ return array(
|
|
41 |
'Advanced_Ads_Frontend_Notices' => $baseDir . '/classes/frontend-notices.php',
|
42 |
'Advanced_Ads_Group' => $baseDir . '/classes/ad_group.php',
|
43 |
'Advanced_Ads_Groups_List' => $baseDir . '/admin/includes/class-ad-groups-list.php',
|
|
|
44 |
'Advanced_Ads_Inline_Css' => $baseDir . '/classes/inline-css.php',
|
45 |
'Advanced_Ads_Model' => $baseDir . '/classes/ad-model.php',
|
46 |
'Advanced_Ads_Overview_Widgets_Callbacks' => $baseDir . '/admin/includes/class-overview-widgets.php',
|
12 |
'Advanced_Ads_Ad' => $baseDir . '/classes/ad.php',
|
13 |
'Advanced_Ads_Ad_Ajax_Callbacks' => $baseDir . '/classes/ad_ajax_callbacks.php',
|
14 |
'Advanced_Ads_Ad_Debug' => $baseDir . '/classes/ad-debug.php',
|
15 |
+
'Advanced_Ads_Ad_Expiration' => $baseDir . '/classes/ad-expiration.php',
|
16 |
'Advanced_Ads_Ad_Health_Notices' => $baseDir . '/classes/ad-health-notices.php',
|
17 |
'Advanced_Ads_Ad_List_Filters' => $baseDir . '/admin/includes/class-list-filters.php',
|
18 |
'Advanced_Ads_Ad_Network' => $baseDir . '/admin/includes/class-ad-network.php',
|
42 |
'Advanced_Ads_Frontend_Notices' => $baseDir . '/classes/frontend-notices.php',
|
43 |
'Advanced_Ads_Group' => $baseDir . '/classes/ad_group.php',
|
44 |
'Advanced_Ads_Groups_List' => $baseDir . '/admin/includes/class-ad-groups-list.php',
|
45 |
+
'Advanced_Ads_In_Content_Injector' => $baseDir . '/classes/in-content-injector.php',
|
46 |
'Advanced_Ads_Inline_Css' => $baseDir . '/classes/inline-css.php',
|
47 |
'Advanced_Ads_Model' => $baseDir . '/classes/ad-model.php',
|
48 |
'Advanced_Ads_Overview_Widgets_Callbacks' => $baseDir . '/admin/includes/class-overview-widgets.php',
|
lib/composer/autoload_static.php
CHANGED
@@ -13,6 +13,7 @@ class ComposerStaticInit_advanced_ads
|
|
13 |
'Advanced_Ads_Ad' => __DIR__ . '/../..' . '/classes/ad.php',
|
14 |
'Advanced_Ads_Ad_Ajax_Callbacks' => __DIR__ . '/../..' . '/classes/ad_ajax_callbacks.php',
|
15 |
'Advanced_Ads_Ad_Debug' => __DIR__ . '/../..' . '/classes/ad-debug.php',
|
|
|
16 |
'Advanced_Ads_Ad_Health_Notices' => __DIR__ . '/../..' . '/classes/ad-health-notices.php',
|
17 |
'Advanced_Ads_Ad_List_Filters' => __DIR__ . '/../..' . '/admin/includes/class-list-filters.php',
|
18 |
'Advanced_Ads_Ad_Network' => __DIR__ . '/../..' . '/admin/includes/class-ad-network.php',
|
@@ -42,6 +43,7 @@ class ComposerStaticInit_advanced_ads
|
|
42 |
'Advanced_Ads_Frontend_Notices' => __DIR__ . '/../..' . '/classes/frontend-notices.php',
|
43 |
'Advanced_Ads_Group' => __DIR__ . '/../..' . '/classes/ad_group.php',
|
44 |
'Advanced_Ads_Groups_List' => __DIR__ . '/../..' . '/admin/includes/class-ad-groups-list.php',
|
|
|
45 |
'Advanced_Ads_Inline_Css' => __DIR__ . '/../..' . '/classes/inline-css.php',
|
46 |
'Advanced_Ads_Model' => __DIR__ . '/../..' . '/classes/ad-model.php',
|
47 |
'Advanced_Ads_Overview_Widgets_Callbacks' => __DIR__ . '/../..' . '/admin/includes/class-overview-widgets.php',
|
13 |
'Advanced_Ads_Ad' => __DIR__ . '/../..' . '/classes/ad.php',
|
14 |
'Advanced_Ads_Ad_Ajax_Callbacks' => __DIR__ . '/../..' . '/classes/ad_ajax_callbacks.php',
|
15 |
'Advanced_Ads_Ad_Debug' => __DIR__ . '/../..' . '/classes/ad-debug.php',
|
16 |
+
'Advanced_Ads_Ad_Expiration' => __DIR__ . '/../..' . '/classes/ad-expiration.php',
|
17 |
'Advanced_Ads_Ad_Health_Notices' => __DIR__ . '/../..' . '/classes/ad-health-notices.php',
|
18 |
'Advanced_Ads_Ad_List_Filters' => __DIR__ . '/../..' . '/admin/includes/class-list-filters.php',
|
19 |
'Advanced_Ads_Ad_Network' => __DIR__ . '/../..' . '/admin/includes/class-ad-network.php',
|
43 |
'Advanced_Ads_Frontend_Notices' => __DIR__ . '/../..' . '/classes/frontend-notices.php',
|
44 |
'Advanced_Ads_Group' => __DIR__ . '/../..' . '/classes/ad_group.php',
|
45 |
'Advanced_Ads_Groups_List' => __DIR__ . '/../..' . '/admin/includes/class-ad-groups-list.php',
|
46 |
+
'Advanced_Ads_In_Content_Injector' => __DIR__ . '/../..' . '/classes/in-content-injector.php',
|
47 |
'Advanced_Ads_Inline_Css' => __DIR__ . '/../..' . '/classes/inline-css.php',
|
48 |
'Advanced_Ads_Model' => __DIR__ . '/../..' . '/classes/ad-model.php',
|
49 |
'Advanced_Ads_Overview_Widgets_Callbacks' => __DIR__ . '/../..' . '/admin/includes/class-overview-widgets.php',
|
modules/gadsense/admin/views/adsense-account.php
CHANGED
@@ -26,18 +26,30 @@ if ( $has_token && isset( $mapi_options['accounts'][ $adsense_id ]['details'] )
|
|
26 |
}
|
27 |
|
28 |
$alerts = Advanced_Ads_AdSense_MAPI::get_stored_account_alerts( $adsense_id );
|
29 |
-
$alerts_heading = __( 'AdSense warnings', 'advanced-ads' );
|
30 |
-
$alerts_dismiss = __( 'dismiss', 'advanced-ads' );
|
31 |
|
|
|
|
|
|
|
32 |
$connection_error_messages = Advanced_Ads_AdSense_MAPI::get_connect_error_messages();
|
33 |
-
|
34 |
-
$alerts_advads_messages = Advanced_Ads_Adsense_MAPI::get_adsense_alert_messages();
|
35 |
|
36 |
?>
|
37 |
<div id="mapi-account-alerts" data-heading="<?php echo esc_attr( $alerts_heading ); ?>" data-dismiss="<?php echo esc_attr( $alerts_dismiss ); ?>">
|
38 |
<?php if ( is_array( $alerts ) && isset( $alerts['items'] ) && is_array( $alerts['items'] ) && $alerts['items'] ) : ?>
|
39 |
<div class="card advads-notice-block advads-error">
|
40 |
-
<h3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
<ul>
|
42 |
<?php foreach ( $alerts['items'] as $alert_id => $alert ) : ?>
|
43 |
<?php $internal_id = isset( $alert['id'] ) ? $alert['id'] : str_replace( '-', '_', strtoupper( $alert['type'] ) ); ?>
|
@@ -48,6 +60,8 @@ $alerts_advads_messages = Advanced_Ads_Adsense_MAPI::get_adsense_alert_messages(
|
|
48 |
<?php endif; ?>
|
49 |
<?php endforeach; ?>
|
50 |
</ul>
|
|
|
|
|
51 |
</div>
|
52 |
<?php endif; ?>
|
53 |
</div>
|
26 |
}
|
27 |
|
28 |
$alerts = Advanced_Ads_AdSense_MAPI::get_stored_account_alerts( $adsense_id );
|
|
|
|
|
29 |
|
30 |
+
/* translators: 1: opening anchor tag for link to adsense account 2: closing anchor tag for link to adsense account */
|
31 |
+
$alerts_heading = $adsense_id ? sprintf( __( 'Warning from your %1$sAdSense account%2$s', 'advanced-ads' ), '<a target="_blank" href="https://www.google.com/adsense/new/u/1/' . $adsense_id . '/">', '</a>' ) : __( 'AdSense warnings', 'advanced-ads' );
|
32 |
+
$alerts_dismiss = __( 'dismiss', 'advanced-ads' );
|
33 |
$connection_error_messages = Advanced_Ads_AdSense_MAPI::get_connect_error_messages();
|
34 |
+
$alerts_advads_messages = Advanced_Ads_Adsense_MAPI::get_adsense_alert_messages();
|
|
|
35 |
|
36 |
?>
|
37 |
<div id="mapi-account-alerts" data-heading="<?php echo esc_attr( $alerts_heading ); ?>" data-dismiss="<?php echo esc_attr( $alerts_dismiss ); ?>">
|
38 |
<?php if ( is_array( $alerts ) && isset( $alerts['items'] ) && is_array( $alerts['items'] ) && $alerts['items'] ) : ?>
|
39 |
<div class="card advads-notice-block advads-error">
|
40 |
+
<h3>
|
41 |
+
<?php
|
42 |
+
echo wp_kses(
|
43 |
+
$alerts_heading,
|
44 |
+
array(
|
45 |
+
'a' => array(
|
46 |
+
'target' => true,
|
47 |
+
'href' => true,
|
48 |
+
),
|
49 |
+
)
|
50 |
+
);
|
51 |
+
?>
|
52 |
+
</h3>
|
53 |
<ul>
|
54 |
<?php foreach ( $alerts['items'] as $alert_id => $alert ) : ?>
|
55 |
<?php $internal_id = isset( $alert['id'] ) ? $alert['id'] : str_replace( '-', '_', strtoupper( $alert['type'] ) ); ?>
|
60 |
<?php endif; ?>
|
61 |
<?php endforeach; ?>
|
62 |
</ul>
|
63 |
+
<?php /* translators: %s: date and time of last check in the format set in wp_options */ ?>
|
64 |
+
<p class="description alignright"><?php printf( __( 'last checked: %s', 'advanced-ads' ), $alerts['lastCheck'] ? esc_html( ( new DateTime( '@' . $alerts['lastCheck'], Advanced_Ads_Utils::get_wp_timezone() ) )->format( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) ) : '-' ); ?></p>
|
65 |
</div>
|
66 |
<?php endif; ?>
|
67 |
</div>
|
readme.txt
CHANGED
@@ -2,9 +2,9 @@
|
|
2 |
Contributors: webzunft, advancedads
|
3 |
Tags: ads, ad manager, ad rotation, adsense, banner
|
4 |
Requires at least: 4.9
|
5 |
-
Tested up to: 5.
|
6 |
Requires PHP: 5.6
|
7 |
-
Stable tag: 1.
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
@@ -322,6 +322,15 @@ Yes. You can use plenty of [hooks](https://wpadvancedads.com/codex/) to customiz
|
|
322 |
|
323 |
== Changelog ==
|
324 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
325 |
= 1.30.5 =
|
326 |
|
327 |
- Fix: correct ad weight calculation if ad count in group is retained but ad ids change
|
@@ -339,6 +348,7 @@ Yes. You can use plenty of [hooks](https://wpadvancedads.com/codex/) to customiz
|
|
339 |
|
340 |
= 1.30.2 =
|
341 |
|
|
|
342 |
- Fix: prevent applying array functions to boolean in `Advanced_Ads_Group`
|
343 |
- Fix: add default weight for ads added to groups via the ad edit screen
|
344 |
|
2 |
Contributors: webzunft, advancedads
|
3 |
Tags: ads, ad manager, ad rotation, adsense, banner
|
4 |
Requires at least: 4.9
|
5 |
+
Tested up to: 5.9
|
6 |
Requires PHP: 5.6
|
7 |
+
Stable tag: 1.31.0
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
322 |
|
323 |
== Changelog ==
|
324 |
|
325 |
+
= 1.31.0 =
|
326 |
+
|
327 |
+
- Feature: add "Expired" and "Expiring" views to the ad overview list replacing the expiry date filter
|
328 |
+
- Improvement: use "saved" dashicon when an element was saved correctly or a process finished
|
329 |
+
- Improvement: don't report HTML5 tags or custom elements as invalid tags in custom ad content
|
330 |
+
- Improvement: optimize warnings from AdSense account and clarify that these warnings are not from Advanced Ads
|
331 |
+
- Improvement: separate `inject_in_content` code into class `Advanced_Ads_In_Content_Injector`
|
332 |
+
- Improvement: update video manual display conditions
|
333 |
+
|
334 |
= 1.30.5 =
|
335 |
|
336 |
- Fix: correct ad weight calculation if ad count in group is retained but ad ids change
|
348 |
|
349 |
= 1.30.2 =
|
350 |
|
351 |
+
- Improvement: hide feedback form when the plugin is disabled multiple times without feedback
|
352 |
- Fix: prevent applying array functions to boolean in `Advanced_Ads_Group`
|
353 |
- Fix: add default weight for ads added to groups via the ad edit screen
|
354 |
|