Changeset 2876144
- Timestamp:
- 03/07/2023 09:41:01 PM (2 years ago)
- Location:
- slick-engagement
- Files:
-
- 14 edited
- 5 copied
Legend:
- Unmodified
- Added
- Removed
-
slick-engagement/tags/1.4.0/SlickEngagement_InstallIndicator.php
r1950992 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 22 2 include_once('SlickEngagement_OptionsManager.php'); 23 3 -
slick-engagement/tags/1.4.0/SlickEngagement_LifeCycle.php
r2530813 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 22 2 include_once 'SlickEngagement_InstallIndicator.php'; 23 3 -
slick-engagement/tags/1.4.0/SlickEngagement_OptionsManager.php
r2855418 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 2 22 3 class SlickEngagement_OptionsManager -
slick-engagement/tags/1.4.0/SlickEngagement_Plugin.php
r2861028 r2876144 3 3 include_once 'SlickEngagement_LifeCycle.php'; 4 4 include_once 'SlickEngagement_Widgets.php'; 5 6 define('PLUGIN_VERSION', '1.4.0'); 5 7 6 8 class SlickEngagement_Plugin extends SlickEngagement_LifeCycle 7 9 { 8 10 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 */ 13 14 public function getOptionMetaData() 14 15 { 15 // http://plugin.michael-simpson.com/?page_id=3116 16 return array( 17 17 'SiteCode' => array(__('Site Code', 'slick-engagement')), … … 19 19 ); 20 20 } 21 22 // protected function getOptionValueI18nString($optionValue) {23 // $i18nValue = parent::getOptionValueI18nString($optionValue);24 // return $i18nValue;25 // }26 21 27 22 protected function initOptions() … … 39 34 public function getPluginDisplayName() 40 35 { 41 return 'Slick Engagement';36 return 'Slickstream Engagement'; 42 37 } 43 38 … … 48 43 49 44 /** 50 * See: http://plugin.michael-simpson.com/?page_id=10151 45 * Called by install() to create any database tables if needed. 52 46 * Best Practice: … … 57 51 protected function installDatabaseTables() 58 52 { 59 // global $wpdb;60 // $tableName = $this->prefixTableName('mytable');61 // $wpdb->query("CREATE TABLE IF NOT EXISTS `$tableName` (62 // `id` INTEGER NOT NULL");63 53 } 64 54 65 55 /** 66 * See: http://plugin.michael-simpson.com/?page_id=10167 56 * Drop plugin-created tables on uninstall. 68 57 * @return void … … 70 59 protected function unInstallDatabaseTables() 71 60 { 72 // global $wpdb;73 // $tableName = $this->prefixTableName('mytable');74 // $wpdb->query("DROP TABLE IF EXISTS `$tableName`");75 61 } 76 62 77 63 /** 78 64 * Perform actions when upgrading from version X to version Y 79 * See: http://plugin.michael-simpson.com/?page_id=3580 65 * @return void 81 66 */ … … 86 71 public function addActionsAndFilters() 87 72 { 88 // Add options administration page 89 // http://plugin.michael-simpson.com/?page_id=47 73 // Add options administration page 90 74 add_action('admin_menu', array(&$this, 'addSettingsSubMenuPage')); 91 75 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 102 78 add_action('wp_head', array(&$this, 'addSlickPageHeader')); 103 79 104 // Adding scripts & styles to all pages80 // Adding scripts & styles to all pages 105 81 // Examples: 106 82 // wp_enqueue_script('jquery'); … … 108 84 // wp_enqueue_script('my-script', plugins_url('/js/my-script.js', __FILE__)); 109 85 110 // Register short codes 111 // http://plugin.michael-simpson.com/?page_id=39 112 86 // Register short codes 113 87 add_shortcode('slick-film-strip', array($this, 'doFilmStripShortcode')); 114 88 add_shortcode('slick-game', array($this, 'doGameShortcode')); … … 119 93 add_shortcode('slick-story-explorer', array($this, 'doSlickStoryExplorerShortcode')); 120 94 121 // Register AJAX hooks 122 // http://plugin.michael-simpson.com/?page_id=41 123 95 // Register AJAX hooks 124 96 // Ensure pages can be configured with categories and tags 125 97 add_action('init', array(&$this, 'add_taxonomies_to_pages')); … … 260 232 } 261 233 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/ */ 265 236 public function getPostImage($post) 266 237 { … … 268 239 ob_end_clean(); 269 240 270 /*If there's a featured image, show it*/ 271 241 //If there's a featured image, show it 272 242 if (has_post_thumbnail($post)) { 273 243 $images = wp_get_attachment_image_src(get_post_thumbnail_id($post), 'single-post-thumbnail'); … … 279 249 $first_img = $matches[1][0]; 280 250 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 283 252 if ($first_img) { 284 253 return $first_img; … … 294 263 } 295 264 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 { 301 269 $protocol = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://"; 302 270 $page_url = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; 303 271 $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 336 462 public function addSlickPageHeader() 337 463 { 338 464 global $post; 339 465 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); 345 471 346 472 if ($siteCode) { 347 473 $adThriveAbTest = false; 348 474 $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 349 476 if (substr($serverUrl, 0, 11) === 'adthrive-ab') { 350 477 $pieces = explode(" ", $serverUrl); … … 354 481 } 355 482 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:"); 391 486 echo "<script>\n"; 392 487 echo "'use strict';\n"; … … 395 490 echo "if (window.slickAbTestResult(" . $enabledPercent . ")) {\n"; 396 491 } 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"; 399 493 echo '("' . $serverUrl . '","' . $siteCode . '");' . "\n"; 400 494 if ($adThriveAbTest) { … … 402 496 } 403 497 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 406 504 $ldJsonElements = array(); 407 505 408 506 $ldJsonPlugin = (object) [ 409 507 '@type' => 'Plugin', 410 'version' => '1.3.1',508 'version' => PLUGIN_VERSION, 411 509 ]; 412 510 413 511 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 // }424 512 425 513 $ldJsonSite = (object) [ … … 633 721 ]; 634 722 echo '<script type="application/x-slickstream+json">' . json_encode($ldJson, JSON_UNESCAPED_SLASHES) . '</script>' . "\n"; 723 $this->echoSlickstreamComment("END Page Metadata"); 635 724 } 636 725 } -
slick-engagement/tags/1.4.0/SlickEngagement_ShortCodeLoader.php
r1950992 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 2 22 3 abstract class SlickEngagement_ShortCodeLoader { -
slick-engagement/tags/1.4.0/SlickEngagement_ShortCodeScriptLoader.php
r1950992 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 2 22 3 include_once('SlickEngagement_ShortCodeLoader.php'); -
slick-engagement/tags/1.4.0/readme.txt
r2861028 r2876144 4 4 Tags: search,recommendations,favorites,navigation,engagement,better search,advanced search,category search,relevant search,carousel,bookmarks,stories 5 5 License: GPLv2 or later 6 License URI: http://www.gnu.org/licenses/gpl- 2.0.html6 License URI: http://www.gnu.org/licenses/gpl-3.0.html 7 7 Requires at least: 5.0 8 8 Requires PHP: 5.6 9 9 Tested up to: 6.1.1 10 Stable tag: 1. 3.110 Stable tag: 1.4.0 11 11 12 12 Use Slickstream to upgrade your site search. Get beautiful as-you-type search, relevant content recommendations, user favorites and more! … … 236 236 237 237 = 1.2.4 238 - Remove rendering of sensitive information238 - Security enhancements 239 239 240 240 = 1.2.5 … … 246 246 = 1.3.1 247 247 - Security enhancements 248 249 = 1.4.0 250 - Performance improvements 251 - CLS improvements -
slick-engagement/tags/1.4.0/slick-engagement.php
r2861028 r2876144 3 3 Plugin Name: Slickstream Search and Engagement 4 4 Plugin URI: https://slickstream.com/getting-started 5 Version: 1. 3.15 Version: 1.4.0 6 6 Author: Slickstream 7 7 Author URI: https://slickstream.com 8 8 Description: Use Slickstreams's cloud service and widgets to increase visitor engagement 9 9 Text 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 */ 10 License: GPLv3 or later 11 */ 32 12 33 13 $SlickEngagement_minimalRequiredPhpVersion = '5.0'; -
slick-engagement/tags/1.4.0/slick-engagement_init.php
r1950992 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 2 22 3 function SlickEngagement_init($file) { -
slick-engagement/trunk/SlickEngagement_InstallIndicator.php
r1950992 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 22 2 include_once('SlickEngagement_OptionsManager.php'); 23 3 -
slick-engagement/trunk/SlickEngagement_LifeCycle.php
r2530813 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 22 2 include_once 'SlickEngagement_InstallIndicator.php'; 23 3 -
slick-engagement/trunk/SlickEngagement_OptionsManager.php
r2855418 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 2 22 3 class SlickEngagement_OptionsManager -
slick-engagement/trunk/SlickEngagement_Plugin.php
r2861028 r2876144 3 3 include_once 'SlickEngagement_LifeCycle.php'; 4 4 include_once 'SlickEngagement_Widgets.php'; 5 6 define('PLUGIN_VERSION', '1.4.0'); 5 7 6 8 class SlickEngagement_Plugin extends SlickEngagement_LifeCycle 7 9 { 8 10 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 */ 13 14 public function getOptionMetaData() 14 15 { 15 // http://plugin.michael-simpson.com/?page_id=3116 16 return array( 17 17 'SiteCode' => array(__('Site Code', 'slick-engagement')), … … 19 19 ); 20 20 } 21 22 // protected function getOptionValueI18nString($optionValue) {23 // $i18nValue = parent::getOptionValueI18nString($optionValue);24 // return $i18nValue;25 // }26 21 27 22 protected function initOptions() … … 39 34 public function getPluginDisplayName() 40 35 { 41 return 'Slick Engagement';36 return 'Slickstream Engagement'; 42 37 } 43 38 … … 48 43 49 44 /** 50 * See: http://plugin.michael-simpson.com/?page_id=10151 45 * Called by install() to create any database tables if needed. 52 46 * Best Practice: … … 57 51 protected function installDatabaseTables() 58 52 { 59 // global $wpdb;60 // $tableName = $this->prefixTableName('mytable');61 // $wpdb->query("CREATE TABLE IF NOT EXISTS `$tableName` (62 // `id` INTEGER NOT NULL");63 53 } 64 54 65 55 /** 66 * See: http://plugin.michael-simpson.com/?page_id=10167 56 * Drop plugin-created tables on uninstall. 68 57 * @return void … … 70 59 protected function unInstallDatabaseTables() 71 60 { 72 // global $wpdb;73 // $tableName = $this->prefixTableName('mytable');74 // $wpdb->query("DROP TABLE IF EXISTS `$tableName`");75 61 } 76 62 77 63 /** 78 64 * Perform actions when upgrading from version X to version Y 79 * See: http://plugin.michael-simpson.com/?page_id=3580 65 * @return void 81 66 */ … … 86 71 public function addActionsAndFilters() 87 72 { 88 // Add options administration page 89 // http://plugin.michael-simpson.com/?page_id=47 73 // Add options administration page 90 74 add_action('admin_menu', array(&$this, 'addSettingsSubMenuPage')); 91 75 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 102 78 add_action('wp_head', array(&$this, 'addSlickPageHeader')); 103 79 104 // Adding scripts & styles to all pages80 // Adding scripts & styles to all pages 105 81 // Examples: 106 82 // wp_enqueue_script('jquery'); … … 108 84 // wp_enqueue_script('my-script', plugins_url('/js/my-script.js', __FILE__)); 109 85 110 // Register short codes 111 // http://plugin.michael-simpson.com/?page_id=39 112 86 // Register short codes 113 87 add_shortcode('slick-film-strip', array($this, 'doFilmStripShortcode')); 114 88 add_shortcode('slick-game', array($this, 'doGameShortcode')); … … 119 93 add_shortcode('slick-story-explorer', array($this, 'doSlickStoryExplorerShortcode')); 120 94 121 // Register AJAX hooks 122 // http://plugin.michael-simpson.com/?page_id=41 123 95 // Register AJAX hooks 124 96 // Ensure pages can be configured with categories and tags 125 97 add_action('init', array(&$this, 'add_taxonomies_to_pages')); … … 260 232 } 261 233 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/ */ 265 236 public function getPostImage($post) 266 237 { … … 268 239 ob_end_clean(); 269 240 270 /*If there's a featured image, show it*/ 271 241 //If there's a featured image, show it 272 242 if (has_post_thumbnail($post)) { 273 243 $images = wp_get_attachment_image_src(get_post_thumbnail_id($post), 'single-post-thumbnail'); … … 279 249 $first_img = $matches[1][0]; 280 250 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 283 252 if ($first_img) { 284 253 return $first_img; … … 294 263 } 295 264 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 { 301 269 $protocol = ((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://"; 302 270 $page_url = $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; 303 271 $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 336 462 public function addSlickPageHeader() 337 463 { 338 464 global $post; 339 465 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); 345 471 346 472 if ($siteCode) { 347 473 $adThriveAbTest = false; 348 474 $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 349 476 if (substr($serverUrl, 0, 11) === 'adthrive-ab') { 350 477 $pieces = explode(" ", $serverUrl); … … 354 481 } 355 482 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:"); 391 486 echo "<script>\n"; 392 487 echo "'use strict';\n"; … … 395 490 echo "if (window.slickAbTestResult(" . $enabledPercent . ")) {\n"; 396 491 } 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"; 399 493 echo '("' . $serverUrl . '","' . $siteCode . '");' . "\n"; 400 494 if ($adThriveAbTest) { … … 402 496 } 403 497 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 406 504 $ldJsonElements = array(); 407 505 408 506 $ldJsonPlugin = (object) [ 409 507 '@type' => 'Plugin', 410 'version' => '1.3.1',508 'version' => PLUGIN_VERSION, 411 509 ]; 412 510 413 511 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 // }424 512 425 513 $ldJsonSite = (object) [ … … 633 721 ]; 634 722 echo '<script type="application/x-slickstream+json">' . json_encode($ldJson, JSON_UNESCAPED_SLASHES) . '</script>' . "\n"; 723 $this->echoSlickstreamComment("END Page Metadata"); 635 724 } 636 725 } -
slick-engagement/trunk/SlickEngagement_ShortCodeLoader.php
r1950992 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 2 22 3 abstract class SlickEngagement_ShortCodeLoader { -
slick-engagement/trunk/SlickEngagement_ShortCodeScriptLoader.php
r1950992 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 2 22 3 include_once('SlickEngagement_ShortCodeLoader.php'); -
slick-engagement/trunk/readme.txt
r2861028 r2876144 4 4 Tags: search,recommendations,favorites,navigation,engagement,better search,advanced search,category search,relevant search,carousel,bookmarks,stories 5 5 License: GPLv2 or later 6 License URI: http://www.gnu.org/licenses/gpl- 2.0.html6 License URI: http://www.gnu.org/licenses/gpl-3.0.html 7 7 Requires at least: 5.0 8 8 Requires PHP: 5.6 9 9 Tested up to: 6.1.1 10 Stable tag: 1. 3.110 Stable tag: 1.4.0 11 11 12 12 Use Slickstream to upgrade your site search. Get beautiful as-you-type search, relevant content recommendations, user favorites and more! … … 236 236 237 237 = 1.2.4 238 - Remove rendering of sensitive information238 - Security enhancements 239 239 240 240 = 1.2.5 … … 246 246 = 1.3.1 247 247 - Security enhancements 248 249 = 1.4.0 250 - Performance improvements 251 - CLS improvements -
slick-engagement/trunk/slick-engagement.php
r2861028 r2876144 3 3 Plugin Name: Slickstream Search and Engagement 4 4 Plugin URI: https://slickstream.com/getting-started 5 Version: 1. 3.15 Version: 1.4.0 6 6 Author: Slickstream 7 7 Author URI: https://slickstream.com 8 8 Description: Use Slickstreams's cloud service and widgets to increase visitor engagement 9 9 Text 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 */ 10 License: GPLv3 or later 11 */ 32 12 33 13 $SlickEngagement_minimalRequiredPhpVersion = '5.0'; -
slick-engagement/trunk/slick-engagement_init.php
r1950992 r2876144 1 1 <?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 modify8 it under the terms of the GNU General Public License as published by9 the Free Software Foundation, either version 3 of the License, or10 (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 of14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the15 GNU General Public License for more details.16 17 You should have received a copy of the GNU General Public License18 along with Contact Form to Database Extension.19 If not, see http://www.gnu.org/licenses/gpl-3.0.html20 */21 2 22 3 function SlickEngagement_init($file) {
Note: See TracChangeset
for help on using the changeset viewer.