PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 1.38.0
Advanced Ads – Ad Manager & AdSense v1.38.0
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 / plugin.php
advanced-ads / classes Last commit date
EDD_SL_Plugin_Updater.php 4 years ago ad-ajax.php 3 years ago ad-debug.php 3 years ago ad-expiration.php 3 years ago ad-health-notices.php 3 years ago ad-model.php 3 years ago ad-select.php 3 years ago ad.php 3 years ago ad_ajax_callbacks.php 3 years ago ad_group.php 3 years ago ad_placements.php 3 years ago ad_type_abstract.php 3 years ago ad_type_content.php 3 years ago ad_type_dummy.php 3 years ago ad_type_group.php 3 years ago ad_type_image.php 3 years ago ad_type_plain.php 3 years ago checks.php 3 years ago compatibility.php 3 years ago display-conditions.php 3 years ago filesystem.php 3 years ago frontend-notices.php 3 years ago frontend_checks.php 3 years ago in-content-injector.php 3 years ago inline-css.php 3 years ago plugin.php 3 years ago upgrades.php 6 years ago utils.php 3 years ago visitor-conditions.php 3 years ago widget.php 3 years ago
plugin.php
964 lines
1 <?php
2
3 /**
4 * WordPress integration and definitions:
5 *
6 * - posttypes
7 * - taxonomy
8 * - textdomain
9 */
10 class Advanced_Ads_Plugin {
11 /**
12 * Instance of Advanced_Ads_Plugin
13 *
14 * @var object Advanced_Ads_Plugin
15 */
16 protected static $instance;
17
18 /**
19 * Instance of Advanced_Ads_Model
20 *
21 * @var object Advanced_Ads_Model
22 */
23 protected $model;
24
25 /**
26 * Plugin options
27 *
28 * @var array $options
29 */
30 protected $options;
31
32 /**
33 * Interal plugin options – set by the plugin
34 *
35 * @var array $internal_options
36 */
37 protected $internal_options;
38
39 /**
40 * Default prefix of selectors (id, class) in the frontend
41 * can be changed by options
42 *
43 * @var Advanced_Ads_Plugin
44 */
45 const DEFAULT_FRONTEND_PREFIX = 'advads-';
46
47 /**
48 * Frontend prefix for classes and IDs
49 *
50 * @var string $frontend_prefix
51 */
52 private $frontend_prefix;
53
54 /**
55 * Advanced_Ads_Plugin constructor.
56 */
57 private function __construct() {
58 register_activation_hook( ADVADS_BASE, [ $this, 'activate' ] );
59 register_deactivation_hook( ADVADS_BASE, [ $this, 'deactivate' ] );
60 register_uninstall_hook( ADVADS_BASE, [ 'Advanced_Ads_Plugin', 'uninstall' ] );
61
62 add_action( 'plugins_loaded', [ $this, 'wp_plugins_loaded' ], 20 );
63 add_action( 'init', [ $this, 'run_upgrades' ], 9 );
64 }
65
66 /**
67 * Get instance of Advanced_Ads_Plugin
68 *
69 * @return Advanced_Ads_Plugin
70 */
71 public static function get_instance() {
72 // If the single instance hasn't been set, set it now.
73 if ( null === self::$instance ) {
74 self::$instance = new self();
75 }
76
77 return self::$instance;
78 }
79
80 /**
81 * Get instance of Advanced_Ads_Model
82 *
83 * @param Advanced_Ads_Model $model model to access data.
84 */
85 public function set_model( Advanced_Ads_Model $model ) {
86 $this->model = $model;
87 }
88
89 /**
90 * Execute various hooks after WordPress and all plugins are available
91 */
92 public function wp_plugins_loaded() {
93 // Load plugin text domain.
94 $this->load_plugin_textdomain();
95
96 // activate plugin when new blog is added on multisites // -TODO this is admin-only.
97 add_action( 'wpmu_new_blog', [ $this, 'activate_new_site' ] );
98
99 // Load public-facing style sheet and JavaScript.
100 add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_styles' ] );
101 add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
102 add_action( 'wp_head', [ $this, 'print_head_scripts' ], 7 );
103 // higher priority to make sure other scripts are printed before.
104 add_action( 'wp_footer', [ $this, 'print_footer_scripts' ], 100 );
105
106 // add short codes.
107 add_shortcode( 'the_ad', [ $this, 'shortcode_display_ad' ] );
108 add_shortcode( 'the_ad_group', [ $this, 'shortcode_display_ad_group' ] );
109 add_shortcode( 'the_ad_placement', [ $this, 'shortcode_display_ad_placement' ] );
110
111 // remove default ad group menu item // -TODO only for admin.
112 add_action( 'admin_menu', [ $this, 'remove_taxonomy_menu_item' ] );
113 // load widgets.
114 add_action( 'widgets_init', [ $this, 'widget_init' ] );
115
116 // Call action hooks for ad status changes.
117 add_action( 'transition_post_status', [ $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', [ Advanced_Ads_Ad_Expiration::class, 'wp_untrash_post_status' ], 10, 3 );
124
125 // load display conditions.
126 Advanced_Ads_Display_Conditions::get_instance();
127 new Advanced_Ads_Frontend_Checks();
128 new Advanced_Ads_Compatibility();
129 Advanced_Ads_Ad_Health_Notices::get_instance(); // load to fetch notices.
130 }
131
132 /**
133 * Run upgrades.
134 *
135 * Compatibility with the Piklist plugin that has a function hooked to `posts_where` that access $GLOBALS['wp_query'].
136 * Since `Advanced_Ads_Upgrades` applies `posts_where`: (`Advanced_Ads_Admin_Notices::get_instance()` >
137 * `Advanced_Ads::get_number_of_ads()` > new WP_Query > ... 'posts_where') this function is hooked to `init` so that `$GLOBALS['wp_query']` is instantiated.
138 */
139 public function run_upgrades() {
140 /**
141 * Run upgrades, if this is a new version or version does not exist.
142 */
143 $internal_options = $this->internal_options();
144
145 if ( ! defined( 'DOING_AJAX' ) && ( ! isset( $internal_options['version'] ) || version_compare( $internal_options['version'], ADVADS_VERSION, '<' ) ) ) {
146 new Advanced_Ads_Upgrades();
147 }
148 }
149
150 /**
151 * Register and enqueue public-facing style sheet.
152 */
153 public function enqueue_styles() {
154 // wp_enqueue_style( $this->get_plugin_slug() . '-plugin-styles', plugins_url('assets/css/public.css', __FILE__), array(), ADVADS_VERSION);
155 }
156
157 /**
158 * Return the plugin slug.
159 *
160 * @return string plugin slug variable.
161 */
162 public function get_plugin_slug() {
163 return ADVADS_SLUG;
164 }
165
166 /**
167 * Register and enqueues public-facing JavaScript files.
168 */
169 public function enqueue_scripts() {
170 if ( advads_is_amp() ) {
171 return;
172 }
173 // wp_enqueue_script( $this->get_plugin_slug() . '-plugin-script', plugins_url('assets/js/public.js', __FILE__), array('jquery'), ADVADS_VERSION);
174
175 wp_register_script(
176 $this->get_plugin_slug() . '-advanced-js',
177 sprintf( '%spublic/assets/js/advanced%s.js', ADVADS_BASE_URL, defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ),
178 [ 'jquery' ],
179 ADVADS_VERSION,
180 false
181 );
182
183 $privacy = Advanced_Ads_Privacy::get_instance();
184 $privacy_options = $privacy->options();
185 $privacy_options['enabled'] = ! empty( $privacy_options['enabled'] );
186 $privacy_options['state'] = $privacy->get_state();
187
188 wp_localize_script(
189 $this->get_plugin_slug() . '-advanced-js',
190 'advads_options',
191 [
192 'blog_id' => get_current_blog_id(),
193 'privacy' => $privacy_options,
194 ]
195 );
196
197 $activated_js = apply_filters( 'advanced-ads-activate-advanced-js', isset( $this->options()['advanced-js'] ) );
198
199 if ( $activated_js || ! empty( $_COOKIE['advads_frontend_picker'] ) ) {
200 wp_enqueue_script( $this->get_plugin_slug() . '-advanced-js' );
201 }
202
203 wp_register_script(
204 $this->get_plugin_slug() . '-frontend-picker',
205 sprintf( '%spublic/assets/js/frontend-picker%s.js', ADVADS_BASE_URL, defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min' ),
206 [ 'jquery', $this->get_plugin_slug() . '-advanced-js' ],
207 ADVADS_VERSION,
208 false
209 );
210
211 if ( ! empty( $_COOKIE['advads_frontend_picker'] ) ) {
212 wp_enqueue_script( $this->get_plugin_slug() . '-frontend-picker' );
213 }
214 }
215
216 /**
217 * Print public-facing JavaScript in the HTML head.
218 */
219 public function print_head_scripts() {
220 $short_url = self::get_short_url();
221 $attribution = '<!-- ' . $short_url . ' is managing ads with Advanced Ads%1$s%2$s -->';
222 $version = self::is_new_user( 1585224000 ) ? ' ' . ADVADS_VERSION : '';
223 $plugin_url = self::get_group_by_url( $short_url, 'a' ) ? '' . ADVADS_URL : '';
224 // escaping would break HTML comment tags so we disable checks here.
225 // phpcs:ignore
226 echo apply_filters( 'advanced-ads-attribution', sprintf( $attribution, $version, $plugin_url ) );
227
228 if ( advads_is_amp() ) {
229 return;
230 }
231
232 ob_start();
233 ?>
234 <script id="<?php echo esc_attr( $this->get_frontend_prefix() ); ?>ready">
235 <?php
236 readfile( sprintf(
237 '%spublic/assets/js/ready%s.js',
238 ADVADS_BASE_PATH,
239 defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'
240 ) );
241 ?>
242 </script>
243 <?php
244 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaping would break the HTML
245 echo Advanced_Ads_Utils::get_inline_asset( ob_get_clean() );
246 }
247
248 /**
249 * Print inline scripts in wp_footer.
250 */
251 public function print_footer_scripts() {
252 if ( advads_is_amp() ) {
253 return;
254 }
255
256 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaping would break the HTML
257 echo Advanced_Ads_Utils::get_inline_asset(
258 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- we're getting the contents of a local file
259 sprintf( '<script>%s</script>', file_get_contents( sprintf(
260 '%spublic/assets/js/ready-queue%s.js',
261 ADVADS_BASE_PATH,
262 defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'
263 ) ) )
264 );
265 }
266
267 /**
268 * Register the Advanced Ads widget
269 */
270 public function widget_init() {
271 register_widget( 'Advanced_Ads_Widget' );
272 }
273
274 /**
275 * Fired when a new site is activated with a WPMU environment.
276 *
277 * @param int $blog_id ID of the new blog.
278 */
279 public function activate_new_site( $blog_id ) {
280
281 if ( 1 !== did_action( 'wpmu_new_blog' ) ) {
282 return;
283 }
284
285 switch_to_blog( $blog_id );
286 $this->single_activate();
287 restore_current_blog();
288 }
289
290 /**
291 * Fired for each blog when the plugin is activated.
292 */
293 protected function single_activate() {
294 // $this->post_types_rewrite_flush();
295 // -TODO inform modules
296 $this->create_capabilities();
297 }
298
299 /**
300 * Fired for each blog when the plugin is deactivated.
301 */
302 protected function single_deactivate() {
303 // -TODO inform modules
304 $this->remove_capabilities();
305 }
306
307 /**
308 * Load the plugin text domain for translation.
309 */
310 public function load_plugin_textdomain() {
311 load_plugin_textdomain( 'advanced-ads', false, ADVADS_BASE_DIR . '/languages' );
312 }
313
314 /**
315 * Fired when the plugin is activated.
316 *
317 * @param boolean $network_wide True if WPMU superadmin uses
318 * "Network Activate" action, false if
319 * WPMU is disabled or plugin is
320 * activated on an individual blog.
321 */
322 public function activate( $network_wide ) {
323 if ( function_exists( 'is_multisite' ) && is_multisite() ) {
324
325 if ( $network_wide ) {
326 // get all blog ids.
327 global $wpdb;
328 $blog_ids = $wpdb->get_col( "SELECT blog_id FROM {$wpdb->blogs}" );
329 $original_blog_id = $wpdb->blogid;
330
331 foreach ( $blog_ids as $blog_id ) {
332 switch_to_blog( $blog_id );
333 $this->single_activate();
334 }
335
336 switch_to_blog( $original_blog_id );
337 } else {
338 $this->single_activate();
339 }
340 } else {
341 $this->single_activate();
342 }
343 }
344
345 /**
346 * Fired when the plugin is deactivated.
347 *
348 * @param boolean $network_wide true if Advanced Ads should be disabled network-wide.
349 *
350 * True if WPMU superadmin uses
351 * "Network Deactivate" action, false if
352 * WPMU is disabled or plugin is
353 * deactivated on an individual blog.
354 */
355 public function deactivate( $network_wide ) {
356 if ( function_exists( 'is_multisite' ) && is_multisite() ) {
357
358 if ( $network_wide ) {
359 // get all blog ids.
360 global $wpdb;
361 $blog_ids = $wpdb->get_col( "SELECT blog_id FROM {$wpdb->blogs}" );
362 $original_blog_id = $wpdb->blogid;
363
364 foreach ( $blog_ids as $blog_id ) {
365 switch_to_blog( $blog_id );
366 $this->single_deactivate();
367 }
368
369 switch_to_blog( $original_blog_id );
370 } else {
371 $this->single_deactivate();
372 }
373 } else {
374 $this->single_deactivate();
375 }
376 }
377
378 /**
379 * Remove WP tag edit page for the ad group taxonomy
380 * needed, because we can’t remove it with `show_ui` without also removing the meta box
381 */
382 public function remove_taxonomy_menu_item() {
383 remove_submenu_page( 'edit.php?post_type=advanced_ads', 'edit-tags.php?taxonomy=advanced_ads_groups&amp;post_type=advanced_ads' );
384 }
385
386 /**
387 * Shortcode to include ad in frontend
388 *
389 * @param array $atts shortcode attributes.
390 *
391 * @return string ad content.
392 */
393 public function shortcode_display_ad( $atts ) {
394 $atts = is_array( $atts ) ? $atts : [];
395 $id = isset( $atts['id'] ) ? (int) $atts['id'] : 0;
396 // check if there is an inline attribute with or without value.
397 if ( isset( $atts['inline'] ) || in_array( 'inline', $atts, true ) ) {
398 $atts['inline_wrapper_element'] = true;
399 }
400 $atts = $this->prepare_shortcode_atts( $atts );
401
402 // use the public available function here.
403 return get_ad( $id, $atts );
404 }
405
406 /**
407 * Shortcode to include ad from an ad group in frontend
408 *
409 * @param array $atts shortcode attributes.
410 *
411 * @return string ad group content.
412 */
413 public function shortcode_display_ad_group( $atts ) {
414 $atts = is_array( $atts ) ? $atts : [];
415 $id = isset( $atts['id'] ) ? (int) $atts['id'] : 0;
416 $atts = $this->prepare_shortcode_atts( $atts );
417
418 // use the public available function here.
419 return get_ad_group( $id, $atts );
420 }
421
422 /**
423 * Shortcode to display content of an ad placement in frontend
424 *
425 * @param array $atts shortcode attributes.
426 *
427 * @return string ad placement content.
428 */
429 public function shortcode_display_ad_placement( $atts ) {
430 $atts = is_array( $atts ) ? $atts : [];
431 $id = isset( $atts['id'] ) ? (string) $atts['id'] : '';
432 $atts = $this->prepare_shortcode_atts( $atts );
433
434 // use the public available function here.
435 return get_ad_placement( $id, $atts );
436 }
437
438 /**
439 * Prepare shortcode attributes.
440 *
441 * @param array $atts array with strings.
442 *
443 * @return array
444 */
445 private function prepare_shortcode_atts( $atts ) {
446 $result = [];
447
448 /**
449 * Prepare attributes by converting strings to multi-dimensional array
450 * Example: [ 'output__margin__top' => 1 ] => ['output']['margin']['top'] = 1
451 */
452 if ( ! defined( 'ADVANCED_ADS_DISABLE_CHANGE' ) || ! ADVANCED_ADS_DISABLE_CHANGE ) {
453 foreach ( $atts as $attr => $data ) {
454 $levels = explode( '__', $attr );
455 $last = array_pop( $levels );
456
457 $cur_lvl = &$result;
458
459 foreach ( $levels as $lvl ) {
460 if ( ! isset( $cur_lvl[ $lvl ] ) ) {
461 $cur_lvl[ $lvl ] = [];
462 }
463
464 $cur_lvl = &$cur_lvl[ $lvl ];
465 }
466
467 $cur_lvl[ $last ] = $data;
468 }
469
470 $result = array_diff_key(
471 $result,
472 [
473 'id' => false,
474 'blog_id' => false,
475 'ad_args' => false,
476 ]
477 );
478 }
479
480 // Ad type: 'content' and a shortcode inside.
481 if ( isset( $atts['ad_args'] ) ) {
482 $result = array_merge( $result, json_decode( urldecode( $atts['ad_args'] ), true ) );
483
484 }
485
486 return $result;
487 }
488
489 /**
490 * Return plugin options
491 * these are the options updated by the user
492 *
493 * @return array $options
494 */
495 public function options() {
496 // we can’t store options if WPML String Translations is enabled, or it would not translate the "Ad Label" option.
497 if ( ! isset( $this->options ) || class_exists( 'WPML_ST_String' ) ) {
498 $this->options = get_option( ADVADS_SLUG, [] );
499 }
500
501 // allow to change options dynamically
502 $this->options = apply_filters( 'advanced-ads-options', $this->options );
503
504 return $this->options;
505 }
506
507 /**
508 * Update plugin options (not for settings page, but if automatic options are needed)
509 *
510 * @param array $options new options.
511 */
512 public function update_options( array $options ) {
513 // do not allow to clear options.
514 if ( [] === $options ) {
515 return;
516 }
517
518 $this->options = $options;
519 update_option( ADVADS_SLUG, $options );
520 }
521
522 /**
523 * Return internal plugin options
524 * these are options set by the plugin
525 *
526 * @return array $options
527 */
528 public function internal_options() {
529 if ( ! isset( $this->internal_options ) ) {
530 $defaults = [
531 'version' => ADVADS_VERSION,
532 'installed' => time(), // when was this installed.
533 ];
534 $this->internal_options = get_option( ADVADS_SLUG . '-internal', [] );
535
536 // save defaults.
537 if ( [] === $this->internal_options ) {
538 $this->internal_options = $defaults;
539 $this->update_internal_options( $this->internal_options );
540
541 self::get_instance()->create_capabilities();
542 }
543
544 // for versions installed prior to 1.5.3 set installed date for now.
545 if ( ! isset( $this->internal_options['installed'] ) ) {
546 $this->internal_options['installed'] = time();
547 $this->update_internal_options( $this->internal_options );
548 }
549 }
550
551 return $this->internal_options;
552 }
553
554 /**
555 * Update internal plugin options
556 *
557 * @param array $options new internal options.
558 */
559 public function update_internal_options( array $options ) {
560 // do not allow to clear options.
561 if ( [] === $options ) {
562 return;
563 }
564
565 $this->internal_options = $options;
566 update_option( ADVADS_SLUG . '-internal', $options );
567 }
568
569 /**
570 * Get prefix used for frontend elements
571 *
572 * @return string
573 */
574 public function get_frontend_prefix() {
575 if ( isset( $this->frontend_prefix ) ) {
576 return $this->frontend_prefix;
577 }
578
579 $options = $this->options();
580
581 if ( ! isset( $options['front-prefix'] ) ) {
582 if ( isset( $options['id-prefix'] ) ) {
583 // deprecated: keeps widgets working that previously received an id based on the front-prefix.
584 $frontend_prefix = $options['id-prefix'];
585 } else {
586 $frontend_prefix = preg_match( '/[A-Za-z][A-Za-z0-9_]{4}/', parse_url( get_home_url(), PHP_URL_HOST ), $result )
587 ? $result[0] . '-'
588 : self::DEFAULT_FRONTEND_PREFIX;
589 }
590 } else {
591 $frontend_prefix = $options['front-prefix'];
592 }
593 /**
594 * Applying the filter here makes sure that it is the same frontend prefix for all
595 * calls on this page impression
596 *
597 * @param string $frontend_prefix
598 */
599 $this->frontend_prefix = (string) apply_filters( 'advanced-ads-frontend-prefix', $frontend_prefix );
600 $this->frontend_prefix = $this->sanitize_frontend_prefix( $frontend_prefix );
601
602 return $this->frontend_prefix;
603 }
604
605 /**
606 * Sanitize the frontend prefix to result in valid HTML classes.
607 * See https://www.w3.org/TR/selectors-3/#grammar for valid tokens.
608 *
609 * @param string $prefix The HTML class to sanitize.
610 * @param string $fallback The fallback if the class is invalid.
611 *
612 * @return string
613 */
614 public function sanitize_frontend_prefix( $prefix, $fallback = '' ) {
615 $prefix = sanitize_html_class( $prefix );
616 $nonascii = '[^\0-\177]';
617 $unicode = '\\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?';
618 $escape = sprintf( '%s|\\[^\n\r\f0-9a-f]', $unicode );
619 $nmstart = sprintf( '[_a-z]|%s|%s', $nonascii, $escape );
620 $nmchar = sprintf( '[_a-z0-9-]|%s|%s', $nonascii, $escape );
621
622 if ( ! preg_match( sprintf( '/-?(?:%s)(?:%s)*/i', $nmstart, $nmchar ), $prefix, $matches ) ) {
623 return $fallback;
624 }
625
626 return $matches[0];
627 }
628
629 /**
630 * Get priority used for injection inside content
631 */
632 public function get_content_injection_priority() {
633 $options = $this->options();
634
635 return isset( $options['content-injection-priority'] ) ? (int) $options['content-injection-priority'] : 100;
636 }
637
638 /**
639 * Returns the capability needed to perform an action
640 *
641 * @param string $capability a capability to check, can be internal to Advanced Ads.
642 *
643 * @return string $capability a valid WordPress capability.
644 */
645 public static function user_cap( $capability = 'manage_options' ) {
646
647 global $advanced_ads_capabilities;
648
649 // admins can do everything.
650 // is also a fallback if no option or more specific capability is given.
651 if ( current_user_can( 'manage_options' ) ) {
652 return 'manage_options';
653 }
654
655 return apply_filters( 'advanced-ads-capability', $capability );
656 }
657
658 /**
659 * Create roles and capabilities
660 */
661 public function create_capabilities() {
662 if ( $role = get_role( 'administrator' ) ) {
663 $role->add_cap( 'advanced_ads_manage_options' );
664 $role->add_cap( 'advanced_ads_see_interface' );
665 $role->add_cap( 'advanced_ads_edit_ads' );
666 $role->add_cap( 'advanced_ads_manage_placements' );
667 $role->add_cap( 'advanced_ads_place_ads' );
668 }
669 }
670
671 /**
672 * Remove roles and capabilities
673 */
674 public function remove_capabilities() {
675 if ( $role = get_role( 'administrator' ) ) {
676 $role->remove_cap( 'advanced_ads_manage_options' );
677 $role->remove_cap( 'advanced_ads_see_interface' );
678 $role->remove_cap( 'advanced_ads_edit_ads' );
679 $role->remove_cap( 'advanced_ads_manage_placements' );
680 $role->remove_cap( 'advanced_ads_place_ads' );
681 }
682 }
683
684 /**
685 * Fired when the plugin is uninstalled.
686 */
687 public static function uninstall() {
688 $advads_options = Advanced_Ads::get_instance()->options();
689
690 if ( ! empty( $advads_options['uninstall-delete-data'] ) ) {
691 global $wpdb;
692 $main_blog_id = $wpdb->blogid;
693
694 Advanced_Ads::get_instance()->create_post_types();
695
696 if ( ! is_multisite() ) {
697 self::get_instance()->uninstall_single();
698 } else {
699 $blog_ids = $wpdb->get_col( "SELECT blog_id FROM {$wpdb->blogs}" );
700
701 foreach ( $blog_ids as $blog_id ) {
702 switch_to_blog( $blog_id );
703 self::get_instance()->uninstall_single();
704 }
705 switch_to_blog( $main_blog_id );
706 }
707
708 // Delete assets (main blog).
709 Advanced_Ads_Ad_Blocker_Admin::get_instance()->clear_assets();
710 }
711
712 }
713
714 /**
715 * Fired for each blog when the plugin is uninstalled.
716 */
717 protected function uninstall_single() {
718 global $wpdb;
719
720 // Ads.
721 $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s", Advanced_Ads::POST_TYPE_SLUG ) );
722
723 if ( $post_ids ) {
724 $wpdb->delete(
725 $wpdb->posts,
726 [ 'post_type' => Advanced_Ads::POST_TYPE_SLUG ],
727 [ '%s' ]
728 );
729
730 $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN( %s )", implode( ',', $post_ids ) ) );
731 }
732
733 // Groups.
734 $term_ids = $wpdb->get_col( $wpdb->prepare( "SELECT t.term_id FROM {$wpdb->terms} AS t INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s", Advanced_Ads::AD_GROUP_TAXONOMY ) );
735
736 foreach ( $term_ids as $term_id ) {
737 wp_delete_term( $term_id, Advanced_Ads::AD_GROUP_TAXONOMY );
738 }
739
740 delete_option( 'advanced-ads' );
741 delete_option( 'advanced-ads-internal' );
742 delete_option( 'advanced-ads-notices' );
743 delete_option( 'advads-ad-groups' );
744 delete_option( 'advanced_ads_groups_children' );
745 delete_option( 'advads-ad-weights' );
746 delete_option( 'advanced_ads_ads_txt' );
747 delete_option( 'advanced-ads-ad-health-notices' );
748 delete_option( 'advanced-ads-adsense' );
749 delete_option( 'advanced_ads_adsense_report_domain' );
750 delete_option( 'advanced_ads_adsense_report_unit' );
751 delete_option( 'advanced-ads-adsense-dashboard-filter' );
752 delete_option( 'advanced-ads-adsense-mapi' );
753 delete_option( 'advanced-ads-licenses' );
754 delete_option( 'advanced-ads-ab-module' );
755 delete_option( 'widget_' . Advanced_Ads_Widget::get_base_id() );
756 delete_option( 'advads-ads-placements' );
757
758 // User metadata.
759 delete_metadata( 'user', null, 'advanced-ads-hide-wizard', '', true );
760 delete_metadata( 'user', null, 'advanced-ads-subscribed', '', true );
761 delete_metadata( 'user', null, 'advanced-ads-ad-list-screen-options', '', true );
762 delete_metadata( 'user', null, 'advanced-ads-admin-settings', '', true );
763 delete_metadata( 'user', null, 'advanced-ads-role', '', true );
764 delete_metadata( 'user', null, 'edit_advanced_ads_per_page', '', true );
765 delete_metadata( 'user', null, 'meta-box-order_advanced_ads', '', true );
766 delete_metadata( 'user', null, 'screen_layout_advanced_ads', '', true );
767 delete_metadata( 'user', null, 'closedpostboxes_advanced_ads', '', true );
768 delete_metadata( 'user', null, 'metaboxhidden_advanced_ads', '', true );
769
770 // Post metadata.
771 delete_metadata( 'post', null, '_advads_ad_settings', '', true );
772
773 // Transients.
774 delete_transient( 'advanced-ads_add-on-updates-checked' );
775
776 do_action( 'advanced-ads-uninstall' );
777
778 wp_cache_flush();
779 }
780
781 /**
782 * Check if any add-on is activated
783 *
784 * @return bool true if there is any add-on activated
785 */
786 public static function any_activated_add_on() {
787 return ( defined( 'AAP_VERSION' ) // Advanced Ads Pro.
788 || defined( 'AAGAM_VERSION' ) // Google Ad Manager.
789 || defined( 'AASA_VERSION' ) // Selling Ads.
790 || defined( 'AAT_VERSION' ) // Tracking.
791 || defined( 'AASADS_VERSION' ) // Sticky Ads.
792 || defined( 'AAR_VERSION' ) // Responsive Ads.
793 || defined( 'AAPLDS_VERSION' ) // PopUp and Layer Ads.
794 );
795 }
796
797 /**
798 * Get the correct support URL: wp.org for free users and website for those with any add-on installed
799 *
800 * @param string $utm add UTM parameter to the link leading to https://wpadvancedads.com, if given.
801 *
802 * @return string URL.
803 */
804 public static function support_url( $utm = '' ) {
805
806 $utm = empty( $utm ) ? '?utm_source=advanced-ads&utm_medium=link&utm_campaign=support' : $utm;
807 if ( self::any_activated_add_on() ) {
808 $url = ADVADS_URL . 'support/' . $utm . '-with-addons';
809 } else {
810 $url = ADVADS_URL . 'support/' . $utm . '-free-user';
811 }
812
813 return $url;
814 }
815
816 /**
817 * Create a random group
818 *
819 * @param string $url optional parameter.
820 * @param string $ex group.
821 *
822 * @return bool
823 */
824 public static function get_group_by_url( $url = '', $ex = 'a' ) {
825
826 $url = self::get_short_url( $url );
827
828 $code = intval( substr( md5( $url ), - 1 ), 16 );
829
830 switch ( $ex ) {
831 case 'b':
832 return ( $code & 2 ) >> 1; // returns 1 or 0.
833 case 'c':
834 return ( $code & 4 ) >> 2; // returns 1 or 0.
835 case 'd':
836 return ( $code & 8 ) >> 3; // returns 1 or 0.
837 default:
838 return $code & 1; // returns 1 or 0.
839 }
840 }
841
842 /**
843 * Check if user started after a given date
844 *
845 * @param integer $timestamp time stamp.
846 *
847 * @return bool true if user is added after timestamp.
848 */
849 public static function is_new_user( $timestamp = 0 ) {
850
851 // allow admins to see version for new users in any case.
852 if ( current_user_can( self::user_cap( 'advanced_ads_manage_options' ) )
853 && isset( $_REQUEST['advads-ignore-timestamp'] ) ) {
854 return true;
855 }
856
857 $timestamp = absint( $timestamp );
858
859 $options = self::get_instance()->internal_options();
860 $installed = isset( $options['installed'] ) ? $options['installed'] : 0;
861
862 return ( $installed >= $timestamp );
863 }
864
865 /**
866 * Show stuff to new users only.
867 *
868 * @param integer $timestamp time after which to show whatever.
869 * @param string $group optional group.
870 *
871 * @return bool true if user enabled after given timestamp.
872 */
873 public static function show_to_new_users( $timestamp, $group = 'a' ) {
874
875 return ( self::get_group_by_url( null, $group ) && self::is_new_user( $timestamp ) );
876 }
877
878 /**
879 * Get short version of home_url()
880 * remove protocol and www
881 * remove slash
882 *
883 * @param string $url URL to be shortened.
884 *
885 * @return string
886 */
887 public static function get_short_url( $url = '' ) {
888
889 $url = empty( $url ) ? home_url() : $url;
890
891 // strip protocols.
892 if ( preg_match( '/^(\w[\w\d]*:\/\/)?(www\.)?(.*)$/', trim( $url ), $matches ) ) {
893 $url = $matches[3];
894 }
895
896 // strip slashes.
897 $url = trim( $url, '/' );
898
899 return $url;
900 }
901
902 /**
903 * Return Advanced Ads logo in base64 format for use in WP Admin menu.
904 *
905 * @return string
906 */
907 public static function get_icon_svg() {
908 return 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE4LjEuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJFYmVuZV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDY0Ljk5MyA2NS4wMjQiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDY0Ljk5MyA2NS4wMjQ7IiB4bWw6c3BhY2U9InByZXNlcnZlIj4NCjxwYXRoIHN0eWxlPSJmaWxsOiNFNEU0RTQ7IiBkPSJNNDYuNTcxLDI3LjY0MXYyMy4xMzNIMTQuMjVWMTguNDUzaDIzLjExOGMtMC45NTYtMi4xODMtMS40OTQtNC41OS0xLjQ5NC03LjEyNg0KCWMwLTIuNTM1LDAuNTM4LTQuOTQyLDEuNDk0LTcuMTI0aC02Ljk1N0gwdjQ5LjQ5M2wxLjYxOCwxLjYxOEwwLDUzLjY5NmMwLDYuMjU2LDUuMDY4LDExLjMyNiwxMS4zMjQsMTEuMzI4djBoMTkuMDg3aDMwLjQxMlYyNy42MTENCgljLTIuMTkxLDAuOTY0LTQuNjA5LDEuNTA5LTcuMTU3LDEuNTA5QzUxLjE0MiwyOS4xMiw0OC43NDYsMjguNTg4LDQ2LjU3MSwyNy42NDF6Ii8+DQo8Y2lyY2xlIHN0eWxlPSJmaWxsOiM5ODk4OTg7IiBjeD0iNTMuNjY2IiBjeT0iMTEuMzI4IiByPSIxMS4zMjgiLz4NCjwvc3ZnPg0K';
909 }
910
911 /**
912 * Fires when a post is transitioned from one status to another.
913 *
914 * @param string $new_status New post status.
915 * @param string $old_status Old post status.
916 * @param WP_Post $post Post object.
917 */
918 public function transition_ad_status( $new_status, $old_status, $post ) {
919 if ( ! isset( $post->post_type ) || Advanced_Ads::POST_TYPE_SLUG !== $post->post_type || ! isset( $post->ID ) ) {
920 return;
921 }
922
923 $ad = new Advanced_Ads_Ad( $post->ID );
924
925 if ( $old_status !== $new_status ) {
926 /**
927 * Fires when an ad has transitioned from one status to another.
928 *
929 * @param Advanced_Ads_Ad $ad Ad object.
930 */
931 do_action( "advanced-ads-ad-status-{$old_status}-to-{$new_status}", $ad );
932 }
933
934 if ( 'publish' === $new_status && 'publish' !== $old_status ) {
935 /**
936 * Fires when an ad has transitioned from any other status to `publish`.
937 *
938 * @param Advanced_Ads_Ad $ad Ad object.
939 */
940 do_action( 'advanced-ads-ad-status-published', $ad );
941 }
942
943 if ( 'publish' === $old_status && 'publish' !== $new_status ) {
944 /**
945 * Fires when an ad has transitioned from `publish` to any other status.
946 *
947 * @param Advanced_Ads_Ad $ad Ad object.
948 */
949 do_action( 'advanced-ads-ad-status-unpublished', $ad );
950 }
951
952 if ( $old_status === 'publish' && $new_status === Advanced_Ads_Ad_Expiration::POST_STATUS ) {
953 /**
954 * Fires when an ad is expired.
955 *
956 * @param int $id
957 * @param Advanced_Ads_Ad $ad
958 */
959 do_action( 'advanced-ads-ad-expired', $ad->id, $ad );
960 }
961 }
962
963 }
964