Plugin Directory

Changeset 2876144


Ignore:
Timestamp:
03/07/2023 09:41:01 PM (2 years ago)
Author:
wpslickstream
Message:

tagging version 1.4.0

Location:
slick-engagement
Files:
14 edited
5 copied

Legend:

Unmodified
Added
Removed
  • slick-engagement/tags/1.4.0/SlickEngagement_InstallIndicator.php

    r1950992 r2876144  
    11<?php
    2 /*
    3     "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5     This file is part of WordPress Plugin Template for WordPress.
    6 
    7     WordPress Plugin Template is free software: you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation, either version 3 of the License, or
    10     (at your option) any later version.
    11 
    12     WordPress Plugin Template is distributed in the hope that it will be useful,
    13     but WITHOUT ANY WARRANTY; without even the implied warranty of
    14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15     GNU General Public License for more details.
    16 
    17     You should have received a copy of the GNU General Public License
    18     along with Contact Form to Database Extension.
    19     If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20 */
    21 
    222include_once('SlickEngagement_OptionsManager.php');
    233
  • slick-engagement/tags/1.4.0/SlickEngagement_LifeCycle.php

    r2530813 r2876144  
    11<?php
    2 /*
    3 "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5 This file is part of WordPress Plugin Template for WordPress.
    6 
    7 WordPress Plugin Template is free software: you can redistribute it and/or modify
    8 it under the terms of the GNU General Public License as published by
    9 the Free Software Foundation, either version 3 of the License, or
    10 (at your option) any later version.
    11 
    12 WordPress Plugin Template is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with Contact Form to Database Extension.
    19 If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20  */
    21 
    222include_once 'SlickEngagement_InstallIndicator.php';
    233
  • slick-engagement/tags/1.4.0/SlickEngagement_OptionsManager.php

    r2855418 r2876144  
    11<?php
    2 /*
    3 "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5 This file is part of WordPress Plugin Template for WordPress.
    6 
    7 WordPress Plugin Template is free software: you can redistribute it and/or modify
    8 it under the terms of the GNU General Public License as published by
    9 the Free Software Foundation, either version 3 of the License, or
    10 (at your option) any later version.
    11 
    12 WordPress Plugin Template is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with Contact Form to Database Extension.
    19 If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20  */
    212
    223class SlickEngagement_OptionsManager
  • slick-engagement/tags/1.4.0/SlickEngagement_Plugin.php

    r2861028 r2876144  
    33include_once 'SlickEngagement_LifeCycle.php';
    44include_once 'SlickEngagement_Widgets.php';
     5
     6define('PLUGIN_VERSION', '1.4.0');
    57
    68class SlickEngagement_Plugin extends SlickEngagement_LifeCycle
    79{
    810  const defaultServerUrl = 'https://app.slickstream.com';
    9 /**
    10  * See: http://plugin.michael-simpson.com/?page_id=31
    11  * @return array of option meta data.
    12  */
     11    /**
     12     * @return array of option meta data.
     13     */
    1314    public function getOptionMetaData()
    1415    {
    15 //  http://plugin.michael-simpson.com/?page_id=31
    1616        return array(
    1717            'SiteCode' => array(__('Site Code', 'slick-engagement')),
     
    1919        );
    2020    }
    21 
    22 //    protected function getOptionValueI18nString($optionValue) {
    23     //        $i18nValue = parent::getOptionValueI18nString($optionValue);
    24     //        return $i18nValue;
    25     //    }
    2621
    2722    protected function initOptions()
     
    3934    public function getPluginDisplayName()
    4035    {
    41         return 'Slick Engagement';
     36        return 'Slickstream Engagement';
    4237    }
    4338
     
    4843
    4944/**
    50  * See: http://plugin.michael-simpson.com/?page_id=101
    5145 * Called by install() to create any database tables if needed.
    5246 * Best Practice:
     
    5751    protected function installDatabaseTables()
    5852    {
    59 //        global $wpdb;
    60         //        $tableName = $this->prefixTableName('mytable');
    61         //        $wpdb->query("CREATE TABLE IF NOT EXISTS `$tableName` (
    62         //            `id` INTEGER NOT NULL");
    6353    }
    6454
    6555/**
    66  * See: http://plugin.michael-simpson.com/?page_id=101
    6756 * Drop plugin-created tables on uninstall.
    6857 * @return void
     
    7059    protected function unInstallDatabaseTables()
    7160    {
    72 //        global $wpdb;
    73         //        $tableName = $this->prefixTableName('mytable');
    74         //        $wpdb->query("DROP TABLE IF EXISTS `$tableName`");
    7561    }
    7662
    7763/**
    7864 * Perform actions when upgrading from version X to version Y
    79  * See: http://plugin.michael-simpson.com/?page_id=35
    8065 * @return void
    8166 */
     
    8671    public function addActionsAndFilters()
    8772    {
    88 // Add options administration page
    89         // http://plugin.michael-simpson.com/?page_id=47
     73        // Add options administration page
    9074        add_action('admin_menu', array(&$this, 'addSettingsSubMenuPage'));
    9175
    92 // Example adding a script & style just for the options administration page
    93         // http://plugin.michael-simpson.com/?page_id=47
    94         //        if (strpos($_SERVER['REQUEST_URI'], $this->getSettingsSlug()) !== false) {
    95         //            wp_enqueue_script('my-script', plugins_url('/js/my-script.js', __FILE__));
    96         //            wp_enqueue_style('my-style', plugins_url('/css/my-style.css', __FILE__));
    97         //        }
    98 
    99 // Add Actions & Filters
    100         // http://plugin.michael-simpson.com/?page_id=37
    101 
     76
     77        // Add Actions & Filters
    10278        add_action('wp_head', array(&$this, 'addSlickPageHeader'));
    10379
    104 // Adding scripts & styles to all pages
     80        // Adding scripts & styles to all pages
    10581        // Examples:
    10682        //        wp_enqueue_script('jquery');
     
    10884        //        wp_enqueue_script('my-script', plugins_url('/js/my-script.js', __FILE__));
    10985
    110 // Register short codes
    111         // http://plugin.michael-simpson.com/?page_id=39
    112 
     86        // Register short codes
    11387        add_shortcode('slick-film-strip', array($this, 'doFilmStripShortcode'));
    11488        add_shortcode('slick-game', array($this, 'doGameShortcode'));
     
    11993        add_shortcode('slick-story-explorer', array($this, 'doSlickStoryExplorerShortcode'));
    12094
    121 // Register AJAX hooks
    122         // http://plugin.michael-simpson.com/?page_id=41
    123 
     95        // Register AJAX hooks
    12496        // Ensure pages can be configured with categories and tags
    12597        add_action('init', array(&$this, 'add_taxonomies_to_pages'));
     
    260232    }
    261233
    262 /* determine whether post has a featured image, if not, find the first image inside the post content, $size passes the thumbnail size, $url determines whether to return a URL or a full image tag*/
    263 /* adapted from http://www.amberweinberg.com/wordpress-find-featured-image-or-first-image-in-post-find-dimensions-id-by-url/ */
    264 
     234    /* determine whether post has a featured image, if not, find the first image inside the post content, $size passes the thumbnail size, $url determines whether to return a URL or a full image tag*/
     235    /* adapted from http://www.amberweinberg.com/wordpress-find-featured-image-or-first-image-in-post-find-dimensions-id-by-url/ */
    265236    public function getPostImage($post)
    266237    {
     
    268239        ob_end_clean();
    269240
    270 /*If there's a featured image, show it*/
    271 
     241        //If there's a featured image, show it
    272242        if (has_post_thumbnail($post)) {
    273243            $images = wp_get_attachment_image_src(get_post_thumbnail_id($post), 'single-post-thumbnail');
     
    279249            $first_img = $matches[1][0];
    280250
    281             /*No featured image, so we get the first image inside the post content*/
    282 
     251            //No featured image, so we get the first image inside the post content
    283252            if ($first_img) {
    284253                return $first_img;
     
    294263    }
    295264
    296     public function getPageBootData() {
    297       $siteCode = trim($this->getOption('SiteCode'));
    298       if ($siteCode) {
    299         global $wp;
    300 
     265    // Fetches the Page Boot Data from the server
     266    //TODO: if we find that `/page-boot-data` requests are reduced enough to always use origin, we can add headers to avoid hitting CloudFlare
     267    private function fetchBootData($siteCode)
     268    {
    301269        $protocol = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
    302270        $page_url = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    303271        $remote = self::defaultServerUrl . '/d/page-boot-data?site=' . $siteCode . '&url=' . rawurlencode($page_url);
    304         $headers = array( 'referer' => home_url() );
    305         $response = wp_remote_get( $remote , array( 'timeout' => 3, 'headers' => $headers ) );
    306 
    307         if ( is_array($response) ) {
    308           $response_text = wp_remote_retrieve_body( $response );
    309          
    310           if (!empty($response_text)) {
    311             $boot_data = json_decode($response_text);
    312 
    313             echo "<script>";
    314             echo "window.\$slickBoot = window.\$slickBoot || {};";
    315             echo "window.\$slickBoot.d = " . $response_text . ";";
    316             echo "window.\$slickBoot.s = 'plugin';";
    317             echo "window.\$slickBoot._bd = performance.now();";
    318             echo "</script>";
    319 
    320             $filmstrip_config = isset($boot_data->filmstrip) ? $boot_data->filmstrip : '';
    321             $dcm_config = isset($boot_data->inlineSearch) ? $boot_data->inlineSearch : '';
    322             if ( !empty($filmstrip_config) || !empty($dcm_config) ) {
    323               $filmstrip_str = empty($filmstrip_config) ? '' :  json_encode($filmstrip_config);
    324               $dcm_str = empty($dcm_config) ? '' :  json_encode($dcm_config);
    325               echo "<script>\n";
    326               echo "/* Slickstream CLS Insertion */\n";
    327               echo '"use strict";(async(e,t)=>{const n=e?JSON.parse(e):null;const r=t?JSON.parse(t):null;if(n||r){const e=async()=>{if(document.body){if(n){o(n.selector,n.position||"after selector","slick-film-strip",n.minHeight||72)}if(r){r.forEach((e=>{if(e.selector){o(e.selector,e.position||"after selector","slick-inline-search-panel",e.minHeight||350,e.id)}}))}return}window.requestAnimationFrame(e)};window.requestAnimationFrame(e)}const c=async(e,t)=>{const n=Date.now();while(true){const r=document.querySelector(e);if(r){return r}const c=Date.now();if(c-n>=t){throw new Error("Timeout")}await i(200)}};const i=async e=>new Promise((t=>{setTimeout(t,e)}));const o=async(e,t,n,r,i)=>{try{const o=await c(e,5e3);const s=i?document.querySelector(`.${n}[data-config="${i}"]`):document.querySelector(`.${n}`);if(o&&!s){const e=document.createElement("div");e.style.minHeight=r+"px";e.classList.add(n);if(i){e.dataset.config=i}switch(t){case"after selector":o.insertAdjacentElement("afterend",e);break;case"before selector":o.insertAdjacentElement("beforebegin",e);break;case"first child of selector":o.insertAdjacentElement("afterbegin",e);break;case"last child of selector":o.insertAdjacentElement("beforeend",e);break}return e}}catch(t){console.log("plugin","error",`Failed to inject ${n} for selector ${e}`)}return false}})' . "\n";
    328               echo "('" . addslashes($filmstrip_str) . "','" . addslashes($dcm_str) . "');" . "\n";
    329               echo "</script>\n";
    330             }
    331           }
    332         }
    333       }
    334     }
    335 
     272        $headers = array('referer' => home_url());
     273        $response = wp_remote_get($remote , array('timeout' => 2, 'headers' => $headers));
     274       
     275        if (is_array($response)) {
     276            $response_text = wp_remote_retrieve_body($response);
     277            return json_decode($response_text);
     278        } else {
     279            return null;
     280        }
     281    }
     282
     283    private function echoSlickBootJs($boot_data_obj) {
     284        $boot_data_json = json_encode($boot_data_obj);
     285
     286        if (false === $boot_data_json) {
     287            $this->echoSlickstreamComment('Error encoding boot data JSON');
     288            return;
     289        }
     290
     291        $this->echoSlickstreamComment('Page Boot Data:');
     292
     293        echo <<<JSBLOCK
     294        <script>
     295        window.\$slickBoot = window.\$slickBoot || {};
     296        window.\$slickBoot.d = ${boot_data_json};
     297        window.\$slickBoot.s = 'plugin';
     298        window.\$slickBoot._bd = performance.now();
     299        </script>\n
     300        JSBLOCK;
     301
     302        $this->echoSlickstreamComment('END Page Boot Data');
     303    }
     304
     305    private function echoClsData($boot_data_obj)
     306    {
     307        $filmstrip_config = isset($boot_data_obj->filmstrip) ? $boot_data_obj->filmstrip : '';
     308        $dcm_config = isset($boot_data_obj->inlineSearch) ? $boot_data_obj->inlineSearch : '';
     309
     310        if (!empty($filmstrip_config) || !empty($dcm_config)) {
     311            $filmstrip_str = empty($filmstrip_config) ? '' :  json_encode($filmstrip_config);
     312            $dcm_str = empty($dcm_config) ? '' :  json_encode($dcm_config);
     313
     314            $this->echoSlickstreamComment('CLS Insertion:');
     315
     316            echo "<script>\n";
     317            echo '"use strict";(async(e,t)=>{const n=e?JSON.parse(e):null;const r=t?JSON.parse(t):null;if(n||r){const e=async()=>{if(document.body){if(n){s(n.selector,n.position||"after selector","slick-film-strip",n.minHeight||72,"10px auto")}if(r){r.forEach((e=>{if(e.selector){s(e.selector,e.position||"after selector","slick-inline-search-panel",e.minHeight||350,"50px 15px",e.id)}}))}return}window.requestAnimationFrame(e)};window.requestAnimationFrame(e)}const i=async(e,t)=>{const n=Date.now();while(true){const r=document.querySelector(e);if(r){return r}const i=Date.now();if(i-n>=t){throw new Error("Timeout")}await o(200)}};const o=async e=>new Promise((t=>{setTimeout(t,e)}));const s=async(e,t,n,r,o,s)=>{try{const c=await i(e,5e3);const a=s?document.querySelector(`.${n}[data-config="${s}"]`):document.querySelector(`.${n}`);if(c&&!a){const e=document.createElement("div");e.style.minHeight=r+"px";e.style.margin=o;e.classList.add(n);if(s){e.dataset.config=s}switch(t){case"after selector":c.insertAdjacentElement("afterend",e);break;case"before selector":c.insertAdjacentElement("beforebegin",e);break;case"first child of selector":c.insertAdjacentElement("afterbegin",e);break;case"last child of selector":c.insertAdjacentElement("beforeend",e);break}return e}}catch(t){console.log("plugin","error",`Failed to inject ${n} for selector ${e}`)}return false}})' . "\n";
     318            echo "('" . addslashes($filmstrip_str) . "','" . addslashes($dcm_str) . "');" . "\n";
     319            echo "\n</script>\n";
     320
     321            $this->echoSlickstreamComment('END CLS Insertion');
     322        }
     323    }
     324
     325    //Returns a name for the "page boot data" transient
     326    private function getTransientName()
     327    {
     328        DEFINE('PAGE_BOOT_DATA_TRANSIENT_PREFIX', 'slick_page_boot_');
     329        $normalized_url = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
     330        return PAGE_BOOT_DATA_TRANSIENT_PREFIX . md5($normalized_url);
     331    }
     332
     333    private function echoSlickstreamComment($comment)
     334    {
     335        echo "<!-- [Slickstream] " . $comment . " -->\n";
     336    }
     337
     338    private function getCurrentTimestampByTimeZone($tz_name)
     339    {
     340        $timestamp = time();
     341        $dt = new DateTime('now', new DateTimeZone($tz_name));
     342        $dt->setTimestamp($timestamp);
     343        return $dt->format('Y-m-d H:i:s');
     344    }
     345
     346    // Delete transient boot data if `&delete-boot=1` is passed in
     347    private function handleDeleteBootData()
     348    {
     349        $delete_transient_param = $this->getQueryParamByName('delete-boot');
     350        $delete_transient_data = ($delete_transient_param === '1');
     351
     352        if (!$delete_transient_data) {
     353            return;
     354        }
     355
     356        $this->echoSlickstreamComment("Deleting page boot data from cache");
     357        $comment = (false === delete_transient($this->getTransientName())) ?
     358            "Nothing to do--page not found in cache" :
     359            "Page boot data deleted successfully";
     360        $this->echoSlickstreamComment($comment);
     361    }
     362
     363    private function getQueryParamByName($param_name)
     364    {
     365        $param_val = isset($_GET[$param_name]) ? $_GET[$param_name] : null;
     366        return $param_val;
     367    }
     368
     369    private function echoPageBootData()
     370    {
     371        $siteCode = substr(trim($this->getOption('SiteCode')), 0, 9);
     372
     373        if (!$siteCode) {
     374            $this->echoSlickstreamComment("ERROR: Site Code missing from Plugin Settings; Slickstream services are disabled");
     375            return;
     376        }
     377
     378        global $wp;
     379       
     380        $transient_name = $this->getTransientName(); //Name for WP Transient Cache API Key
     381
     382        // If `delete-boot=1` is passed as a query param, delete the stored page boot data
     383        $this->handleDeleteBootData();
     384
     385        $no_transient_data = false === ($boot_data_obj = get_transient($transient_name)); //get_transient returns `false` if the key doesn't exist
     386
     387        // If `slick-boot=1` is passed as a query param, force a re-fetch of the boot data from the server
     388        // If `slick-boot=0` is passed as a query param, skip fetching boot data from the server
     389        $slick_boot_param = $this->getQueryParamByName('slick-boot');
     390        $force_fetch_boot_data = ($slick_boot_param === '1');
     391        $dont_load_boot_data = ($slick_boot_param === '0');
     392        $slick_boot_param_not_set = ($slick_boot_param === null);
     393   
     394        // Check for existing data in transient cache. If none, then fetch data from server.
     395        //TODO: store cache hits and cache misses in a transient or option?
     396        if ($force_fetch_boot_data || ($no_transient_data && $slick_boot_param_not_set)) {
     397            $this->echoSlickstreamComment("Fetching page boot data from server");
     398            $boot_data_obj = $this->fetchBootData($siteCode);
     399
     400            // Put the results in transient storage; expire after 15 minutes
     401            if ($boot_data_obj) {
     402                set_transient($transient_name, $boot_data_obj, 15 * MINUTE_IN_SECONDS);
     403                $this->echoSlickstreamComment("Storing page boot data in transient cache");
     404            } else {
     405                $this->echoSlickstreamComment("Error Fetching page boot data from server");
     406                return;
     407            }
     408        } else if ($dont_load_boot_data) {
     409            $this->echoSlickstreamComment("Skipping page boot data and CLS output");
     410            return;
     411        } else {
     412            $this->echoSlickstreamComment("Using cached page boot data");
     413        }
     414
     415        $this->echoSlickBootJs($boot_data_obj);
     416        $this->echoClsData($boot_data_obj);
     417    }
     418
     419    //Plugin-based A/B Testing JS Logic
     420    private function getAbTestJs()
     421    {
     422       
     423        $jsBlock = <<<JSBLOCK
     424        window.slickAbTestResult = function(percentEnabled, recalculate = false, testName = 'embed') {
     425        const win = window;
     426        const storage = win.localStorage;
     427        const targetPercentEnabled = parseInt(percentEnabled);
     428       
     429        if (isNaN(targetPercentEnabled)) {
     430            return new Error("Invalid enabled percentage");
     431        }
     432
     433        let enableSlickFeature;
     434        const abTestStorageKey = `slickab-\${testName}-\${targetPercentEnabled}`;
     435        const storedOnOffVal = storage.getItem(abTestStorageKey);
     436       
     437        const percentKey = `slickAbTestPercent-\${testName}`;
     438        const storedPercentVal = parseInt(storage.getItem(percentKey));
     439       
     440        if (recalculate === true || !storedOnOffVal || storedPercentVal !== targetPercentEnabled) {
     441            enableSlickFeature = (Math.random() * 100) <= targetPercentEnabled;
     442            storage.setItem(abTestStorageKey, enableSlickFeature);
     443            storage.setItem(percentKey, targetPercentEnabled);
     444        } else {
     445            enableSlickFeature = storage.getItem(abTestStorageKey) === 'true';
     446        }
     447
     448        const abGroupVal = `slk\${testName}\${targetPercentEnabled}`;
     449        const featureOnOff = enableSlickFeature ? "on" : "off";
     450        win.adthrive = win.adthrive || {};
     451        win.adthrive.cmd = win.adthrive.cmd || [];
     452        win.adthrive.cmd.push(() => { win.adthrive.config.abGroup.set(abGroupVal, featureOnOff); });
     453
     454        return enableSlickFeature;
     455        };
     456        JSBLOCK;
     457       
     458        return $jsBlock;
     459    }
     460
     461    //TODO: Clean this up / migrate to SR functions
    336462    public function addSlickPageHeader()
    337463    {
    338464        global $post;
    339465
    340         $this->getPageBootData();
    341 
    342         echo "\n";
    343         echo '<meta property="slick:wpversion" content="1.3.1" />' . "\n";
    344         $siteCode = trim($this->getOption('SiteCode'));
     466        $this->echoSlickstreamComment("Page Generated at " . $this->getCurrentTimeStampByTimeZone('America/New_York') . " EST");
     467        $this->echoPageBootData();
     468
     469        echo "\n" . '<meta property="slick:wpversion" content="' . PLUGIN_VERSION . '" />' . "\n";
     470        $siteCode = substr(trim($this->getOption('SiteCode')), 0, 9);
    345471
    346472        if ($siteCode) {
    347473            $adThriveAbTest = false;
    348474            $serverUrl = trim($this->getOption('SlickServerUrl', self::defaultServerUrl));
     475            //NOTE: for WP Plugin-based A/B Tests, the SlickServerUrl option is overloaded, hence the weird usage here
    349476            if (substr($serverUrl, 0, 11) === 'adthrive-ab') {
    350477                $pieces = explode(" ", $serverUrl);
     
    354481            }
    355482
    356             $jsBlock = <<<JSBLOCK
    357             window.slickAbTestResult = function(percentEnabled, recalculate = false, testName = 'embed') {
    358                 const win = window;
    359                 const storage = win.localStorage;
    360                 const targetPercentEnabled = parseInt(percentEnabled);
    361                
    362                 if (isNaN(targetPercentEnabled)) {
    363                     return new Error("Invalid enabled percentage");
    364                 }
    365 
    366                 let enableSlickFeature;
    367                 const abTestStorageKey = `slickab-\${testName}-\${targetPercentEnabled}`;
    368                 const storedOnOffVal = storage.getItem(abTestStorageKey);
    369                
    370                 const percentKey = `slickAbTestPercent-\${testName}`;
    371                 const storedPercentVal = parseInt(storage.getItem(percentKey));
    372                
    373                 if (recalculate === true || !storedOnOffVal || storedPercentVal !== targetPercentEnabled) {
    374                     enableSlickFeature = (Math.random() * 100) <= targetPercentEnabled;
    375                     storage.setItem(abTestStorageKey, enableSlickFeature);
    376                     storage.setItem(percentKey, targetPercentEnabled);
    377                 } else {
    378                     enableSlickFeature = storage.getItem(abTestStorageKey) === 'true';
    379                 }
    380 
    381                 const abGroupVal = `slk\${testName}\${targetPercentEnabled}`;
    382                 const featureOnOff = enableSlickFeature ? "on" : "off";
    383                 win.adthrive = win.adthrive || {};
    384                 win.adthrive.cmd = win.adthrive.cmd || [];
    385                 win.adthrive.cmd.push(() => { win.adthrive.config.abGroup.set(abGroupVal, featureOnOff); });
    386 
    387                 return enableSlickFeature;
    388             };
    389             JSBLOCK;
    390 
     483            $jsBlock = $this->getAbTestJs();
     484
     485            $this->echoSlickstreamComment("Bootloader:");
    391486            echo "<script>\n";
    392487            echo "'use strict';\n";
     
    395490                echo "if (window.slickAbTestResult(" . $enabledPercent . ")) {\n";
    396491            }
    397             echo "/* Slickstream Engagement Suite Embedder */\n";
    398             echo '"use strict";(async(e,t)=>{if(location.search.indexOf("no-slick")>=0){return}let o;const c=()=>performance.now();let a=window.$slickBoot=window.$slickBoot||{};a.rt=e;a._es=c();a.ev="2.0.1";a.l=async(e,t)=>{try{let a=0;if(!o&&"caches"in self){o=await caches.open("slickstream-code")}if(o){let i=await o.match(e);if(!i){a=c();await o.add(e);i=await o.match(e);if(i&&!i.ok){i=undefined;o.delete(e)}}if(i){const e=i.headers.get("x-slickstream-consent");return{t:a,d:t?await i.blob():await i.json(),c:e||"na"}}}}catch(e){console.log(e)}return{}};const i=e=>new Request(e,{cache:"no-store"});if(!a.d){const o=i(`${e}/d/page-boot-data?site=${t}&url=${encodeURIComponent(location.href.split("#")[0])}`);let{t:n,d:s,c:l}=await a.l(o);if(s){if(s.bestBy<Date.now()){s=undefined}else if(n){a._bd=n;a.c=l}}if(!s){a._bd=c();const e=await fetch(o);const t=e.headers.get("x-slickstream-consent");a.c=t||"na";s=await e.json()}if(s){a.d=s;a.s="embed"}}if(a.d){let e=a.d.bootUrl;const{t:t,d:o}=await a.l(i(e),true);if(o){a.bo=e=URL.createObjectURL(o);if(t){a._bf=t}}else{a._bf=c()}const n=document.createElement("script");n.src=e;document.head.appendChild(n)}else{console.log("[Slick] Boot failed")}})' . "\n";
     492            echo '"use strict";(async(e,t)=>{if(location.search.indexOf("no-slick")>=0){return}let o;const c=()=>performance.now();let a=window.$slickBoot=window.$slickBoot||{};a.rt=e;a._es=c();a.ev="2.0.1";a.l=async(e,t)=>{try{let a=0;if(!o&&"caches"in self){o=await caches.open("slickstream-code")}if(o){let n=await o.match(e);if(!n){a=c();await o.add(e);n=await o.match(e);if(n&&!n.ok){n=undefined;o.delete(e)}}if(n){const e=n.headers.get("x-slickstream-consent");return{t:a,d:t?await n.blob():await n.json(),c:e||"na"}}}}catch(e){console.log(e)}return{}};const n=e=>new Request(e,{cache:"no-store"});if(!a.d||a.d.bestBy<Date.now()){const o=n(`${e}/d/page-boot-data?site=${t}&url=${encodeURIComponent(location.href.split("#")[0])}`);let{t:s,d:i,c:d}=await a.l(o);if(i){if(i.bestBy<Date.now()){i=undefined}else if(s){a._bd=s;a.c=d}}if(!i){a._bd=c();const e=await fetch(o);const t=e.headers.get("x-slickstream-consent");a.c=t||"na";i=await e.json()}if(i){a.d=i;a.s="embed"}}if(a.d){let e=a.d.bootUrl;const{t:t,d:o}=await a.l(n(e),true);if(o){a.bo=e=URL.createObjectURL(o);if(t){a._bf=t}}else{a._bf=c()}const s=document.createElement("script");s.src=e;document.head.appendChild(s)}else{console.log("[Slick] Boot failed")}})' . "\n";
    399493            echo '("' . $serverUrl . '","' . $siteCode . '");' . "\n";
    400494            if ($adThriveAbTest) {
     
    402496            }
    403497            echo "</script>\n";
    404         }
    405 
     498            $this->echoSlickstreamComment("END Bootloader");
     499        }
     500
     501        $this->echoSlickstreamComment("Page Metadata:");
     502       
     503        //TODO: Move this out into SR functions and cache the output
    406504        $ldJsonElements = array();
    407505
    408506        $ldJsonPlugin = (object) [
    409507            '@type' => 'Plugin',
    410             'version' => '1.3.1',
     508            'version' => PLUGIN_VERSION,
    411509        ];
    412510       
    413511        array_push($ldJsonElements, $ldJsonPlugin);
    414 
    415         // $currentUser = wp_get_current_user();
    416         // if (!empty($currentUser->user_email)) {
    417         //     echo '<meta property="slick:wpuser" content="' . $currentUser->user_email . '" />' . "\n";
    418         //     $ldJsonUser = (object) [
    419         //         '@type' => 'User',
    420         //         'email' => $currentUser->user_email,
    421         //     ];
    422         //     array_push($ldJsonElements, $ldJsonUser);
    423         // }
    424512
    425513        $ldJsonSite = (object) [
     
    633721        ];
    634722        echo '<script type="application/x-slickstream+json">' . json_encode($ldJson, JSON_UNESCAPED_SLASHES) . '</script>' . "\n";
     723        $this->echoSlickstreamComment("END Page Metadata");
    635724    }
    636725}
  • slick-engagement/tags/1.4.0/SlickEngagement_ShortCodeLoader.php

    r1950992 r2876144  
    11<?php
    2 /*
    3     "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5     This file is part of WordPress Plugin Template for WordPress.
    6 
    7     WordPress Plugin Template is free software: you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation, either version 3 of the License, or
    10     (at your option) any later version.
    11 
    12     WordPress Plugin Template is distributed in the hope that it will be useful,
    13     but WITHOUT ANY WARRANTY; without even the implied warranty of
    14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15     GNU General Public License for more details.
    16 
    17     You should have received a copy of the GNU General Public License
    18     along with Contact Form to Database Extension.
    19     If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20 */
    212
    223abstract class SlickEngagement_ShortCodeLoader {
  • slick-engagement/tags/1.4.0/SlickEngagement_ShortCodeScriptLoader.php

    r1950992 r2876144  
    11<?php
    2 /*
    3     "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5     This file is part of WordPress Plugin Template for WordPress.
    6 
    7     WordPress Plugin Template is free software: you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation, either version 3 of the License, or
    10     (at your option) any later version.
    11 
    12     WordPress Plugin Template is distributed in the hope that it will be useful,
    13     but WITHOUT ANY WARRANTY; without even the implied warranty of
    14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15     GNU General Public License for more details.
    16 
    17     You should have received a copy of the GNU General Public License
    18     along with Contact Form to Database Extension.
    19     If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20 */
    212
    223include_once('SlickEngagement_ShortCodeLoader.php');
  • slick-engagement/tags/1.4.0/readme.txt

    r2861028 r2876144  
    44Tags: search,recommendations,favorites,navigation,engagement,better search,advanced search,category search,relevant search,carousel,bookmarks,stories
    55License: GPLv2 or later
    6 License URI: http://www.gnu.org/licenses/gpl-2.0.html
     6License URI: http://www.gnu.org/licenses/gpl-3.0.html
    77Requires at least: 5.0
    88Requires PHP: 5.6
    99Tested up to: 6.1.1
    10 Stable tag: 1.3.1
     10Stable tag: 1.4.0
    1111
    1212Use Slickstream to upgrade your site search.  Get beautiful as-you-type search, relevant content recommendations, user favorites and more!
     
    236236
    237237= 1.2.4
    238 - Remove rendering of sensitive information
     238- Security enhancements
    239239
    240240= 1.2.5
     
    246246= 1.3.1
    247247- Security enhancements
     248
     249= 1.4.0
     250- Performance improvements
     251- CLS improvements
  • slick-engagement/tags/1.4.0/slick-engagement.php

    r2861028 r2876144  
    33Plugin Name: Slickstream Search and Engagement
    44Plugin URI: https://slickstream.com/getting-started
    5 Version: 1.3.1
     5Version: 1.4.0
    66Author: Slickstream
    77Author URI: https://slickstream.com
    88Description: Use Slickstreams's cloud service and widgets to increase visitor engagement
    99Text Domain: slick-engagement
    10 License: GPLv2 or later
    11  */
    12 
    13 /*
    14 "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    15 
    16 This following part of this file is part of WordPress Plugin Template for WordPress.
    17 
    18 WordPress Plugin Template is free software: you can redistribute it and/or modify
    19 it under the terms of the GNU General Public License as published by
    20 the Free Software Foundation, either version 3 of the License, or
    21 (at your option) any later version.
    22 
    23 WordPress Plugin Template is distributed in the hope that it will be useful,
    24 but WITHOUT ANY WARRANTY; without even the implied warranty of
    25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    26 GNU General Public License for more details.
    27 
    28 You should have received a copy of the GNU General Public License
    29 along with Contact Form to Database Extension.
    30 If not, see http://www.gnu.org/licenses/gpl-3.0.html
    31  */
     10License: GPLv3 or later
     11*/
    3212
    3313$SlickEngagement_minimalRequiredPhpVersion = '5.0';
  • slick-engagement/tags/1.4.0/slick-engagement_init.php

    r1950992 r2876144  
    11<?php
    2 /*
    3     "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5     This file is part of WordPress Plugin Template for WordPress.
    6 
    7     WordPress Plugin Template is free software: you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation, either version 3 of the License, or
    10     (at your option) any later version.
    11 
    12     WordPress Plugin Template is distributed in the hope that it will be useful,
    13     but WITHOUT ANY WARRANTY; without even the implied warranty of
    14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15     GNU General Public License for more details.
    16 
    17     You should have received a copy of the GNU General Public License
    18     along with Contact Form to Database Extension.
    19     If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20 */
    212
    223function SlickEngagement_init($file) {
  • slick-engagement/trunk/SlickEngagement_InstallIndicator.php

    r1950992 r2876144  
    11<?php
    2 /*
    3     "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5     This file is part of WordPress Plugin Template for WordPress.
    6 
    7     WordPress Plugin Template is free software: you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation, either version 3 of the License, or
    10     (at your option) any later version.
    11 
    12     WordPress Plugin Template is distributed in the hope that it will be useful,
    13     but WITHOUT ANY WARRANTY; without even the implied warranty of
    14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15     GNU General Public License for more details.
    16 
    17     You should have received a copy of the GNU General Public License
    18     along with Contact Form to Database Extension.
    19     If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20 */
    21 
    222include_once('SlickEngagement_OptionsManager.php');
    233
  • slick-engagement/trunk/SlickEngagement_LifeCycle.php

    r2530813 r2876144  
    11<?php
    2 /*
    3 "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5 This file is part of WordPress Plugin Template for WordPress.
    6 
    7 WordPress Plugin Template is free software: you can redistribute it and/or modify
    8 it under the terms of the GNU General Public License as published by
    9 the Free Software Foundation, either version 3 of the License, or
    10 (at your option) any later version.
    11 
    12 WordPress Plugin Template is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with Contact Form to Database Extension.
    19 If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20  */
    21 
    222include_once 'SlickEngagement_InstallIndicator.php';
    233
  • slick-engagement/trunk/SlickEngagement_OptionsManager.php

    r2855418 r2876144  
    11<?php
    2 /*
    3 "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5 This file is part of WordPress Plugin Template for WordPress.
    6 
    7 WordPress Plugin Template is free software: you can redistribute it and/or modify
    8 it under the terms of the GNU General Public License as published by
    9 the Free Software Foundation, either version 3 of the License, or
    10 (at your option) any later version.
    11 
    12 WordPress Plugin Template is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with Contact Form to Database Extension.
    19 If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20  */
    212
    223class SlickEngagement_OptionsManager
  • slick-engagement/trunk/SlickEngagement_Plugin.php

    r2861028 r2876144  
    33include_once 'SlickEngagement_LifeCycle.php';
    44include_once 'SlickEngagement_Widgets.php';
     5
     6define('PLUGIN_VERSION', '1.4.0');
    57
    68class SlickEngagement_Plugin extends SlickEngagement_LifeCycle
    79{
    810  const defaultServerUrl = 'https://app.slickstream.com';
    9 /**
    10  * See: http://plugin.michael-simpson.com/?page_id=31
    11  * @return array of option meta data.
    12  */
     11    /**
     12     * @return array of option meta data.
     13     */
    1314    public function getOptionMetaData()
    1415    {
    15 //  http://plugin.michael-simpson.com/?page_id=31
    1616        return array(
    1717            'SiteCode' => array(__('Site Code', 'slick-engagement')),
     
    1919        );
    2020    }
    21 
    22 //    protected function getOptionValueI18nString($optionValue) {
    23     //        $i18nValue = parent::getOptionValueI18nString($optionValue);
    24     //        return $i18nValue;
    25     //    }
    2621
    2722    protected function initOptions()
     
    3934    public function getPluginDisplayName()
    4035    {
    41         return 'Slick Engagement';
     36        return 'Slickstream Engagement';
    4237    }
    4338
     
    4843
    4944/**
    50  * See: http://plugin.michael-simpson.com/?page_id=101
    5145 * Called by install() to create any database tables if needed.
    5246 * Best Practice:
     
    5751    protected function installDatabaseTables()
    5852    {
    59 //        global $wpdb;
    60         //        $tableName = $this->prefixTableName('mytable');
    61         //        $wpdb->query("CREATE TABLE IF NOT EXISTS `$tableName` (
    62         //            `id` INTEGER NOT NULL");
    6353    }
    6454
    6555/**
    66  * See: http://plugin.michael-simpson.com/?page_id=101
    6756 * Drop plugin-created tables on uninstall.
    6857 * @return void
     
    7059    protected function unInstallDatabaseTables()
    7160    {
    72 //        global $wpdb;
    73         //        $tableName = $this->prefixTableName('mytable');
    74         //        $wpdb->query("DROP TABLE IF EXISTS `$tableName`");
    7561    }
    7662
    7763/**
    7864 * Perform actions when upgrading from version X to version Y
    79  * See: http://plugin.michael-simpson.com/?page_id=35
    8065 * @return void
    8166 */
     
    8671    public function addActionsAndFilters()
    8772    {
    88 // Add options administration page
    89         // http://plugin.michael-simpson.com/?page_id=47
     73        // Add options administration page
    9074        add_action('admin_menu', array(&$this, 'addSettingsSubMenuPage'));
    9175
    92 // Example adding a script & style just for the options administration page
    93         // http://plugin.michael-simpson.com/?page_id=47
    94         //        if (strpos($_SERVER['REQUEST_URI'], $this->getSettingsSlug()) !== false) {
    95         //            wp_enqueue_script('my-script', plugins_url('/js/my-script.js', __FILE__));
    96         //            wp_enqueue_style('my-style', plugins_url('/css/my-style.css', __FILE__));
    97         //        }
    98 
    99 // Add Actions & Filters
    100         // http://plugin.michael-simpson.com/?page_id=37
    101 
     76
     77        // Add Actions & Filters
    10278        add_action('wp_head', array(&$this, 'addSlickPageHeader'));
    10379
    104 // Adding scripts & styles to all pages
     80        // Adding scripts & styles to all pages
    10581        // Examples:
    10682        //        wp_enqueue_script('jquery');
     
    10884        //        wp_enqueue_script('my-script', plugins_url('/js/my-script.js', __FILE__));
    10985
    110 // Register short codes
    111         // http://plugin.michael-simpson.com/?page_id=39
    112 
     86        // Register short codes
    11387        add_shortcode('slick-film-strip', array($this, 'doFilmStripShortcode'));
    11488        add_shortcode('slick-game', array($this, 'doGameShortcode'));
     
    11993        add_shortcode('slick-story-explorer', array($this, 'doSlickStoryExplorerShortcode'));
    12094
    121 // Register AJAX hooks
    122         // http://plugin.michael-simpson.com/?page_id=41
    123 
     95        // Register AJAX hooks
    12496        // Ensure pages can be configured with categories and tags
    12597        add_action('init', array(&$this, 'add_taxonomies_to_pages'));
     
    260232    }
    261233
    262 /* determine whether post has a featured image, if not, find the first image inside the post content, $size passes the thumbnail size, $url determines whether to return a URL or a full image tag*/
    263 /* adapted from http://www.amberweinberg.com/wordpress-find-featured-image-or-first-image-in-post-find-dimensions-id-by-url/ */
    264 
     234    /* determine whether post has a featured image, if not, find the first image inside the post content, $size passes the thumbnail size, $url determines whether to return a URL or a full image tag*/
     235    /* adapted from http://www.amberweinberg.com/wordpress-find-featured-image-or-first-image-in-post-find-dimensions-id-by-url/ */
    265236    public function getPostImage($post)
    266237    {
     
    268239        ob_end_clean();
    269240
    270 /*If there's a featured image, show it*/
    271 
     241        //If there's a featured image, show it
    272242        if (has_post_thumbnail($post)) {
    273243            $images = wp_get_attachment_image_src(get_post_thumbnail_id($post), 'single-post-thumbnail');
     
    279249            $first_img = $matches[1][0];
    280250
    281             /*No featured image, so we get the first image inside the post content*/
    282 
     251            //No featured image, so we get the first image inside the post content
    283252            if ($first_img) {
    284253                return $first_img;
     
    294263    }
    295264
    296     public function getPageBootData() {
    297       $siteCode = trim($this->getOption('SiteCode'));
    298       if ($siteCode) {
    299         global $wp;
    300 
     265    // Fetches the Page Boot Data from the server
     266    //TODO: if we find that `/page-boot-data` requests are reduced enough to always use origin, we can add headers to avoid hitting CloudFlare
     267    private function fetchBootData($siteCode)
     268    {
    301269        $protocol = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
    302270        $page_url = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    303271        $remote = self::defaultServerUrl . '/d/page-boot-data?site=' . $siteCode . '&url=' . rawurlencode($page_url);
    304         $headers = array( 'referer' => home_url() );
    305         $response = wp_remote_get( $remote , array( 'timeout' => 3, 'headers' => $headers ) );
    306 
    307         if ( is_array($response) ) {
    308           $response_text = wp_remote_retrieve_body( $response );
    309          
    310           if (!empty($response_text)) {
    311             $boot_data = json_decode($response_text);
    312 
    313             echo "<script>";
    314             echo "window.\$slickBoot = window.\$slickBoot || {};";
    315             echo "window.\$slickBoot.d = " . $response_text . ";";
    316             echo "window.\$slickBoot.s = 'plugin';";
    317             echo "window.\$slickBoot._bd = performance.now();";
    318             echo "</script>";
    319 
    320             $filmstrip_config = isset($boot_data->filmstrip) ? $boot_data->filmstrip : '';
    321             $dcm_config = isset($boot_data->inlineSearch) ? $boot_data->inlineSearch : '';
    322             if ( !empty($filmstrip_config) || !empty($dcm_config) ) {
    323               $filmstrip_str = empty($filmstrip_config) ? '' :  json_encode($filmstrip_config);
    324               $dcm_str = empty($dcm_config) ? '' :  json_encode($dcm_config);
    325               echo "<script>\n";
    326               echo "/* Slickstream CLS Insertion */\n";
    327               echo '"use strict";(async(e,t)=>{const n=e?JSON.parse(e):null;const r=t?JSON.parse(t):null;if(n||r){const e=async()=>{if(document.body){if(n){o(n.selector,n.position||"after selector","slick-film-strip",n.minHeight||72)}if(r){r.forEach((e=>{if(e.selector){o(e.selector,e.position||"after selector","slick-inline-search-panel",e.minHeight||350,e.id)}}))}return}window.requestAnimationFrame(e)};window.requestAnimationFrame(e)}const c=async(e,t)=>{const n=Date.now();while(true){const r=document.querySelector(e);if(r){return r}const c=Date.now();if(c-n>=t){throw new Error("Timeout")}await i(200)}};const i=async e=>new Promise((t=>{setTimeout(t,e)}));const o=async(e,t,n,r,i)=>{try{const o=await c(e,5e3);const s=i?document.querySelector(`.${n}[data-config="${i}"]`):document.querySelector(`.${n}`);if(o&&!s){const e=document.createElement("div");e.style.minHeight=r+"px";e.classList.add(n);if(i){e.dataset.config=i}switch(t){case"after selector":o.insertAdjacentElement("afterend",e);break;case"before selector":o.insertAdjacentElement("beforebegin",e);break;case"first child of selector":o.insertAdjacentElement("afterbegin",e);break;case"last child of selector":o.insertAdjacentElement("beforeend",e);break}return e}}catch(t){console.log("plugin","error",`Failed to inject ${n} for selector ${e}`)}return false}})' . "\n";
    328               echo "('" . addslashes($filmstrip_str) . "','" . addslashes($dcm_str) . "');" . "\n";
    329               echo "</script>\n";
    330             }
    331           }
    332         }
    333       }
    334     }
    335 
     272        $headers = array('referer' => home_url());
     273        $response = wp_remote_get($remote , array('timeout' => 2, 'headers' => $headers));
     274       
     275        if (is_array($response)) {
     276            $response_text = wp_remote_retrieve_body($response);
     277            return json_decode($response_text);
     278        } else {
     279            return null;
     280        }
     281    }
     282
     283    private function echoSlickBootJs($boot_data_obj) {
     284        $boot_data_json = json_encode($boot_data_obj);
     285
     286        if (false === $boot_data_json) {
     287            $this->echoSlickstreamComment('Error encoding boot data JSON');
     288            return;
     289        }
     290
     291        $this->echoSlickstreamComment('Page Boot Data:');
     292
     293        echo <<<JSBLOCK
     294        <script>
     295        window.\$slickBoot = window.\$slickBoot || {};
     296        window.\$slickBoot.d = ${boot_data_json};
     297        window.\$slickBoot.s = 'plugin';
     298        window.\$slickBoot._bd = performance.now();
     299        </script>\n
     300        JSBLOCK;
     301
     302        $this->echoSlickstreamComment('END Page Boot Data');
     303    }
     304
     305    private function echoClsData($boot_data_obj)
     306    {
     307        $filmstrip_config = isset($boot_data_obj->filmstrip) ? $boot_data_obj->filmstrip : '';
     308        $dcm_config = isset($boot_data_obj->inlineSearch) ? $boot_data_obj->inlineSearch : '';
     309
     310        if (!empty($filmstrip_config) || !empty($dcm_config)) {
     311            $filmstrip_str = empty($filmstrip_config) ? '' :  json_encode($filmstrip_config);
     312            $dcm_str = empty($dcm_config) ? '' :  json_encode($dcm_config);
     313
     314            $this->echoSlickstreamComment('CLS Insertion:');
     315
     316            echo "<script>\n";
     317            echo '"use strict";(async(e,t)=>{const n=e?JSON.parse(e):null;const r=t?JSON.parse(t):null;if(n||r){const e=async()=>{if(document.body){if(n){s(n.selector,n.position||"after selector","slick-film-strip",n.minHeight||72,"10px auto")}if(r){r.forEach((e=>{if(e.selector){s(e.selector,e.position||"after selector","slick-inline-search-panel",e.minHeight||350,"50px 15px",e.id)}}))}return}window.requestAnimationFrame(e)};window.requestAnimationFrame(e)}const i=async(e,t)=>{const n=Date.now();while(true){const r=document.querySelector(e);if(r){return r}const i=Date.now();if(i-n>=t){throw new Error("Timeout")}await o(200)}};const o=async e=>new Promise((t=>{setTimeout(t,e)}));const s=async(e,t,n,r,o,s)=>{try{const c=await i(e,5e3);const a=s?document.querySelector(`.${n}[data-config="${s}"]`):document.querySelector(`.${n}`);if(c&&!a){const e=document.createElement("div");e.style.minHeight=r+"px";e.style.margin=o;e.classList.add(n);if(s){e.dataset.config=s}switch(t){case"after selector":c.insertAdjacentElement("afterend",e);break;case"before selector":c.insertAdjacentElement("beforebegin",e);break;case"first child of selector":c.insertAdjacentElement("afterbegin",e);break;case"last child of selector":c.insertAdjacentElement("beforeend",e);break}return e}}catch(t){console.log("plugin","error",`Failed to inject ${n} for selector ${e}`)}return false}})' . "\n";
     318            echo "('" . addslashes($filmstrip_str) . "','" . addslashes($dcm_str) . "');" . "\n";
     319            echo "\n</script>\n";
     320
     321            $this->echoSlickstreamComment('END CLS Insertion');
     322        }
     323    }
     324
     325    //Returns a name for the "page boot data" transient
     326    private function getTransientName()
     327    {
     328        DEFINE('PAGE_BOOT_DATA_TRANSIENT_PREFIX', 'slick_page_boot_');
     329        $normalized_url = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
     330        return PAGE_BOOT_DATA_TRANSIENT_PREFIX . md5($normalized_url);
     331    }
     332
     333    private function echoSlickstreamComment($comment)
     334    {
     335        echo "<!-- [Slickstream] " . $comment . " -->\n";
     336    }
     337
     338    private function getCurrentTimestampByTimeZone($tz_name)
     339    {
     340        $timestamp = time();
     341        $dt = new DateTime('now', new DateTimeZone($tz_name));
     342        $dt->setTimestamp($timestamp);
     343        return $dt->format('Y-m-d H:i:s');
     344    }
     345
     346    // Delete transient boot data if `&delete-boot=1` is passed in
     347    private function handleDeleteBootData()
     348    {
     349        $delete_transient_param = $this->getQueryParamByName('delete-boot');
     350        $delete_transient_data = ($delete_transient_param === '1');
     351
     352        if (!$delete_transient_data) {
     353            return;
     354        }
     355
     356        $this->echoSlickstreamComment("Deleting page boot data from cache");
     357        $comment = (false === delete_transient($this->getTransientName())) ?
     358            "Nothing to do--page not found in cache" :
     359            "Page boot data deleted successfully";
     360        $this->echoSlickstreamComment($comment);
     361    }
     362
     363    private function getQueryParamByName($param_name)
     364    {
     365        $param_val = isset($_GET[$param_name]) ? $_GET[$param_name] : null;
     366        return $param_val;
     367    }
     368
     369    private function echoPageBootData()
     370    {
     371        $siteCode = substr(trim($this->getOption('SiteCode')), 0, 9);
     372
     373        if (!$siteCode) {
     374            $this->echoSlickstreamComment("ERROR: Site Code missing from Plugin Settings; Slickstream services are disabled");
     375            return;
     376        }
     377
     378        global $wp;
     379       
     380        $transient_name = $this->getTransientName(); //Name for WP Transient Cache API Key
     381
     382        // If `delete-boot=1` is passed as a query param, delete the stored page boot data
     383        $this->handleDeleteBootData();
     384
     385        $no_transient_data = false === ($boot_data_obj = get_transient($transient_name)); //get_transient returns `false` if the key doesn't exist
     386
     387        // If `slick-boot=1` is passed as a query param, force a re-fetch of the boot data from the server
     388        // If `slick-boot=0` is passed as a query param, skip fetching boot data from the server
     389        $slick_boot_param = $this->getQueryParamByName('slick-boot');
     390        $force_fetch_boot_data = ($slick_boot_param === '1');
     391        $dont_load_boot_data = ($slick_boot_param === '0');
     392        $slick_boot_param_not_set = ($slick_boot_param === null);
     393   
     394        // Check for existing data in transient cache. If none, then fetch data from server.
     395        //TODO: store cache hits and cache misses in a transient or option?
     396        if ($force_fetch_boot_data || ($no_transient_data && $slick_boot_param_not_set)) {
     397            $this->echoSlickstreamComment("Fetching page boot data from server");
     398            $boot_data_obj = $this->fetchBootData($siteCode);
     399
     400            // Put the results in transient storage; expire after 15 minutes
     401            if ($boot_data_obj) {
     402                set_transient($transient_name, $boot_data_obj, 15 * MINUTE_IN_SECONDS);
     403                $this->echoSlickstreamComment("Storing page boot data in transient cache");
     404            } else {
     405                $this->echoSlickstreamComment("Error Fetching page boot data from server");
     406                return;
     407            }
     408        } else if ($dont_load_boot_data) {
     409            $this->echoSlickstreamComment("Skipping page boot data and CLS output");
     410            return;
     411        } else {
     412            $this->echoSlickstreamComment("Using cached page boot data");
     413        }
     414
     415        $this->echoSlickBootJs($boot_data_obj);
     416        $this->echoClsData($boot_data_obj);
     417    }
     418
     419    //Plugin-based A/B Testing JS Logic
     420    private function getAbTestJs()
     421    {
     422       
     423        $jsBlock = <<<JSBLOCK
     424        window.slickAbTestResult = function(percentEnabled, recalculate = false, testName = 'embed') {
     425        const win = window;
     426        const storage = win.localStorage;
     427        const targetPercentEnabled = parseInt(percentEnabled);
     428       
     429        if (isNaN(targetPercentEnabled)) {
     430            return new Error("Invalid enabled percentage");
     431        }
     432
     433        let enableSlickFeature;
     434        const abTestStorageKey = `slickab-\${testName}-\${targetPercentEnabled}`;
     435        const storedOnOffVal = storage.getItem(abTestStorageKey);
     436       
     437        const percentKey = `slickAbTestPercent-\${testName}`;
     438        const storedPercentVal = parseInt(storage.getItem(percentKey));
     439       
     440        if (recalculate === true || !storedOnOffVal || storedPercentVal !== targetPercentEnabled) {
     441            enableSlickFeature = (Math.random() * 100) <= targetPercentEnabled;
     442            storage.setItem(abTestStorageKey, enableSlickFeature);
     443            storage.setItem(percentKey, targetPercentEnabled);
     444        } else {
     445            enableSlickFeature = storage.getItem(abTestStorageKey) === 'true';
     446        }
     447
     448        const abGroupVal = `slk\${testName}\${targetPercentEnabled}`;
     449        const featureOnOff = enableSlickFeature ? "on" : "off";
     450        win.adthrive = win.adthrive || {};
     451        win.adthrive.cmd = win.adthrive.cmd || [];
     452        win.adthrive.cmd.push(() => { win.adthrive.config.abGroup.set(abGroupVal, featureOnOff); });
     453
     454        return enableSlickFeature;
     455        };
     456        JSBLOCK;
     457       
     458        return $jsBlock;
     459    }
     460
     461    //TODO: Clean this up / migrate to SR functions
    336462    public function addSlickPageHeader()
    337463    {
    338464        global $post;
    339465
    340         $this->getPageBootData();
    341 
    342         echo "\n";
    343         echo '<meta property="slick:wpversion" content="1.3.1" />' . "\n";
    344         $siteCode = trim($this->getOption('SiteCode'));
     466        $this->echoSlickstreamComment("Page Generated at " . $this->getCurrentTimeStampByTimeZone('America/New_York') . " EST");
     467        $this->echoPageBootData();
     468
     469        echo "\n" . '<meta property="slick:wpversion" content="' . PLUGIN_VERSION . '" />' . "\n";
     470        $siteCode = substr(trim($this->getOption('SiteCode')), 0, 9);
    345471
    346472        if ($siteCode) {
    347473            $adThriveAbTest = false;
    348474            $serverUrl = trim($this->getOption('SlickServerUrl', self::defaultServerUrl));
     475            //NOTE: for WP Plugin-based A/B Tests, the SlickServerUrl option is overloaded, hence the weird usage here
    349476            if (substr($serverUrl, 0, 11) === 'adthrive-ab') {
    350477                $pieces = explode(" ", $serverUrl);
     
    354481            }
    355482
    356             $jsBlock = <<<JSBLOCK
    357             window.slickAbTestResult = function(percentEnabled, recalculate = false, testName = 'embed') {
    358                 const win = window;
    359                 const storage = win.localStorage;
    360                 const targetPercentEnabled = parseInt(percentEnabled);
    361                
    362                 if (isNaN(targetPercentEnabled)) {
    363                     return new Error("Invalid enabled percentage");
    364                 }
    365 
    366                 let enableSlickFeature;
    367                 const abTestStorageKey = `slickab-\${testName}-\${targetPercentEnabled}`;
    368                 const storedOnOffVal = storage.getItem(abTestStorageKey);
    369                
    370                 const percentKey = `slickAbTestPercent-\${testName}`;
    371                 const storedPercentVal = parseInt(storage.getItem(percentKey));
    372                
    373                 if (recalculate === true || !storedOnOffVal || storedPercentVal !== targetPercentEnabled) {
    374                     enableSlickFeature = (Math.random() * 100) <= targetPercentEnabled;
    375                     storage.setItem(abTestStorageKey, enableSlickFeature);
    376                     storage.setItem(percentKey, targetPercentEnabled);
    377                 } else {
    378                     enableSlickFeature = storage.getItem(abTestStorageKey) === 'true';
    379                 }
    380 
    381                 const abGroupVal = `slk\${testName}\${targetPercentEnabled}`;
    382                 const featureOnOff = enableSlickFeature ? "on" : "off";
    383                 win.adthrive = win.adthrive || {};
    384                 win.adthrive.cmd = win.adthrive.cmd || [];
    385                 win.adthrive.cmd.push(() => { win.adthrive.config.abGroup.set(abGroupVal, featureOnOff); });
    386 
    387                 return enableSlickFeature;
    388             };
    389             JSBLOCK;
    390 
     483            $jsBlock = $this->getAbTestJs();
     484
     485            $this->echoSlickstreamComment("Bootloader:");
    391486            echo "<script>\n";
    392487            echo "'use strict';\n";
     
    395490                echo "if (window.slickAbTestResult(" . $enabledPercent . ")) {\n";
    396491            }
    397             echo "/* Slickstream Engagement Suite Embedder */\n";
    398             echo '"use strict";(async(e,t)=>{if(location.search.indexOf("no-slick")>=0){return}let o;const c=()=>performance.now();let a=window.$slickBoot=window.$slickBoot||{};a.rt=e;a._es=c();a.ev="2.0.1";a.l=async(e,t)=>{try{let a=0;if(!o&&"caches"in self){o=await caches.open("slickstream-code")}if(o){let i=await o.match(e);if(!i){a=c();await o.add(e);i=await o.match(e);if(i&&!i.ok){i=undefined;o.delete(e)}}if(i){const e=i.headers.get("x-slickstream-consent");return{t:a,d:t?await i.blob():await i.json(),c:e||"na"}}}}catch(e){console.log(e)}return{}};const i=e=>new Request(e,{cache:"no-store"});if(!a.d){const o=i(`${e}/d/page-boot-data?site=${t}&url=${encodeURIComponent(location.href.split("#")[0])}`);let{t:n,d:s,c:l}=await a.l(o);if(s){if(s.bestBy<Date.now()){s=undefined}else if(n){a._bd=n;a.c=l}}if(!s){a._bd=c();const e=await fetch(o);const t=e.headers.get("x-slickstream-consent");a.c=t||"na";s=await e.json()}if(s){a.d=s;a.s="embed"}}if(a.d){let e=a.d.bootUrl;const{t:t,d:o}=await a.l(i(e),true);if(o){a.bo=e=URL.createObjectURL(o);if(t){a._bf=t}}else{a._bf=c()}const n=document.createElement("script");n.src=e;document.head.appendChild(n)}else{console.log("[Slick] Boot failed")}})' . "\n";
     492            echo '"use strict";(async(e,t)=>{if(location.search.indexOf("no-slick")>=0){return}let o;const c=()=>performance.now();let a=window.$slickBoot=window.$slickBoot||{};a.rt=e;a._es=c();a.ev="2.0.1";a.l=async(e,t)=>{try{let a=0;if(!o&&"caches"in self){o=await caches.open("slickstream-code")}if(o){let n=await o.match(e);if(!n){a=c();await o.add(e);n=await o.match(e);if(n&&!n.ok){n=undefined;o.delete(e)}}if(n){const e=n.headers.get("x-slickstream-consent");return{t:a,d:t?await n.blob():await n.json(),c:e||"na"}}}}catch(e){console.log(e)}return{}};const n=e=>new Request(e,{cache:"no-store"});if(!a.d||a.d.bestBy<Date.now()){const o=n(`${e}/d/page-boot-data?site=${t}&url=${encodeURIComponent(location.href.split("#")[0])}`);let{t:s,d:i,c:d}=await a.l(o);if(i){if(i.bestBy<Date.now()){i=undefined}else if(s){a._bd=s;a.c=d}}if(!i){a._bd=c();const e=await fetch(o);const t=e.headers.get("x-slickstream-consent");a.c=t||"na";i=await e.json()}if(i){a.d=i;a.s="embed"}}if(a.d){let e=a.d.bootUrl;const{t:t,d:o}=await a.l(n(e),true);if(o){a.bo=e=URL.createObjectURL(o);if(t){a._bf=t}}else{a._bf=c()}const s=document.createElement("script");s.src=e;document.head.appendChild(s)}else{console.log("[Slick] Boot failed")}})' . "\n";
    399493            echo '("' . $serverUrl . '","' . $siteCode . '");' . "\n";
    400494            if ($adThriveAbTest) {
     
    402496            }
    403497            echo "</script>\n";
    404         }
    405 
     498            $this->echoSlickstreamComment("END Bootloader");
     499        }
     500
     501        $this->echoSlickstreamComment("Page Metadata:");
     502       
     503        //TODO: Move this out into SR functions and cache the output
    406504        $ldJsonElements = array();
    407505
    408506        $ldJsonPlugin = (object) [
    409507            '@type' => 'Plugin',
    410             'version' => '1.3.1',
     508            'version' => PLUGIN_VERSION,
    411509        ];
    412510       
    413511        array_push($ldJsonElements, $ldJsonPlugin);
    414 
    415         // $currentUser = wp_get_current_user();
    416         // if (!empty($currentUser->user_email)) {
    417         //     echo '<meta property="slick:wpuser" content="' . $currentUser->user_email . '" />' . "\n";
    418         //     $ldJsonUser = (object) [
    419         //         '@type' => 'User',
    420         //         'email' => $currentUser->user_email,
    421         //     ];
    422         //     array_push($ldJsonElements, $ldJsonUser);
    423         // }
    424512
    425513        $ldJsonSite = (object) [
     
    633721        ];
    634722        echo '<script type="application/x-slickstream+json">' . json_encode($ldJson, JSON_UNESCAPED_SLASHES) . '</script>' . "\n";
     723        $this->echoSlickstreamComment("END Page Metadata");
    635724    }
    636725}
  • slick-engagement/trunk/SlickEngagement_ShortCodeLoader.php

    r1950992 r2876144  
    11<?php
    2 /*
    3     "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5     This file is part of WordPress Plugin Template for WordPress.
    6 
    7     WordPress Plugin Template is free software: you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation, either version 3 of the License, or
    10     (at your option) any later version.
    11 
    12     WordPress Plugin Template is distributed in the hope that it will be useful,
    13     but WITHOUT ANY WARRANTY; without even the implied warranty of
    14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15     GNU General Public License for more details.
    16 
    17     You should have received a copy of the GNU General Public License
    18     along with Contact Form to Database Extension.
    19     If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20 */
    212
    223abstract class SlickEngagement_ShortCodeLoader {
  • slick-engagement/trunk/SlickEngagement_ShortCodeScriptLoader.php

    r1950992 r2876144  
    11<?php
    2 /*
    3     "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5     This file is part of WordPress Plugin Template for WordPress.
    6 
    7     WordPress Plugin Template is free software: you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation, either version 3 of the License, or
    10     (at your option) any later version.
    11 
    12     WordPress Plugin Template is distributed in the hope that it will be useful,
    13     but WITHOUT ANY WARRANTY; without even the implied warranty of
    14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15     GNU General Public License for more details.
    16 
    17     You should have received a copy of the GNU General Public License
    18     along with Contact Form to Database Extension.
    19     If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20 */
    212
    223include_once('SlickEngagement_ShortCodeLoader.php');
  • slick-engagement/trunk/readme.txt

    r2861028 r2876144  
    44Tags: search,recommendations,favorites,navigation,engagement,better search,advanced search,category search,relevant search,carousel,bookmarks,stories
    55License: GPLv2 or later
    6 License URI: http://www.gnu.org/licenses/gpl-2.0.html
     6License URI: http://www.gnu.org/licenses/gpl-3.0.html
    77Requires at least: 5.0
    88Requires PHP: 5.6
    99Tested up to: 6.1.1
    10 Stable tag: 1.3.1
     10Stable tag: 1.4.0
    1111
    1212Use Slickstream to upgrade your site search.  Get beautiful as-you-type search, relevant content recommendations, user favorites and more!
     
    236236
    237237= 1.2.4
    238 - Remove rendering of sensitive information
     238- Security enhancements
    239239
    240240= 1.2.5
     
    246246= 1.3.1
    247247- Security enhancements
     248
     249= 1.4.0
     250- Performance improvements
     251- CLS improvements
  • slick-engagement/trunk/slick-engagement.php

    r2861028 r2876144  
    33Plugin Name: Slickstream Search and Engagement
    44Plugin URI: https://slickstream.com/getting-started
    5 Version: 1.3.1
     5Version: 1.4.0
    66Author: Slickstream
    77Author URI: https://slickstream.com
    88Description: Use Slickstreams's cloud service and widgets to increase visitor engagement
    99Text Domain: slick-engagement
    10 License: GPLv2 or later
    11  */
    12 
    13 /*
    14 "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    15 
    16 This following part of this file is part of WordPress Plugin Template for WordPress.
    17 
    18 WordPress Plugin Template is free software: you can redistribute it and/or modify
    19 it under the terms of the GNU General Public License as published by
    20 the Free Software Foundation, either version 3 of the License, or
    21 (at your option) any later version.
    22 
    23 WordPress Plugin Template is distributed in the hope that it will be useful,
    24 but WITHOUT ANY WARRANTY; without even the implied warranty of
    25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    26 GNU General Public License for more details.
    27 
    28 You should have received a copy of the GNU General Public License
    29 along with Contact Form to Database Extension.
    30 If not, see http://www.gnu.org/licenses/gpl-3.0.html
    31  */
     10License: GPLv3 or later
     11*/
    3212
    3313$SlickEngagement_minimalRequiredPhpVersion = '5.0';
  • slick-engagement/trunk/slick-engagement_init.php

    r1950992 r2876144  
    11<?php
    2 /*
    3     "WordPress Plugin Template" Copyright (C) 2018 Michael Simpson  (email : [email protected])
    4 
    5     This file is part of WordPress Plugin Template for WordPress.
    6 
    7     WordPress Plugin Template is free software: you can redistribute it and/or modify
    8     it under the terms of the GNU General Public License as published by
    9     the Free Software Foundation, either version 3 of the License, or
    10     (at your option) any later version.
    11 
    12     WordPress Plugin Template is distributed in the hope that it will be useful,
    13     but WITHOUT ANY WARRANTY; without even the implied warranty of
    14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15     GNU General Public License for more details.
    16 
    17     You should have received a copy of the GNU General Public License
    18     along with Contact Form to Database Extension.
    19     If not, see http://www.gnu.org/licenses/gpl-3.0.html
    20 */
    212
    223function SlickEngagement_init($file) {
Note: See TracChangeset for help on using the changeset viewer.