PluginProbe
Visual Website Optimizer / 4.10
Visual Website Optimizer v4.10
trunk 1.0 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 4.0 4.1 4.10 All 37 releases
visual-web-optimizer / visual-website-optimizer.php

visual-website-optimizer.php in Visual Website Optimizer 4.10, at visual-website-optimizer.php

877 lines 37.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 *
4 * Plugin Name: VWO
5 * Plugin URI: https://vwo.com/
6 * Description: VWO is the all-in-one platform that helps you conduct visitor research, build an optimization roadmap, and run continuous experimentation. Simply enable the plugin and start running tests on your WordPress website without doing any other code changes. Visit <a href="https://vwo.com/">VWO</a> for more details.
7 * Author: VWO
8 * Version: 4.10
9 * visual-website-optimizer.php
10 * Author URI: https://vwo.com/
11 *
12 * @package VWO
13 * @author VWO
14 * @version 4.10
15 **/
16
17 /**
18 * Generate Common Code
19 *
20 * @param integer $vwo_clicks integer. Defaults to 10.
21 */
22 function get_vwo_clhf_script_common_code( $vwo_clicks = 10 ) {
23 ob_start();
24 // @codingStandardsIgnoreStart
25 ?>
26 <!-- Start VWO Common Smartcode -->
27 <script <?php echo vwo_clhf_ignore_js_attr(); ?> type='text/javascript'>
28 var _vwo_clicks = <?php echo esc_html( $vwo_clicks ); ?>;
29 </script>
30 <!-- End VWO Common Smartcode -->
31 <?php
32 // @codingStandardsIgnoreEnd
33 $script_code = ob_get_clean();
34 return $script_code;
35 }
36
37 /**
38 * Get ignore js field setting
39 *
40 * @return bool boolean
41 */
42 function get_vwo_clhf_ignore_js() {
43 $ignore_js = get_option( 'ignore_js' );
44 $ignore_js = ( '1' === $ignore_js ) ? true : false;
45 return $ignore_js;
46 }
47
48 /**
49 * Get ignore js script attribute value
50 *
51 * @return string Returns script attribute value
52 */
53 function vwo_clhf_ignore_js_attr() {
54 $ignore_js = get_vwo_clhf_ignore_js();
55 $js_attr = '';
56 if ( function_exists( 'get_vwo_clhf_ignore_js' ) && $ignore_js ) {
57 $js_attr = 'data-cfasync="false" nowprocket';
58 }
59 // Always exclude VWO scripts from Jetpack Boost deferral
60 if ( ! empty( $js_attr ) ) {
61 $js_attr .= ' data-jetpack-boost="ignore"';
62 } else {
63 $js_attr = 'data-jetpack-boost="ignore"';
64 }
65 return $js_attr;
66 }
67
68 /**
69 * Generate Synchronous Code
70 *
71 * @param int $vwo_id integer. Defaults to 0.
72 * @return string string for sync script.
73 */
74 function get_vwo_clhf_script_sync_code( $vwo_id = 0 ) {
75 ob_start();
76 // @codingStandardsIgnoreStart
77 ?>
78 <!-- Start VWO Smartcode -->
79 <script <?php echo vwo_clhf_ignore_js_attr(); ?> src="https://dev.visualwebsiteoptimizer.com/lib/<?php echo esc_html( $vwo_id ); ?>.js"></script>
80 <!-- End VWO Smartcode -->
81 <?php
82 // @codingStandardsIgnoreEnd
83 $sync_script = ob_get_clean();
84 return $sync_script;
85 }
86
87 /**
88 * Generate Asynchronous Code
89 *
90 * @param int $vwo_id integer.
91 * @param int $settings_tolerance integer.
92 * @param int $library_tolerance integer.
93 * @param bool $use_existing_jquery boolean.
94 * @return string String for async script.
95 */
96 function get_vwo_clhf_script_async_code( $vwo_id, $settings_tolerance, $library_tolerance, $use_existing_jquery ) {
97 ob_start();
98 // @codingStandardsIgnoreStart
99 ?>
100 <!-- Start VWO Async SmartCode -->
101 <link rel="preconnect" href="https://dev.visualwebsiteoptimizer.com" />
102 <script <?php echo vwo_clhf_ignore_js_attr(); ?> type='text/javascript' id='vwoCode'>
103 /* Fix: wp-rocket (application/ld+json) */
104 window._vwo_code || (function () {
105 var w=window,
106 d=document;
107 var account_id=<?php echo esc_html( $vwo_id ); ?>,
108 version=2.2,
109 settings_tolerance=<?php echo esc_html( $settings_tolerance ); ?>,
110 library_tolerance=<?php echo esc_html( $library_tolerance ); ?>,
111 use_existing_jquery=<?php echo ( $use_existing_jquery ) ? 'true' : 'false'; ?>,
112 platform='web',
113 hide_element='body',
114 hide_element_style='opacity:0 !important;filter:alpha(opacity=0) !important;background:none !important';
115 /* DO NOT EDIT BELOW THIS LINE */
116 if(f=!1,v=d.querySelector('#vwoCode'),cc={},-1<d.URL.indexOf('__vwo_disable__')||w._vwo_code)return;try{var e=JSON.parse(localStorage.getItem('_vwo_'+account_id+'_config'));cc=e&&'object'==typeof e?e:{}}catch(e){}function r(t){try{return decodeURIComponent(t)}catch(e){return t}}var s=function(){var e={combination:[],combinationChoose:[],split:[],exclude:[],uuid:null,consent:null,optOut:null},t=d.cookie||'';if(!t)return e;for(var n,i,o=/(?:^|;\s*)(?:(_vis_opt_exp_(\d+)_combi=([^;]*))|(_vis_opt_exp_(\d+)_combi_choose=([^;]*))|(_vis_opt_exp_(\d+)_split=([^:;]*))|(_vis_opt_exp_(\d+)_exclude=[^;]*)|(_vis_opt_out=([^;]*))|(_vwo_global_opt_out=[^;]*)|(_vwo_uuid=([^;]*))|(_vwo_consent=([^;]*)))/g;null!==(n=o.exec(t));)try{n[1]?e.combination.push({id:n[2],value:r(n[3])}):n[4]?e.combinationChoose.push({id:n[5],value:r(n[6])}):n[7]?e.split.push({id:n[8],value:r(n[9])}):n[10]?e.exclude.push({id:n[11]}):n[12]?e.optOut=r(n[13]):n[14]?e.optOut=!0:n[15]?e.uuid=r(n[16]):n[17]&&(i=r(n[18]),e.consent=i&&3<=i.length?i.substring(0,3):null)}catch(e){}return e}();function i(){var e=function(){if(w.VWO&&Array.isArray(w.VWO))for(var e=0;e<w.VWO.length;e++){var t=w.VWO[e];if(Array.isArray(t)&&('setVisitorId'===t[0]||'setSessionId'===t[0]))return!0}return!1}(),t='a='+account_id+'&u='+encodeURIComponent(w._vis_opt_url||d.URL)+'&vn='+version+'&ph=1'+('undefined'!=typeof platform?'&p='+platform:'')+'&st='+w.performance.now();e||((n=function(){var e,t=[],n={},i=w.VWO&&w.VWO.appliedCampaigns||{};for(e in i){var o=i[e]&&i[e].v;o&&(t.push(e+'-'+o+'-1'),n[e]=!0)}if(s&&s.combination)for(var r=0;r<s.combination.length;r++){var a=s.combination[r];n[a.id]||t.push(a.id+'-'+a.value)}return t.join('|')}())&&(t+='&c='+n),(n=function(){var e=[],t={};if(s&&s.combinationChoose)for(var n=0;n<s.combinationChoose.length;n++){var i=s.combinationChoose[n];e.push(i.id+'-'+i.value),t[i.id]=!0}if(s&&s.split)for(var o=0;o<s.split.length;o++)t[(i=s.split[o]).id]||e.push(i.id+'-'+i.value);return e.join('|')}())&&(t+='&cc='+n),(n=function(){var e={},t=[];if(w.VWO&&Array.isArray(w.VWO))for(var n=0;n<w.VWO.length;n++){var i=w.VWO[n];if(Array.isArray(i)&&'setVariation'===i[0]&&i[1]&&Array.isArray(i[1]))for(var o=0;o<i[1].length;o++){var r,a=i[1][o];a&&'object'==typeof a&&(r=a.e,a=a.v,r&&a&&(e[r]=a))}}for(r in e)t.push(r+'-'+e[r]);return t.join('|')}())&&(t+='&sv='+n)),s&&s.optOut&&(t+='&o='+s.optOut);var n=function(){var e=[],t={};if(s&&s.exclude)for(var n=0;n<s.exclude.length;n++){var i=s.exclude[n];t[i.id]||(e.push(i.id),t[i.id]=!0)}return e.join('|')}();return n&&(t+='&e='+n),s&&s.uuid&&(t+='&id='+s.uuid),s&&s.consent&&(t+='&consent='+s.consent),w.name&&-1<w.name.indexOf('_vis_preview')&&(t+='&pM=true'),w.VWO&&w.VWO.ed&&(t+='&ed='+w.VWO.ed),t}code={nonce:v&&v.nonce,use_existing_jquery:function(){return'undefined'!=typeof use_existing_jquery?use_existing_jquery:void 0},library_tolerance:function(){return'undefined'!=typeof library_tolerance?library_tolerance:void 0},settings_tolerance:function(){return cc.sT||settings_tolerance},hide_element_style:function(){return'{'+(cc.hES||hide_element_style)+'}'},hide_element:function(){return performance.getEntriesByName('first-contentful-paint')[0]?'':'string'==typeof cc.hE?cc.hE:hide_element},getVersion:function(){return version},finish:function(e){var t;f||(f=!0,(t=d.getElementById('_vis_opt_path_hides'))&&t.parentNode.removeChild(t),e&&((new Image).src='https://dev.visualwebsiteoptimizer.com/ee.gif?a='+account_id+e))},finished:function(){return f},addScript:function(e){var t=d.createElement('script');t.type='text/javascript',e.src?t.src=e.src:t.text=e.text,v&&t.setAttribute('nonce',v.nonce),d.getElementsByTagName('head')[0].appendChild(t)},load:function(e,t){t=t||{};var n=new XMLHttpRequest;n.open('GET',e,!0),n.withCredentials=!t.dSC,n.responseType=t.responseType||'text',n.onload=function(){if(t.onloadCb)return t.onloadCb(n,e);200===n.status?_vwo_code.addScript({text:n.responseText}):_vwo_code.finish('&e=loading_failure:'+e)},n.onerror=function(){if(t.onerrorCb)return t.onerrorCb(e);_vwo_code.finish('&e=loading_failure:'+e)},n.send()},init:function(){var e,t=this.settings_tolerance();w._vwo_settings_timer=setTimeout(function(){_vwo_code.finish()},t),'body'!==this.hide_element()?(n=d.createElement('style'),e=(t=this.hide_element())?t+this.hide_element_style():'',t=d.getElementsByTagName('head')[0],n.setAttribute('id','_vis_opt_path_hides'),v&&n.setAttribute('nonce',v.nonce),n.setAttribute('type','text/css'),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(d.createTextNode(e)),t.appendChild(n)):(n=d.getElementsByTagName('head')[0],(e=d.createElement('div')).style.cssText='z-index: 2147483647 !important;position: fixed !important;left: 0 !important;top: 0 !important;width: 100% !important;height: 100% !important;background: white !important;',e.setAttribute('id','_vis_opt_path_hides'),e.classList.add('_vis_hide_layer'),n.parentNode.insertBefore(e,n.nextSibling));var n='https://dev.visualwebsiteoptimizer.com/j.php?'+i();-1!==w.location.search.indexOf('_vwo_xhr')?this.addScript({src:n}):this.load(n+'&x=true',{l:1})}};w._vwo_code=code;code.init();})();
117 </script>
118 <!-- End VWO Async SmartCode -->
119 <?php
120 // @codingStandardsIgnoreEnd
121 $async_script = ob_get_clean();
122 return $async_script;
123 }
124
125 // ------------------------------------------------------------------------//
126 // ---Hook-----------------------------------------------------------------//
127 // ------------------------------------------------------------------------//
128 add_action( 'wp_head', 'vwo_clhf_headercode', 1 );
129 add_action( 'admin_menu', 'vwo_clhf_plugin_menu' );
130 add_action( 'admin_init', 'vwo_clhf_register_mysettings' );
131 add_action( 'admin_notices', 'vwo_clhf_warn_nosettings' );
132
133
134 // ------------------------------------------------------------------------//
135 // ---Functions------------------------------------------------------------//
136 // ------------------------------------------------------------------------//
137 // options page link
138
139 /**
140 * Generate a function comment for the given function body.
141 *
142 * @throws Exception Description of exception.
143 * @return void
144 */
145 function vwo_clhf_plugin_menu() {
146 add_options_page( 'Visual Website Optimizer', 'VWO', 'create_users', 'clhf_vwo_options', 'vwo_clhf_plugin_options' );
147 }
148
149 /**
150 * Register the settings for the VWO options.
151 *
152 * @return void
153 */
154 function vwo_clhf_register_mysettings() {
155 register_setting('clhf_vwo_options', 'vwo_id', array(
156 'sanitize_callback' => 'vwo_clhf_sanitize_settings',
157 ));
158 register_setting( 'clhf_vwo_options', 'code_type' );
159 register_setting( 'clhf_vwo_options', 'vwo_clicks' );
160 register_setting( 'clhf_vwo_options', 'ignore_js', 'boolval' );
161 register_setting( 'clhf_vwo_options', 'settings_tolerance', 'intval' );
162 register_setting( 'clhf_vwo_options', 'library_tolerance', 'intval' );
163 register_setting( 'clhf_vwo_options', 'use_existing_jquery', 'boolval' );
164 register_setting( 'clhf_vwo_options', 'enable_woocommerce_event_tracking', 'boolval');
165 register_setting( 'clhf_vwo_options', 'track_product_view', 'boolval' );
166 register_setting( 'clhf_vwo_options', 'track_add_to_cart', 'boolval' );
167 register_setting( 'clhf_vwo_options', 'track_remove_from_cart', 'boolval' );
168 register_setting( 'clhf_vwo_options', 'track_checkout', 'boolval' );
169 register_setting( 'clhf_vwo_options', 'track_purchase', 'boolval' );
170 register_setting( 'clhf_vwo_options', 'vwo_server_side_tracking', 'boolval' );
171 }
172
173 // ------------------------------------------------------------------------//
174 // ---Output Functions-----------------------------------------------------//
175 // ------------------------------------------------------------------------//
176
177
178 /**
179 * Generates the action vwo_clhf_headercode function.
180 *
181 * @throws Exception Description of exception.
182 * @return void
183 */
184 function vwo_clhf_headercode() {
185 // Runs in the header.
186 $vwo_id = get_option( 'vwo_id' );
187 $code_type = get_option( 'code_type' );
188
189 if ( $vwo_id ) {
190 if ( empty( get_option( 'vwo_clicks' ) ) ) {
191 update_option( 'vwo_clicks', '10' );
192 }
193 $vwo_clicks = get_option( 'vwo_clicks' );
194
195 // Common script code.
196 // @codingStandardsIgnoreLine
197 echo get_vwo_clhf_script_common_code( $vwo_clicks );
198
199 if ( 'SYNC' === $code_type ) {
200 // Sync script code.
201 // @codingStandardsIgnoreLine
202 echo get_vwo_clhf_script_sync_code( $vwo_id );
203 } else {
204
205 $settings_tolerance = get_option( 'settings_tolerance' );
206 if ( ! is_numeric( $settings_tolerance ) ) {
207 $settings_tolerance = 2000;
208 }
209
210 $library_tolerance = get_option( 'library_tolerance' );
211 if ( ! is_numeric( $library_tolerance ) ) {
212 $library_tolerance = 2500;
213 }
214
215 $use_existing_jquery = get_option( 'use_existing_jquery' );
216 $use_existing_jquery = ( '1' === $use_existing_jquery ) ? true : false;
217
218 // Async script code.
219 // @codingStandardsIgnoreLine
220 echo get_vwo_clhf_script_async_code( $vwo_id, $settings_tolerance, $library_tolerance, $use_existing_jquery );
221 }
222 }
223 }
224
225 // ------------------------------------------------------------------------//
226 // ---Page Output Functions------------------------------------------------//
227 // ------------------------------------------------------------------------//
228 // options page
229
230
231 /**
232 * Generates the options page for the VWO plugin.
233 *
234 * @throws Exception Description of exception.
235 * @return void
236 */
237 function vwo_clhf_plugin_options() {
238
239 ?>
240 <div class="wrap">
241 <h1 style="margin-bottom: 15px;"><img src="https://static.wingify.com/gcp/images/vwo-logo-color.svg" alt="VWO Logo" style="vertical-align: middle; margin-right: 10px; margin-top: -5px; height: 20px;">Configuration</h1>
242
243 <form method="post" action="options.php" novalidate>
244 <?php
245 settings_fields('clhf_vwo_options');
246 ?>
247 <div class="vwo-admin-content">
248 <?php vwo_clhf_render_tabs(); ?>
249 <div class="tab-content">
250 <div id="tab-general" class="tab-pane active">
251 <?php vwo_clhf_render_general_settings(); ?>
252 </div>
253 <div id="tab-advanced" class="tab-pane">
254 <?php vwo_clhf_render_advanced_settings(); ?>
255 </div>
256 <div id="tab-woocommerce" class="tab-pane">
257 <?php vwo_clhf_render_woocommerce_settings(); ?>
258 </div>
259 </div>
260 </div>
261 <?php submit_button(); ?>
262 </form>
263 </div>
264 <?php
265 vwo_clhf_render_styles();
266 vwo_clhf_render_scripts();
267 }
268
269 function vwo_clhf_render_tabs() {
270 ?>
271 <h2 class="nav-tab-wrapper">
272 <a href="#tab-general" class="nav-tab nav-tab-active">General Settings</a>
273 <a href="#tab-advanced" class="nav-tab">Advanced Settings</a>
274 <a href="#tab-woocommerce" class="nav-tab">WooCommerce</a>
275 </h2>
276 <?php
277 }
278
279 function vwo_clhf_render_general_settings() {
280 ?>
281 <main class="main-grid">
282 <div class="form-container">
283 <?php
284 vwo_clhf_render_field([
285 'id' => 'vwo_id',
286 'label' => 'Your VWO Account ID',
287 'type' => 'text',
288 'tooltip' => 'Enter your VWO Account ID here',
289 ]);
290 vwo_clhf_render_field([
291 'id' => 'code_type',
292 'label' => 'Code Type',
293 'type' => 'radio',
294 'options' => [
295 [
296 'label' => 'Asynchronous',
297 'value' => 'ASYNC',
298 'sublabel' => 'Loads faster without blocking other elements',
299 ],
300 [
301 'label' => 'Synchronous',
302 'value' => 'SYNC',
303 'sublabel' => 'Executes immediately but may slow down page load',
304 ],
305 ],
306 ]);
307 ?>
308 </div>
309 <div class="main-grid__description" style="width:350px;">
310 <div style="font-size: 18px; font-weight: 700; color: #000000; margin-bottom: 8px;">New to VWO?</div>
311 <div style="font-size: 14px; color: #757575; font-weight: 400; line-height: 20px; margin-bottom: 20px;">Create a free account to start optimising your website, no credit card required.</div>
312 <div>
313 <a target="_blank" href="https://vwo.com/free-trial/?utm_source=integration_wordpress&utm_medium=referral&utm_campaign=plugin_page&utm_content=config_screen_banner" style="text-decoration: none; display: block; width: 162px; background: #fff; color: #2271B1; border: 1px solid #2271B1; padding: 10px 12px; font-size: 14px; font-weight: 600; cursor: pointer; text-align: center; border-radius: 8px;">
314 Get Started for Free</a>
315 <div>
316 <div style="margin-bottom: 28px; margin-top: 20px;">
317 <div style="font-weight: 600; color: #363A42; font-size: 14px; margin-bottom: 8px;">VWO Dashboard?</div>
318 <div style="font-size: 14px; color: #757575; font-weight: 400;">Visit our knowledge base to learn how to use the VWO dashboard.</div>
319 <a href="https://app.vwo.com" target="_blank" style="display: inline-flex; align-items: center; color: #2271B1; border-radius: 8px; padding: 6px 12px; font-size: 12px; font-weight: 600; cursor: pointer; text-decoration: none; margin-top: 10px; border: 1px solid #2271B1;">
320 <span style="margin-right: 4px;">Go to Dashboard</span>
321 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 32 32">
322 <path fill="#2271B1" d="M17.88 1v3.75h5.62l-9.38 9.38 3.76 3.74 9.37-9.37v5.63H31V1H17.87zm9.37 26.25H4.75V4.75h7.5V1H1v30h30V19.75h-3.75v7.5z"/>
323 </svg>
324 </a>
325 </div>
326 <div style="font-size: 13px;">
327 Need help? Visit our <a style="color: inherit;" href="https://help.vwo.com/hc/en-us/articles/360020745993-Integrating-VWO-With-WordPress">Knowledge Base</a> for guides and FAQs.
328 </div>
329 </div>
330 </main>
331 <?php
332 }
333
334 function vwo_clhf_render_advanced_settings() {
335 ?>
336 <div class="form-container">
337 <?php
338 vwo_clhf_render_field([
339 'id' => 'vwo_clicks',
340 'label' => 'No. of Heatmap Clicks',
341 'type' => 'number',
342 'tooltip' => 'Set the number of heatmap clicks to record',
343 'min' => 3,
344 'default' => 10,
345 ]);
346 vwo_clhf_render_field([
347 'id' => 'settings_tolerance',
348 'label' => 'Settings Timeout',
349 'type' => 'number',
350 'tooltip' => 'Set the timeout for settings in milliseconds',
351 'default' => 2000,
352 'class' => 'async-option',
353 'suffix' => 'ms',
354 ]);
355 vwo_clhf_render_field([
356 'id' => 'library_tolerance',
357 'label' => 'Library Timeout',
358 'type' => 'number',
359 'tooltip' => 'Set the timeout for library in milliseconds',
360 'default' => 2500,
361 'class' => 'async-option',
362 'suffix' => 'ms',
363 ]);
364 vwo_clhf_render_field([
365 'id' => 'use_existing_jquery',
366 'label' => 'Use Existing jQuery',
367 'type' => 'checkbox',
368 'tooltip' => 'Use the existing jQuery library on your site',
369 'class' => 'async-option',
370 ]);
371 vwo_clhf_render_field([
372 'id' => 'ignore_js',
373 'label' => 'Skip Deferred Execution',
374 'type' => 'checkbox',
375 'tooltip' => 'Skip deferred execution of the VWO script',
376 ]);
377 ?>
378 </div>
379 <?php
380 }
381
382 function vwo_clhf_render_woocommerce_settings() {
383 $value = get_option('enable_woocommerce_event_tracking', false);
384 $vwo_server_side_tracking = get_option('vwo_server_side_tracking', false);
385 ?>
386 <div>
387 <div class="woocommerce-main-header">
388 <div class="checkbox-container">
389 <input type="checkbox" id="enable_woocommerce_event_tracking" name="enable_woocommerce_event_tracking" class="vwo-checkbox" <?php echo checked($value, '1', false) ?>>
390 <label class="vwo-checkbox-label" for="enable_woocommerce_event_tracking">Toggle</label>
391 <label class="form-label form-label--checkbox" for="enable_woocommerce_event_tracking">Enable WooCommerce Event Tracking</label>
392 </div>
393 <p class="form-description form-description--checkbox">Event tracking will not work unless WooCommerce is enabled on your WordPress site.</p>
394 </div>
395 <div class="woocommerce-main-header">
396 <div class="checkbox-container vwo_server_side_tracking">
397 <input type="checkbox" id="vwo_server_side_tracking" name="vwo_server_side_tracking" class="vwo-checkbox" <?php echo checked($vwo_server_side_tracking, '1', false) ?>>
398 <label class="vwo-checkbox-label" for="vwo_server_side_tracking">Toggle</label>
399 <label class="form-label form-label--checkbox" for="Enable Server-Side Tracking">Enable Server-Side Tracking</label>
400 </div>
401 <p class="form-description form-description--checkbox">Enable server-side tracking instead of JavaScript-based tracking.</p>
402 </div>
403
404
405 <div class="woocommerce-row woocommerce-row--disabled">
406 <?php
407 vwo_clhf_render_woocommerce_event_tracking([
408 'id' => 'track_product_view',
409 'label' => 'Product Viewed',
410 'description' => 'This event logs an instance where a customer views a product details page.',
411 'readmore_link' => 'https://help.vwo.com/hc/en-us/articles/360020745993-Integrating-VWO-With-WordPress'
412 ]);
413 vwo_clhf_render_woocommerce_event_tracking([
414 'id' => 'track_add_to_cart',
415 'label' => 'Add To Cart',
416 'description' => 'This event logs an instance where a customer adds a product to their cart.',
417 'readmore_link' => 'https://help.vwo.com/hc/en-us/articles/360020745993-Integrating-VWO-With-WordPress'
418 ]);
419 vwo_clhf_render_woocommerce_event_tracking([
420 'id' => 'track_remove_from_cart',
421 'label' => 'Product Removed From Cart',
422 'description' => 'This event logs an instance where a customer removes a product from their cart.',
423 'readmore_link' => 'https://help.vwo.com/hc/en-us/articles/360020745993-Integrating-VWO-With-WordPress'
424 ]);
425 // vwo_clhf_render_woocommerce_event_tracking([
426 // 'id' => 'track_checkout',
427 // 'label' => 'Checkout Page',
428 // 'description' => 'This event logs an instance where a customer visits the checkout page.',
429 // 'readmore_link' => 'https://help.vwo.com/hc/en-us/articles/360020745993-Integrating-VWO-With-WordPress'
430 // ]);
431 vwo_clhf_render_woocommerce_event_tracking([
432 'id' => 'track_purchase',
433 'label' => 'Purchase Order',
434 'description' => 'This event logs an instance where a customer completes a purchase.',
435 'readmore_link' => 'https://help.vwo.com/hc/en-us/articles/360020745993-Integrating-VWO-With-WordPress'
436 ]);
437 ?>
438 </div>
439 </div>
440 <?php
441 }
442
443 function vwo_clhf_render_woocommerce_event_tracking($field) {
444 $value = get_option($field['id'], isset($field['default']) ? $field['default'] : '');
445 ?>
446 <div class="woocommerce-row-item">
447 <div class="woocommerce-row-item-header">
448 <h3 class="woocommerce-row-item-title"><?php echo esc_html($field['label']); ?></h3>
449 <input type="checkbox" name="<?php echo esc_attr($field['id']); ?>" id="<?php echo esc_attr($field['id']); ?>" <?php echo checked($value, '1', false) ?> class="vwo-checkbox">
450 <label for="<?php echo esc_attr($field['id']); ?>" class="vwo-checkbox-label">Toggle</label>
451 </div>
452 <p class="woocommerce-row-item-description">
453 <?php echo esc_html($field['description']); ?>
454 <?php /* if (isset($field['readmore_link'])): ?>
455 <a href="<?php echo esc_url($field['readmore_link']); ?>" target="_blank">Read more</a>
456 <?php endif; */ ?>
457 </p>
458 </div>
459 <?php
460 }
461
462
463 function vwo_clhf_render_field($field) {
464 $isCheckbox = $field['type'] === 'checkbox';
465 $value = get_option($field['id'], isset($field['default']) ? $field['default'] : '');
466
467 echo '<div class="' . esc_attr(isset($field['class'])?$field['class']:"") . '">';
468
469 $label = '<label class="form-label" for="' . esc_attr($field['id']) . '">' . esc_html($field['label']) . '</label>';
470
471 switch ($field['type']) {
472 case 'text':
473 case 'number':
474 echo $label;
475 echo '<input type="' . esc_attr($field['type']) . '" id="' . esc_attr($field['id']) . '" name="' . esc_attr($field['id']) . '" value="' . esc_attr($value) . '"';
476 if (isset($field['min'])) echo ' min="' . esc_attr($field['min']) . '"';
477 echo ' class="form-input" />';
478 if (isset($field['suffix'])) echo ' ' . esc_html($field['suffix']);
479 break;
480 case 'radio':
481 echo $label;
482 foreach ($field['options'] as $options) {
483 echo '<div class="radio-container-wrapper">
484 <div class="radio-container">';
485 echo '<label class="form-radio-label"><input type="radio" name="' . esc_attr($field['id']) . '" value="' . esc_attr($options['value']) . '"' . checked($value, $options['value'], false) . ' /> ' . esc_html($options['label']) . '</label> ';
486 echo '</div>';
487 echo '<p class="radio-sublabel">' . esc_html($options['sublabel']) . '</p>';
488 echo '</div>';
489 }
490 break;
491 case 'checkbox':
492 echo '<div class="checkbox-container">';
493 echo '<input type="checkbox" id="' . esc_attr($field['id']) . '" name="' . esc_attr($field['id']) . '" class="vwo-checkbox" value="1"' . checked($value, '1', false) . ' />';
494 echo '<label class="vwo-checkbox-label" for="' . esc_attr($field['id']) . '">Toggle</label>';
495 echo '<label class="form-label form-label--checkbox" for="' . esc_attr($field['id']) . '">' . esc_html($field['label']) . '</label>';
496 echo '</div>';
497 break;
498 }
499
500 if (isset($field['tooltip'])) {
501 echo '<p class="form-description ' . ($isCheckbox ? 'form-description--checkbox' : '') . '">' . esc_html($field['tooltip']) . '</p>';
502 }
503
504 echo '</div>';
505 }
506
507 function vwo_clhf_render_styles() {
508 ?>
509 <style>
510 input[type="radio"] {
511 margin: 0 !important;
512 }
513 input[type=radio]:checked::before {
514 background-color: #3858E9;
515 }
516 .vwo-admin-content {
517 background: #fff;
518 padding: 20px;
519 border: 1px solid #ccd0d4;
520 box-shadow: 0 1px 1px rgba(0,0,0,.04);
521 margin-top: 20px;
522 }
523 .vwo-admin-content .nav-tab,
524 .vwo-admin-content .nav-tab-active{
525 outline:none;
526 box-shadow: none;
527 }
528 .main-grid {
529 display: flex;
530 justify-content: space-between;
531 }
532 .main-grid__description {
533 background-color: #f9f9f9;
534 padding: 24px;
535 border-radius: 8px;
536 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
537 font-family: 'Segoe UI', sans-serif;
538 height: fit-content;max-width: 650px;
539 border: 1px solid #E0E0E0;
540 margin: 20px;
541 }
542 .main-grid__description h2 {
543 font-weight: 600;
544 margin-bottom: 10px;
545 margin-top: 0;
546 font-size: 20px;
547 color: #333;
548 }
549 .main-grid__description p {
550 font-size: 14px;
551 color: #757575;
552 line-height: 1.6;
553 margin-top: 21px;
554 margin-bottom: 0px;
555 }
556 .main-grid__description a {
557 color: #3858E9;
558 }
559 .form-container {
560 margin-top: 24px;
561 margin-bottom: 30px;
562 display: flex;
563 flex-direction: column;
564 gap: 28px;
565 flex: 1;
566 }
567 .form-label {
568 font-size: 12px;
569 color: #1E1E1E;
570 display: block;
571 margin-bottom: 10px;
572 font-weight: 500;
573 }
574 .form-label--checkbox {
575 cursor: pointer;
576 margin-bottom: 0;
577 }
578 .form-radio-label {
579 display: flex;
580 align-items: center;
581 gap: 10px;
582 margin-bottom: 10px;
583 cursor: pointer;
584 }
585 .form-radio-label:last-child {
586 margin-bottom: 0;
587 }
588 .form-description {
589 color: #757575;
590 margin-top: 10px;
591 margin-bottom: 0;
592 font-size: 12px;
593 }
594 .form-description--checkbox {
595 margin-top: 5px;
596 margin-left: 42px;
597 }
598 .form-input {
599 width: 100%;
600 max-width: 400px;
601 border: 1px solid #949494 !important;
602 border-radius: 2px !important;
603 }
604 .checkbox-container, .radio-container {
605 display: flex;
606 gap: 10px;
607 }
608 .radio-container-wrapper {
609 margin-bottom: 20px;
610 }
611 .radio-container-wrapper:last-child {
612 margin-bottom: 0;
613 }
614 .radio-sublabel {
615 font-size: 12px;
616 color: #757575;
617 margin-top: 5px;
618 margin-bottom: 0;
619 margin-left: 26px;
620 }
621 .checkbox-container .form-description {
622 width: 100%;
623 }
624 .async-option {
625 display: none;
626 }
627 .tab-pane {
628 display: none;
629 }
630 .tab-pane.active {
631 display: block;
632 }
633 .description {
634 max-width: 800px;
635 margin-bottom: 20px;
636 }
637
638 .woocommerce-row {
639 display: grid;
640 grid-template-columns: repeat(3, 1fr);
641 gap: 16px;
642 }
643 .woocommerce-row-item {
644 border: 1px solid rgba(0, 0, 0, 0.10);
645 border-radius: 8px;
646 }
647 .woocommerce-row-item-header {
648 display: flex;
649 justify-content: space-between;
650 align-items: center;
651 gap: 5px;
652 padding: 10px;
653 border-bottom: 1px solid rgba(0, 0, 0, 0.10);
654 }
655 .woocommerce-row-item-title {
656 margin: 0;
657 font-size: 13px;
658 font-weight: 500;
659 color: #1E1E1E;
660 }
661 .woocommerce-row-item-description {
662 margin: 0;
663 font-size: 12px;
664 color: #757575;
665 padding: 10px;
666 }
667 .woocommerce-row-item-description a {
668 color: #3858E9;
669 }
670 .woocommerce-main-header {
671 margin: 30px 0;
672 }
673 .woocommerce-row--disabled {
674 opacity: 0.4;
675 cursor: not-allowed;
676 pointer-events: none;
677 }
678 input[type=checkbox].vwo-checkbox{
679 height: 0;
680 width: 0;
681 visibility: hidden;
682 position: absolute;
683 clip: rect(1px,1px,1px,1px);
684 overflow: hidden;
685 }
686
687 label.vwo-checkbox-label {
688 box-sizing: border-box;
689 cursor: pointer;
690 text-indent: -9999px;
691 width: 32px;
692 height: 18px;
693 border: 1px solid #000;
694 background: #fff;
695 display: block;
696 border-radius: 100px;
697 position: relative;
698 }
699
700 label.vwo-checkbox-label:after {
701 content: '';
702 position: absolute;
703 top: 50%;
704 transform: translateY(-50%);
705 left: 2px;
706 width: 12px;
707 height: 12px;
708 background: #000;
709 border-radius: 90px;
710 transition: 0.3s;
711 }
712
713 input.vwo-checkbox:checked + label.vwo-checkbox-label {
714 background: #3858E9;
715 border-color: #3858E9;
716 }
717
718 input.vwo-checkbox:checked + label.vwo-checkbox-label:after {
719 left: calc(100% - 2px);
720 transform: translateX(-100%) translateY(-50%);
721 background-color: #fff;
722 }
723
724 </style>
725 <?php
726 }
727
728 function vwo_clhf_render_scripts() {
729 ?>
730 <script>
731 jQuery(document).ready(function($) {
732 function toggleAsyncOptions() {
733 var isAsync = $('input[name="code_type"]:checked').val() === 'ASYNC';
734 $('.async-option').toggle(isAsync);
735 }
736 function toggleWooCommerceOptions() {
737 var isWooCommerce = $('input[name="enable_woocommerce_event_tracking"]:checked');
738
739 if(isWooCommerce.length > 0) {
740 $('.woocommerce-row').removeClass('woocommerce-row--disabled');
741 $('.vwo_server_side_tracking').removeClass('woocommerce-row--disabled');
742
743 } else {
744 $('.woocommerce-row').addClass('woocommerce-row--disabled');
745 $('.vwo_server_side_tracking').addClass('woocommerce-row--disabled');
746 }
747 }
748
749 $('input[name="enable_woocommerce_event_tracking"]').change(toggleWooCommerceOptions);
750 $("label[for='enable_woocommerce_event_tracking']").click(toggleWooCommerceOptions);
751 toggleWooCommerceOptions(); // Run on page load
752
753 $('input[name="code_type"]').change(toggleAsyncOptions);
754 toggleAsyncOptions(); // Run on page load
755
756 // Handle tab switching
757 $('.nav-tab-wrapper .nav-tab').on('click', function(e) {
758 e.preventDefault();
759 var targetTab = $(this).attr('href');
760
761 // Update active tab
762 $('.nav-tab-wrapper .nav-tab').removeClass('nav-tab-active');
763 $(this).addClass('nav-tab-active');
764
765 // Show target tab content
766 $('.tab-pane').removeClass('active').hide();
767 $(targetTab).addClass('active').show();
768 });
769
770 // Ensure the first tab is visible on page load
771 $('#tab-general').show();
772 });
773 </script>
774 <?php
775 }
776
777 function vwo_clhf_enqueue_admin_scripts($hook) {
778 if ('settings_page_clhf_vwo_options' !== $hook) {
779 return;
780 }
781 wp_enqueue_style('wp-admin');
782 }
783 add_action('admin_enqueue_scripts', 'vwo_clhf_enqueue_admin_scripts');
784
785 /**
786 * Displays a warning message if VWO settings are not configured.
787 * This function checks if the user is an admin and if the VWO ID option is set. If the user is not an admin or
788 * the VWO ID option is not set, it displays a warning message.
789 *
790 * @throws Exception Description of exception.
791 * @return void
792 */
793 function vwo_clhf_warn_nosettings() {
794 if ( ! is_admin() ) {
795 return;
796 }
797
798 $clhf_option = get_option( 'vwo_id' );
799 if ( ! $clhf_option || $clhf_option < 1 ) {
800 echo "<div id='vwo-warning' class='updated fade'><p><strong>VWO is almost ready.</strong> You must <a href=\"options-general.php?page=clhf_vwo_options\">enter your Account ID</a> for it to work.</p></div>";
801 }
802 }
803
804
805 add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'vwo_clhf_add_plugin_page_settings_link' );
806
807 /**
808 * Function to add Settings Links on Plugin page
809 *
810 * @param array $links Array of links.
811 * @return array
812 */
813 function vwo_clhf_add_plugin_page_settings_link( $links ) {
814 $links[] = '<a href="' .
815 admin_url( 'options-general.php?page=clhf_vwo_options' ) .
816 '">' . __( 'Settings' ) . '</a>';
817 return $links;
818 }
819
820 /**
821 * Disables VWO in Divi Builder.
822 *
823 * @throws Exception Description of exception.
824 * @return void
825 */
826 function disable_vwo_in_divi_builder() {
827 if ( has_action( 'wp_head', 'vwo_clhf_headercode' ) && function_exists( 'et_core_is_fb_enabled' ) && et_core_is_fb_enabled() ) {
828 remove_action( 'wp_head', 'vwo_clhf_headercode', 1 );
829 }
830 }
831
832 add_action( 'wp_head', 'disable_vwo_in_divi_builder', 0 );
833
834 // Add this new function to validate settings
835 function vwo_clhf_validate_settings() {
836 $has_errors = false;
837
838 // Validate VWO Account ID
839 $vwo_id = get_option('vwo_id');
840 if (empty($vwo_id) || !is_numeric($vwo_id)) {
841 add_settings_error('vwo_clhf_options', 'vwo_id', 'Please enter a valid VWO Account ID.', 'error');
842 $has_errors = true;
843 }
844
845 // Add more validation for other fields as needed
846
847 return $has_errors;
848 }
849
850 // Add this new function to sanitize and validate settings
851 function vwo_clhf_sanitize_settings($input) {
852 // Sanitize and validate VWO Account ID
853 $vwo_id = sanitize_text_field($input);
854 if (empty($vwo_id) || !is_numeric($vwo_id)) {
855 add_settings_error('vwo_clhf_options', 'vwo_id', 'Please enter a valid VWO Account ID.', 'error');
856 }
857
858 // Add more sanitization and validation for other fields as needed
859 // Check if vwo_id is changed
860 $current_vwo_id = get_option('vwo_id');
861 if ($current_vwo_id !== $vwo_id) {
862 update_option('vwo_coll_url','');
863 }
864 return $vwo_id;
865 }
866
867 function enqueue_jquery_script() {
868 wp_enqueue_script('jquery');
869 }
870 add_action('wp_enqueue_scripts', 'enqueue_jquery_script');
871
872 if (file_exists(plugin_dir_path(__FILE__) . 'woocommerce-events.php')) {
873 include_once plugin_dir_path(__FILE__) . 'woocommerce-events.php';
874 }
875
876
877 ?>