PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 1.8.4
Advanced Ads – Ad Manager & AdSense v1.8.4
2.0.23 2.0.22 2.0.21 1.38.0 1.39.0 1.39.1 1.39.2 1.39.3 1.39.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.40.0 1.40.1 1.40.2 1.41.0 1.42.0 1.42.1 1.42.2 1.43.0 1.44.0 1.44.1 1.45.0 1.45.1 1.46.0 1.47.0 1.47.1 1.47.2 1.47.3 1.47.4 1.47.5 1.48.0 1.48.1 1.49.0 1.5.0 1.5.0.1 1.5.1 1.5.2 1.5.2.1 1.5.4 1.5.4.1 1.5.5 1.50.0 1.51.0 1.51.1 1.51.2 1.51.3 1.52.0 1.52.1 1.52.2 1.52.3 1.52.4 1.53.0 1.53.1 1.53.2 1.54.0 1.54.1 1.55.0 1.56.0 1.56.1 1.56.2 1.56.3 1.56.4 1.6 1.6.1 1.6.10 1.6.10.1 1.6.10.2 1.6.11 1.6.11.1 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.17.1 1.6.17.2 1.6.2 1.6.2.1 1.6.3 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.6.1 1.6.7 1.6.7.1 1.6.8 1.6.8.1 1.6.8.2 1.6.8.3 1.6.9 1.6.9.1 1.6.9.2 1.6.9.3 1.6.9.4 1.7 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.1.1 1.7.1.2 1.7.1.3 1.7.1.4 1.7.1.5 1.7.10 trunk 1.7.11 1.0.1 1.7.12 1.0.2 1.7.13 1.0.3 1.7.14 1.1.0 1.7.15 1.1.1 1.7.16 1.1.2 1.7.17 1.1.3 1.7.18 1.10 1.7.19 1.10.1 1.7.2 1.10.10 1.7.2.1 1.10.11 1.7.20 1.10.12 1.7.21 1.10.2 1.7.22 1.10.3 1.7.23 1.10.4 1.7.24 1.10.5 1.7.25 1.10.6 1.7.3 1.10.7 1.7.4 1.10.8 1.7.4.1 1.10.9 1.7.4.2 1.11 1.7.4.3 1.11.1 1.7.4.4 1.11.2 1.7.4.5 1.12 1.7.5 1.13 1.7.5.1 1.13.1 1.7.6 1.13.2 1.7.7 1.13.3 1.7.8 1.13.4 1.7.9 1.13.5 1.7.9.1 1.13.6 1.7.9.2 1.13.7 1.7.9.3 1.13.8 1.8 1.14 1.8.1 1.14.1 1.8.10 1.14.10 1.8.11 1.14.11 1.8.12 1.14.2 1.8.13 1.14.3 1.8.14 1.14.4 1.8.15 1.14.5 1.8.16 1.14.6 1.8.17 1.14.7 1.8.18 1.14.8 1.8.19 1.14.9 1.8.2 1.15 1.8.20 1.16 1.8.21 1.16.1 1.8.22 1.17 1.8.23 1.17.1 1.8.24 1.17.10 1.8.25 1.17.10-rc.1 1.8.26 1.17.11 1.8.27 1.17.12 1.8.28 1.17.12-rc.1 1.8.29 1.17.2 1.8.3 1.17.3 1.8.30 1.17.4 1.8.4 1.17.5 1.8.5 1.17.6 1.8.6 1.17.7 1.8.7 1.17.8 1.8.8 1.17.9 1.8.9 1.17.9-beta.1 1.9 1.18.0 2.0.0 1.19.0 2.0.1 1.19.1 2.0.10 1.2 2.0.11 1.2.1 2.0.12 1.2.2 2.0.13 1.2.3 2.0.14 1.2.4 2.0.15 1.2.5 2.0.16 1.2.6 2.0.17 1.2.7 2.0.18 1.20.0 2.0.19 1.20.0-rc.1 2.0.2 1.20.0-rc.2 2.0.20 1.20.1 2.0.3 1.20.2 2.0.4 1.20.3 2.0.5 1.21.0 2.0.6 1.21.1 2.0.7 1.22.0 2.0.8 1.22.1 2.0.9 1.22.2 1.23.0 1.23.1 1.23.2 1.24.0 1.24.1 1.24.2 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.29.0 1.29.1 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.30.0 1.30.1 1.30.2 1.30.2-rc.1 1.30.3 1.30.4 1.30.4-rc.1 1.30.5 1.31.0 1.31.1 1.32.0 1.32.0-rc.1 1.33.0 1.33.1 1.33.2 1.34.0 1.35.0 1.35.1 1.36.0 1.36.1 1.36.2 1.36.3 1.37.0 1.37.1 1.37.2
advanced-ads / classes / ad_placements.php
advanced-ads / classes Last commit date
EDD_SL_Plugin_Updater.php 8 years ago ad-ajax.php 8 years ago ad-debug.php 8 years ago ad-model.php 8 years ago ad-select.php 9 years ago ad.php 8 years ago ad_ajax_callbacks.php 8 years ago ad_group.php 8 years ago ad_placements.php 8 years ago ad_type_abstract.php 11 years ago ad_type_content.php 8 years ago ad_type_dummy.php 8 years ago ad_type_group.php 8 years ago ad_type_image.php 8 years ago ad_type_plain.php 8 years ago checks.php 8 years ago display-conditions.php 8 years ago filesystem.php 8 years ago frontend_checks.php 8 years ago plugin.php 8 years ago upgrades.php 8 years ago utils.php 8 years ago visitor-conditions.php 8 years ago widget.php 8 years ago
ad_placements.php
567 lines
1 <?php
2
3 /**
4 * Advanced Ads
5 *
6 * @package Advanced_Ads_Placements
7 * @author Thomas Maier <thomas.maier@webgilde.com>
8 * @license GPL-2.0+
9 * @link http://webgilde.com
10 * @copyright 2014 Thomas Maier, webgilde GmbH
11 */
12
13 /**
14 * grouping placements functions
15 *
16 * @since 1.1.0
17 * @package Advanced_Ads_Placements
18 * @author Thomas Maier <thomas.maier@webgilde.com>
19 */
20 class Advanced_Ads_Placements {
21
22 /**
23 * get placement types
24 *
25 * @since 1.2.1
26 * @return arr $types array with placement types
27 */
28 public static function get_placement_types() {
29 $types = array(
30 'default' => array(
31 'title' => __( 'Manual Placement', 'advanced-ads' ),
32 'description' => __( 'Manual placement to use as function or shortcode.', 'advanced-ads' ),
33 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/manual.png',
34 'options' => array( 'show_position' => true )
35 ),
36 'header' => array(
37 'title' => __( 'Header Code', 'advanced-ads' ),
38 'description' => __( 'Injected in Header (before closing &lt;/head&gt; Tag, often not visible).', 'advanced-ads' ),
39 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/header.png'
40 ),
41 'footer' => array(
42 'title' => __( 'Footer Code', 'advanced-ads' ),
43 'description' => __( 'Injected in Footer (before closing &lt;/body&gt; Tag).', 'advanced-ads' ),
44 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/footer.png'
45 ),
46 'post_top' => array(
47 'title' => __( 'Before Content', 'advanced-ads' ),
48 'description' => __( 'Injected before the post content.', 'advanced-ads' ),
49 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/content-before.png',
50 'options' => array( 'show_position' => true )
51 ),
52 'post_bottom' => array(
53 'title' => __( 'After Content', 'advanced-ads' ),
54 'description' => __( 'Injected after the post content.', 'advanced-ads' ),
55 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/content-after.png',
56 'options' => array( 'show_position' => true )
57 ),
58 'post_content' => array(
59 'title' => __( 'Content', 'advanced-ads' ),
60 'description' => __( 'Injected into the content. You can choose the paragraph after which the ad content is displayed.', 'advanced-ads' ),
61 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/content-within.png',
62 'options' => array( 'show_position' => true )
63 ),
64 'sidebar_widget' => array(
65 'title' => __( 'Sidebar Widget', 'advanced-ads' ),
66 'description' => __( 'Create a sidebar widget with an ad. Can be placed and used like any other widget.', 'advanced-ads' ),
67 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/widget.png'
68 ),
69 );
70 return apply_filters( 'advanced-ads-placement-types', $types );
71 }
72
73 /**
74 * update placements if sent
75 *
76 * @since 1.5.2
77 */
78 static function update_placements(){
79
80 // check user permissions
81 if( ! current_user_can( Advanced_Ads_Plugin::user_cap( 'advanced_ads_manage_placements') ) ) {
82 return;
83 }
84
85 $success = null;
86
87 if ( isset($_POST['advads']['placement']) && check_admin_referer( 'advads-placement', 'advads_placement' ) ){
88 $success = self::save_new_placement( $_POST['advads']['placement'] );
89 }
90 // save placement data
91 if ( isset($_POST['advads']['placements']) && check_admin_referer( 'advads-placement', 'advads_placement' )){
92 $success = self::save_placements( $_POST['advads']['placements'] );
93 }
94
95 $success = apply_filters( 'advanced-ads-update-placements', $success );
96
97 if(isset($success)){
98 $message = $success ? 'updated' : 'error';
99 wp_redirect( esc_url_raw( add_query_arg(array('message' => $message)) ) );
100 }
101 }
102
103 /**
104 * save a new placement
105 *
106 * @since 1.1.0
107 * @param array $new_placement
108 * @return mixed slug if saved; false if not
109 */
110 public static function save_new_placement($new_placement) {
111 // load placements // -TODO use model
112 $placements = Advanced_Ads::get_ad_placements_array();
113
114 // create slug
115 $new_placement['slug'] = sanitize_title( $new_placement['name'] );
116
117 // check if slug already exists or is empty
118 if ( $new_placement['slug'] === '' || isset( $placements[$new_placement['slug']]) || !isset( $new_placement['type'] ) ) {
119 return false;
120 }
121
122 // make sure only allowed types are being saved
123 $placement_types = Advanced_Ads_Placements::get_placement_types();
124 $new_placement['type'] = (isset($placement_types[$new_placement['type']])) ? $new_placement['type'] : 'default';
125 // escape name
126 $new_placement['name'] = esc_attr( $new_placement['name'] );
127
128 // add new place to all placements
129 $placements[$new_placement['slug']] = array(
130 'type' => $new_placement['type'],
131 'name' => $new_placement['name'],
132 'item' => $new_placement['item']
133 );
134
135 // add index options
136 if ( isset($new_placement['options']) ){
137 $placements[$new_placement['slug']]['options'] = $new_placement['options'];
138 if ( isset($placements[$new_placement['slug']]['options']['index']) ) {
139 $placements[$new_placement['slug']]['options']['index'] = absint( $placements[$new_placement['slug']]['options']['index'] ); }
140 }
141
142 // save array
143 Advanced_Ads::get_instance()->get_model()->update_ad_placements_array( $placements );
144
145 return $new_placement['slug'];
146 }
147
148 /**
149 * save placements
150 *
151 * @since 1.1.0
152 * @param array $placement_items
153 * @return mixed true if saved; error message if not
154 */
155 public static function save_placements($placement_items) {
156
157 // load placements // -TODO use model
158 $placements = Advanced_Ads::get_ad_placements_array();
159
160 foreach ( $placement_items as $_placement_slug => $_placement ) {
161 // remove the placement
162 if ( isset($_placement['delete']) ) {
163 unset($placements[$_placement_slug]);
164 continue;
165 }
166 // save item
167 if ( isset($_placement['item']) ) {
168 $placements[$_placement_slug]['item'] = $_placement['item']; }
169 // save item options
170 if ( isset($_placement['options']) ){
171 $placements[$_placement_slug]['options'] = $_placement['options'];
172 if ( isset($placements[$_placement_slug]['options']['index']) ) {
173 $placements[$_placement_slug]['options']['index'] = absint( $placements[$_placement_slug]['options']['index'] ); }
174 } else {
175 $placements[$_placement_slug]['options'] = array();
176 }
177 }
178
179 // save array
180 Advanced_Ads::get_instance()->get_model()->update_ad_placements_array( $placements );
181
182 return true;
183 }
184
185 /**
186 * get items for item select field
187 *
188 * @since 1.1
189 * @return arr $select items for select field
190 */
191 public static function items_for_select() {
192 $select = array();
193 $model = Advanced_Ads::get_instance()->get_model();
194
195 // load all ad groups
196 $groups = $model->get_ad_groups();
197 foreach ( $groups as $_group ) {
198 $select['groups']['group_' . $_group->term_id] = $_group->name;
199 }
200
201 // load all ads
202 $ads = $model->get_ads( array('orderby' => 'title', 'order' => 'ASC') );
203 foreach ( $ads as $_ad ) {
204 $select['ads']['ad_' . $_ad->ID] = $_ad->post_title;
205 }
206
207 return $select;
208 }
209
210 /**
211 * get html tags for content injection
212 *
213 * @since 1.3.5
214 * @return arr $tags array with tags that can be used for content injection
215 */
216 public static function tags_for_content_injection(){
217 $tags = apply_filters( 'advanced-ads-tags-for-injection', array(
218 'p' => sprintf( __( 'paragraph (%s)', 'advanced-ads' ), '&lt;p&gt;' ),
219 'pwithoutimg' => sprintf( __( 'paragraph without image (%s)', 'advanced-ads' ), '&lt;p&gt;' ),
220 'h2' => sprintf( __( 'headline 2 (%s)', 'advanced-ads' ), '&lt;h2&gt;' ),
221 'h3' => sprintf( __( 'headline 3 (%s)', 'advanced-ads' ), '&lt;h3&gt;' ),
222 'h4' => sprintf( __( 'headline 4 (%s)', 'advanced-ads' ), '&lt;h4&gt;' ),
223 ));
224
225 return $tags;
226 }
227
228 /**
229 * return content of a placement
230 *
231 * @since 1.1.0
232 * @param string $id slug of the display
233 * @param array $args optional arguments (passed to child)
234 */
235 public static function output( $id = '', $args = array() ) {
236 // get placement data for the slug
237 if ( $id == '' ) {
238 return;
239 }
240
241 $placements = Advanced_Ads::get_ad_placements_array();
242 $placement = ( isset( $placements[ $id ] ) && is_array( $placements[ $id ] ) ) ? $placements[ $id ] : array();
243
244 if ( isset( $args['change-placement'] ) ) {
245 // some options was provided by the user
246 $placement = Advanced_Ads_Utils::merge_deep_array( array( $placement, $args['change-placement'] ) ) ;
247 }
248
249 if ( isset( $placement['item'] ) && $placement['item'] !== '' ) {
250 $_item = explode( '_', $placement['item'] );
251
252 if ( ! isset( $_item[1] ) || empty( $_item[1] ) ) {
253 return ;
254 }
255
256 // inject options
257 if ( isset( $placement['options'] ) && is_array( $placement['options'] ) ) {
258 foreach ( $placement['options'] as $_k => $_v ) {
259 if ( ! isset( $args[ $_k ] ) ) {
260 $args[ $_k ] = $_v;
261 }
262 }
263 }
264
265 // inject placement type
266 if ( isset( $placement['type'] ) ) {
267 $args[ 'placement_type' ] = $placement['type'];
268 }
269
270 // options
271 $prefix = Advanced_Ads_Plugin::get_instance()->get_frontend_prefix();
272
273 // return either ad or group content
274 switch ( $_item[0] ) {
275 case 'ad':
276 case Advanced_Ads_Select::AD :
277 // create class from placement id (not if header injection)
278 if ( ! isset( $placement['type'] ) || $placement['type'] !== 'header' ) {
279 if ( ! isset( $args['output'] ) ) {
280 $args['output'] = array();
281 }
282 if ( ! isset( $args['output']['class'] ) ) {
283 $args['output']['class'] = array();
284 }
285 $class = $prefix . $id;
286 if ( ! in_array( $class, $args['output']['class'] ) ) {
287 $args['output']['class'][] = $class;
288 }
289 }
290
291 // fix method id
292 $_item[0] = Advanced_Ads_Select::AD;
293 break;
294
295 // avoid loops (programmatical error)
296 case Advanced_Ads_Select::PLACEMENT :
297 return;
298
299 case Advanced_Ads_Select::GROUP :
300 $class = $prefix . $id;
301 if ( ( isset( $placement['type'] ) && $placement['type'] !== 'header' )
302 && ( !isset( $args['output']['class'] )
303 || !is_array( $args['output']['class'] )
304 || !in_array( $class, $args['output']['class'] ) ) ) {
305 $args['output']['class'][] = $class;
306 }
307 default:
308 }
309
310 // create placement id for various features
311 $args['output']['placement_id'] = $id;
312
313 // add the placement to the global output array
314 $advads = Advanced_Ads::get_instance();
315 $advads->current_ads[] = array('type' => 'placement', 'id' => $id, 'title' => $placement['name']);
316
317 $result = Advanced_Ads_Select::get_instance()->get_ad_by_method( (int) $_item[1], $_item[0], $args );
318
319 if ( $result && ! empty( $args['placement_clearfix'] ) ) {
320 $result .= '<br style="clear: both; display: block; float: none; color:blue;"/>';
321 }
322
323 return $result;
324 }
325 }
326
327 /**
328 * inject ads directly into the content
329 *
330 * @since 1.2.1
331 * @param string $placement_id id of the placement
332 * @param arr $options placement options
333 * @param string $content
334 * @return type
335 * @link inspired by http://www.wpbeginner.com/wp-tutorials/how-to-insert-ads-within-your-post-content-in-wordpress/
336 */
337 public static function &inject_in_content($placement_id, $options, &$content) {
338
339 // get plugin options
340 $plugin_options = Advanced_Ads::get_instance()->options();
341
342 // test ad is emtpy
343 $whitespaces = json_decode('"\t\n\r \u00A0"');
344 $adContent = Advanced_Ads_Select::get_instance()->get_ad_by_method( $placement_id, 'placement', $options );
345 if ( ! extension_loaded( 'dom' )
346 || trim( $adContent, $whitespaces ) === ''
347 ) {
348 return $content;
349 }
350
351 // parse document as DOM (fragment - having only a part of an actual post given)
352 // -TODO may want to verify the wpcharset is supported by server (mb_list_encodings)
353 // prevent messages from dom parser
354 $wpCharset = get_bloginfo('charset');
355 // check if mbstring exists
356 if ( ! function_exists( 'mb_convert_encoding' ) ) {
357 if ( $wpCharset === "UTF-8" ) {
358 $content = htmlspecialchars_decode( htmlentities( $content, ENT_COMPAT, $wpCharset, false ) );
359 } else {
360 return $content;
361 }
362 } else {
363 $content = mb_convert_encoding( $content, 'HTML-ENTITIES', $wpCharset );
364 }
365
366 // check which priority the wpautop filter has; might have been disabled on purpose
367 $wpautop_priority = has_filter( 'the_content', 'wpautop');
368 if ( $wpautop_priority && Advanced_Ads_Plugin::get_instance()->get_content_injection_priority() < $wpautop_priority ) {
369 $content = wpautop( $content );
370 }
371
372 $dom = new DOMDocument('1.0', $wpCharset);
373 // may loose some fragments or add autop-like code
374 libxml_use_internal_errors(true); // avoid notices and warnings - html is most likely malformed
375 $success = $dom->loadHtml('<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wpCharset . '" /><body>' . $content);
376 libxml_use_internal_errors(false);
377 if ($success !== true) {
378 // -TODO handle cases were dom-parsing failed (at least inform user)
379 return $content;
380 }
381
382 // parse arguments
383 $tag = isset($options['tag']) ? $options['tag'] : 'p';
384 $tag = preg_replace('/[^a-z0-9]/i', '', $tag); // simplify tag
385
386 // allow more complex xPath expression
387 $tag = apply_filters( 'advanced-ads-placement-content-injection-xpath', $tag, $options );
388
389 if ( $tag === 'pwithoutimg' ) {
390 $tag = 'p[not(descendant::img)]';
391 }
392
393 // only has before and after
394 $before = isset($options['position']) && $options['position'] === 'before';
395 $paragraph_id = isset($options['index']) ? $options['index'] : 1;
396 $paragraph_id = max( 1, (int) $paragraph_id );
397 $paragraph_select_from_bottom = isset($options['start_from_bottom']) && $options['start_from_bottom'];
398
399 // select positions
400 $xpath = new DOMXPath($dom);
401 $items = $xpath->query('/html/body/' . $tag);
402 $offset = null;
403
404 $options = array(
405 'allowEmpty' => false, // whether the tag can be empty to be counted
406 );
407 // if there are too few items at this level test nesting
408 $options['itemLimit'] = $tag === 'p' ? 2 : 1;
409
410 // trigger such a high item limit that all elements will be considered
411 if( ! empty($plugin_options['content-injection-level-disabled'] ) ){
412 $options['itemLimit'] = 1000;
413 }
414
415 // allow hooks to change some options
416 $options = apply_filters(
417 'advanced-ads-placement-content-injection-options',
418 $options,
419 $tag );
420
421 if ($items->length < $options['itemLimit'] ) {
422 $items = $xpath->query('/html/body/*/' . $tag);
423 }
424 // try third level
425 if ( $items->length < $options['itemLimit'] ) {
426 $items = $xpath->query('/html/body/*/*/' . $tag);
427 }
428 // try all levels as last resort
429 if ( $items->length < $options['itemLimit'] ) {
430 $items = $xpath->query( '//' . $tag );
431 }
432
433 // allow to select other elements
434 $items = apply_filters( 'advanced-ads-placement-content-injection-items', $items, $xpath, $tag );
435
436 // filter empty tags from items
437 $paragraphs = array();
438 foreach ($items as $item) {
439 if ( $options['allowEmpty'] || ( isset($item->textContent) && trim($item->textContent, $whitespaces) !== '' ) ) {
440 $paragraphs[] = $item;
441 }
442 }
443
444 $paragraph_count = count($paragraphs);
445 if ($paragraph_count >= $paragraph_id) {
446 $offset = $paragraph_select_from_bottom ? $paragraph_count - $paragraph_id : $paragraph_id - 1;
447
448 // convert HTML to XML!
449 $adDom = new DOMDocument('1.0', $wpCharset);
450 libxml_use_internal_errors(true);
451 // replace `</` with `<\/` in ad content when placed within `document.write()` to prevent code from breaking
452 // source for this regex: http://stackoverflow.com/questions/17852537/preg-replace-only-specific-part-of-string
453 $adContent = preg_replace('#(document.write.+)</(.*)#', '$1<\/$2', $adContent); // escapes all closing html tags
454 // $adContent = preg_replace('#(document.write.+)</sc(.*)#', '$1<\/sc$2', $adContent); // only escapes closing </script> tags
455 // $adContent = preg_replace('#(document.write[^<^)]+)</sc(.*)#', '$1<\/sc$2', $adContent); // too restrict, doesn’t work when beginning <script> tag is in the same line
456 $adDom->loadHtml('<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wpCharset . '" /><body>' . $adContent);
457 // log errors
458 if ( defined ( 'WP_DEBUG' ) && WP_DEBUG && current_user_can( 'advanced_ads_manage_options' ) ) {
459 foreach( libxml_get_errors() as $_error ) {
460 // continue, if there is '&' symbol, but not HTML entity
461 if ( false === stripos( $_error->message, 'htmlParseEntityRef:' ) ) {
462 Advanced_Ads::log( 'possible content injection error for placement "' . $placement_id . '": ' . print_r( $_error, true ) );
463 }
464 }
465 }
466
467 // inject
468 $node = apply_filters( 'advanced-ads-placement-content-injection-node', $paragraphs[$offset], $tag, $before );
469 if ($before) {
470 $refNode = $node;
471
472 foreach ( $adDom->getElementsByTagName( 'body' )->item( 0 )->childNodes as $importedNode ) {
473 $importedNode = $dom->importNode( $importedNode, true );
474 $refNode->parentNode->insertBefore( $importedNode, $refNode );
475 }
476 } else {
477 // append before next node or as last child to body
478 $refNode = $node->nextSibling;
479 if (isset($refNode)) {
480
481 foreach ( $adDom->getElementsByTagName( 'body' )->item( 0 )->childNodes as $importedNode ) {
482 $importedNode = $dom->importNode( $importedNode, true );
483 $refNode->parentNode->insertBefore( $importedNode, $refNode );
484 }
485
486 } else {
487 // append to body; -TODO using here that we only select direct children of the body tag
488 foreach ( $adDom->getElementsByTagName( 'body' )->item( 0 )->childNodes as $importedNode ) {
489 $importedNode = $dom->importNode( $importedNode, true );
490 $node->parentNode->appendChild( $importedNode );
491 }
492 }
493 }
494
495 libxml_use_internal_errors(false);
496 /**
497 * show a warning to ad admins in the Ad Health bar in the frontend, when
498 *
499 * * the level limitation was not disabled
500 * * could not inject one ad (as by use of `elseif` here)
501 * * but there are enough elements on the site, but just in sub-containers
502 *
503 */
504 } elseif( current_user_can( Advanced_Ads_Plugin::user_cap( 'advanced_ads_manage_options') )
505 && empty($plugin_options['content-injection-level-disabled'] ) ) {
506
507 // check if there are more elements without limitation
508 $all_items = $xpath->query( '//' . $tag );
509 if( $paragraph_id <= $all_items->length ){
510
511 // add item to ad health
512 global $wp_admin_bar;
513 if( $wp_admin_bar instanceof WP_Admin_Bar ){
514 $wp_admin_bar->add_node( array(
515 'parent' => 'advanced_ads_ad_health',
516 'id' => 'advanced_ads_ad_health_the_content_not_enough_elements',
517 'title' => sprintf(__( 'Set <em>%s</em> to show more ads', 'advanced-ads' ), __('Disable level limitation', 'advanced-ads' ) ),
518 'href' => admin_url( '/admin.php?page=advanced-ads-settings#top#general' ),
519 'meta' => array(
520 'class' => 'advanced_ads_ad_health_warning',
521 'target' => '_blank'
522 )
523 ) );
524
525 // manipulate $display_fine
526 add_filter( 'advanced-ads-ad-health-display-fine', '__return_false' );
527 }
528 }
529 }
530
531 // convert to text-representation
532 $content = $dom->saveHTML();
533 // remove head and tail (required for dom parser but unwanted for content)
534 $content = substr($content, stripos($content, '<body>') + 6);
535 $content = str_replace(array('</body>', '</html>'), '', $content);
536
537 // no fall-back desired: if there are too few paragraphs do nothing
538
539 // fix shortcode quotes (malformed by backend editor)
540 $matches = array();
541 if (0 < preg_match_all('/\[[^]]+\]/Siu', $content, $matches, PREG_OFFSET_CAPTURE) && isset($matches[0])) {
542 foreach ($matches[0] as $match) {
543 $offset = $match[1];
544 $content = substr($content, 0, $offset) . str_replace(array('', '', '&#8220;', '&quote;', '&#8243;'), '"', $match[0]) . substr($content, $offset + strlen($match[0]));
545 }
546 }
547
548 return $content;
549 }
550
551 /**
552 * check if the placement can be displayed
553 *
554 * @since 1.6.9
555 * @param int $id placement id
556 * @return bool true if placement can be displayed
557 */
558 static function can_display( $id = 0 ){
559 if ( ! isset($id) || $id === 0 ) {
560 return true;
561 }
562
563 return apply_filters( 'advanced-ads-can-display-placement', true, $id );
564 }
565
566 }
567