PluginProbe
Taboola / 3.0.1
Taboola v3.0.1
1.0.4 1.0.5 1.0.6 1.0.8 2.0.1 2.0.2 2.1.0 2.1.1 2.2.2 2.2.3 3.0.0 3.0.1 3.0.2 3.1.0 trunk 1.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.2 1.0.3
taboola / taboola_widget.php

taboola_widget.php in Taboola 3.0.1, at taboola_widget.php

980 lines 42.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Taboola
4 * Plugin URI: https://developers.taboola.com/web-integrations/docs/wordpress-plugin
5 * Description: Taboola
6 * Version: 3.0.1
7 * Author: Taboola
8 */
9
10 define( 'TABOOLA_PLUGIN_VERSION', '3.0.1' ); // track every release
11 define( 'TABOOLA_MIN_VER', '3.0' ); // bump only when DB changes
12 define( 'TABOOLA_DEBUG_MODE', false );
13
14 define( 'TABOOLA_OPTION_NAME', 'taboola_plugin_version' );
15
16 define( 'TABOOLA_XPATH_MARKER', '/' );
17 define( 'TABOOLA_JS_INDICATOR', '{JS}' );
18 define( 'TABOOLA_JS_MARKER', '{' );
19 define( 'TABOOLA_CONTENT_FORMAT_STRING', 'string' );
20 define( 'TABOOLA_CONTENT_FORMAT_SCRIPT', 'script' );
21 define( 'TABOOLA_CONTENT_FORMAT_HTML', 'html' );
22
23 include_once 'widget.php';
24 require_once 'JavaScriptWrapper.php';
25 require_once plugin_dir_path( __FILE__ ) . 'simple_html_dom.php'; // ← NEW
26
27 if ( ! class_exists( 'TaboolaWP' ) ) {
28 class TaboolaWP {
29
30 /* ─────────────────────────── properties ─────────────────────────── */
31 public $data = [];
32 public $_is_widget_on_page;
33 public $_is_head_script_loaded = false;
34
35 private $tpl_sw = 'importScripts("https://cdn.taboola.com/webpush/tsw.js");';
36 private $msg_sw_error = <<<SWE
37 <p>The file <code>sw.js</code> in the WP root is not writable.
38 Please change its permissions or paste the code below manually:</p>
39 <pre><code>{{SW}}</code></pre>
40 <p>Also make sure it's reachable at <code>{{DOMAIN}}/sw.js</code></p>
41 SWE;
42
43 public $plugin_name;
44 public $plugin_directory;
45 public $plugin_url;
46 public $settings;
47 public $tbl_taboola_settings;
48
49 /* ─────────────────────────── constructor ─────────────────────────── */
50 public function __construct() {
51 global $wpdb;
52 //initialize plugin constant
53 define( 'TaboolaWP', true );
54
55 $this->_is_widget_on_page = false;
56 $this->_is_head_script_loaded = false;
57
58 $this->plugin_name = plugin_basename( __FILE__ );
59 $this->plugin_directory = plugin_dir_path( __FILE__ );
60 $this->plugin_url = trailingslashit(
61 WP_PLUGIN_URL . '/' . dirname( plugin_basename( __FILE__ ) )
62 );
63 $this->tbl_taboola_settings = $wpdb->prefix . '_taboola_settings';
64 $this->settings = $wpdb->get_row(
65 "SELECT * FROM {$this->tbl_taboola_settings} LIMIT 1"
66 );
67
68 /* activation / upgrade */
69 register_activation_hook( $this->plugin_name, [ $this, 'update_db' ] );
70 add_action( 'admin_init', [ $this, 'update_db' ] );
71
72 /* widgets */
73 if ( $this->settings && ! empty( $this->settings->publisher_id ) ) {
74 add_action(
75 'widgets_init',
76 static fn() => register_widget( 'WP_Widget_Taboola' )
77 );
78 }
79
80 /* admin vs front-end hooks */
81 if ( is_admin() ) {
82 add_action( 'admin_menu', [ $this, 'admin_generate_menu' ] );
83 add_filter( 'plugin_action_links',
84 [ $this, 'plugin_action_links' ], 10, 2 );
85 }
86
87
88
89
90 elseif ( $this->settings ) {
91 /* loader & flush */
92 add_action( 'wp_head', [ $this, 'taboola_header_loader_inject' ] );
93 if ( ! empty( $this->settings->publisher_id_push ) ) {
94 add_action( 'wp_head', [ $this, 'taboola_webpush_loader_js' ] );
95
96 $sw = 'sw.js';
97 $sw_path = ABSPATH . $sw;
98
99 $content = file_exists( $sw_path ) ? file_get_contents( $sw_path ) : '';
100
101 if ( strpos( $content, $this->tpl_sw ) === false ) {
102 if ( ! is_writable( ABSPATH ) || ( file_exists( $sw_path ) && ! is_writable( $sw_path ) ) ) {
103 return $this->notice( $this->msg_sw_error );
104 }
105 $content = $this->tpl_sw . PHP_EOL . $content;
106 if ( file_put_contents( $sw_path, $content ) === false ) {
107 return $this->notice( $this->msg_sw_error );
108 }
109 }
110 }
111 add_action( 'wp_footer', [ $this, 'taboola_footer_loader_js' ] );
112
113 /* content widgets */
114 add_filter( 'the_content', [ $this, 'load_taboola_content' ] );
115 add_filter( 'the_content', [ $this, 'load_taboola_content_mid' ] );
116
117 /* full-page buffer – home & category */
118 add_action( 'template_redirect', [ $this, 'tb_home_buffer_start' ], 0 );
119 add_action( 'shutdown', [ $this, 'tb_home_buffer_flush' ], PHP_INT_MAX );
120
121 add_action( 'template_redirect', [ $this, 'tb_cat_buffer_start' ], 0 );
122 add_action( 'shutdown', [ $this, 'tb_cat_buffer_flush' ], PHP_INT_MAX );
123 }
124 } // __construct
125
126
127 /* ======================================================================
128 CATEGORY ▸ should we show the widget?
129 ====================================================================== */
130 private function should_show_content_widget_category(): bool {
131 return (
132 trim( $this->settings->publisher_id ) !== '' &&
133 ( is_category() || is_archive() || is_search() ) &&
134 $this->settings->category_enabled &&
135 trim( $this->settings->category_widget_id ) !== ''
136 );
137 }
138
139 /* ----------------------------------------------------------------------
140 HOMEPAGE ▸ full-page buffer
141 -------------------------------------------------------------------- */
142 public function tb_home_buffer_start() {
143 if ( $this->should_show_content_widget_home() ) {
144 ob_start( [ $this, 'tb_home_buffer_inject' ] );
145 }
146 }
147 public function tb_home_buffer_inject( $html ) {
148 return $this->load_taboola_content_home( $html );
149 }
150
151 /* ----------------------------------------------------------------------
152 CATEGORY ▸ buffer hooks
153 -------------------------------------------------------------------- */
154 public function tb_cat_buffer_start() {
155 if ( $this->should_show_content_widget_category() ) {
156 ob_start( [ $this, 'tb_cat_buffer_inject' ] );
157 }
158 }
159 public function tb_cat_buffer_inject( $html ) {
160 return $this->load_taboola_content_category( $html );
161 }
162 public function tb_cat_buffer_flush() {
163 if ( ob_get_length() ) {
164 echo ob_get_clean();
165 }
166 }
167
168 /* ----------------------------------------------------------------------
169 CATEGORY ▸ choose where to inject
170 -------------------------------------------------------------------- */
171 private function embed_taboola_content_location_category(
172 string $html,
173 array $taboola_content,
174 string $selector ) : string {
175
176 $formatted = $this->format_taboola_content_category( $taboola_content );
177
178 /* A. no selector → bottom of page */
179 if ( $selector === '' ) {
180 return str_ireplace( '</body>', $formatted . '</body>', $html );
181 }
182
183 /* B. selector given → try server-side injection */
184 $doc = str_get_html( $html );
185 if ( ! $doc ) {
186 // parser failed → graceful fallback
187 return str_ireplace( '</body>', $formatted . '</body>', $html );
188 }
189
190 $occurrence = max( 0, $this->settings->category_location_string_occurrence - 1 );
191 $target = $doc->find( $selector, $occurrence );
192
193 if ( $target ) { // selector found
194 $target->outertext .= $formatted;
195 return (string) $doc; // done – no duplicate
196 }
197
198 /* C. selector not found → bottom of page */
199 return str_ireplace( '</body>', $formatted . '</body>', $html );
200 }
201
202 /* ------------------------------------------------------------------ */
203 public function tb_home_buffer_flush() {
204 if ( ob_get_length() ) {
205 echo ob_get_clean();
206 }
207 }
208
209
210
211
212 function plugin_action_links($links, $file) {
213 static $this_plugin;
214
215 if (!$this_plugin) {
216 $this_plugin = plugin_basename(__FILE__);
217 }
218
219 if ($file == $this_plugin) {
220 $settings_link = '<a href="' . get_bloginfo('wpurl') . '/wp-admin/options-general.php?page=taboola_widget">Settings</a>';
221 array_unshift($links, $settings_link);
222 }
223
224 return $links;
225 }
226
227 private function should_show_content_widget(){
228 $retVal = ((trim($this->settings->publisher_id) != '') && is_single() && $this->settings->first_bc_enabled && trim($this->settings->first_bc_widget_id) != '');
229 return $retVal;
230 }
231
232 private function should_show_content_widget_mid(){
233 // PC - only if v2 was installed:
234 if (!$this->is_db_updated_for_min_ver("2.0.0"))
235 return false;
236 $retVal1 = ((trim($this->settings->publisher_id) != '') && is_single() && !empty($this->settings->mid_enabled));
237 return $retVal1;
238 }
239
240 private function should_show_content_widget_home(){
241 // PC - only if v2 was installed:
242
243 //error_log( print_r( $this->settings, true ) ); // TEMP line
244
245 if (!$this->is_db_updated_for_min_ver("2.0.0"))
246 return false;
247 $retVal2 = ((trim($this->settings->publisher_id) != '') && (is_front_page() || is_home()) && $this->settings->home_enabled && trim($this->settings->home_widget_id) != '');
248 return $retVal2;
249 }
250
251 private function should_show_sidebar_widget(){
252 $retVal = ((trim($this->settings->publisher_id) != '') && is_active_widget( false, false, TABOOLA_WIDGET_BASE_ID, true ));
253 return $retVal;
254 }
255
256 // Determine if a taboola widget should be added somewhere on the current page (content or sidebar)
257 function is_widget_on_page(){
258 return $this->should_show_content_widget() || $this->should_show_content_widget_mid() || $this->should_show_content_widget_home() || $this->should_show_sidebar_widget() || $this->should_show_content_widget_category() ;
259 }
260
261 function get_page_type(){
262 $page_type='article';
263 if (is_front_page()){
264 $page_type='home';
265 }else if (is_category() || is_archive() || is_search()){
266 $page_type='category';
267 }
268 return $page_type;
269 }
270
271 // return the head loader script
272 function taboola_header_loader_js() {
273 if ($this->is_widget_on_page()){
274
275 // New logic to get all mid-article locations
276 $mid_locations_string = '';
277 if (!empty($this->settings->mid_widgets)) {
278 $mid_widgets_array = json_decode($this->settings->mid_widgets, true);
279 if (is_array($mid_widgets_array)) {
280 $locations = array_column($mid_widgets_array, 'location_string');
281 $mid_locations_string = implode(', ', $locations);
282 }
283 }
284
285 $stringParams = array(
286 '{{PUBLISHER_ID}}' => $this->settings->publisher_id,
287 '{{PAGE_TYPE}}' => $this->get_page_type(),
288 '{{WORDPRESS_VERSION}}' => get_bloginfo('version'),
289 '{{PHP_VERSION}}' => phpversion(),
290 '{{PLUGIN_VERSION}}' => TABOOLA_PLUGIN_VERSION,
291 '{{LOC_MID}}' => $mid_locations_string,
292 '{{LOC_HOME}}' => $this->settings->home_location_string ?? ''
293 );
294
295 $scriptWrapper = new JavaScriptWrapper("loaderInjectionScript.js",$stringParams);
296 return $scriptWrapper->getScriptMarkupString();
297 }
298 return "";
299 }
300
301 // This function is used for the hook action, injects the header content to the <head> tag.
302 function taboola_header_loader_inject(){
303 echo $this->taboola_header_loader_js();
304 }
305
306 // adding webpush loader
307 function taboola_webpush_loader_js() {
308 if(is_single() || is_home() || is_category() || is_front_page()){
309 $stringParamsWeb = array(
310 '{{PUBLISHER_ID}}' => $this->settings->publisher_id_push
311 );
312 $webpushInjectionScript = new JavaScriptWrapper("webPush.js",$stringParamsWeb);
313 echo $webpushInjectionScript;
314 }
315 }
316
317 function taboola_footer_loader_js() {
318
319 // Only adding flush script if a widget is going to be placed on the page.
320 if ($this->is_widget_on_page()){
321 $flushInjectionScript = new JavaScriptWrapper('flushInjectionScript.js',array());
322 echo $flushInjectionScript->getScriptMarkupString();
323 }
324 }
325
326 // Below-article widget
327 function load_taboola_content($content)
328 {
329 $taboola_content = array();
330 if ($this->should_show_content_widget()){
331
332 $firstWidgetParams = array(
333 '{{WIDGET_ID}}' => $this->settings->first_bc_widget_id,
334 '{{CONTAINER}}' => 'taboola-below-article-thumbnails',
335 // PC - If v2 was not installed, then use v1 logic
336 '{{PLACEMENT}}' => (!empty($this->settings->first_bc_placement)) ? $this->settings->first_bc_placement : 'below-article' // In case v1 upgrade has not run yet
337 );
338
339 $firstWidgetScript = new JavaScriptWrapper("widgetInjectionScript.js",$firstWidgetParams);
340 $taboola_content[TABOOLA_CONTENT_FORMAT_HTML][] = "<div id='taboola-below-article-thumbnails'></div>";
341 $taboola_content[TABOOLA_CONTENT_FORMAT_SCRIPT][] = $firstWidgetScript;
342
343 $content = $this->embed_taboola_content_location($content,$taboola_content);
344 }
345
346 return $content;
347 }
348
349 // Mid-article-widget
350 function load_taboola_content_mid($content) {
351 if ($this->should_show_content_widget_mid()){
352 $mid_widgets = json_decode($this->settings->mid_widgets ?? '[]');
353
354 if (is_array($mid_widgets) && !empty($mid_widgets)) {
355 foreach ($mid_widgets as $index => $widget) {
356 $container_id = 'taboola-mid-article-thumbnails-' . $index;
357
358 $widgetParams = array(
359 '{{WIDGET_ID}}' => $widget->widget_id,
360 '{{CONTAINER}}' => $container_id,
361 '{{PLACEMENT}}' => $widget->placement
362 );
363
364 $widgetScript = new JavaScriptWrapper("widgetInjectionScript.js", $widgetParams);
365 $taboola_content_mid = array(
366 TABOOLA_CONTENT_FORMAT_HTML => array("<div id='{$container_id}'></div>"),
367 TABOOLA_CONTENT_FORMAT_SCRIPT => array($widgetScript),
368 );
369
370 $content = $this->embed_taboola_content_location_mid(
371 $content,
372 $taboola_content_mid,
373 $widget->location_string,
374 $widget->occurrence
375 );
376 }
377 }
378 }
379 return $content;
380 }
381
382 // Homepage widget
383 function load_taboola_content_home($content)
384 {
385 //error_log( 'TB-DEBUG ② entered load_taboola_content_home' );
386 $taboola_content_home = array();
387 if ($this->should_show_content_widget_home()){
388
389 $homeWidgetParams = array('{{WIDGET_ID}}' => $this->settings->home_widget_id,
390 '{{CONTAINER}}' => 'taboola-homepage-thumbnails',
391 '{{PLACEMENT}}' => $this->settings->home_placement);
392
393 $homeWidgetScript = new JavaScriptWrapper("widgetInjectionScript.js",$homeWidgetParams);
394 $taboola_content_home[TABOOLA_CONTENT_FORMAT_HTML][] = "<div id='taboola-homepage-thumbnails'></div>";
395 $taboola_content_home[TABOOLA_CONTENT_FORMAT_SCRIPT][] = $homeWidgetScript;
396
397 $content = $this->embed_taboola_content_location_home($content,$taboola_content_home,trim($this->settings->home_location_string));
398 }
399 return $content;
400
401 }
402 /* ------------------------------------------------------------------
403 * CATEGORY ▸ build widget & inject
404 * ------------------------------------------------------------------*/
405 public function load_taboola_content_category( $content ) {
406
407 // 1) Build the DIV that Taboola will fill
408 $taboola[TABOOLA_CONTENT_FORMAT_HTML][] =
409 "<div id='taboola-category-thumbnails'></div>";
410
411 // 2) Build the JS that loads the feed (reuse the wrapper)
412 $taboola[TABOOLA_CONTENT_FORMAT_SCRIPT][] =
413 new JavaScriptWrapper( 'widgetInjectionScript.js', [
414 '{{WIDGET_ID}}' => $this->settings->category_widget_id,
415 '{{CONTAINER}}' => 'taboola-category-thumbnails',
416 '{{PLACEMENT}}' => $this->settings->category_placement,
417 ]);
418
419 // 3) Decide where to insert (selector or end of <body>)
420 return $this->embed_taboola_content_location_category(
421 $content,
422 $taboola,
423 trim( $this->settings->category_location_string )
424 );
425 }
426
427 // Below-article widget
428
429 // Extract the taboola content in the required format:
430 // String - for injecting on the servr side
431 // Script or HTML - for injecting on the client side
432 function format_taboola_content($taboola_content,$format){
433 $ret_val = null;
434
435 switch($format){
436 case TABOOLA_CONTENT_FORMAT_STRING:
437 $result_string = join("",$taboola_content[TABOOLA_CONTENT_FORMAT_HTML]).
438 "<script type='text/javascript'>".join("\n",$taboola_content[TABOOLA_CONTENT_FORMAT_SCRIPT])."</script>";
439 $ret_val = $result_string;
440 break;
441
442 // script or html
443 default:
444 $ret_val = str_replace("\n","",join("",$taboola_content[$format]));
445 break;
446 }
447
448 return $ret_val;
449 }
450
451
452 // Mid-article widget
453 function format_taboola_content_mid($taboola_content_mid,$format){
454 $ret_val = null;
455
456 switch($format){
457 case TABOOLA_CONTENT_FORMAT_STRING:
458 $result_string = join("",$taboola_content_mid[TABOOLA_CONTENT_FORMAT_HTML]).
459 "<script type='text/javascript'>".join("\n",$taboola_content_mid[TABOOLA_CONTENT_FORMAT_SCRIPT])."</script>";
460 $ret_val = $result_string;
461 break;
462
463 // script or html
464 default:
465 $ret_val = str_replace("\n","",join("",$taboola_content_mid[$format]));
466 break;
467 }
468
469 return $ret_val;
470 }
471
472
473 // Homepage widget
474 function format_taboola_content_home($taboola_content_home,$format){
475
476 $ret_val = null;
477
478 switch($format){
479 case TABOOLA_CONTENT_FORMAT_STRING:
480 $result_string = join("",$taboola_content_home[TABOOLA_CONTENT_FORMAT_HTML]).
481 "<script type='text/javascript'>".join("\n",$taboola_content_home[TABOOLA_CONTENT_FORMAT_SCRIPT])."</script>";
482 $ret_val = $result_string;
483 break;
484
485 // script or html
486 default:
487 $ret_val = str_replace("\n","",join("",$taboola_content_home[$format]));
488 break;
489 }
490
491 return $ret_val;
492
493 }
494
495
496 // ► CATEGORY formatter ◄
497 private function format_taboola_content_category( $arr ) {
498 return implode( "\n", [
499 implode( "\n", $arr[TABOOLA_CONTENT_FORMAT_HTML] ?? [] ),
500 '<script type="text/javascript">' .
501 implode( "\n", $arr[TABOOLA_CONTENT_FORMAT_SCRIPT] ?? [] ) .
502 '</script>',
503 ]);
504 }
505 // Below-article widget
506 // Do the actual logic of choosing where to place the taboola content.
507 function embed_taboola_content_location($content, $taboola_content){
508 $do_default = true;
509
510 // tag is placed outside of content in order to allow "read more" functionality.
511 if ($this->settings->out_of_content_enabled){
512
513 $scriptWrapper = new JavaScriptWrapper("js_inject.min.js",array(
514 "{{HTML}}" => $this->format_taboola_content($taboola_content,TABOOLA_CONTENT_FORMAT_HTML),
515 "{{SCRIPT}}" => $this->format_taboola_content($taboola_content,TABOOLA_CONTENT_FORMAT_SCRIPT))
516 );
517 $scriptWrapper->appendScript("injectWidgetByMarker('tbmarker');");
518 $content = $content."<span id='tbmarker'></span><script type='text/javascript'>".$scriptWrapper."</script>";
519 $do_default = false;
520 }
521
522 // Default for below-article widget - add to the end of the content
523 if ($do_default){
524 $content = $content.$this->format_taboola_content($taboola_content,TABOOLA_CONTENT_FORMAT_STRING);
525 }
526
527 return $content;
528 }
529
530 // Mid-article widget
531 // Do the actual logic of choosing where to place the taboola content based on the "location" attribute
532 function embed_taboola_content_location_mid($content, $taboola_content_mid, $location, $occurrence = 1){
533 $do_default = true;
534
535 if (isset($location) && $location != ''){
536 $first_char = substr($location,0,1);
537
538 // DIV/XPATH provided for JS handling
539 if ($first_char == TABOOLA_JS_MARKER){
540 $full_indicator = substr($location,0,strlen(TABOOLA_JS_INDICATOR));
541
542 if ($full_indicator == TABOOLA_JS_INDICATOR){
543
544 $xpath = substr($location,strlen(TABOOLA_JS_INDICATOR));
545 $scriptWrapper = new JavaScriptWrapper("js_inject.min.js",array(
546 "{{HTML}}" => $this->format_taboola_content_mid($taboola_content_mid,TABOOLA_CONTENT_FORMAT_HTML),
547 "{{SCRIPT}}" => $this->format_taboola_content_mid($taboola_content_mid,TABOOLA_CONTENT_FORMAT_SCRIPT))
548 );
549 $scriptWrapper->appendScript("injectWidgetByXpath('".$xpath."');");
550 $content = $content."<span id='tbdefault'></span><script type='text/javascript'>".$scriptWrapper."</script>";
551
552 $do_default = false;
553 }
554
555 // server side selector provided (see simple_html_dom selectors http://simplehtmldom.sourceforge.net/manual.htm)
556 // basically it's CSS selectors like in jQuery
557 } else{
558 require_once('simple_html_dom.php');
559
560 $html_doc = str_get_html($content);
561 $target_location = $html_doc->find($location, ($occurrence) - 1);
562
563 // if the location was found within the html content
564 if (isset($target_location) && is_object($target_location)){
565
566 // adding taboola content AFTER the target location
567 $target_location->outertext = $target_location->outertext.$this->format_taboola_content_mid($taboola_content_mid,TABOOLA_CONTENT_FORMAT_STRING);
568 $content = $html_doc;
569 $do_default = false;
570 }
571 }
572 }
573
574 return $content;
575 }
576
577 // Homepage widget
578 // Do the actual logic of choosing where to place the taboola content based on the "location" attribute
579 function embed_taboola_content_location_home($content, $taboola_content_home, $location){
580
581
582 // error_log( 'TB-DEBUG ③ raw selector string: [' . $location . ']' );
583
584 // load parser
585 //require_once plugin_dir_path( __FILE__ ) . 'simple_html_dom.php';
586 // $html_doc = str_get_html( $content );
587
588 // occurrence: settings is 1-based, find() wants 0-based
589 // $occurrence = max( 1, intval( $this->settings->home_location_string_occurrence ) );
590 // $node = $html_doc->find( $location, $occurrence - 1 );
591 // $found = is_object( $node ) ? 1 : 0;
592
593 // error_log( "TB-DEBUG ③ found {$found} matching node(s) for selector [{$location}]" );
594 // ────────────────────────────
595 $do_default = true;
596
597 if (isset($location) && $location != ''){
598 $first_char = substr($location,0,1);
599
600 // DIV/XPATH provided for JS handling
601 if ($first_char == TABOOLA_JS_MARKER){
602 $full_indicator = substr($location,0,strlen(TABOOLA_JS_INDICATOR));
603
604 if ($full_indicator == TABOOLA_JS_INDICATOR){
605
606 $xpath = substr($location,strlen(TABOOLA_JS_INDICATOR));
607 $scriptWrapper = new JavaScriptWrapper("js_inject.min.js",array(
608 "{{HTML}}" => $this->format_taboola_content_home($taboola_content_home,TABOOLA_CONTENT_FORMAT_HTML),
609 "{{SCRIPT}}" => $this->format_taboola_content_home($taboola_content_home,TABOOLA_CONTENT_FORMAT_SCRIPT))
610 );
611 $scriptWrapper->appendScript("injectWidgetByXpath('".$xpath."');");
612 $content = $content."<span id='tbdefault'></span><script type='text/javascript'>".$scriptWrapper."</script>";
613
614 $do_default = false;
615 }
616
617 // server side selector provided (see simple_html_dom selectors http://simplehtmldom.sourceforge.net/manual.htm)
618 // basically it's CSS selectors like in jQuery
619 } else{
620 require_once('simple_html_dom.php');
621
622 $html_doc = str_get_html($content);
623 $target_location = $html_doc->find($location,($this->settings->home_location_string_occurrence)-1);
624
625 // if the location was found within the html content
626 if (isset($target_location) && is_object($target_location)){
627
628 // adding taboola content AFTER the target location
629 $target_location->outertext = $target_location->outertext.$this->format_taboola_content_home($taboola_content_home,TABOOLA_CONTENT_FORMAT_STRING);
630 $content = $html_doc;
631 $do_default = false;
632 }
633 }
634 }
635 // Default for below-article widget - add to the end of the content
636 if ($do_default){
637 $content = $content.$this->format_taboola_content_home($taboola_content_home,TABOOLA_CONTENT_FORMAT_STRING);
638 }
639 return $content;
640
641
642 }
643
644 function admin_generate_menu(){
645 global $current_user;
646 add_menu_page(__('Taboola','taboola_widget'), __('Taboola','taboola_widget'), 'manage_options', 'taboola_widget', array(&$this, 'admin_taboola_settings'), $this->plugin_url.'img/taboola_icon.png', 110);
647 }
648
649 function admin_taboola_settings(){
650 global $wpdb;
651 $settings = $wpdb->get_row("select * from ".$wpdb->prefix."_taboola_settings limit 1");
652 $taboola_errors = array();
653 if($_SERVER['REQUEST_METHOD'] == 'POST'){
654
655 if(trim(strip_tags($_POST['publisher_id'])) == ''){
656 $taboola_errors[] = "Publisher ID";
657 }
658
659 if(isset($_POST['web_push_enabled'])) {
660 if (trim(strip_tags($_POST['publisher_id_push'])) == '') {
661 $taboola_errors[] = "Publisher Push ID";
662 }
663 }
664
665 if(isset($_POST['first_bc_enabled'])) {
666 if (trim(strip_tags($_POST['first_bc_widget_id'])) == '') {
667 $taboola_errors[] = "Below-article > Widget ID";
668 }
669 if (trim(strip_tags($_POST['first_bc_placement'])) == '') {
670 $taboola_errors[] = "Below-article > Placement Name";
671 }
672 }
673
674 if(isset($_POST['mid_enabled'])) {
675 if(isset($_POST['mid_widget_id']) && is_array($_POST['mid_widget_id'])) {
676 foreach ($_POST['mid_widget_id'] as $index => $widget_id) {
677 if(trim($widget_id) == '') {
678 $taboola_errors[] = "Mid-article Widget #".($index + 1)." > Widget ID";
679 }
680 if(trim($_POST['mid_placement'][$index]) == '') {
681 $taboola_errors[] = "Mid-article Widget #".($index + 1)." > Placement Name";
682 }
683 }
684 }
685 }
686
687 if(isset($_POST['home_enabled'])) {
688 if (trim(strip_tags($_POST['home_widget_id'])) == '') {
689 $taboola_errors[] = "Homepage > Widget ID";
690 }
691 if (trim(strip_tags($_POST['home_placement'])) == '') {
692 $taboola_errors[] = "Homepage > Placement Name";
693 }
694
695 if (trim(strip_tags($_POST['home_location_string'])) == '') {
696 $taboola_errors[] = "Homepage > CSS selector";
697 }
698 else {
699 if (!empty($_POST['home_location_string']) && !$this->is_home_location_string_occurrence_valid($_POST['home_location_string_occurrence'])) {
700 $taboola_errors[] = "Homepage > Occurance (must be >= 1)";
701 }
702 }
703 }
704 if ( isset($_POST['category_enabled']) ) {
705 if ( trim(strip_tags($_POST['category_widget_id'])) == '' )
706 $taboola_errors[] = "Category > Widget ID";
707 if ( trim(strip_tags($_POST['category_placement'])) == '' )
708 $taboola_errors[] = "Category > Placement Name";
709 }
710
711 if(count($taboola_errors) == 0){
712
713 $mid_widgets_data = array();
714 if (isset($_POST['mid_widget_id']) && is_array($_POST['mid_widget_id'])) {
715 foreach ($_POST['mid_widget_id'] as $index => $widget_id) {
716 if (!empty(trim($widget_id))) {
717
718 $location_string = 'p';
719 if (isset($_POST['mid_paragraph_ui_mode'][$index]) && $_POST['mid_paragraph_ui_mode'][$index] === 'Other') {
720 if (isset($_POST['mid_location_string'][$index])) {
721 $location_string = sanitize_text_field($_POST['mid_location_string'][$index]);
722 }
723 }
724
725 $mid_widgets_data[] = array(
726 'widget_id' => sanitize_text_field($widget_id),
727 'placement' => sanitize_text_field($_POST['mid_placement'][$index]),
728 'location_string' => $location_string,
729 'occurrence' => intval($_POST['mid_location_string_occurrence'][$index]),
730 );
731 }
732 }
733 }
734 $mid_widgets_json = json_encode($mid_widgets_data);
735
736 $data = array(
737 "publisher_id" => trim($_POST['publisher_id']),
738
739 "web_push_enabled" => isset($_POST['web_push_enabled']) ? true : false,
740 "publisher_id_push" => !empty($_POST['publisher_id_push']) ? trim($_POST['publisher_id_push']) : '',
741
742 "first_bc_enabled" => isset($_POST['first_bc_enabled']) ? true : false,
743 "first_bc_widget_id" => !empty($_POST['first_bc_widget_id']) ? trim($_POST['first_bc_widget_id']) : '',
744 "first_bc_placement" => !empty($_POST['first_bc_placement']) ? trim($_POST['first_bc_placement']) : '',
745
746 "out_of_content_enabled" => isset($_POST['out_of_content_enabled']) ? true : false,
747
748 "mid_enabled" => isset($_POST['mid_enabled']) ? true : false,
749 "mid_widgets" => $mid_widgets_json,
750
751 "home_enabled" => isset($_POST['home_enabled']) ? true : false,
752 "home_widget_id" => !empty($_POST['home_widget_id']) ? trim($_POST['home_widget_id']) : '',
753 "home_placement" => !empty($_POST['home_placement']) ? trim($_POST['home_placement']) : '',
754
755 "home_location_string_occurrence" => !empty($_POST['home_location_string_occurrence']) ? $_POST['home_location_string_occurrence'] : '',
756 "home_location_string" => !empty($_POST['home_location_string']) ? trim($_POST['home_location_string']) : '',
757 "category_enabled" => isset($_POST['category_enabled']) ? true : false,
758 "category_widget_id" => !empty($_POST['category_widget_id']) ? trim($_POST['category_widget_id']) : '',
759 "category_placement" => !empty($_POST['category_placement']) ? trim($_POST['category_placement']) : '',
760 "category_location_string_occurrence" => !empty($_POST['category_location_string_occurrence']) ? $_POST['category_location_string_occurrence'] : '',
761 "category_location_string" => !empty($_POST['category_location_string']) ? trim($_POST['category_location_string']) : '',
762
763 );
764
765 $is_valid_nonce = false;
766
767 if (isset( $_POST['my_plugin_nonce']) && wp_verify_nonce( $_POST['my_plugin_nonce'], 'my_plugin_update_field_action' ) ) {
768 $is_valid_nonce = true;
769 }
770
771 if ($is_valid_nonce) {
772 if($settings == NULL){
773 $wpdb->insert($this->tbl_taboola_settings, $data);
774 } else {
775 $wpdb->update($this->tbl_taboola_settings, $data, array('id' => $settings->id));
776 }
777 }
778 }
779 $settings = $wpdb->get_row("select * from ".$wpdb->prefix."_taboola_settings limit 1");
780 }
781 include_once('settings.php');
782 }
783
784 function is_mid_location_string_valid($mid_location_string){
785 // TODO:: validate the location string
786 return true;
787 }
788
789 function is_mid_location_string_occurrence_valid($mid_location_string_occurrence){
790
791 if ((int)$mid_location_string_occurrence >= 1) {
792 return true;
793 }
794 return false;
795 }
796
797 function is_home_location_string_valid($home_location_string){
798 // TODO:: validate the location string
799 return true;
800 }
801
802 function is_home_location_string_occurrence_valid($home_location_string_occurrence){
803
804 if ((int)$home_location_string_occurrence >= 1) {
805 return true;
806 }
807 return false;
808 }
809
810 function columnExists($column_name) {
811 global $wpdb;
812 $table_name = $wpdb->prefix . "_taboola_settings";
813 tb_write_log("table name : " . $table_name);
814 tb_write_log("column name : " . $column_name);
815
816 $column_exists = $wpdb->get_var("SHOW COLUMNS FROM $table_name LIKE '$column_name'") !== null;
817
818 if ($column_exists) {
819 tb_write_log("Yes - column " . $column_name . " DOES exist!"); //PC
820 return true;
821 } else {
822 tb_write_log("No - column " . $column_name . " does NOT exist!"); //PC
823 return false;
824 }
825 }
826
827 function is_upgrade_from_v1() {
828
829 if($this->columnExists("first_bc_widget_id") && !$this->columnExists("first_bc_placement")){
830 tb_write_log("This IS a v1 upgrade!"); //PC
831 return true;
832 }
833 else {
834 tb_write_log("This is NOT a v1 upgrade!"); //PC
835 return false;
836 }
837 }
838
839 function is_db_updated_for_min_ver($min_ver) {
840 global $wpdb;
841 $table_name = $wpdb->prefix . "_taboola_settings";
842
843 if($wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name) {
844 tb_write_log("Table NOT FOUND");
845 return false;
846 }
847 else {
848 tb_write_log("Table EXISTS");
849 }
850 $saved_version = get_option(TABOOLA_OPTION_NAME, '1.0.0');
851
852 $db_is_up_to_date = version_compare($saved_version, $min_ver, '>=');
853 return $db_is_up_to_date;
854
855 }
856
857 function is_db_updated_for_current_ver() {
858 global $wpdb;
859 $saved_version = get_option(TABOOLA_OPTION_NAME, '1.0.0');
860 $plugin_version = $this->get_loaded_plugin_version();
861 $db_is_up_to_date = version_compare($saved_version, $plugin_version, '>=');
862 return $db_is_up_to_date;
863 }
864
865 function get_loaded_plugin_version() {
866 $plugin_data = get_plugin_data( __FILE__ );
867 $loaded_plugin_version = $plugin_data['Version'];
868 return $loaded_plugin_version;
869 }
870
871 function save_taboola_version($min_ver) {
872 tb_write_log("SAVING NEW MIN VERSION: " . $min_ver); // PC
873 $saved_version = get_option(TABOOLA_OPTION_NAME, '');
874 if ($saved_version == '') {
875 add_option(TABOOLA_OPTION_NAME, $min_ver);
876 }
877 else {
878 update_option(TABOOLA_OPTION_NAME, $min_ver);
879 }
880 }
881
882 function update_db(){
883 if ($this->is_db_updated_for_min_ver(TABOOLA_MIN_VER)) {
884 return;
885 }
886
887 $this->save_taboola_version(TABOOLA_MIN_VER);
888
889 global $wpdb;
890 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
891
892 $charset_collate = '';
893 if ( ! empty( $wpdb->charset ) ) {
894 $charset_collate = "DEFAULT CHARACTER SET {$wpdb->charset}";
895 }
896 if ( ! empty( $wpdb->collate ) ) {
897 $charset_collate .= " COLLATE {$wpdb->collate}";
898 }
899
900 $is_upgrade_from_v1 = $this->is_upgrade_from_v1();
901 $sql_table_settings = "
902 CREATE TABLE `" . $wpdb->prefix . "_taboola_settings` (
903 `id` INT NOT NULL AUTO_INCREMENT ,
904 `publisher_id` VARCHAR(255) DEFAULT NULL,
905 `web_push_enabled` TINYINT(1) NOT NULL DEFAULT FALSE,
906 `publisher_id_push` INT(15) DEFAULT NULL,
907 `first_bc_enabled` TINYINT(1) NOT NULL DEFAULT FALSE,
908 `first_bc_widget_id` VARCHAR(255) DEFAULT NULL,
909 `first_bc_placement` VARCHAR(255) DEFAULT " . ($is_upgrade_from_v1 ? "'below-article'" : "NULL") .",
910 `out_of_content_enabled` TINYINT(1) NOT NULL DEFAULT TRUE,
911 `mid_enabled` TINYINT(1) NOT NULL DEFAULT FALSE,
912 `mid_widgets` TEXT DEFAULT NULL,
913 `home_enabled` TINYINT(1) NOT NULL DEFAULT FALSE,
914 `home_widget_id` VARCHAR(255) DEFAULT NULL,
915 `home_placement` VARCHAR(255) DEFAULT NULL,
916 `home_location_string` TEXT DEFAULT NULL,
917 `home_location_string_occurrence` SMALLINT DEFAULT NULL,
918 `category_enabled` TINYINT(1) NOT NULL DEFAULT FALSE,
919 `category_widget_id` VARCHAR(255) DEFAULT NULL,
920 `category_placement` VARCHAR(255) DEFAULT NULL,
921 `category_location_string` TEXT DEFAULT NULL,
922 `category_location_string_occurrence` SMALLINT DEFAULT NULL,
923 PRIMARY KEY (`id`)
924 ) $charset_collate;";
925 dbDelta($sql_table_settings);
926 }
927 }
928 }
929
930 global $taboolaWP;
931 $taboolaWP = new TaboolaWP();
932
933 function tb_write_log($log_msg)
934 {
935 if (!TABOOLA_DEBUG_MODE)
936 return;
937
938 $log_filename = "logs";
939 if (!file_exists($log_filename))
940 {
941 mkdir($log_filename, 0777, true);
942 }
943 $log_file_data = $log_filename.'/debug.log';
944
945 $date = date('Y-m-d H:i:s');
946 $log_msg_with_date = $date." : ".$log_msg;
947
948 file_put_contents($log_file_data, $log_msg_with_date . "\n", FILE_APPEND);
949 }
950
951 function tb_console_log( $data ){
952
953 If(wp_get_environment_type() === 'development') {
954
955 echo '<script>';
956 echo 'console.log('. json_encode( $data ) .')';
957 echo '</script>';
958
959 }
960 }
961
962 function tb_print_to_page($data) {
963 If(wp_get_environment_type() === 'development') {
964 print_r($data);
965 die;
966 }
967 }
968
969 function enqueue_taboola_scripts() {
970 wp_register_script(
971 'taboola-injector',
972 plugins_url('js/js_inject.min.js', __FILE__),
973 array(),
974 null,
975 true
976 );
977
978 wp_enqueue_script('taboola-injector');
979 }
980 add_action('wp_enqueue_scripts', 'enqueue_taboola_scripts');