PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 1.7
Advanced Ads – Ad Manager & AdSense v1.7
2.0.25 2.0.24 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 10 years ago ad-ajax.php 10 years ago ad-model.php 11 years ago ad-select.php 10 years ago ad.php 10 years ago ad_ajax_callbacks.php 10 years ago ad_group.php 10 years ago ad_placements.php 10 years ago ad_type_abstract.php 11 years ago ad_type_content.php 10 years ago ad_type_image.php 10 years ago ad_type_plain.php 10 years ago checks.php 10 years ago display-conditions.php 10 years ago plugin.php 10 years ago upgrades.php 10 years ago visitor-conditions.php 10 years ago widget.php 10 years ago
ad_placements.php
466 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 ),
35 'header' => array(
36 'title' => __( 'Header Code', 'advanced-ads' ),
37 'description' => __( 'Injected in Header (before closing &lt;/head&gt; Tag, often not visible).', 'advanced-ads' ),
38 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/header.png'
39 ),
40 'footer' => array(
41 'title' => __( 'Footer Code', 'advanced-ads' ),
42 'description' => __( 'Injected in Footer (before closing &lt;/body&gt; Tag).', 'advanced-ads' ),
43 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/footer.png'
44 ),
45 'post_top' => array(
46 'title' => __( 'Before Content', 'advanced-ads' ),
47 'description' => __( 'Injected before the post content.', 'advanced-ads' ),
48 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/content-before.png'
49 ),
50 'post_bottom' => array(
51 'title' => __( 'After Content', 'advanced-ads' ),
52 'description' => __( 'Injected after the post content.', 'advanced-ads' ),
53 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/content-after.png'
54 ),
55 'post_content' => array(
56 'title' => __( 'Post Content', 'advanced-ads' ),
57 'description' => __( 'Injected into the post content. You can choose the paragraph after which the ad content is displayed.', 'advanced-ads' ),
58 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/content-within.png'
59 ),
60 'sidebar_widget' => array(
61 'title' => __( 'Sidebar Widget', 'advanced-ads' ),
62 'description' => __( 'Create a sidebar widget with an ad. Can be placed and used like any other widget.', 'advanced-ads' ),
63 'image' => ADVADS_BASE_URL . 'admin/assets/img/placements/widget.png'
64 ),
65 );
66 return apply_filters( 'advanced-ads-placement-types', $types );
67 }
68
69 /**
70 * update placements if sent
71 *
72 * @since 1.5.2
73 */
74 static function update_placements(){
75
76 // check user permissions
77 if( ! current_user_can( Advanced_Ads_Plugin::user_cap( 'advanced_ads_manage_placements') ) ) {
78 return;
79 }
80 remove_query_arg('message');
81
82 if ( isset($_POST['advads']['placement']) && check_admin_referer( 'advads-placement', 'advads_placement' ) ){
83 $success = self::save_new_placement( $_POST['advads']['placement'] );
84 }
85 // save placement data
86 if ( isset($_POST['advads']['placements']) && check_admin_referer( 'advads-placement', 'advads_placement' )){
87 $success = self::save_placements( $_POST['advads']['placements'] );
88 }
89
90 if(isset($success)){
91 $message = $success ? 'updated' : 'error';
92 wp_redirect( add_query_arg(array('message' => $message)) );
93 }
94 }
95
96 /**
97 * save a new placement
98 *
99 * @since 1.1.0
100 * @param array $new_placement
101 * @return mixed true if saved; error message if not
102 */
103 public static function save_new_placement($new_placement) {
104 // load placements // -TODO use model
105 $placements = Advanced_Ads::get_ad_placements_array();
106
107 // create slug
108 $new_placement['slug'] = sanitize_title( $new_placement['name'] );
109
110 // check if slug already exists or is empty
111 if ( $new_placement['slug'] === '' || isset( $placements[$new_placement['slug']]) || !isset( $new_placement['type'] ) ) {
112 return false;
113 }
114
115 // make sure only allowed types are being saved
116 $placement_types = Advanced_Ads_Placements::get_placement_types();
117 $new_placement['type'] = (isset($placement_types[$new_placement['type']])) ? $new_placement['type'] : 'default';
118 // escape name
119 $new_placement['name'] = esc_attr( $new_placement['name'] );
120
121 // add new place to all placements
122 $placements[$new_placement['slug']] = array(
123 'type' => $new_placement['type'],
124 'name' => $new_placement['name'],
125 'item' => $new_placement['item']
126 );
127
128 // save array
129 update_option( 'advads-ads-placements', $placements );
130
131 return true;
132 }
133
134 /**
135 * save placements
136 *
137 * @since 1.1.0
138 * @param array $placement_items
139 * @return mixed true if saved; error message if not
140 */
141 public static function save_placements($placement_items) {
142
143 // load placements // -TODO use model
144 $placements = Advanced_Ads::get_ad_placements_array();
145
146 foreach ( $placement_items as $_placement_slug => $_placement ) {
147 // remove the placement
148 if ( isset($_placement['delete']) ) {
149 unset($placements[$_placement_slug]);
150 continue;
151 }
152 // save item
153 if ( isset($_placement['item']) ) {
154 $placements[$_placement_slug]['item'] = $_placement['item']; }
155 // save item options
156 if ( isset($_placement['options']) ){
157 $placements[$_placement_slug]['options'] = $_placement['options'];
158 if ( isset($placements[$_placement_slug]['options']['index']) ) {
159 $placements[$_placement_slug]['options']['index'] = absint( $placements[$_placement_slug]['options']['index'] ); }
160 } else {
161 $placements[$_placement_slug]['options'] = array();
162 }
163 }
164
165 // save array
166 update_option( 'advads-ads-placements', $placements );
167
168 return true;
169 }
170
171 /**
172 * get items for item select field
173 *
174 * @since 1.1
175 * @return arr $select items for select field
176 */
177 public static function items_for_select() {
178 $select = array();
179 $model = Advanced_Ads::get_instance()->get_model();
180
181 // load all ad groups
182 $groups = $model->get_ad_groups();
183 foreach ( $groups as $_group ) {
184 $select['groups']['group_' . $_group->term_id] = $_group->name;
185 }
186
187 // load all ads
188 $ads = $model->get_ads( array('orderby' => 'name', 'order' => 'ASC') );
189 foreach ( $ads as $_ad ) {
190 $select['ads']['ad_' . $_ad->ID] = $_ad->post_title;
191 }
192
193 return $select;
194 }
195
196 /**
197 * get html tags for content injection
198 *
199 * @since 1.3.5
200 * @return arr $tags array with tags that can be used for content injection
201 */
202 public static function tags_for_content_injection(){
203 $tags = apply_filters( 'advanced-ads-tags-for-injection', array(
204 'p' => sprintf( __( 'paragraph (%s)', 'advanced-ads' ), '&lt;p&gt;' ),
205 'h2' => sprintf( __( 'headline 2 (%s)', 'advanced-ads' ), '&lt;h2&gt;' ),
206 'h3' => sprintf( __( 'headline 3 (%s)', 'advanced-ads' ), '&lt;h3&gt;' ),
207 'h4' => sprintf( __( 'headline 4 (%s)', 'advanced-ads' ), '&lt;h4&gt;' ),
208 ));
209
210 return $tags;
211 }
212
213 /**
214 * return content of a placement
215 *
216 * @since 1.1.0
217 * @param string $id slug of the display
218 * @param array $args optional arguments (passed to child)
219 */
220 public static function output( $id = '', $args = array() ) {
221 // get placement data for the slug
222 if ( $id == '' ) {
223 return;
224 }
225
226 $placements = Advanced_Ads::get_ad_placements_array();
227
228 if ( isset( $placements[ $id ]['item'] ) && $placements[ $id ]['item'] !== '' ) {
229 $_item = explode( '_', $placements[ $id ]['item'] );
230
231 if ( ! isset( $_item[1] ) || empty( $_item[1] ) ) {
232 return ;
233 }
234
235 // inject options
236 if ( isset( $placements[ $id ]['options'] ) && is_array( $placements[ $id ]['options'] ) ) {
237 foreach ( $placements[ $id ]['options'] as $_k => $_v ) {
238 if ( ! isset( $args[ $_k ] ) ) {
239 $args[ $_k ] = $_v;
240 }
241 }
242 }
243
244 // inject placement type
245 if ( isset( $placements[ $id ]['type'] ) ) {
246 $args[ 'placement_type' ] = $placements[ $id ]['type'];
247 }
248
249 // options
250 $prefix = Advanced_Ads_Plugin::get_instance()->get_frontend_prefix();
251
252 // return either ad or group content
253 switch ( $_item[0] ) {
254 case 'ad':
255 case Advanced_Ads_Select::AD :
256 // create class from placement id (not if header injection)
257 if ( ! isset( $placements[ $id ]['type'] ) || $placements[ $id ]['type'] !== 'header' ) {
258 if ( ! isset( $args['output'] ) ) {
259 $args['output'] = array();
260 }
261 if ( ! isset( $args['output']['class'] ) ) {
262 $args['output']['class'] = array();
263 }
264 $class = $prefix . $id;
265 if ( ! in_array( $class, $args['output']['class'] ) ) {
266 $args['output']['class'][] = $class;
267 }
268
269 $args['output']['placement_id'] = $id;
270 }
271
272 // fix method id
273 $_item[0] = Advanced_Ads_Select::AD;
274 break;
275
276 // avoid loops (programmatical error)
277 case Advanced_Ads_Select::PLACEMENT :
278 return;
279
280 case Advanced_Ads_Select::GROUP :
281 $class = $prefix . $id;
282 if ( ( isset( $placements[ $id ]['type'] ) && $placements[ $id ]['type'] !== 'header' )
283 && ( !isset( $args['output']['class'] )
284 || !is_array( $args['output']['class'] )
285 || !in_array( $class, $args['output']['class'] ) ) ) {
286 $args['output']['class'][] = $class;
287 }
288 default:
289 }
290
291 // add the placement to the global output array
292 $advads = Advanced_Ads::get_instance();
293 $advads->current_ads[] = array('type' => 'placement', 'id' => $id, 'title' => $placements[ $id ]['name']);
294
295 return Advanced_Ads_Select::get_instance()->get_ad_by_method( (int) $_item[1], $_item[0], $args );
296 }
297 }
298
299 /**
300 * inject ads directly into the content
301 *
302 * @since 1.2.1
303 * @param string $placement_id id of the placement
304 * @param arr $options placement options
305 * @param string $content
306 * @return type
307 * @link inspired by http://www.wpbeginner.com/wp-tutorials/how-to-insert-ads-within-your-post-content-in-wordpress/
308 */
309 public static function &inject_in_content($placement_id, $options, &$content) {
310 // test ad is emtpy
311 $whitespaces = json_decode('"\t\n\r \u00A0"');
312 $adContent = Advanced_Ads_Select::get_instance()->get_ad_by_method( $placement_id, 'placement', $options );
313 if ( trim( $adContent, $whitespaces ) === '' ) {
314 return $content;
315 }
316
317 // parse document as DOM (fragment - having only a part of an actual post given)
318 // -TODO may want to verify the wpcharset is supported by server (mb_list_encodings)
319 // prevent messages from dom parser
320 $wpCharset = get_bloginfo('charset');
321 // check if mbstring exists
322 if ( ! function_exists( 'mb_convert_encoding' ) ) {
323 if ( $wpCharset === "UTF-8" ) {
324 $content = htmlspecialchars_decode( htmlentities( $content, ENT_COMPAT, $wpCharset, false ) );
325 } else {
326 return $content;
327 }
328 } else {
329 $content = mb_convert_encoding( $content, 'HTML-ENTITIES', $wpCharset );
330 }
331
332 // check which priority the wpautop filter has; might have been disabled on purpose
333 $wpautop_priority = has_filter( 'the_content', 'wpautop');
334 if ( $wpautop_priority && Advanced_Ads_Plugin::get_instance()->get_content_injection_priority() < $wpautop_priority ) {
335 $content = wpautop( $content );
336 }
337
338 $dom = new DOMDocument('1.0', $wpCharset);
339 // may loose some fragments or add autop-like code
340 libxml_use_internal_errors(true); // avoid notices and warnings - html is most likely malformed
341 $success = $dom->loadHtml('<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wpCharset . '" /><body>' . $content);
342 libxml_use_internal_errors(false);
343 if ($success !== true) {
344 // -TODO handle cases were dom-parsing failed (at least inform user)
345 return $content;
346 }
347
348 // parse arguments
349 $tag = isset($options['tag']) ? $options['tag'] : 'p';
350 $tag = preg_replace('/[^a-z0-9]/i', '', $tag); // simplify tag
351
352 // allow more complex xPath expression
353 $tag = apply_filters( 'advanced-ads-placement-content-injection-xpath', $tag, $options );
354
355 // only has before and after
356 $before = isset($options['position']) && $options['position'] === 'before';
357 $paragraph_id = isset($options['index']) ? $options['index'] : 1;
358 $paragraph_id = max( 1, (int) $paragraph_id );
359 $paragraph_select_from_bottom = isset($options['start_from_bottom']) && $options['start_from_bottom'];
360
361 // select positions
362 $xpath = new DOMXPath($dom);
363 $items = $xpath->query('/html/body/' . $tag);
364 $offset = null;
365
366 $options = array(
367 'allowEmpty' => false, // whether the tag can be empty to be counted
368 );
369 // if there are too few items at this level test nesting
370 $options['itemLimit'] = $tag === 'p' ? 2 : 1;
371
372 // allow hooks to change some options
373 $options = apply_filters(
374 'advanced-ads-placement-content-injection-options',
375 $options,
376 $tag );
377
378 if ($items->length < $options['itemLimit'] ) {
379 $items = $xpath->query('/html/body/*/' . $tag);
380 }
381 // try third level as last resort
382 if ($items->length < $options['itemLimit']) {
383 $items = $xpath->query('/html/body/*/*/' . $tag);
384 }
385
386 // allow to select other elements
387 $items = apply_filters( 'advanced-ads-placement-content-injection-items', $items, $xpath, $tag );
388
389 // filter empty tags from items
390 $paragraphs = array();
391 foreach ($items as $item) {
392 if ( $options['allowEmpty'] || ( isset($item->textContent) && trim($item->textContent, $whitespaces) !== '' ) ) {
393 $paragraphs[] = $item;
394 }
395 }
396
397 $paragraph_count = count($paragraphs);
398 if ($paragraph_count >= $paragraph_id) {
399 $offset = $paragraph_select_from_bottom ? $paragraph_count - $paragraph_id : $paragraph_id - 1;
400
401 // convert HTML to XML!
402 $adDom = new DOMDocument('1.0', $wpCharset);
403 libxml_use_internal_errors(true);
404 $adDom->loadHtml('<!DOCTYPE html><html><meta http-equiv="Content-Type" content="text/html; charset=' . $wpCharset . '" /><body>' . $adContent);
405 $adNode = $adDom->lastChild->lastChild; // >html>body
406 libxml_use_internal_errors(false);
407 $adContent = $adDom->saveXML($adNode);
408 $adContent = substr($adContent, 6, -7);
409 $adNode = $dom->createDocumentFragment();
410 $adNode->appendXML($adContent);
411
412 // inject
413 $node = apply_filters( 'advanced-ads-placement-content-injection-node', $paragraphs[$offset], $tag, $before );
414 if ($before) {
415 $refNode = $node;
416 $items = $xpath->query('/html/body/' . $tag);
417 $refNode->parentNode->insertBefore($adNode, $refNode);
418 } else {
419 // append before next node or as last child to body
420 $refNode = $node->nextSibling;
421 if (isset($refNode)) {
422 $refNode->parentNode->insertBefore($adNode, $refNode);
423 } else {
424 // append to body; -TODO using here that we only select direct children of the body tag
425 $paragraphs[$offset]->parentNode->appendChild($adNode);
426 }
427 }
428 }
429
430 // convert to text-representation
431 $content = $dom->saveHTML();
432 // remove head and tail (required for dom parser but unwanted for content)
433 $content = substr($content, stripos($content, '<body>') + 6);
434 $content = str_replace(array('</body>', '</html>'), '', $content);
435
436 // no fall-back desired: if there are too few paragraphs do nothing
437
438 // fix shortcode quotes (malformed by backend editor)
439 $matches = array();
440 if (0 < preg_match_all('/\[[^]]+\]/Siu', $content, $matches, PREG_OFFSET_CAPTURE) && isset($matches[0])) {
441 foreach ($matches[0] as $match) {
442 $offset = $match[1];
443 $content = substr($content, 0, $offset) . str_replace(array('', '', '&#8220;', '&quote;', '&#8243;'), '"', $match[0]) . substr($content, $offset + strlen($match[0]));
444 }
445 }
446
447 return $content;
448 }
449
450 /**
451 * check if the placement can be displayed
452 *
453 * @since 1.6.9
454 * @param int $id placement id
455 * @return bool true if placement can be displayed
456 */
457 static function can_display( $id = 0 ){
458 if ( ! isset($id) || $id === 0 ) {
459 return true;
460 }
461
462 return apply_filters( 'advanced-ads-can-display-placement', true, $id );
463 }
464
465 }
466