PluginProbe
Taboola / trunk
Taboola vtrunk
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
← All changes | taboola_widget.php +74 -25 3.0.1trunk View file →
@@ -2,13 +2,13 @@
2 2 /**
3 3 * Plugin Name: Taboola
4 4 * Plugin URI: https://developers.taboola.com/web-integrations/docs/wordpress-plugin
5 5 * Description: Taboola
6 - * Version: 3.0.1
6 + * Version: 3.1.0
7 7 * Author: Taboola
8 8 */
9 9
10 -define( 'TABOOLA_PLUGIN_VERSION', '3.0.1' ); // track every release
10 +define( 'TABOOLA_PLUGIN_VERSION', '3.1.0' ); // track every release
11 11 define( 'TABOOLA_MIN_VER', '3.0' ); // bump only when DB changes
12 12 define( 'TABOOLA_DEBUG_MODE', false );
13 13
14 14 define( 'TABOOLA_OPTION_NAME', 'taboola_plugin_version' );
@@ -21,9 +21,11 @@
21 21 define( 'TABOOLA_CONTENT_FORMAT_HTML', 'html' );
22 22
23 23 include_once 'widget.php';
24 24 require_once 'JavaScriptWrapper.php';
25 -require_once plugin_dir_path( __FILE__ ) . 'simple_html_dom.php'; // ← NEW
25 +if ( ! class_exists( 'simple_html_dom' ) ) {
26 + require_once plugin_dir_path( __FILE__ ) . 'simple_html_dom.php'; // ← NEW
27 +}
26 28
27 29 if ( ! class_exists( 'TaboolaWP' ) ) {
28 30 class TaboolaWP {
29 31
@@ -501,8 +503,31 @@
501 503 implode( "\n", $arr[TABOOLA_CONTENT_FORMAT_SCRIPT] ?? [] ) .
502 504 '</script>',
503 505 ]);
504 506 }
507 + /* ------------------------------------------------------------------
508 + * wpautop() hardening for anything injected through the_content.
509 + *
510 + * wpautop() pads block-level tags with blank lines, then splits the
511 + * content on blank lines and wraps each chunk in <p>. Its <script>
512 + * protection only runs after that split, so two things tear an injected
513 + * <script> apart and spill its tail onto the page as reader-visible text:
514 + * 1. a blank line anywhere in the script body, and
515 + * 2. a block-level tag (e.g. <div>) sitting inside a JS string literal.
516 + * Both have to be neutralised; fixing only one still breaks.
517 + * ------------------------------------------------------------------*/
518 +
519 + // Hide markup from wpautop's block-tag scan. \x3C decodes back to "<"
520 + // when the surrounding JS string literal is evaluated.
521 + private function js_escape_markup($markup){
522 + return str_replace('<', '\x3C', (string) $markup);
523 + }
524 +
525 + // Collapse blank lines so wpautop has no paragraph boundary to split on.
526 + private function wpautop_safe_script($script){
527 + return preg_replace('/(\R[ \t]*){2,}/', "\n", (string) $script);
528 + }
529 +
505 530 // Below-article widget
506 531 // Do the actual logic of choosing where to place the taboola content.
507 532 function embed_taboola_content_location($content, $taboola_content){
508 533 $do_default = true;
@@ -510,13 +535,13 @@
510 535 // tag is placed outside of content in order to allow "read more" functionality.
511 536 if ($this->settings->out_of_content_enabled){
512 537
513 538 $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))
539 + "{{HTML}}" => $this->js_escape_markup($this->format_taboola_content($taboola_content,TABOOLA_CONTENT_FORMAT_HTML)),
540 + "{{SCRIPT}}" => $this->js_escape_markup($this->format_taboola_content($taboola_content,TABOOLA_CONTENT_FORMAT_SCRIPT)))
516 541 );
517 542 $scriptWrapper->appendScript("injectWidgetByMarker('tbmarker');");
518 - $content = $content."<span id='tbmarker'></span><script type='text/javascript'>".$scriptWrapper."</script>";
543 + $content = $content."<span id='tbmarker'></span><script type='text/javascript'>".$this->wpautop_safe_script($scriptWrapper)."</script>";
519 544 $do_default = false;
520 545 }
521 546
522 547 // Default for below-article widget - add to the end of the content
@@ -542,13 +567,13 @@
542 567 if ($full_indicator == TABOOLA_JS_INDICATOR){
543 568
544 569 $xpath = substr($location,strlen(TABOOLA_JS_INDICATOR));
545 570 $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))
571 + "{{HTML}}" => $this->js_escape_markup($this->format_taboola_content_mid($taboola_content_mid,TABOOLA_CONTENT_FORMAT_HTML)),
572 + "{{SCRIPT}}" => $this->js_escape_markup($this->format_taboola_content_mid($taboola_content_mid,TABOOLA_CONTENT_FORMAT_SCRIPT)))
548 573 );
549 574 $scriptWrapper->appendScript("injectWidgetByXpath('".$xpath."');");
550 - $content = $content."<span id='tbdefault'></span><script type='text/javascript'>".$scriptWrapper."</script>";
575 + $content = $content."<span id='tbdefault'></span><script type='text/javascript'>".$this->wpautop_safe_script($scriptWrapper)."</script>";
551 576
552 577 $do_default = false;
553 578 }
554 579
@@ -554,9 +579,11 @@
554 579
555 580 // server side selector provided (see simple_html_dom selectors http://simplehtmldom.sourceforge.net/manual.htm)
556 581 // basically it's CSS selectors like in jQuery
557 582 } else{
558 - require_once('simple_html_dom.php');
583 + if ( ! class_exists( 'simple_html_dom' ) ) {
584 + require_once('simple_html_dom.php');
585 + }
559 586
560 587 $html_doc = str_get_html($content);
561 588 $target_location = $html_doc->find($location, ($occurrence) - 1);
562 589
@@ -604,13 +631,13 @@
604 631 if ($full_indicator == TABOOLA_JS_INDICATOR){
605 632
606 633 $xpath = substr($location,strlen(TABOOLA_JS_INDICATOR));
607 634 $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))
635 + "{{HTML}}" => $this->js_escape_markup($this->format_taboola_content_home($taboola_content_home,TABOOLA_CONTENT_FORMAT_HTML)),
636 + "{{SCRIPT}}" => $this->js_escape_markup($this->format_taboola_content_home($taboola_content_home,TABOOLA_CONTENT_FORMAT_SCRIPT)))
610 637 );
611 638 $scriptWrapper->appendScript("injectWidgetByXpath('".$xpath."');");
612 - $content = $content."<span id='tbdefault'></span><script type='text/javascript'>".$scriptWrapper."</script>";
639 + $content = $content."<span id='tbdefault'></span><script type='text/javascript'>".$this->wpautop_safe_script($scriptWrapper)."</script>";
613 640
614 641 $do_default = false;
615 642 }
616 643
@@ -615,10 +642,12 @@
615 642 }
616 643
617 644 // server side selector provided (see simple_html_dom selectors http://simplehtmldom.sourceforge.net/manual.htm)
618 645 // basically it's CSS selectors like in jQuery
619 - } else{
646 + } else{
647 + if ( ! class_exists( 'simple_html_dom' ) ) {
620 648 require_once('simple_html_dom.php');
649 + }
621 650
622 651 $html_doc = str_get_html($content);
623 652 $target_location = $html_doc->find($location,($this->settings->home_location_string_occurrence)-1);
624 653
@@ -645,12 +674,19 @@
645 674 global $current_user;
646 675 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 676 }
648 677
678 + // Empty numeric inputs must reach MySQL as NULL, not '', or strict mode
679 + // rejects the whole row.
680 + private function nullable_int($value){
681 + return (isset($value) && trim((string) $value) !== '') ? (int) $value : null;
682 + }
683 +
649 684 function admin_taboola_settings(){
650 685 global $wpdb;
651 686 $settings = $wpdb->get_row("select * from ".$wpdb->prefix."_taboola_settings limit 1");
652 687 $taboola_errors = array();
688 + $taboola_save_error = '';
653 689 if($_SERVER['REQUEST_METHOD'] == 'POST'){
654 690
655 691 if(trim(strip_tags($_POST['publisher_id'])) == ''){
656 692 $taboola_errors[] = "Publisher ID";
@@ -732,33 +768,38 @@
732 768 }
733 769 }
734 770 $mid_widgets_json = json_encode($mid_widgets_data);
735 771
772 + /* $wpdb formats every value as %s unless told otherwise, so a PHP
773 + false or an empty string reaches MySQL as ''. Under
774 + STRICT_TRANS_TABLES (the MySQL 8 default) '' is rejected for the
775 + TINYINT/INT columns and the whole write is refused. Send real
776 + integers for the flags and NULL for empty numeric fields. */
736 777 $data = array(
737 778 "publisher_id" => trim($_POST['publisher_id']),
738 779
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']) : '',
780 + "web_push_enabled" => isset($_POST['web_push_enabled']) ? 1 : 0,
781 + "publisher_id_push" => $this->nullable_int($_POST['publisher_id_push'] ?? null),
741 782
742 - "first_bc_enabled" => isset($_POST['first_bc_enabled']) ? true : false,
783 + "first_bc_enabled" => isset($_POST['first_bc_enabled']) ? 1 : 0,
743 784 "first_bc_widget_id" => !empty($_POST['first_bc_widget_id']) ? trim($_POST['first_bc_widget_id']) : '',
744 785 "first_bc_placement" => !empty($_POST['first_bc_placement']) ? trim($_POST['first_bc_placement']) : '',
745 786
746 - "out_of_content_enabled" => isset($_POST['out_of_content_enabled']) ? true : false,
787 + "out_of_content_enabled" => isset($_POST['out_of_content_enabled']) ? 1 : 0,
747 788
748 - "mid_enabled" => isset($_POST['mid_enabled']) ? true : false,
789 + "mid_enabled" => isset($_POST['mid_enabled']) ? 1 : 0,
749 790 "mid_widgets" => $mid_widgets_json,
750 791
751 - "home_enabled" => isset($_POST['home_enabled']) ? true : false,
792 + "home_enabled" => isset($_POST['home_enabled']) ? 1 : 0,
752 793 "home_widget_id" => !empty($_POST['home_widget_id']) ? trim($_POST['home_widget_id']) : '',
753 794 "home_placement" => !empty($_POST['home_placement']) ? trim($_POST['home_placement']) : '',
754 795
755 - "home_location_string_occurrence" => !empty($_POST['home_location_string_occurrence']) ? $_POST['home_location_string_occurrence'] : '',
796 + "home_location_string_occurrence" => $this->nullable_int($_POST['home_location_string_occurrence'] ?? null),
756 797 "home_location_string" => !empty($_POST['home_location_string']) ? trim($_POST['home_location_string']) : '',
757 - "category_enabled" => isset($_POST['category_enabled']) ? true : false,
798 + "category_enabled" => isset($_POST['category_enabled']) ? 1 : 0,
758 799 "category_widget_id" => !empty($_POST['category_widget_id']) ? trim($_POST['category_widget_id']) : '',
759 800 "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'] : '',
801 + "category_location_string_occurrence" => $this->nullable_int($_POST['category_location_string_occurrence'] ?? null),
761 802 "category_location_string" => !empty($_POST['category_location_string']) ? trim($_POST['category_location_string']) : '',
762 803
763 804 );
764 805
@@ -769,12 +810,20 @@
769 810 }
770 811
771 812 if ($is_valid_nonce) {
772 813 if($settings == NULL){
773 - $wpdb->insert($this->tbl_taboola_settings, $data);
814 + $saved = $wpdb->insert($this->tbl_taboola_settings, $data);
774 815 } else {
775 - $wpdb->update($this->tbl_taboola_settings, $data, array('id' => $settings->id));
816 + $saved = $wpdb->update($this->tbl_taboola_settings, $data, array('id' => $settings->id));
776 817 }
818 +
819 + // update() returns 0 when nothing changed; only false is a failure.
820 + if ($saved === false) {
821 + $taboola_save_error = "The database rejected the write, so your changes were not saved: "
822 + . ($wpdb->last_error !== '' ? $wpdb->last_error : 'unknown database error');
823 + }
824 + } else {
825 + $taboola_save_error = "Security check failed - the settings page had been open too long. Reload it and apply your changes again.";
777 826 }
778 827 }
779 828 $settings = $wpdb->get_row("select * from ".$wpdb->prefix."_taboola_settings limit 1");
780 829 }