Call Now Button - Version 1.0.4

Version Description

= * Live button preview in Premium * Easy activation of Premium via email * Tab switching while editing * Bugfix for timezones in scheduler * Update notice stays visible till closed

Download this release

Release Info

Developer jasperroel
Plugin Icon 128x128 Call Now Button
Version 1.0.4
Comparing to
See all releases

Code changes from version 1.0.3 to 1.0.4

call-now-button.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Call Now Button
4
  Plugin URI: https://callnowbutton.com
5
  Description: Mobile visitors will see a <strong>Call Now Button</strong> on your website. Easy to use but flexible to meet more demanding requirements. Change placement and color, hide on specific pages, track how many people click them or conversions of your Google Ads campaigns. It's all optional but possible.
6
- Version: 1.0.3
7
  Author: Jerry Rietveld
8
  Author URI: https://www.callnowbutton.com
9
  GitHub Plugin URI: https://github.com/callnowbutton/wp-plugin
@@ -26,7 +26,7 @@ License: GPL2
26
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
  */
28
 
29
- define('CNB_VERSION', '1.0.3');
30
  define('CNB_NAME', 'Call Now Button');
31
  define('CNB_BASENAME', plugin_basename(__FILE__));
32
  define('CNB_BASEFOLDER', plugin_basename(dirname(__FILE__)));
3
  Plugin Name: Call Now Button
4
  Plugin URI: https://callnowbutton.com
5
  Description: Mobile visitors will see a <strong>Call Now Button</strong> on your website. Easy to use but flexible to meet more demanding requirements. Change placement and color, hide on specific pages, track how many people click them or conversions of your Google Ads campaigns. It's all optional but possible.
6
+ Version: 1.0.4
7
  Author: Jerry Rietveld
8
  Author URI: https://www.callnowbutton.com
9
  GitHub Plugin URI: https://github.com/callnowbutton/wp-plugin
26
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
  */
28
 
29
+ define('CNB_VERSION', '1.0.4');
30
  define('CNB_NAME', 'Call Now Button');
31
  define('CNB_BASENAME', plugin_basename(__FILE__));
32
  define('CNB_BASEFOLDER', plugin_basename(dirname(__FILE__)));
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: call button, click to call, convert, call now button, contact button
5
  Requires at least: 3.9
6
  Requires PHP: 5.4
7
  Tested up to: 5.8
8
- Stable tag: 1.0.3
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -111,6 +111,13 @@ Yes, you can upgrade to Premium to enable tons of extra features. Checkout [call
111
 
112
 
113
  == Changelog ==
 
 
 
 
 
 
 
114
  = 1.0.3 =
115
  * Fixes a plugin upgrade bug
116
 
5
  Requires at least: 3.9
6
  Requires PHP: 5.4
7
  Tested up to: 5.8
8
+ Stable tag: 1.0.4
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
111
 
112
 
113
  == Changelog ==
114
+ = 1.0.4 =
115
+ * Live button preview in Premium
116
+ * Easy activation of Premium via email
117
+ * Tab switching while editing
118
+ * Bugfix for timezones in scheduler
119
+ * Update notice stays visible till closed
120
+
121
  = 1.0.3 =
122
  * Fixes a plugin upgrade bug
123
 
resources/js/action-type-to-icon-text.js ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function cnbActiontypeToIcontext(actionType) {
2
+ switch (actionType) {
3
+ case 'ANCHOR': return 'anchor';
4
+ case 'WHATSAPP': return 'whatsapp';
5
+ case 'EMAIL': return 'email';
6
+ case 'LINK': return 'link';
7
+ case 'MAP': return 'directions';
8
+ case 'HOURS': return 'access_time';
9
+ case 'PHONE':
10
+ default:
11
+ return 'call';
12
+ }
13
+ }
14
+
15
+ function updateIconText() {
16
+ const type = jQuery('#cnb_action_type').val();
17
+ const iconText = cnbActiontypeToIcontext(type)
18
+ jQuery('#cnb_action_icon_text').val(iconText);
19
+ }
20
+
21
+ function initUpdateIconText() {
22
+ jQuery('form.cnb-container :input').on('change input', function() {
23
+ updateIconText()
24
+ });
25
+ }
26
+
27
+ jQuery(() => {
28
+ initUpdateIconText()
29
+ })
resources/js/call-now-button.js CHANGED
@@ -1,7 +1,21 @@
1
  function cnb_setup_colors() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  // Add color picker
3
- jQuery('.cnb-color-field').wpColorPicker();
4
- jQuery('.cnb-iconcolor-field').wpColorPicker();
5
 
6
  // Reveal additional button placements when clicking "more"
7
  jQuery("#cnb-more-placements").on('click', function(e){
@@ -60,10 +74,22 @@ function cnb_hide_on_show_always() {
60
  let show_always_checkbox = document.getElementById('actions_schedule_show_always');
61
  if (show_always_checkbox) {
62
  if (show_always_checkbox.checked) {
63
- // Hide
64
- jQuery('.cnb_hide_on_show_always').hide();
 
 
 
65
  } else {
66
- jQuery('.cnb_hide_on_show_always').show();
 
 
 
 
 
 
 
 
 
67
  }
68
  }
69
  return false;
@@ -88,11 +114,29 @@ function cnb_animate_saving() {
88
  return;
89
  }
90
  // Check if the form will actually subbmit...
91
- const valid = jQuery(this).closest('form')[0].checkValidity();
 
92
  if (valid) {
93
  jQuery(this).addClass('is-busy');
94
  jQuery(this).prop('value', 'Saving...');
95
  jQuery(this).prop('aria-disabled', 'true');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  }
97
  })
98
  }
@@ -100,42 +144,41 @@ function cnb_animate_saving() {
100
  let cnb_add_condition_counter = 0;
101
  function cnb_add_condition() {
102
  let template = `
103
- <td colspan="2" style="padding: 0;">
104
- <table class="cnb_condition_rule">
105
- <tbody>
106
- <tr>
107
- <td>
108
- <input type="hidden" name="condition[${cnb_add_condition_counter}][id]" value="" />
109
- <input type="hidden" name="condition[${cnb_add_condition_counter}][conditionType]" value="URL" />
110
- <input type="hidden" name="condition[${cnb_add_condition_counter}][delete]" id="cnb_condition_${cnb_add_condition_counter}_delete" value="" />
111
- <select name="condition[${cnb_add_condition_counter}][filterType]">
112
- <option value="INCLUDE">Include</option>
113
- <option value="EXCLUDE">Exclude</option>
114
- </select>
115
- </td>
116
- <td>
117
- <select class="js-condition-matchtype" data-cnb-condition-id="${cnb_add_condition_counter}" name="condition[${cnb_add_condition_counter}][matchType]">
118
- <option value="SIMPLE">Page path is:</option>
119
- <option value="EXACT">Page URL is:</option>
120
- <option value="SUBSTRING">Page URL contains:</option>
121
- <option value="REGEX">Page URL matches RegEx:</option>
122
- </select>
123
- </td>
124
- <td class="max_width_column">
125
- <input class="js-condition-matchvalue-${cnb_add_condition_counter}" type="text" name="condition[${cnb_add_condition_counter}][matchValue]" value="" placeholder="e.g. /blog/" />
126
- <a onclick="return cnb_remove_condition('${cnb_add_condition_counter}');" title="Remove Condition" class="button-link button-link-delete"><span class="dashicons dashicons-no" style="padding-top: 5px;"></span>
127
- </a>
128
- </td>
129
- </tr>
130
- </tbody>
131
- </table>
132
  </td>
133
  `;
134
 
135
  let table = document.getElementById('cnb_form_table_visibility');
136
  let container = document.getElementById('cnb_form_table_add_condition');
137
  let rowElement = document.createElement('tr');
138
- rowElement.className = 'appearance cnb_condition_new';
139
  rowElement.vAlign = 'top';
140
  rowElement.id = 'cnb_condition_' + cnb_add_condition_counter;
141
  rowElement.innerHTML = template;
@@ -143,6 +186,7 @@ function cnb_add_condition() {
143
 
144
  cnb_add_condition_counter++;
145
  cnb_show_condition_placeholder();
 
146
  return false;
147
  }
148
 
@@ -165,6 +209,30 @@ function cnb_show_condition_placeholder() {
165
  });
166
  }
167
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  function cnb_setup_toggle_label_clicks() {
169
  jQuery('.cnb_toggle_state').on( "click", function() {
170
  const stateLabel = jQuery(this).data('cnb_toggle_state_label');
@@ -177,12 +245,14 @@ function cnb_remove_condition(id) {
177
  let deleteElement = document.getElementById('cnb_condition_' + id + '_delete');
178
  deleteElement.value = 'true';
179
  jQuery(container).css("background-color", "#ff726f");
 
180
  jQuery(container).fadeOut(function() {
181
  jQuery(container).css("background-color", "");
182
  if (container.className.includes('cnb_condition_new')) {
183
  container.remove();
184
  }
185
  });
 
186
  }
187
 
188
  function cnb_action_appearance() {
@@ -347,7 +417,10 @@ function show_advanced_view_only() {
347
  function cnb_strip_beta_from_referrer() {
348
  const referer = jQuery('input[name="_wp_http_referer"]');
349
  if (referer && referer.val()) {
350
- referer.val(referer.val().replace('&beta', ''))
 
 
 
351
  }
352
  }
353
 
@@ -368,7 +441,16 @@ function cnb_delete_action() {
368
  };
369
 
370
  // Send remove request
371
- jQuery.post(ajaxurl, data);
 
 
 
 
 
 
 
 
 
372
 
373
  // Remove container
374
  const action_row = jQuery(this).closest('tr');
@@ -501,6 +583,55 @@ function cnb_button_overview_add_new_click() {
501
  return false;
502
  }
503
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  jQuery( function() {
505
  // Generic
506
  cnb_setup_colors();
@@ -514,6 +645,10 @@ jQuery( function() {
514
  cnb_strip_beta_from_referrer();
515
  cnb_animate_saving();
516
  cnb_setup_toggle_label_clicks();
 
 
 
 
517
 
518
  if (typeof show_advanced_view_only_set !== 'undefined' && show_advanced_view_only_set && show_advanced_view_only_set === 1) {
519
  show_advanced_view_only()
@@ -523,6 +658,10 @@ jQuery( function() {
523
  cnb_hide_on_modal();
524
  }
525
 
 
 
 
 
526
  cnb_delete_action();
527
  cnb_button_overview_modal();
528
 
1
  function cnb_setup_colors() {
2
+ // This "change" options ensures that if a color is changed and a livePreview is available,
3
+ // we update it. Cannot not be done via an ".on('change')", since the wpColorPicker cannot
4
+ // respond to those events
5
+ const options = {
6
+ change: () => {
7
+ jQuery(() => {
8
+ if (typeof livePreview !== 'undefined') {
9
+ livePreview();
10
+ }
11
+ });
12
+
13
+ }
14
+ }
15
+
16
  // Add color picker
17
+ jQuery('.cnb-color-field').wpColorPicker(options);
18
+ jQuery('.cnb-iconcolor-field').wpColorPicker(options);
19
 
20
  // Reveal additional button placements when clicking "more"
21
  jQuery("#cnb-more-placements").on('click', function(e){
74
  let show_always_checkbox = document.getElementById('actions_schedule_show_always');
75
  if (show_always_checkbox) {
76
  if (show_always_checkbox.checked) {
77
+ // Hide all items specific for Scheduler
78
+ jQuery('.cnb_hide_on_show_always:not(.cnb_advanced_view)').hide();
79
+
80
+ // Hide Domain Timezone notice
81
+ jQuery('#cnb-notice-domain-timezone-unsupported').parent('.notice').hide();
82
  } else {
83
+ // Show all items specific for Scheduler (except for "cnb_advanced_view")
84
+ jQuery('.cnb_hide_on_show_always:not(.cnb_advanced_view)').show();
85
+
86
+ // Show Domain Timezone notice (and move to the correct place)
87
+ const domainTimezoneNotice = jQuery('#cnb-notice-domain-timezone-unsupported').parent('.notice');
88
+ domainTimezoneNotice.show();
89
+ const domainTimezoneNoticePlaceholder = jQuery('#domain-timezone-notice-placeholder');
90
+ if (domainTimezoneNoticePlaceholder.length !== 0) {
91
+ domainTimezoneNotice.insertAfter(domainTimezoneNoticePlaceholder);
92
+ }
93
  }
94
  }
95
  return false;
114
  return;
115
  }
116
  // Check if the form will actually subbmit...
117
+ const form = jQuery(this).closest('form');
118
+ const valid = form[0].checkValidity();
119
  if (valid) {
120
  jQuery(this).addClass('is-busy');
121
  jQuery(this).prop('value', 'Saving...');
122
  jQuery(this).prop('aria-disabled', 'true');
123
+ } else {
124
+ // Clear old notices
125
+ jQuery('.cnb-form-validation-notice').remove();
126
+
127
+ const invalidFields = form.find(':invalid')
128
+ // Find tab with error and switch to it if found
129
+ const tabName = invalidFields.first().closest('[data-tab-name]').data('tabName')
130
+ if (tabName) {
131
+ cnb_switch_tab(tabName);
132
+ }
133
+ // Collect all errors and create notification
134
+ invalidFields.each( function(index,node) {
135
+ const notification = jQuery('<div class="cnb-form-validation-notice notice notice-warning"></div>');
136
+ const label = node.labels.length > 0 ? node.labels[0].innerText + ': ' : '';
137
+ notification.text(label + node.validationMessage);
138
+ notification.insertAfter(form.find('#submit'));
139
+ })
140
  }
141
  })
142
  }
144
  let cnb_add_condition_counter = 0;
145
  function cnb_add_condition() {
146
  let template = `
147
+ <td colspan="2" class="cnb_padding_0">
148
+ <div class="cnb_condition_rule">
149
+ <input type="hidden" name="condition[${cnb_add_condition_counter}][id]" value="" />
150
+ <input type="hidden" name="condition[${cnb_add_condition_counter}][conditionType]" value="URL" />
151
+ <input type="hidden" name="condition[${cnb_add_condition_counter}][delete]" id="cnb_condition_${cnb_add_condition_counter}_delete" value="" />
152
+ <div>
153
+ <select name="condition[${cnb_add_condition_counter}][filterType]">
154
+ <option value="INCLUDE">Include</option>
155
+ <option value="EXCLUDE">Exclude</option>
156
+ </select>
157
+ </div>
158
+
159
+ <div>
160
+ <select class="js-condition-matchtype" data-cnb-condition-id="${cnb_add_condition_counter}" name="condition[${cnb_add_condition_counter}][matchType]">
161
+ <option value="SIMPLE">Page path is:</option>
162
+ <option value="EXACT">Page URL is:</option>
163
+ <option value="SUBSTRING">Page URL contains:</option>
164
+ <option value="REGEX">Page URL matches RegEx:</option>
165
+ </select>
166
+ </div>
167
+
168
+ <div class="max_width_column">
169
+ <input class="js-condition-matchvalue-${cnb_add_condition_counter}" type="text" name="condition[${cnb_add_condition_counter}][matchValue]" value="" placeholder="e.g. /blog/" />
170
+ <a onclick="return cnb_remove_condition('${cnb_add_condition_counter}');" title="Remove Condition" class="button-link button-link-delete">
171
+ <span class="dashicons dashicons-no" style="padding-top: 5px;"></span>
172
+ </a>
173
+ </div>
174
+ </div>
 
175
  </td>
176
  `;
177
 
178
  let table = document.getElementById('cnb_form_table_visibility');
179
  let container = document.getElementById('cnb_form_table_add_condition');
180
  let rowElement = document.createElement('tr');
181
+ rowElement.className = 'appearance cnb_condition_new cnb-condition';
182
  rowElement.vAlign = 'top';
183
  rowElement.id = 'cnb_condition_' + cnb_add_condition_counter;
184
  rowElement.innerHTML = template;
186
 
187
  cnb_add_condition_counter++;
188
  cnb_show_condition_placeholder();
189
+ cnb_button_edit_conditions_hide_on_show_on_all_pages();
190
  return false;
191
  }
192
 
209
  });
210
  }
211
 
212
+ function cnb_button_edit_conditions_change_listener() {
213
+ jQuery('#cnb_form_table_visibility').on('change', function() {
214
+ cnb_button_edit_conditions_hide_on_show_on_all_pages();
215
+ })
216
+ }
217
+ // Show the rules section based on the checkbox status
218
+ function cnb_button_edit_conditions_hide_on_show_on_all_pages() {
219
+ const condition_count = jQuery('.cnb-condition').length;
220
+ const condition_toggle = jQuery('#conditions_show_on_all_pages');
221
+ condition_toggle.removeAttr('disabled');
222
+ if (condition_count > 0) {
223
+ // Ensure disabled
224
+ condition_toggle.prop('checked', false);
225
+ condition_toggle.attr('disabled', 'disabled');
226
+ } else {
227
+ if(condition_toggle.prop('checked')) {
228
+ jQuery(".cnb_hide_on_show_on_all_pages").hide();
229
+ } else {
230
+ jQuery(".cnb_hide_on_show_on_all_pages").show();
231
+ }
232
+ }
233
+ return false;
234
+ }
235
+
236
  function cnb_setup_toggle_label_clicks() {
237
  jQuery('.cnb_toggle_state').on( "click", function() {
238
  const stateLabel = jQuery(this).data('cnb_toggle_state_label');
245
  let deleteElement = document.getElementById('cnb_condition_' + id + '_delete');
246
  deleteElement.value = 'true';
247
  jQuery(container).css("background-color", "#ff726f");
248
+ container.classList.remove('cnb-condition');
249
  jQuery(container).fadeOut(function() {
250
  jQuery(container).css("background-color", "");
251
  if (container.className.includes('cnb_condition_new')) {
252
  container.remove();
253
  }
254
  });
255
+ cnb_button_edit_conditions_hide_on_show_on_all_pages();
256
  }
257
 
258
  function cnb_action_appearance() {
417
  function cnb_strip_beta_from_referrer() {
418
  const referer = jQuery('input[name="_wp_http_referer"]');
419
  if (referer && referer.val()) {
420
+ referer.val(referer.val().replace(/[?&]beta/, ''))
421
+ referer.val(referer.val().replace(/[?&]api_key=[0-9a-z-]+/, ''))
422
+ referer.val(referer.val().replace(/[?&]api_key_ott=[0-9a-z-]+/, ''))
423
+ referer.val(referer.val().replace(/[?&]cloud_enabled=[0-9]/, ''))
424
  }
425
  }
426
 
441
  };
442
 
443
  // Send remove request
444
+ jQuery.post(ajaxurl, data)
445
+ .done((result) => {
446
+ // Update the global "cnb_actions" variable
447
+ if (result && result.button && result.button.actions) {
448
+ cnb_actions = result.button.actions
449
+ if (typeof livePreview !== 'undefined') {
450
+ livePreview();
451
+ }
452
+ }
453
+ });
454
 
455
  // Remove container
456
  const action_row = jQuery(this).closest('tr');
583
  return false;
584
  }
585
 
586
+
587
+ function cnb_init_tabs() {
588
+ jQuery('a.nav-tab').on('click', (e) => {
589
+ e.preventDefault();
590
+ return cnb_switch_tab(jQuery( e.target ).data('tabName'))
591
+ });
592
+ }
593
+
594
+ function cnb_switch_tab(tabName, addToHistory = true) {
595
+ const tab = jQuery('a.nav-tab[data-tab-name][data-tab-name="' + tabName + '"]');
596
+ const tabContent = jQuery('table[data-tab-name][data-tab-name="' + tabName + '"], div[data-tab-name][data-tab-name="' + tabName + '"]');
597
+
598
+ // Does tab name exist (if not, don't do anything)
599
+ if (tab.length === 0) return false;
600
+
601
+ // Hide all tabs
602
+ const otherTabs = jQuery('a.nav-tab[data-tab-name][data-tab-name!="' + tabName + '"]');
603
+ const otherTabsContent = jQuery('table[data-tab-name][data-tab-name!="' + tabName + '"], div[data-tab-name][data-tab-name!="' + tabName + '"]');
604
+ otherTabs.removeClass('nav-tab-active')
605
+ otherTabsContent.hide();
606
+
607
+ // Display passed in tab
608
+ tab.addClass('nav-tab-active')
609
+ tabContent.show();
610
+
611
+ // Push this to URL
612
+ if (addToHistory) {
613
+ const url = new URL(window.location);
614
+ const data = {
615
+ cnb_switch_tab_event: true,
616
+ tab_name: tabName
617
+ }
618
+
619
+ url.searchParams.set('tab', tabName);
620
+ window.history.pushState(data, '', url);
621
+ }
622
+
623
+ return false;
624
+ }
625
+
626
+ function cnb_switch_tab_from_history_listener() {
627
+ window.addEventListener('popstate', (event) => {
628
+ if (event && event.state && event.state.cnb_switch_tab_event && event.state.tab_name) {
629
+ // Switch back but do NOT add this action to the history again to prevent loops
630
+ cnb_switch_tab(event.state.tab_name, false)
631
+ }
632
+ });
633
+ }
634
+
635
  jQuery( function() {
636
  // Generic
637
  cnb_setup_colors();
645
  cnb_strip_beta_from_referrer();
646
  cnb_animate_saving();
647
  cnb_setup_toggle_label_clicks();
648
+ cnb_switch_tab_from_history_listener();
649
+
650
+ // Allow for tab switching to be dynamic
651
+ cnb_init_tabs();
652
 
653
  if (typeof show_advanced_view_only_set !== 'undefined' && show_advanced_view_only_set && show_advanced_view_only_set === 1) {
654
  show_advanced_view_only()
658
  cnb_hide_on_modal();
659
  }
660
 
661
+ // page: button-edit (conditions tabs)
662
+ cnb_button_edit_conditions_change_listener();
663
+ cnb_button_edit_conditions_hide_on_show_on_all_pages();
664
+
665
  cnb_delete_action();
666
  cnb_button_overview_modal();
667
 
resources/js/dismiss.js CHANGED
@@ -2,16 +2,65 @@
2
  * Admin code for dismissing notifications.
3
  *
4
  */
5
- (function( $ ) {
6
- 'use strict';
7
- $( function() {
8
- const plugin_slug = 'call-now-button';
9
- $( '.notice-' + plugin_slug ).on( 'click', '.notice-dismiss', function( event, el ) {
10
- const $notice = $(this).parent('.notice.is-dismissible');
11
- const dismiss_url = $notice.attr('data-dismiss-url');
12
- if ( dismiss_url ) {
13
- $.get( dismiss_url );
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  });
16
- } );
17
- })( jQuery );
 
 
 
 
 
 
 
2
  * Admin code for dismissing notifications.
3
  *
4
  */
5
+ function cnb_dismissables_listener() {
6
+ jQuery( '.notice-call-now-button').on( 'click', '.notice-dismiss',
7
+ function() {
8
+ const $notice = jQuery(this).parent('.is-dismissible');
9
+ const dismiss_url = $notice.attr('data-dismiss-url');
10
+ if ( dismiss_url ) {
11
+ jQuery.get( dismiss_url );
12
+ }
13
+ });
14
+ }
15
+
16
+ function cnb_set_sidenav_counter(value) {
17
+ const counter = jQuery('#cnb-nav-counter');
18
+ counter.text(value)
19
+ if (value) {
20
+ counter.parent().textNodes().first().replaceWith('Call Now Bu...')
21
+ counter.show();
22
+ } else {
23
+ counter.parent().textNodes().first().replaceWith('Call Now Button')
24
+ counter.hide()
25
+ }
26
+ }
27
+
28
+ function cnb_decrease_sidenav_counter() {
29
+ const counter = jQuery('#cnb-nav-counter');
30
+ const counterValue = parseInt(counter.text())
31
+ const newValue = counterValue - 1;
32
+ cnb_set_sidenav_counter(newValue)
33
+ }
34
+
35
+ function cnb_upgrade_notice_dismiss_listener() {
36
+ jQuery('#cnb_is_updated').closest('.notice-call-now-button').on('click', '.notice-dismiss',
37
+ () => {
38
+ cnb_decrease_sidenav_counter();
39
+ })
40
+ }
41
+
42
+ function cnb_welcome_panel_dismiss_listener() {
43
+ jQuery('#welcome-panel').on('click', '.notice-dismiss', () => {
44
+ cnb_decrease_sidenav_counter();
45
+ jQuery('#welcome-panel').remove();
46
+ })
47
+ }
48
+
49
+ /**
50
+ * Add a jQuery extension so it can be used on any jQuery object
51
+ * Copied from https://stackoverflow.com/a/4106957
52
+ */
53
+ function cnb_add_jquery_textnodes() {
54
+ jQuery.fn.textNodes = function () {
55
+ return this.contents().filter(function () {
56
+ return (this.nodeType === Node.TEXT_NODE && this.nodeValue.trim() !== "");
57
  });
58
+ }
59
+ }
60
+
61
+ jQuery(() => {
62
+ cnb_add_jquery_textnodes();
63
+ cnb_dismissables_listener();
64
+ cnb_upgrade_notice_dismiss_listener();
65
+ cnb_welcome_panel_dismiss_listener();
66
+ })
resources/js/domain-upgrade.js CHANGED
@@ -15,6 +15,7 @@ function showMessage(type='success', message='') {
15
  cnb_notice.addClass('notice notice-' + type);
16
  cnb_notice.show();
17
  }
 
18
  /**
19
  * function for the currency selector on the Upgrade page
20
  */
@@ -77,7 +78,7 @@ function cnb_domain_upgrade_notice_profile_saved() {
77
  }
78
 
79
  function do_cnb_ajax_submit_profile() {
80
- const form = jQuery('.call-now-button_page_call-now-button-domains .cnb-settings-profile');
81
 
82
  // Prep data
83
  const formData = form.serialize();
@@ -86,32 +87,43 @@ function do_cnb_ajax_submit_profile() {
86
  data: formData
87
  };
88
 
89
- try {
90
- jQuery.post({
91
- url: ajaxurl,
92
- data: data,
93
- success: function () {
94
- // Close box
95
- cnb_domain_upgrade_notice_profile_saved();
96
- jQuery('#TB_closeWindowButton').trigger('click');
97
- }
98
- });
99
- } catch (e) {
100
- showMessage('error', e.message);
 
 
 
 
 
 
 
 
 
101
  }
102
  return false;
103
  }
 
104
  /**
105
  * This calls the admin-ajax action called 'cnb_settings_profile_save'
 
 
106
  */
107
  function cnb_ajax_submit_profile() {
108
- console.log('attaching listerers...');
109
- jQuery('.call-now-button_page_call-now-button-domains .cnb-settings-profile')
110
  .on('submit', function(e) {
111
  e.preventDefault();
112
  return do_cnb_ajax_submit_profile();
113
  });
114
- jQuery('.call-now-button_page_call-now-button-domains .cnb-settings-profile #submit')
115
  .on('click', function(e){
116
  e.preventDefault();
117
  return do_cnb_ajax_submit_profile();
15
  cnb_notice.addClass('notice notice-' + type);
16
  cnb_notice.show();
17
  }
18
+
19
  /**
20
  * function for the currency selector on the Upgrade page
21
  */
78
  }
79
 
80
  function do_cnb_ajax_submit_profile() {
81
+ const form = jQuery('.cnb-settings-profile');
82
 
83
  // Prep data
84
  const formData = form.serialize();
87
  data: formData
88
  };
89
 
90
+ const valid = form[0].checkValidity();
91
+ if (valid) {
92
+ try {
93
+ jQuery.post({
94
+ url: ajaxurl,
95
+ data: data,
96
+ success: function () {
97
+ // Hide "Next", show "Upgrade"
98
+ jQuery('.open-profile-details-modal').hide();
99
+ jQuery('.button-upgrade').show();
100
+
101
+ // Close box
102
+ cnb_domain_upgrade_notice_profile_saved();
103
+ jQuery('#TB_closeWindowButton').trigger('click');
104
+ }
105
+ });
106
+ } catch (e) {
107
+ showMessage('error', e.message);
108
+ }
109
+ } else {
110
+ // Noop, errors are shown in the form itself
111
  }
112
  return false;
113
  }
114
+
115
  /**
116
  * This calls the admin-ajax action called 'cnb_settings_profile_save'
117
+ *
118
+ * This is used on the modal on domain-upgrade
119
  */
120
  function cnb_ajax_submit_profile() {
121
+ jQuery('.cnb-settings-profile')
 
122
  .on('submit', function(e) {
123
  e.preventDefault();
124
  return do_cnb_ajax_submit_profile();
125
  });
126
+ jQuery('.cnb-settings-profile #submit')
127
  .on('click', function(e){
128
  e.preventDefault();
129
  return do_cnb_ajax_submit_profile();
resources/js/form-to-json.js ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Copied from https://bugs.jquery.com/ticket/2207#comment:7
3
+ */
4
+ function formToJson() {
5
+ (function($){
6
+ $.extend({
7
+ isArray: function (arr){
8
+ if (typeof arr == 'object'){
9
+ if (arr.constructor === Array){
10
+ return true;
11
+ }
12
+ }
13
+ return false;
14
+ },
15
+ arrayMerge: function (){
16
+ let a = {};
17
+ let n = 0;
18
+ const argv = $.arrayMerge.arguments;
19
+ for (let i = 0; i < argv.length; i++){
20
+ if ($.isArray(argv[i])){
21
+ for (let j = 0; j < argv[i].length; j++){
22
+ a[n++] = argv[i][j];
23
+ }
24
+ a = $.makeArray(a);
25
+ } else {
26
+ for (const k in argv[i]){
27
+ if (isNaN(k)){
28
+ let v = argv[i][k];
29
+ if (typeof v == 'object' && a[k]){
30
+ v = $.arrayMerge(a[k], v);
31
+ }
32
+ a[k] = v;
33
+ } else {
34
+ a[n++] = argv[i][k];
35
+ }
36
+ }
37
+ }
38
+ }
39
+ return a;
40
+ },
41
+ count: function (arr){
42
+ if ($.isArray(arr)){
43
+ return arr.length;
44
+ } else {
45
+ let n = 0;
46
+ for (const k in arr){
47
+ if (!isNaN(k)){
48
+ n++;
49
+ }
50
+ }
51
+ return n;
52
+ }
53
+ }
54
+ });
55
+ $.fn.extend({
56
+ serializeAssoc: function (){
57
+ const o = {
58
+ aa: {},
59
+ add: function (name, value) {
60
+ const tmp = name.match(/^(.*)\[([^\]]*)\]$/);
61
+ if (tmp) {
62
+ const v = {};
63
+ if (tmp[2])
64
+ v[tmp[2]] = value;
65
+ else
66
+ v[$.count(v)] = value;
67
+ this.add(tmp[1], v);
68
+ } else if (typeof value == 'object') {
69
+ if (typeof this.aa[name] != 'object') {
70
+ this.aa[name] = {};
71
+ }
72
+ this.aa[name] = $.arrayMerge(this.aa[name], value);
73
+ } else {
74
+ this.aa[name] = value;
75
+ }
76
+ }
77
+ };
78
+ const a = $(this).serializeArray();
79
+ for (let i = 0; i < a.length; i++){
80
+ o.add(a[i].name, a[i].value);
81
+ }
82
+ return o.aa;
83
+ }
84
+ });
85
+ })(jQuery);
86
+ }
resources/js/preview.js ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function getCleanDomain() {
2
+ return document.location.hostname;
3
+ }
4
+
5
+ function createButtonFromData(formData) {
6
+ let domainType = 'FREE';
7
+ if (formData && formData.domain) {
8
+ domainType = formData.domain.type;
9
+ }
10
+
11
+ return {
12
+ "userId": "local",
13
+ "domains": [
14
+ {
15
+ "id": "domain",
16
+ "user": "local",
17
+ "type": domainType,
18
+ "name": getCleanDomain()
19
+ }
20
+ ],
21
+ "buttons": [
22
+ {
23
+ "id": "button",
24
+ "domain": getCleanDomain(),
25
+ "domainId": "domain",
26
+ "active": true,
27
+ "name": "Live preview",
28
+ "type": formData.cnb.type,
29
+ "options": formData.cnb.options,
30
+ "actions": Object.keys(formData.actions)
31
+ ,
32
+ "conditions": []
33
+ }
34
+ ],
35
+ "actions": Object.values(formData.actions),
36
+ "conditions": [],
37
+ "options": {
38
+ "debugMode": true,
39
+ "cssLocation": "https://static.callnowbutton.com/css/main.css"
40
+ }
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Via https://dev.to/afewminutesofcode/how-to-convert-an-array-into-an-object-in-javascript-25a4
46
+ *
47
+ */
48
+ function convertArrayToObject (array, key) {
49
+ const initialValue = {};
50
+ return array.reduce((obj, item) => {
51
+ return {
52
+ ...obj,
53
+ [item[key]]: item,
54
+ };
55
+ }, initialValue);
56
+ }
57
+
58
+ function livePreview() {
59
+ const parsedData = jQuery('.cnb-container').serializeAssoc()
60
+
61
+ // Find a button via JS (instead of via a form)
62
+ if (typeof cnb_button !== 'undefined') {
63
+ parsedData.cnb = cnb_button
64
+ }
65
+
66
+ // Ensure it is always visible
67
+ parsedData.cnb.options.displayMode = 'ALWAYS';
68
+
69
+ // Ensure a Multi button / Buttonbar gets its actions
70
+ if (typeof cnb_actions !== 'undefined') {
71
+ if (parsedData &&
72
+ parsedData.actions
73
+ && ((parsedData.actions[Object.keys(parsedData.actions)[0]]
74
+ && parsedData.actions[Object.keys(parsedData.actions)[0]].actionType)
75
+ || parsedData.actions.new)) {
76
+ parsedData.actions = Object.assign(convertArrayToObject(cnb_actions, 'id'), parsedData.actions)
77
+ } else {
78
+ parsedData.actions = convertArrayToObject(cnb_actions, 'id')
79
+ }
80
+ }
81
+
82
+ if (typeof cnb_domain !== 'undefined') {
83
+ parsedData.domain = cnb_domain;
84
+ }
85
+
86
+ // Ensure a "new" Action (in case of a new SINGLE) gets an ID to work with
87
+ if (parsedData && parsedData.actions && parsedData.actions.new) {
88
+ parsedData.actions.new.id = "new"
89
+ }
90
+
91
+ // Ensure WhatsApp works
92
+ if (parsedData.action_id && parsedData.actions &&
93
+ parsedData.actions[parsedData.action_id] && parsedData.actions[parsedData.action_id].actionType === 'WHATSAPP') {
94
+ const input = document.querySelector('#cnb_action_value_input_whatsapp');
95
+ const iti = window.intlTelInputGlobals.getInstance(input);
96
+ parsedData.actions[parsedData.action_id].actionValue = iti.getNumber()
97
+ }
98
+
99
+ // Delete old items
100
+ jQuery('.cnb-single.call-now-button').remove()
101
+ jQuery('.cnb-full.call-now-button').remove()
102
+ jQuery('.cnb-multi.call-now-button').remove()
103
+ // And ensure that the actual WordPress editing screen does not disappear with the Button
104
+ jQuery('.call-now-button').css('display', 'block');
105
+
106
+ window.CNB_DATA = createButtonFromData(parsedData);
107
+ if (typeof CNB !== 'undefined') {
108
+ const result = CNB.render();
109
+ // If there is a Multibutton, expand it
110
+ const multiButton = jQuery('.cnb-multi.call-now-button .cnb-floating-main')
111
+ if (multiButton.length > 0) {
112
+ multiButton[0].dispatchEvent(new window.CustomEvent('toggle'));
113
+ }
114
+
115
+ // Move the result into a new special div (if found)
116
+ const button = jQuery('.cnb-single.call-now-button, .cnb-full.call-now-button, .cnb-multi.call-now-button').detach()
117
+ const previewContainer = jQuery('#cnb-button-preview')
118
+ if (previewContainer.length > 0) {
119
+ previewContainer.append(button)
120
+ }
121
+ return result
122
+ }
123
+ }
124
+
125
+ function initButtonEdit() {
126
+ jQuery(() => {
127
+ const idElement = jQuery('form.cnb-container :input[name="cnb[id]"]');
128
+ if (idElement.length > 0 && !idElement.val().trim()) {
129
+ return false;
130
+ }
131
+
132
+ // Load the required dependencies and render the preview once
133
+ // All refreshes happen inside
134
+ formToJson();
135
+ livePreview()
136
+ jQuery("form.cnb-container :input").on('change input', function() {
137
+ livePreview()
138
+ });
139
+ // No need to call "livePreview", this is done via the ".done()" handler on cnb_delete_action()
140
+ // jQuery('form.cnb-container a[data-ajax="true"]').on('change input', function() {});
141
+ })
142
+ }
143
+
144
+
145
+ jQuery(() => {
146
+ initButtonEdit()
147
+ })
resources/js/settings.js ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * This calls the admin-ajax action called 'cnb_email_activation' (function cnb_admin_cnb_email_activation)
3
+ */
4
+ function cnb_email_activation(admin_email) {
5
+ // Prep data
6
+ const data = {
7
+ 'action': 'cnb_email_activation',
8
+ 'admin_email': admin_email
9
+ };
10
+
11
+ const errorMessage = '<h3 class="title">Something went wrong!</h3>' +
12
+ '<p>Something has gone wrong and we do not know why...</p>' +
13
+ '<p>As unlikely as it is, our service might be experiencing issues (check <a href="https://status.callnowbutton.com">our status page</a>).</p>' +
14
+ '<p>If you think you\'ve found a bug, please report it at our <a href="https://callnowbutton.com/support/" target="_blank">Help Center</a>.';
15
+ const errorDetails = '<p>Technical details:</p><p style="color:red"><span id="cnb_email_activation_details"></span></p>';
16
+
17
+ // Send remove request
18
+ jQuery.post(ajaxurl, data)
19
+ .done((result) => {
20
+ if (result && result.email) {
21
+ jQuery('#cnb_email_activation').html('Check your inbox for an activation email sent to <strong><span id="cnb_email_activation_email"></span></strong>.')
22
+ jQuery('#cnb_email_activation_email').text(result.email)
23
+ }
24
+
25
+ if (result && result.errors) {
26
+ jQuery('#cnb_email_activation').html(errorMessage + errorDetails);
27
+
28
+ const keys = Object.keys(result.errors)
29
+ keys.forEach((key) => {
30
+ // Create Text Nodes to ensure escaping of the content
31
+ const codeMsg = document.createTextNode(key)
32
+ const errorMsg = document.createTextNode(result.errors[key])
33
+ const code = jQuery('<code>').append(codeMsg)
34
+ jQuery('#cnb_email_activation_details').append('<br />', code, ': ', errorMsg);
35
+ })
36
+ }
37
+ })
38
+ .fail((result) => {
39
+ jQuery('#cnb_email_activation').html(errorMessage + errorDetails);
40
+
41
+ // Create Text Nodes to ensure escaping of the content
42
+ const codeMsg = document.createTextNode(result.status + ' ' + result.statusText)
43
+ const errorMsg = document.createTextNode(result.responseText)
44
+ const code = jQuery('<code>').append(codeMsg)
45
+ jQuery('#cnb_email_activation_details').append('<br />', code, ': ', errorMsg);
46
+ });
47
+ return false;
48
+ }
49
+
50
+ // Note: IDE marks this as unused, but it is used by notices.php (function cnb_settings_get_account_missing_notice)
51
+ function cnb_email_activation_alternate() {
52
+ const alternate_admin_email = jQuery('#cnb_email_activation_alternate_address').val()
53
+ return cnb_email_activation(alternate_admin_email);
54
+ }
55
+
56
+ function init_settings() {
57
+ jQuery("#cnb_email_activation_alternate_form").hide()
58
+ }
59
+
60
+ jQuery(() => {
61
+ init_settings();
62
+ })
resources/js/timezone-picker-fix.js ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Remove <optgroup label="UTC"> and <optgroup label="Manual Offsets">
3
+ */
4
+ function cnb_remove_utc_and_utc_offsets() {
5
+ const timezonePicker = jQuery(".cnb_timezone_picker");
6
+ timezonePicker.children().remove("optgroup[label='Manual Offsets']");
7
+ // We also specifically do not support "Pacific/Kanton"
8
+ timezonePicker.find("option[value='Pacific/Kanton']").remove();
9
+ }
10
+
11
+ jQuery(() => {
12
+ cnb_remove_utc_and_utc_offsets();
13
+ })
resources/style/call-now-button.css CHANGED
@@ -339,6 +339,27 @@ input[type='range'] {
339
  display: flex;
340
  }
341
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
342
  /* Styling of the Conditions */
343
  .cnb_condition_rule {
344
  position: relative;
@@ -354,6 +375,12 @@ input[type='range'] {
354
  width: 100%;
355
  }
356
 
 
 
 
 
 
 
357
  @media screen and (min-width: 783px) {
358
  .cnb_condition_rule .max_width_column input[type=text] {
359
  width: calc(100% - 30px);
@@ -363,16 +390,18 @@ input[type='range'] {
363
  .cnb_condition_rule {
364
  padding: 25px 12px 10px 10px;
365
  }
366
- .cnb_condition_rule .button-link-delete {
367
- position: absolute;
368
- top:0;
369
- right: 5px;
370
  }
371
  }
372
 
 
373
  .cnb_condition_rule .button-link-delete {
374
- text-decoration: none;
375
- }
 
 
 
376
  .cnb_condition_rule .button-link-delete .dashicons {
377
  padding-top:5px;
378
  }
@@ -380,6 +409,8 @@ input[type='range'] {
380
  background: repeating-linear-gradient(45deg,#eee, #eee 10px,#f4f4f4 10px, #f4f4f4 20px);
381
  border: 1px solid #c3c4c7;
382
  box-shadow: 0 1px 1px rgb(0 0 0 / 4%);
 
 
383
  }
384
  /* Title of edit button screens */
385
  h1 span.cnb_button_name {
@@ -414,6 +445,7 @@ label.cnb_toggle_label {
414
  position: relative;
415
  display: inline-block;
416
  margin-left: -20px;
 
417
  }
418
 
419
  label.cnb_toggle_label:after {
@@ -459,6 +491,9 @@ input[type=checkbox].cnb_day_selector {
459
  height: 0;
460
  width: 0;
461
  visibility: hidden;
 
 
 
462
  }
463
 
464
  label.cnb_day_selector {
@@ -473,6 +508,7 @@ label.cnb_day_selector {
473
  font-size: 12px;
474
  float: left;
475
  margin-right: 10px;
 
476
  background-color: #ddd;
477
  color: #555;
478
  }
@@ -484,14 +520,17 @@ input[type=checkbox].cnb_day_selector:checked + label.cnb_day_selector {
484
 
485
  /* main section with or without sidebar */
486
  .cnb-one-column-section,
487
- .cnb-two-column-section {
 
488
  padding-top: 10px;
489
  }
490
- .cnb-two-column-section {
 
491
  min-width: 763px;
492
  }
493
  .cnb-one-column-section::after,
494
- .cnb-two-column-section::after {
 
495
  content:'';
496
  display: block;
497
  clear: both;
@@ -500,18 +539,32 @@ input[type=checkbox].cnb_day_selector:checked + label.cnb_day_selector {
500
  margin-right: 300px;
501
  padding: 0;
502
  }
 
 
 
 
 
503
  .cnb-one-column-section .cnb-body-column .cnb-body-content,
504
- .cnb-two-column-section .cnb-body-column .cnb-body-content {
 
505
  width: 100%;
506
  min-width: 463px;
507
  float: left;
508
  margin-bottom: 20px;
509
  position: relative;
510
  }
511
- .cnb-two-column-section .cnb-side-column {
 
 
 
 
512
  float: right;
513
  width: 280px;
514
  }
 
 
 
 
515
 
516
  .cnb-side-column .cnb-promobox {
517
  min-width: 255px;
@@ -613,19 +666,22 @@ input[type=checkbox].cnb_day_selector:checked + label.cnb_day_selector {
613
  .cnb-two-promobox-row .cnb-body-column {
614
  width:49%;
615
  }
616
-
617
  @media only screen and (max-width: 850px) {
618
- .cnb-two-column-section {
 
619
  min-width: 0;
620
  }
621
  .cnb-one-column-section .cnb-body-column,
622
- .cnb-two-column-section .cnb-body-column {
 
623
  margin: 0;
624
  }
625
- .cnb-two-column-section .cnb-body-column .cnb-body-content {
 
626
  min-width: 0;
627
  }
628
- .cnb-two-column-section .cnb-side-column {
 
629
  float: right;
630
  margin-right: 0;
631
  width: 100%;
@@ -637,3 +693,98 @@ input[type=checkbox].cnb_day_selector:checked + label.cnb_day_selector {
637
  display: none;
638
  }
639
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
  display: flex;
340
  }
341
 
342
+ .cnb-callout-bar {
343
+ padding: 10px 5px 3px;
344
+ border: 1px solid #c3c4c7;
345
+ background-color: #fff;
346
+ text-align: center;
347
+ position: relative;
348
+ max-width: 960px;
349
+ margin:0 auto 50px;
350
+ box-shadow: 0 1px 1px rgb(0 0 0 / 4%);
351
+ }
352
+ .cnb-callout-bar p {
353
+ display: inline-block;
354
+ margin-top:5px
355
+ }
356
+ @media screen and (max-width: 782px) {
357
+ .pricebox.cnb-premium-free,
358
+ .cnb-premium-label {
359
+ display: none;
360
+ }
361
+ }
362
+
363
  /* Styling of the Conditions */
364
  .cnb_condition_rule {
365
  position: relative;
375
  width: 100%;
376
  }
377
 
378
+ .cnb_condition_rule div:nth-child(4) {
379
+ float: left;
380
+ margin-right: 10px;
381
+ margin-bottom: 10px;
382
+ }
383
+
384
  @media screen and (min-width: 783px) {
385
  .cnb_condition_rule .max_width_column input[type=text] {
386
  width: calc(100% - 30px);
390
  .cnb_condition_rule {
391
  padding: 25px 12px 10px 10px;
392
  }
393
+ .cnb_condition_rule div:nth-child(5) {
394
+ margin-bottom:10px;
 
 
395
  }
396
  }
397
 
398
+
399
  .cnb_condition_rule .button-link-delete {
400
+ position: absolute;
401
+ top:0;
402
+ right: 5px;
403
+ text-decoration: none;}
404
+
405
  .cnb_condition_rule .button-link-delete .dashicons {
406
  padding-top:5px;
407
  }
409
  background: repeating-linear-gradient(45deg,#eee, #eee 10px,#f4f4f4 10px, #f4f4f4 20px);
410
  border: 1px solid #c3c4c7;
411
  box-shadow: 0 1px 1px rgb(0 0 0 / 4%);
412
+ padding: 10px;
413
+ width: 95%;
414
  }
415
  /* Title of edit button screens */
416
  h1 span.cnb_button_name {
445
  position: relative;
446
  display: inline-block;
447
  margin-left: -20px;
448
+ user-select:none;
449
  }
450
 
451
  label.cnb_toggle_label:after {
491
  height: 0;
492
  width: 0;
493
  visibility: hidden;
494
+ min-width: 0;
495
+ border: none;
496
+ position: absolute;
497
  }
498
 
499
  label.cnb_day_selector {
508
  font-size: 12px;
509
  float: left;
510
  margin-right: 10px;
511
+ margin-bottom: 10px;
512
  background-color: #ddd;
513
  color: #555;
514
  }
520
 
521
  /* main section with or without sidebar */
522
  .cnb-one-column-section,
523
+ .cnb-two-column-section,
524
+ .cnb-two-column-section-preview {
525
  padding-top: 10px;
526
  }
527
+ .cnb-two-column-section,
528
+ .cnb-two-column-section-preview {
529
  min-width: 763px;
530
  }
531
  .cnb-one-column-section::after,
532
+ .cnb-two-column-section::after,
533
+ .cnb-two-column-section-preview::after {
534
  content:'';
535
  display: block;
536
  clear: both;
539
  margin-right: 300px;
540
  padding: 0;
541
  }
542
+ .cnb-two-column-section-preview .cnb-body-column {
543
+ margin-right: 372px;
544
+ padding: 0;
545
+ }
546
+
547
  .cnb-one-column-section .cnb-body-column .cnb-body-content,
548
+ .cnb-two-column-section .cnb-body-column .cnb-body-content,
549
+ .cnb-two-column-section-preview .cnb-body-column .cnb-body-content {
550
  width: 100%;
551
  min-width: 463px;
552
  float: left;
553
  margin-bottom: 20px;
554
  position: relative;
555
  }
556
+ .cnb-two-column-section-preview .cnb-body-column .cnb-body-content {
557
+ min-width: 0;
558
+ }
559
+
560
+ .cnb-two-column-section .cnb-side-column {
561
  float: right;
562
  width: 280px;
563
  }
564
+ .cnb-two-column-section-preview .cnb-side-column {
565
+ float: right;
566
+ width: 352px;
567
+ }
568
 
569
  .cnb-side-column .cnb-promobox {
570
  min-width: 255px;
666
  .cnb-two-promobox-row .cnb-body-column {
667
  width:49%;
668
  }
 
669
  @media only screen and (max-width: 850px) {
670
+ .cnb-two-column-section,
671
+ .cnb-two-column-section-preview {
672
  min-width: 0;
673
  }
674
  .cnb-one-column-section .cnb-body-column,
675
+ .cnb-two-column-section .cnb-body-column,
676
+ .cnb-two-column-section-preview .cnb-body-column {
677
  margin: 0;
678
  }
679
+ .cnb-two-column-section .cnb-body-column .cnb-body-content,
680
+ .cnb-two-column-section-preview .cnb-body-column .cnb-body-content {
681
  min-width: 0;
682
  }
683
+ .cnb-two-column-section .cnb-side-column,
684
+ .cnb-two-column-section-preview .cnb-side-column {
685
  float: right;
686
  margin-right: 0;
687
  width: 100%;
693
  display: none;
694
  }
695
  }
696
+ @media only screen and (min-width: 851px) {
697
+ .only-on-mobile {
698
+ display: none;
699
+ }
700
+ }
701
+ /*
702
+ Preview phone and button placement
703
+ */
704
+ #phone-preview .phone-outside > div {
705
+ position: absolute;
706
+ }
707
+ #phone-preview .double {
708
+ border-style: double;
709
+ border-width: 4px;
710
+ border-color: #000;
711
+ }
712
+ #phone-preview .single {
713
+ border-style: solid;
714
+ border-width: 1px;
715
+ border-color: #000;
716
+ }
717
+ #phone-preview .phone-outside {
718
+ width: 344px;
719
+ height: 717px;
720
+ border-radius: 38px;
721
+ border: 4px double #000;
722
+ position: relative;
723
+ }
724
+ #phone-preview .phone-inside {
725
+ width: 320px;
726
+ height: 548px;
727
+ top: 84px;
728
+ left: 11px;
729
+ background: #fff;
730
+ }
731
+ #phone-preview .speaker {
732
+ width: 58px;
733
+ height: 7px;
734
+ border-radius: 3px;
735
+ top: 39px;
736
+ left: 50%;
737
+ margin-left: -30px;
738
+ }
739
+ #phone-preview .mic {
740
+ width: 56px;
741
+ height: 55px;
742
+ border-radius: 50%;
743
+ bottom: 10px;
744
+ left: 50%;
745
+ margin-left: -30px;
746
+ }
747
+ #cnb-button-preview {
748
+ position: relative;
749
+ height: 100%;
750
+ overflow: hidden;
751
+ }
752
+ #cnb-button-preview .cnb-full,
753
+ #cnb-button-preview .cnb-multi,
754
+ #cnb-button-preview .cnb-single {
755
+ position: absolute;
756
+ z-index: 99998 !important;
757
+ }
758
+ #cnb-button-preview .cnb-full:before {
759
+ box-shadow: none !important;
760
+ }
761
+ #cnb-button-preview .cnb-full.call-now-button a,
762
+ #cnb-button-preview .cnb-full.call-now-button:before {
763
+ border-radius:0;
764
+ }
765
+ .welcome-column-box {
766
+ padding-right: 10px;
767
+ }
768
+ @media screen and (max-width: 870px) {
769
+ .cnb-mobile-inline {
770
+ display: inline-block;
771
+ margin-bottom:0;
772
+ }
773
+ .only-in-columns {
774
+ display: none;
775
+ }
776
+ .call-now-button .welcome-panel-column .button {
777
+ margin-top:22px !important;
778
+ }
779
+ }
780
+ @media screen and (max-width: 600px) {
781
+ .call-now-button .welcome-panel .welcome-panel-close {
782
+ height: 27px;
783
+ width: 27px;
784
+ }
785
+ .cnb-mobile-inline {
786
+ display: block;
787
+ margin-bottom:0;
788
+ }
789
+
790
+ }
src/admin/action-edit.php CHANGED
@@ -241,6 +241,38 @@ function cnb_action_edit_create_tab_url($button, $tab) {
241
  return esc_url( $tab_link );
242
  }
243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  /**
245
  * @param $action CnbAction
246
  * @param $button CnbButton
@@ -254,14 +286,40 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
254
  * @global WP_Locale $wp_locale WordPress date and time locale object.
255
  */
256
  global $wp_locale;
257
- // CNB week starts on Monday
 
 
 
 
 
 
 
258
  $cnb_days_of_week_order = array(1,2,3,4,5,6,0);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  ?>
260
  <input type="hidden" name="actions[<?php esc_attr_e($action->id) ?>][id]" value="<?php if ($action->id !== null && $action->id !== 'new') { esc_attr_e($action->id); } ?>" />
261
  <input type="hidden" name="actions[<?php esc_attr_e($action->id) ?>][delete]" id="cnb_action_<?php esc_attr_e($action->id) ?>_delete" value="" />
262
- <input type="hidden" name="actions[<?php esc_attr_e($action->id) ?>][iconText]" value="<?php if (isset($action->iconText)) { esc_attr_e($action->iconText); } ?>" />
 
263
  <?php if ($show_table) { ?>
264
- <table class="form-table nav-tab-active">
265
  <?php } ?>
266
  <?php if (!$button) { ?>
267
  <tr>
@@ -269,10 +327,7 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
269
  </th>
270
  </tr>
271
  <?php } ?>
272
- <tr class="cnb_hide_on_modal">
273
- <th></th>
274
- <td></td>
275
- </tr>
276
  <tr class="cnb_hide_on_modal">
277
  <th scope="row"><label for="cnb_action_type">Button type</label></th>
278
  <td>
@@ -289,7 +344,7 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
289
  <label for="cnb_action_value_input">
290
  <span id="cnb_action_value">Action value</span>
291
  </label>
292
-
293
  </th>
294
  <td>
295
  <input type="text" id="cnb_action_value_input" name="actions[<?php esc_attr_e($action->id) ?>][actionValue]" value="<?php esc_attr_e($action->actionValue) ?>"/>
@@ -404,29 +459,34 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
404
  <?php } ?>
405
 
406
  <tr class="cnb_hide_on_modal">
407
- <th scope="row"><h3>Scheduling</h3> </th>
408
  <td>
409
  <input name="actions[<?php esc_attr_e($action->id) ?>][schedule][showAlways]" type="hidden" value="false" />
410
  <input id="actions_schedule_show_always" class="cnb_toggle_checkbox" onchange="return cnb_hide_on_show_always();" name="actions[<?php esc_attr_e($action->id) ?>][schedule][showAlways]" type="checkbox"
411
  value="true" <?php checked(true, $action->id === 'new' || $action->schedule->showAlways); ?> />
412
  <label for="actions_schedule_show_always" class="cnb_toggle_label">Toggle</label>
413
- <span data-cnb_toggle_state_label="actions_schedule_show_always" class="cnb_toggle_state cnb_toggle_false">Button shows at set times</span>
414
- <span data-cnb_toggle_state_label="actions_schedule_show_always" class="cnb_toggle_state cnb_toggle_true">Always on</span>
415
-
416
  </td>
417
  </tr>
 
 
 
 
 
418
  <tr class="cnb_hide_on_show_always">
419
  <th>Show on these days</th>
420
  <td>
421
  <?php
422
- foreach ($cnb_days_of_week_order as $cnb_days_of_week) {
423
  $selected = '';
 
424
  if (isset($action->schedule) && isset($action->schedule->daysOfWeek)) {
425
- $selected = (isset($action->schedule->daysOfWeek[$cnb_days_of_week]) && $action->schedule->daysOfWeek[$cnb_days_of_week] == true) ? 'checked="checked"' : '';
426
  }
427
  echo '
428
- <input class="cnb_day_selector" id="cnb_weekday_'.esc_attr($cnb_days_of_week).'" type="checkbox" name="actions[' . esc_attr($action->id) . '][schedule][daysOfWeek][' . esc_attr($cnb_days_of_week) . ']" value="true" '.$selected.'>
429
- <label title="'.$wp_locale->get_weekday($cnb_days_of_week).'" class="cnb_day_selector" for="cnb_weekday_'.esc_attr($cnb_days_of_week).'">'.strtoupper(substr($wp_locale->get_weekday($cnb_days_of_week),0,2)).'</label>
430
  ';
431
  }
432
 
@@ -441,13 +501,11 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
441
  <th><label for="actions[<?php esc_attr_e($action->id) ?>][schedule][stop]">End time</label></th>
442
  <td><input type="time" name="actions[<?php esc_attr_e($action->id) ?>][schedule][stop]" id="actions[<?php esc_attr_e($action->id) ?>][schedule][stop]" value="<?php if (isset($action->schedule)) { esc_attr_e($action->schedule->stop); } ?>"></td>
443
  </tr>
444
- <tr class="cnb_hide_on_show_always">
445
  <th><label for="actions[<?php esc_attr_e($action->id) ?>][schedule][timezone]">Timezone</label></th>
446
  <td>
447
- <select name="actions[<?php esc_attr_e($action->id) ?>][schedule][timezone]" id="actions[<?php esc_attr_e($action->id) ?>][schedule][timezone]">
448
  <?php
449
- // Uses domain timezone if no timezone can be found
450
- $timezone = (isset($action->schedule) && !empty($action->schedule->timezone)) ? $action->schedule->timezone : (isset($domain) ? $domain->timezone : null);
451
  echo wp_timezone_choice($timezone);
452
  ?>
453
  </select>
@@ -458,10 +516,10 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
458
  Currently set to <code><?php esc_html_e($timezone)?></code>.
459
  <?php } ?>
460
  </p>
461
- <?php if (isset($domain) && !empty($domain->timezone) && $domain->timezone !== $timezone) { ?>
462
- <p class="notice notice-warning">
463
- Be aware that the timezone for this action (<code><?php esc_html_e($timezone)?></code>) is different from the timezone for your domain (<code><?php esc_html_e($domain->timezone)?></code>).
464
- </p>
465
  <?php } ?>
466
  </td>
467
  </tr>
@@ -557,20 +615,55 @@ function cnb_admin_page_action_edit_render() {
557
  $form_action
558
  );
559
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
  do_action('cnb_header');
561
  ?>
 
 
 
562
 
563
  <?php if ($bid !== null) { ?>
 
564
  <h2 class="nav-tab-wrapper">
565
- <a href="<?php echo cnb_action_edit_create_tab_url($button, 'basic_options') ?>"
566
- class="nav-tab">Basics</a>
567
- <a href="<?php echo cnb_action_edit_create_tab_url($button, 'extra_options') ?>"
568
- class="nav-tab ">Presentation</a>
569
- <a href="<?php echo cnb_action_edit_create_tab_url($button, 'visibility') ?>"
570
- class="nav-tab ">Visibility</a>
571
  </h2>
572
  <?php } ?>
573
- <form action="<?php echo $redirect_link; ?>" method="post">
 
 
 
 
 
 
 
574
  <input type="hidden" name="page" value="call-now-button-actions" />
575
  <input type="hidden" name="action" value="<?php echo $action->id === 'new' ? 'cnb_create_action' :'cnb_update_action' ?>" />
576
  <?php
@@ -578,5 +671,19 @@ function cnb_admin_page_action_edit_render() {
578
  submit_button();
579
  ?>
580
  </form>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
581
  <?php do_action('cnb_footer');
582
  }
241
  return esc_url( $tab_link );
242
  }
243
 
244
+ /**
245
+ *
246
+ * WP_Locale considers "0" to be Sunday, whereas the CallNowButton APi considers "0" to be Monday. See the below table:
247
+ *
248
+ +-----------+-----------+------------+
249
+ | Day | WP_Locale | API Server |
250
+ +-----------+-----------+------------+
251
+ | Monday | 1 | 0 |
252
+ +-----------+-----------+------------+
253
+ | Tuesday | 2 | 1 |
254
+ +-----------+-----------+------------+
255
+ | Wednesday | 3 | 2 |
256
+ +-----------+-----------+------------+
257
+ | Thursday | 4 | 3 |
258
+ +-----------+-----------+------------+
259
+ | Friday | 5 | 4 |
260
+ +-----------+-----------+------------+
261
+ | Saturday | 6 | 5 |
262
+ +-----------+-----------+------------+
263
+ | Sunday | 0 | 6 |
264
+ +-----------+-----------+------------+
265
+ *
266
+ * So, we need to translate.
267
+ * @param int $wp_locale_day
268
+ *
269
+ * @return int The index for the CNB API Server
270
+ */
271
+ function cnb_wp_locale_day_to_daysofweek_array_index($wp_locale_day) {
272
+ if ($wp_locale_day == 0) return 6;
273
+ return $wp_locale_day - 1;
274
+ }
275
+
276
  /**
277
  * @param $action CnbAction
278
  * @param $button CnbButton
286
  * @global WP_Locale $wp_locale WordPress date and time locale object.
287
  */
288
  global $wp_locale;
289
+ //
290
+ /**
291
+ * CNB week starts on Monday (0), WP_Local starts on Sunday (0)
292
+ * See cnb_wp_locale_day_to_daysofweek_array_index()
293
+ *
294
+ * This array only signifies the order to DISPLAY the days in the UI according to WP_Locale
295
+ * So, in this case, we make the UI render the week starting on Monday (1) and end on Sunday (0).
296
+ */
297
  $cnb_days_of_week_order = array(1,2,3,4,5,6,0);
298
+
299
+ if (empty($action->actionType)) {
300
+ $action->actionType = 'PHONE';
301
+ }
302
+ $action->iconText = cnb_actiontype_to_icontext($action->actionType);
303
+ $action->iconType = 'DEFAULT';
304
+
305
+ wp_enqueue_script(
306
+ CNB_SLUG . '-timezone-picker-fix',
307
+ plugins_url( '../../resources/js/timezone-picker-fix.js', __FILE__ ),
308
+ array('jquery'),
309
+ CNB_VERSION,
310
+ true);
311
+
312
+ // Uses domain timezone if no timezone can be found
313
+ $timezone = (isset($action->schedule) && !empty($action->schedule->timezone)) ? $action->schedule->timezone : (isset($domain) ? $domain->timezone : null);
314
+ $action_tz_different_from_domain = isset($domain) && !empty($domain->timezone) && $domain->timezone !== $timezone;
315
+ cnb_domain_timezone_check( $domain );
316
  ?>
317
  <input type="hidden" name="actions[<?php esc_attr_e($action->id) ?>][id]" value="<?php if ($action->id !== null && $action->id !== 'new') { esc_attr_e($action->id); } ?>" />
318
  <input type="hidden" name="actions[<?php esc_attr_e($action->id) ?>][delete]" id="cnb_action_<?php esc_attr_e($action->id) ?>_delete" value="" />
319
+ <input type="hidden" name="actions[<?php esc_attr_e($action->id) ?>][iconText]" value="<?php if (isset($action->iconText)) { esc_attr_e($action->iconText); } ?>" id="cnb_action_icon_text" />
320
+ <input type="hidden" name="actions[<?php esc_attr_e($action->id) ?>][iconType]" value="<?php if (isset($action->iconType)) { esc_attr_e($action->iconType); } ?>" />
321
  <?php if ($show_table) { ?>
322
+ <table data-tab-name="actions" class="form-table nav-tab-active">
323
  <?php } ?>
324
  <?php if (!$button) { ?>
325
  <tr>
327
  </th>
328
  </tr>
329
  <?php } ?>
330
+
 
 
 
331
  <tr class="cnb_hide_on_modal">
332
  <th scope="row"><label for="cnb_action_type">Button type</label></th>
333
  <td>
344
  <label for="cnb_action_value_input">
345
  <span id="cnb_action_value">Action value</span>
346
  </label>
347
+
348
  </th>
349
  <td>
350
  <input type="text" id="cnb_action_value_input" name="actions[<?php esc_attr_e($action->id) ?>][actionValue]" value="<?php esc_attr_e($action->actionValue) ?>"/>
459
  <?php } ?>
460
 
461
  <tr class="cnb_hide_on_modal">
462
+ <th scope="row">Always on</th>
463
  <td>
464
  <input name="actions[<?php esc_attr_e($action->id) ?>][schedule][showAlways]" type="hidden" value="false" />
465
  <input id="actions_schedule_show_always" class="cnb_toggle_checkbox" onchange="return cnb_hide_on_show_always();" name="actions[<?php esc_attr_e($action->id) ?>][schedule][showAlways]" type="checkbox"
466
  value="true" <?php checked(true, $action->id === 'new' || $action->schedule->showAlways); ?> />
467
  <label for="actions_schedule_show_always" class="cnb_toggle_label">Toggle</label>
468
+ <span data-cnb_toggle_state_label="actions_schedule_show_always" class="cnb_toggle_state cnb_toggle_false">(No)</span>
469
+ <span data-cnb_toggle_state_label="actions_schedule_show_always" class="cnb_toggle_state cnb_toggle_true">Yes</span>
 
470
  </td>
471
  </tr>
472
+ <tr>
473
+ <td colspan="2" class="cnb_padding_0">
474
+ <span id="domain-timezone-notice-placeholder"></span>
475
+ </td>
476
+ </tr>
477
  <tr class="cnb_hide_on_show_always">
478
  <th>Show on these days</th>
479
  <td>
480
  <?php
481
+ foreach ($cnb_days_of_week_order as $cnb_day_of_week) {
482
  $selected = '';
483
+ $api_server_index = cnb_wp_locale_day_to_daysofweek_array_index($cnb_day_of_week);
484
  if (isset($action->schedule) && isset($action->schedule->daysOfWeek)) {
485
+ $selected = (isset($action->schedule->daysOfWeek[$api_server_index]) && $action->schedule->daysOfWeek[$api_server_index] == true) ? 'checked="checked"' : '';
486
  }
487
  echo '
488
+ <input class="cnb_day_selector" id="cnb_weekday_'.esc_attr($api_server_index).'" type="checkbox" name="actions[' . esc_attr($action->id) . '][schedule][daysOfWeek][' . esc_attr($api_server_index) . ']" value="true" '.$selected.'>
489
+ <label title="'.$wp_locale->get_weekday($cnb_day_of_week).'" class="cnb_day_selector" for="cnb_weekday_'.esc_attr($api_server_index).'">'.strtoupper(substr($wp_locale->get_weekday($cnb_day_of_week),0,2)).'</label>
490
  ';
491
  }
492
 
501
  <th><label for="actions[<?php esc_attr_e($action->id) ?>][schedule][stop]">End time</label></th>
502
  <td><input type="time" name="actions[<?php esc_attr_e($action->id) ?>][schedule][stop]" id="actions[<?php esc_attr_e($action->id) ?>][schedule][stop]" value="<?php if (isset($action->schedule)) { esc_attr_e($action->schedule->stop); } ?>"></td>
503
  </tr>
504
+ <tr class="cnb_hide_on_show_always<?php if (!$action_tz_different_from_domain) { ?> cnb_advanced_view<?php } ?>">
505
  <th><label for="actions[<?php esc_attr_e($action->id) ?>][schedule][timezone]">Timezone</label></th>
506
  <td>
507
+ <select name="actions[<?php esc_attr_e($action->id) ?>][schedule][timezone]" id="actions[<?php esc_attr_e($action->id) ?>][schedule][timezone]" class="cnb_timezone_picker">
508
  <?php
 
 
509
  echo wp_timezone_choice($timezone);
510
  ?>
511
  </select>
516
  Currently set to <code><?php esc_html_e($timezone)?></code>.
517
  <?php } ?>
518
  </p>
519
+ <?php if ($action_tz_different_from_domain) { ?>
520
+ <div class="notice notice-warning inline">
521
+ <p>Be aware that the timezone for this action (<code><?php esc_html_e($timezone)?></code>) is different from the timezone for your domain (<code><?php esc_html_e($domain->timezone)?></code>).</p>
522
+ </div>
523
  <?php } ?>
524
  </td>
525
  </tr>
615
  $form_action
616
  );
617
 
618
+ wp_enqueue_script(
619
+ CNB_SLUG . '-action-type-to-icon-text',
620
+ plugins_url( '../../resources/js/action-type-to-icon-text.js', __FILE__ ),
621
+ array('jquery'),
622
+ CNB_VERSION,
623
+ true);
624
+
625
+ wp_enqueue_script(
626
+ CNB_SLUG . '-form-to-json',
627
+ plugins_url( '../../resources/js/form-to-json.js', __FILE__ ),
628
+ array('jquery'),
629
+ CNB_VERSION,
630
+ true);
631
+
632
+ wp_enqueue_script(
633
+ CNB_SLUG . '-preview',
634
+ plugins_url( '../../resources/js/preview.js', __FILE__ ),
635
+ array('jquery'),
636
+ CNB_VERSION,
637
+ true);
638
+
639
+ wp_enqueue_script(
640
+ CNB_SLUG . '-client',
641
+ 'https://static.callnowbutton.com/js/client.js',
642
+ array(),
643
+ CNB_VERSION,
644
+ true);
645
+
646
  do_action('cnb_header');
647
  ?>
648
+ <div class="cnb-two-column-section-preview">
649
+ <div class="cnb-body-column">
650
+ <div class="cnb-body-content">
651
 
652
  <?php if ($bid !== null) { ?>
653
+ <!-- These are FAKE buttons -->
654
  <h2 class="nav-tab-wrapper">
655
+ <a data-tab-name="actions" href="<?php echo cnb_action_edit_create_tab_url($button, 'basic_options') ?>"
656
+ class="nav-tab nav-tab-active">Action</a>
 
 
 
 
657
  </h2>
658
  <?php } ?>
659
+ <script>
660
+ let cnb_button = <?php echo json_encode($button); ?>;
661
+ let cnb_actions = <?php echo json_encode($button->actions); ?>;
662
+ let cnb_domain = <?php echo json_encode($button->domain) ?>;
663
+
664
+ </script>
665
+
666
+ <form class="cnb-container" action="<?php echo $redirect_link; ?>" method="post">
667
  <input type="hidden" name="page" value="call-now-button-actions" />
668
  <input type="hidden" name="action" value="<?php echo $action->id === 'new' ? 'cnb_create_action' :'cnb_update_action' ?>" />
669
  <?php
671
  submit_button();
672
  ?>
673
  </form>
674
+ </div>
675
+ </div>
676
+ <div class="cnb-side-column">
677
+ <div id="phone-preview">
678
+ <div class="phone-outside double">
679
+ <div class="speaker single"></div>
680
+ <div class="phone-inside single">
681
+ <div id="cnb-button-preview"></div>
682
+ </div>
683
+ <div class="mic double"></div>
684
+ </div>
685
+ </div>
686
+ </div>
687
+ </div>
688
  <?php do_action('cnb_footer');
689
  }
src/admin/admin-ajax.php CHANGED
@@ -5,7 +5,7 @@ require_once dirname( __FILE__ ) . '/action-overview.php';
5
  require_once dirname( __FILE__ ) . '/settings-profile.php';
6
 
7
  // part of domain-upgrade
8
- function cnb_admin_page_domain_upgrade_get_checkout($arg) {
9
  $planId = filter_input( INPUT_POST, 'planId', FILTER_SANITIZE_STRING );
10
  $domainId = filter_input( INPUT_POST, 'domainId', FILTER_SANITIZE_STRING );
11
 
@@ -59,7 +59,14 @@ function cnb_admin_button_delete_actions() {
59
  $button_id = !empty($_REQUEST['bid']) ? sanitize_text_field($_REQUEST['bid']) : null;
60
 
61
  $result = cnb_delete_action_real($action_id, $button_id);
62
- wp_send_json($result);
 
 
 
 
 
 
 
63
  }
64
 
65
  add_action( 'wp_ajax_cnb_delete_action', 'cnb_admin_button_delete_actions' );
@@ -72,3 +79,17 @@ function cnb_admin_settings_profile_save() {
72
  }
73
 
74
  add_action( 'wp_ajax_cnb_settings_profile_save', 'cnb_admin_settings_profile_save' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  require_once dirname( __FILE__ ) . '/settings-profile.php';
6
 
7
  // part of domain-upgrade
8
+ function cnb_admin_page_domain_upgrade_get_checkout() {
9
  $planId = filter_input( INPUT_POST, 'planId', FILTER_SANITIZE_STRING );
10
  $domainId = filter_input( INPUT_POST, 'domainId', FILTER_SANITIZE_STRING );
11
 
59
  $button_id = !empty($_REQUEST['bid']) ? sanitize_text_field($_REQUEST['bid']) : null;
60
 
61
  $result = cnb_delete_action_real($action_id, $button_id);
62
+ // Instead of sending just the actual result (which is currently ignored anyway)
63
+ // We sent both the result and an updated button so the preview code can re-render the button
64
+ $return = array(
65
+ 'result' => $result,
66
+ 'button' => CnbAppRemote::cnb_remote_get_button_full( $button_id )
67
+ );
68
+ wp_send_json($return);
69
+
70
  }
71
 
72
  add_action( 'wp_ajax_cnb_delete_action', 'cnb_admin_button_delete_actions' );
79
  }
80
 
81
  add_action( 'wp_ajax_cnb_settings_profile_save', 'cnb_admin_settings_profile_save' );
82
+
83
+ function cnb_admin_cnb_email_activation() {
84
+ $admin_email = esc_attr(get_bloginfo('admin_email'));
85
+ $admin_url = esc_url( admin_url('admin.php') );
86
+
87
+ $custom_email = trim(filter_input( INPUT_POST, 'admin_email', FILTER_SANITIZE_STRING ));
88
+ if (!empty($custom_email)) {
89
+ $admin_email = $custom_email;
90
+ }
91
+ $data = CnbAppRemote::cnb_remote_email_activation($admin_email, $admin_url);
92
+ wp_send_json($data);
93
+ }
94
+
95
+ add_action( 'wp_ajax_cnb_email_activation', 'cnb_admin_cnb_email_activation' );
src/admin/api/CnbAdminCloud.php CHANGED
@@ -418,7 +418,6 @@ class CnbAdminCloud {
418
  $cnbAppRemote = new CnbAppRemote();
419
  $domain = array(
420
  'name' => $cnbAppRemote->cnb_clean_site_url(),
421
- 'timezone' => wp_timezone_string(),
422
  'trackGA' => isset($cnb_options['tracking'] ) && $cnb_options['tracking'] != 0,
423
  'trackConversion' => isset($cnb_options['conversions'] ) && $cnb_options['conversions'] != 0,
424
  'properties' => array(),
@@ -610,10 +609,13 @@ class CnbAdminCloud {
610
  $iconColor = $action->iconColor;
611
  }
612
 
 
 
 
613
  $button = array(
614
  'name' => 'Button created via Wordpress plugin',
615
  'domain' => $domain->id,
616
- 'active' => false,
617
  'actions' => $actions,
618
  'conditions' => $conditions,
619
  'type' => $type,
418
  $cnbAppRemote = new CnbAppRemote();
419
  $domain = array(
420
  'name' => $cnbAppRemote->cnb_clean_site_url(),
 
421
  'trackGA' => isset($cnb_options['tracking'] ) && $cnb_options['tracking'] != 0,
422
  'trackConversion' => isset($cnb_options['conversions'] ) && $cnb_options['conversions'] != 0,
423
  'properties' => array(),
609
  $iconColor = $action->iconColor;
610
  }
611
 
612
+ // 'active' is based on the status of enabled and if the number has a value
613
+ $has_a_number = !empty($action->actionValue);
614
+ $is_enabled = $options && array_key_exists('active', $options) && $options['active'] == 1;
615
  $button = array(
616
  'name' => 'Button created via Wordpress plugin',
617
  'domain' => $domain->id,
618
+ 'active' => ($is_enabled && $has_a_number),
619
  'actions' => $actions,
620
  'conditions' => $conditions,
621
  'type' => $type,
src/admin/api/CnbAppRemote.php CHANGED
@@ -110,7 +110,7 @@ class CnbAppRemoteHelper {
110
  public function convertDomain($domain) {
111
  return array(
112
  'name' => $domain['name'],
113
- 'timezone' => $domain['timezone'],
114
  'trackGA' => $domain['trackGA'],
115
  'trackConversion' => $domain['trackConversion'],
116
  'renew' => $domain['renew'],
@@ -224,21 +224,26 @@ class CnbAppRemote {
224
  return self::cnb__get_transient_base() . self::cnb_get_api_base();
225
  }
226
 
227
- public static function cnb_remote_get_args() {
228
  global $cnb_options;
229
 
230
- $api_key = isset( $cnb_options['api_key'] ) ? $cnb_options['api_key'] : false;
231
- if ( ! $api_key ) {
232
- return new WP_Error( 'CNB_API_NOT_SETUP_YET' );
 
 
 
 
 
 
 
 
 
 
233
  }
234
- $header_name = 'X-CNB-Api-Key';
235
- $header_value = $api_key;
236
 
237
  return array(
238
- 'headers' => array(
239
- $header_name => $header_value,
240
- 'Content-Type' => 'application/json'
241
- ),
242
  );
243
  }
244
 
@@ -356,8 +361,8 @@ class CnbAppRemote {
356
  return self::cnb_remote_handle_response( $response );
357
  }
358
 
359
- public static function cnb_remote_post( $rest_endpoint, $body = null ) {
360
- $args = self::cnb_remote_get_args();
361
  if ( $args instanceof WP_Error ) {
362
  return $args;
363
  }
@@ -375,9 +380,9 @@ class CnbAppRemote {
375
  return self::cnb_remote_handle_response( $response );
376
  }
377
 
378
- public static function cnb_remote_get( $rest_endpoint ) {
379
  $cnb_get_cache = new CnbGet();
380
- $args = self::cnb_remote_get_args();
381
  if ( $args instanceof WP_Error ) {
382
  return $args;
383
  }
@@ -486,6 +491,17 @@ class CnbAppRemote {
486
  return self::cnb_remote_get( $rest_endpoint );
487
  }
488
 
 
 
 
 
 
 
 
 
 
 
 
489
  public static function cnb_remote_get_apikeys() {
490
  $rest_endpoint = '/v1/apikey';
491
 
@@ -716,6 +732,25 @@ class CnbAppRemote {
716
  $rest_endpoint = '/v1/stripe/createBillingPortal';
717
 
718
  return self::cnb_remote_post( $rest_endpoint);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
719
 
 
 
720
  }
721
  }
110
  public function convertDomain($domain) {
111
  return array(
112
  'name' => $domain['name'],
113
+ 'timezone' => isset($domain['timezone']) ? $domain['timezone'] : null,
114
  'trackGA' => $domain['trackGA'],
115
  'trackConversion' => $domain['trackConversion'],
116
  'renew' => $domain['renew'],
224
  return self::cnb__get_transient_base() . self::cnb_get_api_base();
225
  }
226
 
227
+ public static function cnb_remote_get_args($authenticated = true) {
228
  global $cnb_options;
229
 
230
+ $headers = array(
231
+ 'Content-Type' => 'application/json'
232
+ );
233
+
234
+ if ($authenticated) {
235
+ $api_key = isset( $cnb_options['api_key'] ) ? $cnb_options['api_key'] : false;
236
+ if ( ! $api_key ) {
237
+ return new WP_Error( 'CNB_API_NOT_SETUP_YET' );
238
+ }
239
+ $header_name = 'X-CNB-Api-Key';
240
+ $header_value = $api_key;
241
+
242
+ $headers[$header_name] = $header_value;
243
  }
 
 
244
 
245
  return array(
246
+ 'headers' => $headers,
 
 
 
247
  );
248
  }
249
 
361
  return self::cnb_remote_handle_response( $response );
362
  }
363
 
364
+ public static function cnb_remote_post( $rest_endpoint, $body = null, $authenticated = true ) {
365
+ $args = self::cnb_remote_get_args($authenticated);
366
  if ( $args instanceof WP_Error ) {
367
  return $args;
368
  }
380
  return self::cnb_remote_handle_response( $response );
381
  }
382
 
383
+ public static function cnb_remote_get( $rest_endpoint, $authenticated = true ) {
384
  $cnb_get_cache = new CnbGet();
385
+ $args = self::cnb_remote_get_args($authenticated);
386
  if ( $args instanceof WP_Error ) {
387
  return $args;
388
  }
491
  return self::cnb_remote_get( $rest_endpoint );
492
  }
493
 
494
+ /**
495
+ * @param $ott string a one-time token to retrieve an API key
496
+ *
497
+ * @return CnbApiKey|WP_Error
498
+ */
499
+ public static function cnb_remote_get_apikey_via_ott($ott) {
500
+ $rest_endpoint = '/v1/apikey/ott/' . $ott;
501
+
502
+ return self::cnb_remote_get( $rest_endpoint, false );
503
+ }
504
+
505
  public static function cnb_remote_get_apikeys() {
506
  $rest_endpoint = '/v1/apikey';
507
 
732
  $rest_endpoint = '/v1/stripe/createBillingPortal';
733
 
734
  return self::cnb_remote_post( $rest_endpoint);
735
+ }
736
+
737
+ /**
738
+ * Data model:
739
+ {
740
+ "email": "jasper+wp-signup-test-02@studiostacks.com",
741
+ "domain": "http://www.button.local:8000/",
742
+ "adminUrl": "http://www.button.local:8000/wp-admin"
743
+ }
744
+ */
745
+ public static function cnb_remote_email_activation($admin_email, $admin_url) {
746
+ $cnbAppRemote = new CnbAppRemote();
747
+ $body = array(
748
+ 'email' => $admin_email,
749
+ 'domain' => $cnbAppRemote->cnb_clean_site_url(),
750
+ 'adminUrl' => $admin_url
751
+ );
752
 
753
+ $rest_endpoint = '/v1/user/wp';
754
+ return self::cnb_remote_post( $rest_endpoint, $body, false);
755
  }
756
  }
src/admin/api/RemoteTrace.php CHANGED
@@ -17,7 +17,7 @@ class RemoteTrace {
17
 
18
  protected $cacheHit = false;
19
 
20
- public function __construct($endpoint) {
21
  $cnb_remoted_traces = RemoteTracer::getInstance();
22
 
23
  $this->endpoint = $endpoint;
17
 
18
  protected $cacheHit = false;
19
 
20
+ public function __construct($endpoint = null) {
21
  $cnb_remoted_traces = RemoteTracer::getInstance();
22
 
23
  $this->endpoint = $endpoint;
src/admin/api/RemoteTracer.php CHANGED
@@ -48,7 +48,7 @@ class RemoteTracer {
48
  }
49
 
50
  /**
51
- * Remove all traces (used by tests to reset the internal state
52
  */
53
  public function clearTraces() {
54
  self::$instance->traces = array();
48
  }
49
 
50
  /**
51
+ * Remove all traces (used by tests to reset the internal state)
52
  */
53
  public function clearTraces() {
54
  self::$instance->traces = array();
src/admin/apikey-overview.php CHANGED
@@ -205,9 +205,9 @@ class Cnb_Apikey_List_Table extends WP_List_Table {
205
  $data[] = array(
206
  'id' => $apikey->id,
207
  'name' => $apikey->name,
208
- 'created' => $apikey->created,
209
  'lastUsed' => $apikey->lastUsed,
210
- 'updateTime' => $apikey->updateTime,
211
  );
212
  }
213
  return $data;
205
  $data[] = array(
206
  'id' => $apikey->id,
207
  'name' => $apikey->name,
208
+ 'created' => null,
209
  'lastUsed' => $apikey->lastUsed,
210
+ 'updateTime' => null,
211
  );
212
  }
213
  return $data;
src/admin/button-edit.php CHANGED
@@ -223,6 +223,33 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
223
  $default_domain['id'] = 0;
224
  }
225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  ?>
227
  <form action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post" class="cnb-container">
228
  <input type="hidden" name="page" value="call-now-button" />
@@ -240,7 +267,7 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
240
  <input type="hidden" name="actions[<?php esc_attr_e($action->id) ?>][id]" value="<?php esc_attr_e($action->id) ?>" />
241
  <?php } ?>
242
 
243
- <table class="form-table <?php if(!$hide_on_modal) { echo cnb_is_active_tab('basic_options'); } else { echo 'nav-tab-only'; } ?>">
244
  <tr class="cnb_hide_on_modal">
245
  <th></th>
246
  <td></td>
@@ -248,24 +275,24 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
248
  <tr>
249
  <th scope="row"><label for="cnb[name]">Button name</label></th>
250
 
251
- <td class="activated">
252
- <label for="cnb[name]"><input type="text" name="cnb[name]" id="cnb[name]" required="required" value="<?php esc_attr_e($button->name); ?>" /></label>
253
- </td>
254
- </tr>
255
- <tr class="cnb_hide_on_modal">
256
- <th scope="row"><label for="cnb-enable">Button status</label></th>
257
 
258
- <td class="activated">
259
  <input type="hidden" name="cnb[active]" value="0" />
260
  <input id="cnb-enable" class="cnb_toggle_checkbox" type="checkbox" name="cnb[active]" value="1" <?php checked(true, $button->active); ?> />
261
  <label for="cnb-enable" class="cnb_toggle_label">Toggle</label>
262
  <span data-cnb_toggle_state_label="cnb-enable" class="cnb_toggle_state cnb_toggle_false">Inactive</span>
263
  <span data-cnb_toggle_state_label="cnb-enable" class="cnb_toggle_state cnb_toggle_true">Active</span>
264
- </td>
265
- </tr>
266
- <tr class="cnb_hide_on_modal cnb_advanced_view">
267
- <th scope="row"><label for="cnb[domain]">Domain</label></th>
268
- <td>
269
  <select name="cnb[domain]" id="cnb[domain]">
270
  <?php
271
  foreach ($domains as $domain) { ?>
@@ -275,45 +302,43 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
275
  </option>
276
  <?php } ?>
277
  </select>
278
- </td>
279
  </tr>
280
  <?php if ($button->type !== 'SINGLE') { ?>
281
  <tr class="cnb_hide_on_modal">
282
  <th colspan="2" class="cnb_padding_0">
283
- <h2 >Actions <?php echo '<a href="' . $new_action_url . '" class="page-title-action">Add Action</a>'; ?>
284
- <a href="https://help.callnowbutton.com/portal/en/kb/articles/adding-actions-to-a-multi-button-or-buttonbar" target="_blank" class="cnb-nounderscore">
285
- <span class="dashicons dashicons-editor-help"></span>
286
- </a></h2>
287
  </th>
288
  </tr>
289
- <?php } ?>
290
- <?php
291
- $is_active_tab_basic_options = cnb_is_active_tab('basic_options');
292
- if ($button->type === 'SINGLE') {
293
- if (!empty($is_active_tab_basic_options)) {
294
- // Create a dummy Action
295
- $action = new CnbAction();
296
- $action->id = 'new';
297
- $action->actionType = '';
298
- $action->actionValue = '';
299
- $action->labelText = '';
300
- $action->properties = new CnbActionProperties();
301
-
302
- if (sizeof($button->actions) > 0) {
303
- $action = $button->actions[0];
304
- }
305
- cnb_admin_page_action_edit_render_main($action, $button, $default_domain, false);
306
- }
307
  } else {
308
- // Only render the Actions' table if that is the active tab (otherwise it's a pretty expensive operation)
309
- if (!empty($is_active_tab_basic_options)) {
310
- ?></table>
311
- <div class="cnb-button-edit-action-table <?php if(!$hide_on_modal) { echo cnb_is_active_tab('basic_options'); } else { echo 'nav-tab-only'; } ?>">
312
- <?php cnb_admin_page_action_overview_render_form(array('button' => $button));
313
- ?></div>
314
- <table class="form-table <?php if(!$hide_on_modal) { echo cnb_is_active_tab('basic_options'); } else { echo 'nav-tab-only'; } ?>"><?php
315
- }
316
- } ?>
 
 
 
 
 
 
 
 
 
 
 
 
317
  <?php if ($button_id === 'new') { ?>
318
  <tr>
319
  <th scope="row">Select button type</th>
@@ -338,7 +363,7 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
338
  </tr>
339
  <?php } ?>
340
  </table>
341
- <table class="form-table <?php echo cnb_is_active_tab('extra_options') ?>">
342
  <?php if ($button->type === 'FULL') { ?>
343
  <tr>
344
  <th colspan="2">
@@ -409,6 +434,7 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
409
  <label title="bottom-center" for="appearance3">Center</label>
410
  </div>
411
 
 
412
  <!-- Extra placement options -->
413
  <br class="cnb-extra-placement">
414
  <div class="cnb-radio-item cnb-extra-placement <?php echo $button->options->placement == "MIDDLE_RIGHT" ? "cnb-extra-active" : ""; ?>">
@@ -439,45 +465,50 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
439
  </div>
440
  <a href="#" id="cnb-more-placements">More placement options...</a>
441
  <!-- END extra placement options -->
 
442
  <?php } ?>
443
  </div>
444
  </td>
445
  </tr>
446
  </table>
447
- <table class="form-table <?php echo cnb_is_active_tab('visibility') ?>">
448
  <tbody id="cnb_form_table_visibility">
449
- <tr>
450
- <td></td>
451
- </tr>
452
- <tr>
 
453
  <th scope="row"><label for="cnb_button_options_displaymode">Display on </label></th>
454
  <td class="appearance">
455
- <select name="cnb[options][displayMode]" id="cnb_button_options_displaymode">
456
- <option value="MOBILE_ONLY"<?php selected('MOBILE_ONLY', $button->options->displayMode) ?>>Mobile only</option>
457
- <option value="DESKTOP_ONLY"<?php selected('DESKTOP_ONLY', $button->options->displayMode) ?>>Desktop only</option>
458
- <option value="ALWAYS"<?php selected('ALWAYS', $button->options->displayMode) ?>>All screens</option>
459
- </select>
460
  </td>
461
  </tr>
462
- <tr>
463
- <th>
464
- <h2>Select pages</h2>
465
- </th>
466
- </tr>
467
- <tr>
468
- <th><input type="button" onclick="return cnb_add_condition();" value="Add New Rule" class="button button-secondary page-title-action"></th>
 
 
 
 
469
  </tr>
470
  <?php if (empty($button->conditions)) { ?>
471
- <tr>
472
  <td colspan="2">
473
- <p class="cnb_paragraph">You have no page visibility rules set up. This means that your button will show on all pages.</p>
474
- <p class="cnb_paragraph">Page visibility rules give you full control over which pages the button should appear on.</p>
475
- <p class="cnb_paragraph">Click the <code>Add New Rule</code> button above to add a rule. You can freely mix and match rules to meet your requirements.</p>
476
  </td>
477
  </tr>
478
  <?php } else { ?>
479
  <?php foreach ($button->conditions as $condition) { ?>
480
- <tr class="appearance" id="cnb_condition_<?php esc_attr_e($condition->id) ?>">
481
  <td colspan="2" style="padding: 0;">
482
  <table class="cnb_condition_rule">
483
  <tbody>
@@ -523,9 +554,7 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
523
  <?php } } ?>
524
  <tr id="cnb_form_table_add_condition">
525
  <th></th>
526
- <td>
527
-
528
- </td>
529
  </tr>
530
  </tbody>
531
  </table>
@@ -572,19 +601,42 @@ function cnb_admin_page_edit_render() {
572
  do_action('cnb_header');
573
  ?>
574
 
575
- <h2 class="nav-tab-wrapper">
576
- <a href="<?php echo cnb_create_tab_url_button($button, 'basic_options') ?>"
577
- class="nav-tab <?php echo cnb_is_active_tab('basic_options') ?>">Basics</a>
578
- <?php if ($button_id !== 'new') { ?>
579
- <a href="<?php echo cnb_create_tab_url_button($button, 'extra_options') ?>"
580
- class="nav-tab <?php echo cnb_is_active_tab('extra_options') ?>">Presentation</a>
581
- <a href="<?php echo cnb_create_tab_url_button($button, 'visibility') ?>"
582
- class="nav-tab <?php echo cnb_is_active_tab('visibility') ?>">Visibility</a>
583
- <?php } else { ?>
584
- <a class="nav-tab"><i>Additional options available after saving</i></a>
585
- <?php } ?>
586
- </h2>
 
 
 
 
 
587
  <?php
588
  cnb_button_edit_form($button_id, $button, $default_domain, $options);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  do_action('cnb_footer');
590
  }
223
  $default_domain['id'] = 0;
224
  }
225
 
226
+ wp_enqueue_script(
227
+ CNB_SLUG . '-action-type-to-icon-text',
228
+ plugins_url( '../../resources/js/action-type-to-icon-text.js', __FILE__ ),
229
+ array('jquery'),
230
+ CNB_VERSION,
231
+ true);
232
+
233
+ wp_enqueue_script(
234
+ CNB_SLUG . '-form-to-json',
235
+ plugins_url( '../../resources/js/form-to-json.js', __FILE__ ),
236
+ array('jquery'),
237
+ CNB_VERSION,
238
+ true);
239
+
240
+ wp_enqueue_script(
241
+ CNB_SLUG . '-preview',
242
+ plugins_url( '../../resources/js/preview.js', __FILE__ ),
243
+ array('jquery'),
244
+ CNB_VERSION,
245
+ true);
246
+
247
+ wp_enqueue_script(
248
+ CNB_SLUG . '-client',
249
+ 'https://static.callnowbutton.com/js/client.js',
250
+ array(),
251
+ CNB_VERSION,
252
+ true);
253
  ?>
254
  <form action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post" class="cnb-container">
255
  <input type="hidden" name="page" value="call-now-button" />
267
  <input type="hidden" name="actions[<?php esc_attr_e($action->id) ?>][id]" value="<?php esc_attr_e($action->id) ?>" />
268
  <?php } ?>
269
 
270
+ <table class="form-table <?php if(!$hide_on_modal) { echo cnb_is_active_tab('basic_options'); } else { echo 'nav-tab-only'; } ?>" data-tab-name="basic_options">
271
  <tr class="cnb_hide_on_modal">
272
  <th></th>
273
  <td></td>
275
  <tr>
276
  <th scope="row"><label for="cnb[name]">Button name</label></th>
277
 
278
+ <td class="activated">
279
+ <label for="cnb[name]"><input type="text" name="cnb[name]" id="cnb[name]" required="required" value="<?php esc_attr_e($button->name); ?>" /></label>
280
+ </td>
281
+ </tr>
282
+ <tr class="cnb_hide_on_modal">
283
+ <th scope="row"><label for="cnb-enable">Button status</label></th>
284
 
285
+ <td class="activated">
286
  <input type="hidden" name="cnb[active]" value="0" />
287
  <input id="cnb-enable" class="cnb_toggle_checkbox" type="checkbox" name="cnb[active]" value="1" <?php checked(true, $button->active); ?> />
288
  <label for="cnb-enable" class="cnb_toggle_label">Toggle</label>
289
  <span data-cnb_toggle_state_label="cnb-enable" class="cnb_toggle_state cnb_toggle_false">Inactive</span>
290
  <span data-cnb_toggle_state_label="cnb-enable" class="cnb_toggle_state cnb_toggle_true">Active</span>
291
+ </td>
292
+ </tr>
293
+ <tr class="cnb_hide_on_modal cnb_advanced_view">
294
+ <th scope="row"><label for="cnb[domain]">Domain</label></th>
295
+ <td>
296
  <select name="cnb[domain]" id="cnb[domain]">
297
  <?php
298
  foreach ($domains as $domain) { ?>
302
  </option>
303
  <?php } ?>
304
  </select>
305
+ </td>
306
  </tr>
307
  <?php if ($button->type !== 'SINGLE') { ?>
308
  <tr class="cnb_hide_on_modal">
309
  <th colspan="2" class="cnb_padding_0">
310
+ <h2 >Actions <?php echo '<a href="' . $new_action_url . '" class="page-title-action">Add Action</a>'; ?></h2>
 
 
 
311
  </th>
312
  </tr>
313
+ <?php }
314
+ if ($button->type === 'SINGLE') {
315
+ $action = new CnbAction();
316
+
317
+ // If there is a real one, use that one
318
+ if (sizeof($button->actions) > 0) {
319
+ $action = $button->actions[0];
 
 
 
 
 
 
 
 
 
 
 
320
  } else {
321
+ // Create a dummy Action
322
+ $action->id = 'new';
323
+ $action->actionType = '';
324
+ $action->actionValue = '';
325
+ $action->labelText = '';
326
+ $action->properties = new CnbActionProperties();
327
+ }
328
+ cnb_admin_page_action_edit_render_main($action, $button, $default_domain, false);
329
+ } else {
330
+ ?>
331
+ </table>
332
+
333
+ <div data-tab-name="basic_options" class="cnb-button-edit-action-table <?php if($hide_on_modal) { echo cnb_is_active_tab('basic_options'); } else { echo 'nav-tab-only'; } ?>" <?php if(!cnb_is_active_tab('basic_options')) { echo 'style="display:none"'; } ?>>
334
+ <?php cnb_admin_page_action_overview_render_form(array('button' => $button)); ?>
335
+ <script>
336
+ let cnb_actions = <?php echo json_encode($button->actions) ?>;
337
+ let cnb_domain = <?php echo json_encode($default_domain) ?>;
338
+ </script>
339
+ </div>
340
+ <table class="form-table <?php if(!$hide_on_modal) { echo cnb_is_active_tab('basic_options'); } else { echo 'nav-tab-only'; } ?>"><?php
341
+ } ?>
342
  <?php if ($button_id === 'new') { ?>
343
  <tr>
344
  <th scope="row">Select button type</th>
363
  </tr>
364
  <?php } ?>
365
  </table>
366
+ <table class="form-table <?php echo cnb_is_active_tab('extra_options') ?>" data-tab-name="extra_options">
367
  <?php if ($button->type === 'FULL') { ?>
368
  <tr>
369
  <th colspan="2">
434
  <label title="bottom-center" for="appearance3">Center</label>
435
  </div>
436
 
437
+ <?php if ($button->type !== 'MULTI') { ?>
438
  <!-- Extra placement options -->
439
  <br class="cnb-extra-placement">
440
  <div class="cnb-radio-item cnb-extra-placement <?php echo $button->options->placement == "MIDDLE_RIGHT" ? "cnb-extra-active" : ""; ?>">
465
  </div>
466
  <a href="#" id="cnb-more-placements">More placement options...</a>
467
  <!-- END extra placement options -->
468
+ <?php } ?>
469
  <?php } ?>
470
  </div>
471
  </td>
472
  </tr>
473
  </table>
474
+ <table class="form-table <?php echo cnb_is_active_tab('visibility') ?>" data-tab-name="visibility">
475
  <tbody id="cnb_form_table_visibility">
476
+ <tr>
477
+ <th></th>
478
+ <td></td>
479
+ </tr>
480
+ <tr>
481
  <th scope="row"><label for="cnb_button_options_displaymode">Display on </label></th>
482
  <td class="appearance">
483
+ <select name="cnb[options][displayMode]" id="cnb_button_options_displaymode">
484
+ <option value="MOBILE_ONLY"<?php selected('MOBILE_ONLY', $button->options->displayMode) ?>>Mobile only</option>
485
+ <option value="DESKTOP_ONLY"<?php selected('DESKTOP_ONLY', $button->options->displayMode) ?>>Desktop only</option>
486
+ <option value="ALWAYS"<?php selected('ALWAYS', $button->options->displayMode) ?>>All screens</option>
487
+ </select>
488
  </td>
489
  </tr>
490
+ <tr>
491
+ <th>Show on all pages</th>
492
+ <td>
493
+ <input class="cnb_toggle_checkbox" type="checkbox" id="conditions_show_on_all_pages" <?php checked(true, empty($button->conditions)); ?> />
494
+ <label for="conditions_show_on_all_pages" class="cnb_toggle_label">Toggle</label>
495
+ <span data-cnb_toggle_state_label="conditions_show_on_all_pages" class="cnb_toggle_state cnb_toggle_false">(No)</span>
496
+ <span data-cnb_toggle_state_label="conditions_show_on_all_pages" class="cnb_toggle_state cnb_toggle_true">Yes</span>
497
+ </td>
498
+ </tr>
499
+ <tr class="cnb_hide_on_show_on_all_pages">
500
+ <th><input type="button" onclick="return cnb_add_condition();" value="Add page rule" class="button button-secondary page-title-action"></th>
501
  </tr>
502
  <?php if (empty($button->conditions)) { ?>
503
+ <tr class="cnb_hide_on_show_on_all_pages">
504
  <td colspan="2">
505
+ <p class="cnb_paragraph">You have no page visibility rules set up. This means that your button will still show on all pages.</p>
506
+ <p class="cnb_paragraph">Click the <code>Add page rule</code> button above to add a page rule. You can freely mix and match rules to meet your requirements.</p>
 
507
  </td>
508
  </tr>
509
  <?php } else { ?>
510
  <?php foreach ($button->conditions as $condition) { ?>
511
+ <tr class="appearance cnb-condition" id="cnb_condition_<?php esc_attr_e($condition->id) ?>">
512
  <td colspan="2" style="padding: 0;">
513
  <table class="cnb_condition_rule">
514
  <tbody>
554
  <?php } } ?>
555
  <tr id="cnb_form_table_add_condition">
556
  <th></th>
557
+ <td></td>
 
 
558
  </tr>
559
  </tbody>
560
  </table>
601
  do_action('cnb_header');
602
  ?>
603
 
604
+ <div class="cnb-two-column-section-preview">
605
+ <div class="cnb-body-column">
606
+ <div class="cnb-body-content">
607
+
608
+ <h2 class="nav-tab-wrapper">
609
+ <a href="<?php echo cnb_create_tab_url_button($button, 'basic_options') ?>"
610
+ class="nav-tab <?php echo cnb_is_active_tab('basic_options') ?>" data-tab-name="basic_options">Basics</a>
611
+ <?php if ($button_id !== 'new') { ?>
612
+ <a href="<?php echo cnb_create_tab_url_button($button, 'extra_options') ?>"
613
+ class="nav-tab <?php echo cnb_is_active_tab('extra_options') ?>" data-tab-name="extra_options">Presentation</a>
614
+ <a href="<?php echo cnb_create_tab_url_button($button, 'visibility') ?>"
615
+ class="nav-tab <?php echo cnb_is_active_tab('visibility') ?>" data-tab-name="visibility">Visibility</a>
616
+ <?php } else { ?>
617
+ <a class="nav-tab"><i>Additional options available after saving</i></a>
618
+ <?php } ?>
619
+ </h2>
620
+
621
  <?php
622
  cnb_button_edit_form($button_id, $button, $default_domain, $options);
623
+ ?>
624
+ <!-- <div id="cnb-button-preview"></div> -->
625
+ </div>
626
+ </div>
627
+ <div class="cnb-side-column">
628
+ <div id="phone-preview">
629
+ <div class="phone-outside double">
630
+ <div class="speaker single"></div>
631
+ <div class="phone-inside single">
632
+ <div id="cnb-button-preview"></div>
633
+ </div>
634
+ <div class="mic double"></div>
635
+ </div>
636
+ </div>
637
+ </div>
638
+ </div>
639
+
640
+ <?php
641
  do_action('cnb_footer');
642
  }
src/admin/button-overview.php CHANGED
@@ -567,7 +567,7 @@ function cnb_admin_page_overview_render_list() {
567
 
568
  <br class="clear">
569
  <?php
570
- echo '</div></div>';
571
  // Do not do this when there are errors!
572
  if (!is_wp_error($data)) {
573
  cnb_admin_page_render_thickbox( $cnb_cloud_domain );
567
 
568
  <br class="clear">
569
  <?php
570
+ echo '</div>';
571
  // Do not do this when there are errors!
572
  if (!is_wp_error($data)) {
573
  cnb_admin_page_render_thickbox( $cnb_cloud_domain );
src/admin/domain-edit.php CHANGED
@@ -154,6 +154,32 @@ function cnb_admin_page_domain_edit_process() {
154
  }
155
  }
156
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  /**
158
  * Main entrypoint, used by `domain-overview.php`.
159
  */
@@ -172,6 +198,13 @@ function cnb_admin_page_domain_edit_render() {
172
  cnb_add_header_domain_edit($domain);
173
  });
174
 
 
 
 
 
 
 
 
175
  do_action('cnb_header');
176
  ?>
177
 
@@ -251,7 +284,7 @@ function cnb_admin_page_domain_edit_render_form_tracking($domain) { ?>
251
 
252
  <p class="description">
253
  Supports Classic, Universal Analytics and Global site tag (v3 and v4).<br>
254
- Using Google Tag Manager? Set up click tracking in GTM. <a href="https://callnowbutton.com/support/click-tracking/google-tag-manager-event-tracking/?utm_source=wp-plugin&amp;utm_medium=referral&amp;utm_campaign=description_link&amp;utm_term=google-tag-manager-event-tracking" target="_blank">Learn how to do this...</a>
255
  </p>
256
  </td>
257
  </tr>
@@ -286,8 +319,7 @@ function cnb_admin_page_domain_edit_render_form_button_display($domain) {
286
  </fieldset></td>
287
  </tr>
288
  <tr class="z-index">
289
- <th scope="row"><label for="cnb_order_slider">Order (<span id="cnb_order_value"></span>)</label> <a
290
- href="https://callnowbutton.com/set-order/" target="_blank" class="cnb-nounderscore">
291
  <span class="dashicons dashicons-editor-help"></span>
292
  </a></th>
293
  <td>
@@ -308,6 +340,9 @@ function cnb_admin_page_domain_edit_render_form_button_display($domain) {
308
  function cnb_admin_page_domain_edit_render_form_advanced($domain, $header=true) {
309
  global $cnb_options;
310
  $show_advanced_view_only = array_key_exists('advanced_view', $cnb_options) && $cnb_options['advanced_view'] === 1;
 
 
 
311
  if($header) { ?>
312
  <tr>
313
  <th colspan="2"><h2>Advanced</h2></th>
@@ -332,12 +367,17 @@ function cnb_admin_page_domain_edit_render_form_advanced($domain, $header=true)
332
  <tr>
333
  <th scope="row"><label for="domain_timezone">Timezone</label></th>
334
  <td>
335
- <select name="domain[timezone]" id="domain_timezone">
336
  <?php echo wp_timezone_choice($domain->timezone) ?>
337
  </select>
338
  <p class="description" id="domain_timezone-description">
339
  <?php if (empty($domain->timezone)) { ?>
340
  Please select your timezone.
 
 
 
 
 
341
  <?php } else { ?>
342
  Currently set to <code><?php esc_html_e($domain->timezone) ?></code>.
343
  <?php } ?>
154
  }
155
  }
156
 
157
+ /**
158
+ * @param CnbDomain $domain
159
+ *
160
+ * @return void
161
+ */
162
+ function cnb_domain_timezone_check($domain) {
163
+ if ($domain && !is_wp_error($domain) && !empty($domain->timezone)) {
164
+ $domain_timezone = $domain->timezone;
165
+
166
+ if (!is_valid_timezone_string($domain_timezone)) {
167
+ $url = admin_url( 'admin.php' );
168
+ $redirect_link =
169
+ add_query_arg(
170
+ array(
171
+ 'page' => 'call-now-button-settings',
172
+ 'tab' => 'advanced_options#domain_timezone',
173
+
174
+ ),
175
+ $url );
176
+ $redirect_url = esc_url( $redirect_link );
177
+ $message = "<p id='cnb-notice-domain-timezone-unsupported'>Please set your timezone in the <a href=\"". $redirect_url . "\">Advanced settings</a> tab to avoid unpredictable behavior when using the scheduler.</p>";
178
+ $notice = new CnbNotice('warning', $message, false);
179
+ CnbAdminNotices::get_instance()->renderNotice($notice);
180
+ }
181
+ }
182
+ }
183
  /**
184
  * Main entrypoint, used by `domain-overview.php`.
185
  */
198
  cnb_add_header_domain_edit($domain);
199
  });
200
 
201
+ wp_enqueue_script(
202
+ CNB_SLUG . '-timezone-picker-fix',
203
+ plugins_url( '../../resources/js/timezone-picker-fix.js', __FILE__ ),
204
+ array('jquery'),
205
+ CNB_VERSION,
206
+ true);
207
+
208
  do_action('cnb_header');
209
  ?>
210
 
284
 
285
  <p class="description">
286
  Supports Classic, Universal Analytics and Global site tag (v3 and v4).<br>
287
+ Using Google Tag Manager? Set up click tracking in GTM. <a href="<?php echo CNB_SUPPORT ?>wordpress-free/settings/google-tag-manager-event-tracking/" target="_blank">Learn how to do this...</a>
288
  </p>
289
  </td>
290
  </tr>
319
  </fieldset></td>
320
  </tr>
321
  <tr class="z-index">
322
+ <th scope="row"><label for="cnb_order_slider">Order (<span id="cnb_order_value"></span>)</label> <a href="<?php echo CNB_SUPPORT ?>wordpress-free/settings/set-order/" target="_blank" class="cnb-nounderscore">
 
323
  <span class="dashicons dashicons-editor-help"></span>
324
  </a></th>
325
  <td>
340
  function cnb_admin_page_domain_edit_render_form_advanced($domain, $header=true) {
341
  global $cnb_options;
342
  $show_advanced_view_only = array_key_exists('advanced_view', $cnb_options) && $cnb_options['advanced_view'] === 1;
343
+
344
+ cnb_domain_timezone_check($domain);
345
+
346
  if($header) { ?>
347
  <tr>
348
  <th colspan="2"><h2>Advanced</h2></th>
367
  <tr>
368
  <th scope="row"><label for="domain_timezone">Timezone</label></th>
369
  <td>
370
+ <select name="domain[timezone]" id="domain_timezone" class="cnb_timezone_picker">
371
  <?php echo wp_timezone_choice($domain->timezone) ?>
372
  </select>
373
  <p class="description" id="domain_timezone-description">
374
  <?php if (empty($domain->timezone)) { ?>
375
  Please select your timezone.
376
+ <?php
377
+ $wordpress_timezone_string = wp_timezone_string();
378
+ if (is_valid_timezone_string($wordpress_timezone_string)) { ?>
379
+ <br />WordPress is set to: <code><?php echo wp_timezone_string() ?></code>
380
+ <?php } ?>
381
  <?php } else { ?>
382
  Currently set to <code><?php esc_html_e($domain->timezone) ?></code>.
383
  <?php } ?>
src/admin/domain-upgrade.php CHANGED
@@ -72,8 +72,10 @@ function cnb_admin_page_domain_upgrade_render_content() {
72
  }
73
  wp_enqueue_script(
74
  CNB_SLUG . '-domain-upgrade',
75
- plugins_url( '../../resources/js/domain-upgrade.js', __FILE__ )
76
- );
 
 
77
 
78
  // Stripe integration
79
  echo '<script src="https://js.stripe.com/v3/"></script>';
72
  }
73
  wp_enqueue_script(
74
  CNB_SLUG . '-domain-upgrade',
75
+ plugins_url( '../../resources/js/domain-upgrade.js', __FILE__ ),
76
+ array('jquery'),
77
+ CNB_VERSION,
78
+ true);
79
 
80
  // Stripe integration
81
  echo '<script src="https://js.stripe.com/v3/"></script>';
src/admin/legacy-edit.php CHANGED
@@ -23,7 +23,7 @@ function cnb_admin_page_leagcy_edit_render_tracking() {
23
  global $cnb_options;
24
  ?>
25
  <tr>
26
- <th scope="row">Click tracking <a href="<?php echo CNB_SUPPORT; ?>click-tracking/<?php cnb_utm_params("question-mark", "click-tracking"); ?>" target="_blank" class="cnb-nounderscore">
27
  <span class="dashicons dashicons-editor-help"></span>
28
  </a></th>
29
  <td>
@@ -43,7 +43,7 @@ function cnb_admin_page_leagcy_edit_render_tracking() {
43
  <input id="tracking2" type="radio" name="cnb[tracking]" value="1" <?php checked('1', $cnb_options['tracking']); ?> />
44
  <label for="tracking2">Classic Google Analytics (ga.js)</label>
45
  </div>
46
- <p class="description">Using Google Tag Manager? Set up click tracking in GTM. <a href="<?php echo CNB_SUPPORT; ?>click-tracking/google-tag-manager-event-tracking/<?php cnb_utm_params("description_link", "google-tag-manager-event-tracking"); ?>" target="_blank">Learn how to do this...</a></p>
47
  </td>
48
  </tr>
49
  <?php
@@ -53,7 +53,7 @@ function cnb_admin_page_leagcy_edit_render_conversions() {
53
  global $cnb_options;
54
  ?>
55
  <tr>
56
- <th scope="row">Google Ads <a href="<?php echo CNB_SUPPORT; ?>google-ads/<?php cnb_utm_params("question-mark", "google-ads"); ?>" target="_blank" class="cnb-nounderscore">
57
  <span class="dashicons dashicons-editor-help"></span>
58
  </a></th>
59
  <td class="conversions">
@@ -66,7 +66,7 @@ function cnb_admin_page_leagcy_edit_render_conversions() {
66
  <div class="cnb-radio-item">
67
  <input id="cnb_conversions_2" name="cnb[conversions]" type="radio" value="2" <?php checked('2', $cnb_options['conversions']); ?> /> <label for="cnb_conversions_2">Conversion Tracking using JavaScript</label>
68
  </div>
69
- <p class="description">Select this option if you want to track clicks on the button as Google Ads conversions. This option requires the Event snippet to be present on the page. <a href="<?php echo CNB_SUPPORT; ?>google-ads/<?php cnb_utm_params("question-mark", "google-ads"); ?>" target="_blank">Learn more...</a></p>
70
  </td>
71
  </tr>
72
  <?php
@@ -76,7 +76,7 @@ function cnb_admin_page_leagcy_edit_render_zoom() {
76
  global $cnb_options;
77
  ?>
78
  <tr class="zoom">
79
- <th scope="row">Button size <span id="cnb_slider_value"></span></th>
80
  <td>
81
  <label class="cnb_slider_value">Smaller&nbsp;&laquo;&nbsp;</label>
82
  <input type="range" min="0.7" max="1.3" name="cnb[zoom]" value="<?php esc_attr_e($cnb_options['zoom']) ?>" class="slider" id="cnb_slider" step="0.1">
@@ -90,7 +90,7 @@ function cnb_admin_page_leagcy_edit_render_zindex() {
90
  global $cnb_options;
91
  ?>
92
  <tr class="z-index">
93
- <th scope="row">Order (<span id="cnb_order_value"></span>) <a href="https://callnowbutton.com/set-order/" target="_blank" class="cnb-nounderscore">
94
  <span class="dashicons dashicons-editor-help"></span>
95
  </a></th>
96
  <td>
@@ -111,27 +111,27 @@ function cnb_admin_page_legacy_edit_render() {
111
 
112
  do_action('cnb_header');
113
  ?>
114
-
115
-
116
  <div class="cnb-two-column-section">
117
  <div class="cnb-body-column">
118
  <div class="cnb-body-content">
119
 
120
  <h2 class="nav-tab-wrapper">
121
  <a href="<?php echo cnb_create_tab_url_legacy('basic_options') ?>"
122
- class="nav-tab <?php echo cnb_is_active_tab('basic_options') ?>">Basics</a>
123
  <a href="<?php echo cnb_create_tab_url_legacy('extra_options') ?>"
124
- class="nav-tab <?php echo cnb_is_active_tab('extra_options') ?>">Presentation</a>
125
  </h2>
126
 
 
127
  <form method="post" action="<?php echo esc_url( admin_url('options.php') ); ?>" class="cnb-container">
128
  <?php settings_fields('cnb_options'); ?>
129
- <table class="form-table <?php echo cnb_is_active_tab('basic_options') ?>">
130
  <tr>
131
  <th colspan="2"></th>
132
  </tr>
133
  <tr>
134
- <th scope="row">Button status</th>
135
  <td>
136
  <input type="hidden" name="cnb[active]" value="0" />
137
  <input id="cnb-active" type="checkbox" name="cnb[active]" value="1" <?php checked('1', $cnb_options['active']); ?>>
@@ -139,13 +139,13 @@ function cnb_admin_page_legacy_edit_render() {
139
  </td>
140
  </tr>
141
  <tr>
142
- <th scope="row">Phone number <a href="<?php echo CNB_SUPPORT; ?>wordpress-free/basics/phone-number/<?php cnb_utm_params("question-mark", "phone-number"); ?>" target="_blank" class="cnb-nounderscore">
143
  <span class="dashicons dashicons-editor-help"></span>
144
  </a></th>
145
- <td><input type="text" name="cnb[number]" value="<?php esc_attr_e($cnb_options['number']) ?>" /></td>
146
  </tr>
147
  <tr class="button-text">
148
- <th scope="row">Button text <small style="font-weight: 400">(optional)</small> <a href="<?php echo CNB_SUPPORT; ?>wordpress-free/basics/using-text-buttons/<?php cnb_utm_params("question-mark", "using-text-buttons"); ?>" target="_blank" class="cnb-nounderscore">
149
  <span class="dashicons dashicons-editor-help"></span>
150
  </a></th>
151
  <td>
@@ -155,21 +155,21 @@ function cnb_admin_page_legacy_edit_render() {
155
  </tr>
156
  </table>
157
 
158
- <table class="form-table <?php echo cnb_is_active_tab('extra_options') ?>">
159
  <tr>
160
  <th colspan="2"></th>
161
  </tr>
162
 
163
  <tr>
164
  <th scope="row">Button color</th>
165
- <td><input name="cnb[color]" type="text" value="<?php esc_attr_e($cnb_options['color']) ?>" class="cnb-color-field" data-default-color="#009900" /></td>
166
  </tr>
167
  <tr>
168
  <th scope="row">Icon color</th>
169
  <td><input name="cnb[iconcolor]" type="text" value="<?php esc_attr_e($cnb_options['iconcolor']) ?>" class="cnb-iconcolor-field" data-default-color="#ffffff" /></td>
170
  </tr>
171
  <tr>
172
- <th scope="row">Position <a href="<?php echo CNB_SUPPORT; ?>button-position/<?php cnb_utm_params("question-mark", "button-position"); ?>" target="_blank" class="cnb-nounderscore">
173
  <span class="dashicons dashicons-editor-help"></span>
174
  </a></th>
175
  <td class="appearance">
@@ -231,12 +231,12 @@ function cnb_admin_page_legacy_edit_render() {
231
  </td>
232
  </tr>
233
  <tr class="appearance">
234
- <th scope="row">Limit appearance <a href="<?php echo CNB_SUPPORT; ?>limit-appearance/<?php cnb_utm_params("question-mark", "limit-appearance"); ?>" target="_blank" class="cnb-nounderscore">
235
  <span class="dashicons dashicons-editor-help"></span>
236
  </a></th>
237
  <td>
238
- <input type="text" name="cnb[show]" value="<?php esc_attr_e($cnb_options['show']) ?>" placeholder="E.g. 14, 345" />
239
- <p class="description">Enter IDs of the posts &amp; pages, separated by commas (leave blank for all). <a href="<?php echo CNB_SUPPORT; ?>limit-appearance/<?php cnb_utm_params("question-mark", "limit-appearance"); ?>">Learn more...</a></p>
240
  <div class="cnb-radio-item">
241
  <input id="limit1" type="radio" name="cnb[limit]" value="include" <?php checked('include', $cnb_options['limit']);?> />
242
  <label for="limit1">Limit to these posts and pages.</label>
23
  global $cnb_options;
24
  ?>
25
  <tr>
26
+ <th scope="row">Click tracking <a href="<?php echo CNB_SUPPORT ?>wordpress-free/settings/click-tracking/<?php cnb_utm_params("question-mark", "click-tracking"); ?>" target="_blank" class="cnb-nounderscore">
27
  <span class="dashicons dashicons-editor-help"></span>
28
  </a></th>
29
  <td>
43
  <input id="tracking2" type="radio" name="cnb[tracking]" value="1" <?php checked('1', $cnb_options['tracking']); ?> />
44
  <label for="tracking2">Classic Google Analytics (ga.js)</label>
45
  </div>
46
+ <p class="description">Using Google Tag Manager? Set up click tracking in GTM. <a href="<?php echo CNB_SUPPORT ?>wordpress-free/settings/google-tag-manager-event-tracking/<?php cnb_utm_params("description_link", "google-tag-manager-event-tracking"); ?>" target="_blank">Learn how to do this...</a></p>
47
  </td>
48
  </tr>
49
  <?php
53
  global $cnb_options;
54
  ?>
55
  <tr>
56
+ <th scope="row">Google Ads <a href="<?php echo CNB_SUPPORT ?>wordpress-free/settings/google-ads/<?php cnb_utm_params("question-mark", "google-ads"); ?>" target="_blank" class="cnb-nounderscore">
57
  <span class="dashicons dashicons-editor-help"></span>
58
  </a></th>
59
  <td class="conversions">
66
  <div class="cnb-radio-item">
67
  <input id="cnb_conversions_2" name="cnb[conversions]" type="radio" value="2" <?php checked('2', $cnb_options['conversions']); ?> /> <label for="cnb_conversions_2">Conversion Tracking using JavaScript</label>
68
  </div>
69
+ <p class="description">Select this option if you want to track clicks on the button as Google Ads conversions. This option requires the Event snippet to be present on the page. <a href="<?php echo CNB_SUPPORT ?>wordpress-free/settings/google-ads/<?php cnb_utm_params("question-mark", "google-ads"); ?>" target="_blank">Learn more...</a></p>
70
  </td>
71
  </tr>
72
  <?php
76
  global $cnb_options;
77
  ?>
78
  <tr class="zoom">
79
+ <th scope="row"><label for="cnb_slider">Button size <span id="cnb_slider_value"></span></label></th>
80
  <td>
81
  <label class="cnb_slider_value">Smaller&nbsp;&laquo;&nbsp;</label>
82
  <input type="range" min="0.7" max="1.3" name="cnb[zoom]" value="<?php esc_attr_e($cnb_options['zoom']) ?>" class="slider" id="cnb_slider" step="0.1">
90
  global $cnb_options;
91
  ?>
92
  <tr class="z-index">
93
+ <th scope="row"><label for="cnb_order_slider">Order (<span id="cnb_order_value"></span>)</label> <a href="<?php echo CNB_SUPPORT ?>wordpress-free/settings/set-order/" target="_blank" class="cnb-nounderscore">
94
  <span class="dashicons dashicons-editor-help"></span>
95
  </a></th>
96
  <td>
111
 
112
  do_action('cnb_header');
113
  ?>
114
+ <?php cnb_get_welcome_panel() ?>
 
115
  <div class="cnb-two-column-section">
116
  <div class="cnb-body-column">
117
  <div class="cnb-body-content">
118
 
119
  <h2 class="nav-tab-wrapper">
120
  <a href="<?php echo cnb_create_tab_url_legacy('basic_options') ?>"
121
+ class="nav-tab <?php echo cnb_is_active_tab('basic_options') ?>" data-tab-name="basic_options">Basics</a>
122
  <a href="<?php echo cnb_create_tab_url_legacy('extra_options') ?>"
123
+ class="nav-tab <?php echo cnb_is_active_tab('extra_options') ?>" data-tab-name="extra_options">Presentation</a>
124
  </h2>
125
 
126
+
127
  <form method="post" action="<?php echo esc_url( admin_url('options.php') ); ?>" class="cnb-container">
128
  <?php settings_fields('cnb_options'); ?>
129
+ <table class="form-table <?php echo cnb_is_active_tab('basic_options') ?>" data-tab-name="basic_options">
130
  <tr>
131
  <th colspan="2"></th>
132
  </tr>
133
  <tr>
134
+ <th scope="row"><label for="cnb-active">Button status</label></th>
135
  <td>
136
  <input type="hidden" name="cnb[active]" value="0" />
137
  <input id="cnb-active" type="checkbox" name="cnb[active]" value="1" <?php checked('1', $cnb_options['active']); ?>>
139
  </td>
140
  </tr>
141
  <tr>
142
+ <th scope="row"><label for="cnb-number">Phone number</label> <a href="<?php echo CNB_SUPPORT ?>wordpress-free/basics/phone-number/<?php cnb_utm_params("question-mark", "phone-number"); ?>" target="_blank" class="cnb-nounderscore">
143
  <span class="dashicons dashicons-editor-help"></span>
144
  </a></th>
145
+ <td><input type="text" id="cnb-number" name="cnb[number]" value="<?php esc_attr_e($cnb_options['number']) ?>" /></td>
146
  </tr>
147
  <tr class="button-text">
148
+ <th scope="row"><label for="buttonTextField">Button text</label> <small style="font-weight: 400">(optional)</small> <a href="<?php echo CNB_SUPPORT ?>wordpress-free/basics/using-text-buttons/<?php cnb_utm_params("question-mark", "using-text-buttons"); ?>" target="_blank" class="cnb-nounderscore">
149
  <span class="dashicons dashicons-editor-help"></span>
150
  </a></th>
151
  <td>
155
  </tr>
156
  </table>
157
 
158
+ <table class="form-table <?php echo cnb_is_active_tab('extra_options') ?>" data-tab-name="extra_options">
159
  <tr>
160
  <th colspan="2"></th>
161
  </tr>
162
 
163
  <tr>
164
  <th scope="row">Button color</th>
165
+ <td><input id="cnb-color" name="cnb[color]" type="text" value="<?php esc_attr_e($cnb_options['color']) ?>" class="cnb-color-field" data-default-color="#009900" /></td>
166
  </tr>
167
  <tr>
168
  <th scope="row">Icon color</th>
169
  <td><input name="cnb[iconcolor]" type="text" value="<?php esc_attr_e($cnb_options['iconcolor']) ?>" class="cnb-iconcolor-field" data-default-color="#ffffff" /></td>
170
  </tr>
171
  <tr>
172
+ <th scope="row">Position <a href="<?php echo CNB_SUPPORT ?>wordpress-free/presentation/button-position/<?php cnb_utm_params("question-mark", "button-position"); ?>" target="_blank" class="cnb-nounderscore">
173
  <span class="dashicons dashicons-editor-help"></span>
174
  </a></th>
175
  <td class="appearance">
231
  </td>
232
  </tr>
233
  <tr class="appearance">
234
+ <th scope="row"><label for="cnb-show">Limit appearance</label> <a href="<?php echo CNB_SUPPORT ?>wordpress-free/presentation/limit-appearance/<?php cnb_utm_params("question-mark", "limit-appearance"); ?>" target="_blank" class="cnb-nounderscore">
235
  <span class="dashicons dashicons-editor-help"></span>
236
  </a></th>
237
  <td>
238
+ <input type="text" id="cnb-show" name="cnb[show]" value="<?php esc_attr_e($cnb_options['show']) ?>" placeholder="E.g. 14, 345" />
239
+ <p class="description">Enter IDs of the posts &amp; pages, separated by commas (leave blank for all). <a href="<?php echo CNB_SUPPORT ?>wordpress-free/presentation/limit-appearance/<?php cnb_utm_params("question-mark", "limit-appearance"); ?>" target="_blank">Learn more...</a></p>
240
  <div class="cnb-radio-item">
241
  <input id="limit1" type="radio" name="cnb[limit]" value="include" <?php checked('include', $cnb_options['limit']);?> />
242
  <label for="limit1">Limit to these posts and pages.</label>
src/admin/legacy-upgrade.php CHANGED
@@ -7,118 +7,122 @@ function cnb_add_header_legacy_upgrade() {
7
  echo 'Unlock extra features';
8
  }
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  function cnb_admin_page_legacy_upgrade_render() {
11
- global $cnb_options;
 
 
 
 
 
12
 
13
  add_action('cnb_header_name', 'cnb_add_header_legacy_upgrade');
14
-
15
  do_action('cnb_header');
16
  ?>
17
 
18
-
19
  <div class="cnb-one-column-section">
20
- <div class="cnb-body-content">
21
-
22
-
23
-
24
- <div class="cnb-two-promobox-row">
25
- <div class="cnb-body-column hide-on-mobile">
26
- <?php
27
- cnb_promobox(
28
- 'grey',
29
- 'Standard plugin',
30
- '<p>&check; One button<br>
31
- &check; Phone<br>
32
- &check; Circular<br>
33
- &check; Full width<br>
34
- <span class="cnb_description">(single action Buttonbar&#8482;)</span>
35
- &check; Action label<br>
36
- </p>
37
- <hr>
38
- <p>
39
- &check; Placement options<br>
40
- &check; For mobile devices<br>
41
- &check; Include or exclude pages<br>
42
- </p>
43
- <hr>
44
- <p>
45
- &check; Google Analytics tracking<br>
46
- &check; Google Ads conversion tracking<br>
47
- </p>
48
- <hr>
49
- <p>
50
- &check; Adjust the button size<br>
51
- &check; Flexible z-index
52
- </p>',
53
- 'admin-plugins',
54
- '<strong>Free</strong>',
55
- 'Currently active',
56
- 'disabled'
57
- );
58
- ?>
59
- </div>
60
-
61
- <div class="cnb-body-column">
62
- <?php
63
- cnb_promobox(
64
- 'blue',
65
- 'Premium',
66
- '<p class="cnb_align_center">From <strong>&euro;2.49/$2.99</strong> per month or <strong style="text-decoration:underline">FREE</strong> with subtle "<em>powered by</em>" branding.</p>
67
- <hr>
68
- <p><strong>&check; Lots of buttons!</strong><br>
69
- &check; Phone, Email, WhatsApp, Maps, URLs<br>
70
- &check; Circular button<br>
71
- &check; Buttonbar&#8482;
72
- <span class="cnb_description">(multi action full width button)</span>
73
- &check; Multibutton&#8482;
74
- <span class="cnb_description">(single button unfolding into multiple)</span>
75
- &check; Actions labels<br>
76
- </p>
77
- <hr>
78
- <p>
79
- &check; Placement options<br>
80
- &check; For mobile and desktop/laptop<br>
81
- &check; Scheduling<br>
82
- &check; Advanced page targeting
83
- <span class="cnb_description">(for deciding where a button should appear. E.g. only show to Google Ads visitors)</span>
84
- </p>
85
- <hr>
86
- <p>
87
- &check; Google Analytics tracking<br>
88
- &check; Google Ads conversion tracking<br>
89
- </p>
90
- <hr>
91
- <p>
92
- &check; Adjust the button size<br>
93
- &check; Flexible z-index<br>
94
- &check; And much more!</p>
95
- <hr>
96
- <p class="cnb_align_center">From <strong>&euro;2.49/$2.99</strong> per month or <strong style="text-decoration:underline">FREE</strong> with subtle "<em>powered by</em>" branding.</p>',
97
- 'cloud',
98
- 'Go to <a href="'.cnb_settings_url().'">Settings</a> to upgrade manually<span class="hide-on-mobile"> or click <a href="'.get_cnb_wordpress_upgrade_link().'">Activate Premium</a></span>.',
99
- 'Activate Premium',
100
- get_cnb_wordpress_upgrade_link(),
101
- 'Clicking "Activate Premium" will share your WordPress admin email and admin URL with callnowbutton.com so it can prefill your email and return you to this page when the process is done. None of this data is stored! When you click the "Activate" button on the next page, your email will be used for creating an account.'
102
- );
103
- ?>
104
- </div>
105
-
106
-
107
- </div>
108
-
109
-
110
- <div style="max-width:600px;margin:0 auto">
111
- <h1 class="cnb-center">FAQ</h1>
112
- <h3>Can I really get Premium for Free?</h3>
113
- <p>Yes. It's possible to access all premium features of the Call Now Button for free. No credit card is required. You only need an account for that. The difference with the paid Premium plans is that a small "Powered by Call Now Button" notice is added to your buttons.</p>
114
- <h3>Does the Premium plan require an account?</h3>
115
- <p>Yes. We want the Call Now Button to be accessible to all website owners. Even those that do not have a WordPress powered website. The Premium version of the Call Now Button can be used by everyone. You can continue to manage your buttons from your WordPress instance, but you could also do this via our web app. And should you ever move to a different CMS, your button(s) will just move with you.</p>
116
- <h3>What is the "powered by" notice on the Free Premium plan?</h3>
117
- <p>Call Now Button Premium is available for a small yearly or annual fee, but it is also possible to get it for <em>free</em>. The free option introduces a small notice to your buttons that says "Powered by Call Now Button". It's very delicate and will not distract the the visitor from your key message.</p>
118
- </div>
119
-
120
- </div>
121
  </div>
 
 
 
122
  <hr>
123
  <?php
124
  do_action('cnb_footer');
7
  echo 'Unlock extra features';
8
  }
9
 
10
+ function cnb_standard_plugin_promobox() { ?>
11
+ <div class="cnb-body-column hide-on-mobile">
12
+ <?php
13
+ cnb_promobox(
14
+ 'grey',
15
+ 'Standard plugin',
16
+ '<p>&check; One button<br>
17
+ &check; Phone<br>
18
+ &check; Circular<br>
19
+ &check; Full width<br>
20
+ <span class="cnb_description">(single action Buttonbar&#8482;)</span>
21
+ &check; Action label<br>
22
+ </p>
23
+ <hr>
24
+ <p>
25
+ &check; Placement options<br>
26
+ &check; For mobile devices<br>
27
+ &check; Include or exclude pages<br>
28
+ </p>
29
+ <hr>
30
+ <p>
31
+ &check; Google Analytics tracking<br>
32
+ &check; Google Ads conversion tracking<br>
33
+ </p>
34
+ <hr>
35
+ <p>
36
+ &check; Adjust the button size<br>
37
+ &check; Flexible z-index
38
+ </p>',
39
+ 'admin-plugins',
40
+ '<strong>Free</strong>',
41
+ 'Currently active',
42
+ 'disabled'
43
+ );
44
+ ?>
45
+ </div>
46
+ <?php }
47
+
48
+ function cnb_premium_plugin_promobox() { ?>
49
+ <div class="cnb-body-column">
50
+ <?php
51
+ cnb_promobox(
52
+ 'blue',
53
+ 'Premium',
54
+ '<p class="cnb_align_center">From <strong>&euro;2.49/$2.99</strong> per month or <strong style="text-decoration:underline">FREE</strong> with subtle "<em>powered by</em>" branding.</p>
55
+ <hr>
56
+ <p><strong>&check; Lots of buttons!</strong><br>
57
+ &check; Phone, Email, WhatsApp, Maps, URLs<br>
58
+ &check; Circular button<br>
59
+ &check; Buttonbar&#8482;
60
+ <span class="cnb_description">(multi action full width button)</span>
61
+ &check; Multibutton&#8482;
62
+ <span class="cnb_description">(single button unfolding into multiple)</span>
63
+ &check; Actions labels<br>
64
+ </p>
65
+ <hr>
66
+ <p>
67
+ &check; Placement options<br>
68
+ &check; For mobile and desktop/laptop<br>
69
+ &check; Scheduling<br>
70
+ &check; Advanced page targeting
71
+ <span class="cnb_description">(for deciding where a button should appear. E.g. only show to Google Ads visitors)</span>
72
+ </p>
73
+ <hr>
74
+ <p>
75
+ &check; Google Analytics tracking<br>
76
+ &check; Google Ads conversion tracking<br>
77
+ </p>
78
+ <hr>
79
+ <p>
80
+ &check; Adjust the button size<br>
81
+ &check; Flexible z-index<br>
82
+ &check; And much more!</p>
83
+ <hr>
84
+ <p class="cnb_align_center">From <strong>&euro;2.49/$2.99</strong> per month or <strong style="text-decoration:underline">FREE</strong> with subtle "<em>powered by</em>" branding.</p>',
85
+ 'cloud',
86
+ cnb_settings_email_activation_input(),
87
+ 'none'
88
+ );
89
+ ?>
90
+ </div>
91
+ <?php }
92
+
93
+ function cnb_upgrade_faq() { ?>
94
+ <div style="max-width:600px;margin:0 auto">
95
+ <h1 class="cnb-center">FAQ</h1>
96
+ <h3>Can I really get Premium for Free?</h3>
97
+ <p>Yes. It's possible to access all premium features of the Call Now Button for free. No credit card is required. You only need an account for that. The difference with the paid Premium plans is that a small "Powered by Call Now Button" notice is added to your buttons.</p>
98
+ <h3>Does the Premium plan require an account?</h3>
99
+ <p>Yes. We want the Call Now Button to be accessible to all website owners. Even those that do not have a WordPress powered website. The Premium version of the Call Now Button can be used by everyone. You can continue to manage your buttons from your WordPress instance, but you could also do this via our web app. And should you ever move to a different CMS, your button(s) will just move with you.</p>
100
+ <h3>What is the "powered by" notice on the Free Premium plan?</h3>
101
+ <p>Call Now Button Premium is available for a small yearly or annual fee, but it is also possible to get it for <em>free</em>. The free option introduces a small notice to your buttons that says "Powered by Call Now Button". It's very delicate and will not distract the the visitor from your key message.</p>
102
+ </div>
103
+ <?php }
104
+
105
  function cnb_admin_page_legacy_upgrade_render() {
106
+ wp_enqueue_script(
107
+ CNB_SLUG . '-settings',
108
+ plugins_url( '../../resources/js/settings.js', __FILE__ ),
109
+ array('jquery'),
110
+ CNB_VERSION,
111
+ true);
112
 
113
  add_action('cnb_header_name', 'cnb_add_header_legacy_upgrade');
 
114
  do_action('cnb_header');
115
  ?>
116
 
 
117
  <div class="cnb-one-column-section">
118
+ <div class="cnb-body-content">
119
+ <div class="cnb-two-promobox-row">
120
+ <?php cnb_standard_plugin_promobox() ?>
121
+ <?php cnb_premium_plugin_promobox() ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  </div>
123
+ <?php cnb_upgrade_faq() ?>
124
+ </div>
125
+ </div>
126
  <hr>
127
  <?php
128
  do_action('cnb_footer');
src/admin/models/CnbAction.class.php CHANGED
@@ -21,6 +21,9 @@ class CnbAction {
21
  * @var CnbActionProperties
22
  */
23
  public $properties;
 
 
 
24
  }
25
 
26
  class CnbActionProperties {
21
  * @var CnbActionProperties
22
  */
23
  public $properties;
24
+
25
+ public $iconText;
26
+ public $iconType = 'DEFAULT';
27
  }
28
 
29
  class CnbActionProperties {
src/admin/models/CnbApiKey.class.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // don't load directly
3
+ defined( 'ABSPATH' ) || die( '-1' );
4
+
5
+ class CnbApiKey {
6
+ public $id;
7
+ public $name;
8
+ public $key;
9
+ }
src/admin/models/CnbDomain.class.php CHANGED
@@ -47,7 +47,7 @@ class CnbDomain {
47
  $domain->id = null;
48
  }
49
  if ( empty( $domain->timezone ) ) {
50
- $domain->timezone = wp_timezone_string();
51
  }
52
  if ( empty( $domain->type ) ) {
53
  $domain->type = 'FREE';
@@ -69,10 +69,10 @@ class CnbDomain {
69
  $domain->name = null;
70
  }
71
  if ( ! isset( $domain->trackGA ) ) {
72
- $domain->trackGA = true;
73
  }
74
  if ( ! isset( $domain->trackConversion ) ) {
75
- $domain->trackConversion = true;
76
  }
77
  return $domain;
78
  }
47
  $domain->id = null;
48
  }
49
  if ( empty( $domain->timezone ) ) {
50
+ $domain->timezone = null;
51
  }
52
  if ( empty( $domain->type ) ) {
53
  $domain->type = 'FREE';
69
  $domain->name = null;
70
  }
71
  if ( ! isset( $domain->trackGA ) ) {
72
+ $domain->trackGA = false;
73
  }
74
  if ( ! isset( $domain->trackConversion ) ) {
75
+ $domain->trackConversion = false;
76
  }
77
  return $domain;
78
  }
src/admin/partials/admin-footer.php CHANGED
@@ -17,12 +17,12 @@ function cnb_show_feedback_collection() {
17
  $upgrade_url = esc_url( $upgrade_link );?>
18
  <div class="feedback-collection">
19
  <div class="cnb-clear"></div>
20
- <p class="cnb-url cnb-center"><a href="<?php echo CNB_WEBSITE; ?>" target="_blank">Call Now Button</a></p>
21
  <p class="cnb-center">Version <?php echo CNB_VERSION; ?></p>
22
  <p class="cnb-center cnb-spacing">
23
  <a href="<?php echo CNB_SUPPORT;
24
  cnb_utm_params("footer-links", "support"); ?>" target="_blank" title="Support">Support</a> &middot;
25
- <a href="<?php echo CNB_SUPPORT; ?>wordpress-free/feature-request/<?php cnb_utm_params("footer-links", "suggestions"); ?>"
26
  target="_blank" title="Feature Requests">Suggestions</a>
27
  <?php if (!$cnb_cloud_hosting) { ?>
28
  &middot;
@@ -62,4 +62,4 @@ function cnb_show_api_traces() {
62
  echo '</p>';
63
  }
64
  }
65
- }
17
  $upgrade_url = esc_url( $upgrade_link );?>
18
  <div class="feedback-collection">
19
  <div class="cnb-clear"></div>
20
+ <p class="cnb-url cnb-center"><a href="<?php echo CNB_WEBSITE; ?><?php cnb_utm_params("footer-links", "branding"); ?>" target="_blank">Call Now Button</a></p>
21
  <p class="cnb-center">Version <?php echo CNB_VERSION; ?></p>
22
  <p class="cnb-center cnb-spacing">
23
  <a href="<?php echo CNB_SUPPORT;
24
  cnb_utm_params("footer-links", "support"); ?>" target="_blank" title="Support">Support</a> &middot;
25
+ <a href="<?php echo CNB_SUPPORT; ?>feature-request/<?php cnb_utm_params("footer-links", "suggestions"); ?>"
26
  target="_blank" title="Feature Requests">Suggestions</a>
27
  <?php if (!$cnb_cloud_hosting) { ?>
28
  &middot;
62
  echo '</p>';
63
  }
64
  }
65
+ }
src/admin/partials/admin-functions.php CHANGED
@@ -1,16 +1,56 @@
1
  <?php
2
 
 
 
3
  function cnb_get_active_tab_name() {
4
  // using filter_var instead of filter_input so we can do some "just in time" rewriting of the tab variable if needed
5
  return isset($_GET['tab']) ? filter_var( $_GET['tab'], FILTER_SANITIZE_STRING ) : 'basic_options';
6
  }
 
7
  function cnb_is_active_tab($tab_name) {
8
  $active_tab = cnb_get_active_tab_name();
9
  return $active_tab === $tab_name ? 'nav-tab-active' : '';
10
  }
11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  function cnb_get_changelog() {
13
  return array(
 
 
 
 
 
14
  '1.0.0' => '🎉Introducing Call Now Button Premium!🎉',
15
  '0.5.0' => 'Better button creation flow, UI improvements, small fixes',
16
  '0.4.7' => 'Small UI improvements',
@@ -82,22 +122,23 @@ function cnb_get_condition_match_types() {
82
  }
83
 
84
  /**
85
- * @param $original
 
86
  *
87
- * @return array
88
  */
89
  function cnb_create_days_of_week_array($original) {
90
  // If original does not exist, leave it as it is
91
  if ($original === null || !is_array($original)) {
92
  return $original;
93
  }
 
 
94
  $result = array(false, false, false, false, false, false, false);
95
  foreach ($result as $day_of_week_index => $day_of_week) {
96
- $result[$day_of_week_index] =
97
- isset($original[$day_of_week_index]) && $original[$day_of_week_index] === "true" ?
98
- true :
99
- $day_of_week;
100
- }
101
  return $result;
102
  }
103
 
1
  <?php
2
 
3
+ require_once dirname( __FILE__ ) . '/../../utils/notices.php';
4
+
5
  function cnb_get_active_tab_name() {
6
  // using filter_var instead of filter_input so we can do some "just in time" rewriting of the tab variable if needed
7
  return isset($_GET['tab']) ? filter_var( $_GET['tab'], FILTER_SANITIZE_STRING ) : 'basic_options';
8
  }
9
+
10
  function cnb_is_active_tab($tab_name) {
11
  $active_tab = cnb_get_active_tab_name();
12
  return $active_tab === $tab_name ? 'nav-tab-active' : '';
13
  }
14
 
15
+ function set_changelog_version() {
16
+ $cnb_options = get_option('cnb');
17
+ $updated_options = array_merge(
18
+ $cnb_options,
19
+ array(
20
+ 'changelog_version' => CNB_VERSION
21
+ )
22
+ );
23
+ update_option('cnb', $updated_options);
24
+ }
25
+
26
+ function get_changelog_version($cnb_options) {
27
+ if (!$cnb_options) {
28
+ return CNB_VERSION;
29
+ }
30
+
31
+ if (!key_exists('changelog_version', $cnb_options) && key_exists('version', $cnb_options)) {
32
+ return $cnb_options['version'];
33
+ }
34
+
35
+ return $cnb_options['changelog_version'];
36
+ }
37
+
38
+ function has_changelog($cnb_options) {
39
+ // These is a message...
40
+ $changelog_message = cnb_get_changelog_message(cnb_get_changelog(), get_changelog_version($cnb_options));
41
+ // ... and the notice has not been dismissed yet
42
+ $dismiss_name = CnbAdminNotices::get_instance()->get_dismiss_option_name(cnb_get_upgrade_notice_dismiss_name());
43
+ $dismissed = CnbAdminNotices::get_instance()->is_dismissed($dismiss_name);
44
+ return !empty($changelog_message) && !$dismissed;
45
+ }
46
+
47
  function cnb_get_changelog() {
48
  return array(
49
+ '1.0.4' => array(
50
+ 'Live button preview for Premium',
51
+ 'Easy premium activation via email',
52
+ 'Switch between tabs while editing your button',
53
+ ),
54
  '1.0.0' => '🎉Introducing Call Now Button Premium!🎉',
55
  '0.5.0' => 'Better button creation flow, UI improvements, small fixes',
56
  '0.4.7' => 'Small UI improvements',
122
  }
123
 
124
  /**
125
+ * @param array $original Array of "daysOfWeek", index 0 == Monday, values should be strings and contain "true"
126
+ * in order to be evaulated correctly.
127
  *
128
+ * @return array cleaned up array with proper booleans for the days.
129
  */
130
  function cnb_create_days_of_week_array($original) {
131
  // If original does not exist, leave it as it is
132
  if ($original === null || !is_array($original)) {
133
  return $original;
134
  }
135
+
136
+ // Default everything is NOT selected, then we enable only those days that are passed in via $original
137
  $result = array(false, false, false, false, false, false, false);
138
  foreach ($result as $day_of_week_index => $day_of_week) {
139
+ $day_of_week_is_enabled = isset($original[$day_of_week_index]) && $original[$day_of_week_index] === "true";
140
+ $result[$day_of_week_index] = $day_of_week_is_enabled;
141
+ }
 
 
142
  return $result;
143
  }
144
 
src/admin/partials/admin-header.php CHANGED
@@ -49,9 +49,7 @@ function cnb_admin_header_args( $cnb_options, $cnb_settings, $cnb_cloud_notifica
49
  }
50
 
51
  // inform existing users about updates to the button
52
- if ( $cnb_settings['updated'][0] ) {
53
- cnb_upgrade_notice($cnb_settings['updated'][1], $cnb_changelog);
54
- }
55
  cnb_show_advanced();
56
  }
57
 
49
  }
50
 
51
  // inform existing users about updates to the button
52
+ cnb_upgrade_notice($cnb_options, $cnb_changelog);
 
 
53
  cnb_show_advanced();
54
  }
55
 
src/admin/partials/domain-upgrade/overview.php CHANGED
@@ -18,7 +18,7 @@ function getProfileEditModal($additional_classes=null, $link_text='Verify your i
18
  'height' => '800'),
19
  $url );
20
  printf(
21
- '<a href="%1$s" title="%2$s" class="thickbox open-profile-details-modal %4$s" id="cnb-button-overview-modal-add-new" onclick="cnb_btn=\'%5$s\'">%3$s</a>',
22
  $full_url,
23
  __(esc_html($modal_header)),
24
  __(esc_html($link_text)),
@@ -39,16 +39,13 @@ function cnb_domain_upgrade_overview($domain, $user) {
39
  if ($user && !is_wp_error($user) && isset($user->address) && !empty($user->address->country)) {
40
  $profile_set = true;
41
  }
 
42
  ?>
43
  <script>
44
  <?php if (!$profile_set) { ?>
45
  // Unless a profile hasn't been set yet, in which case, ensure we ask customers for that first
46
  jQuery(function() {
47
  jQuery('.button-upgrade').hide();
48
- jQuery('.open-profile-details-modal').on('click', function() {
49
- jQuery('.open-profile-details-modal').hide();
50
- jQuery('.button-upgrade').show();
51
- });
52
  });
53
  <?php } else { ?>
54
  // Hide the "Next" buttons, we already have a profile
@@ -64,12 +61,12 @@ function cnb_domain_upgrade_overview($domain, $user) {
64
  });
65
  <?php } ?>
66
  </script>
67
- <p>Your domain <strong><?php esc_html_e($domain->name) ?></strong> is currently on the Premium <code><?php esc_html_e($domain->type) ?></code> plan.</p>
68
 
69
  <form id="wp_domain_upgrade" method="post">
70
  <input type="hidden" name="cnb_domain_id" id="cnb_domain_id" value="<?php esc_attr_e($domain->id) ?>">
71
 
72
- <h2>Select a plan to remove the "Powered by Call Now Button" message from your buttons</h2>
73
 
74
  <h2 class="nav-tab-wrapper">
75
  <a href="#" data-cnb-currency="eur" class="cnb-currency-select cnb-currency-eur nav-tab<?php if($active_currency !== 'usd') {?> nav-tab-active<?php }?>">Euro (&euro;)</a>
@@ -78,58 +75,78 @@ function cnb_domain_upgrade_overview($domain, $user) {
78
  <div class="cnb-message notice"><p class="cnb-error-message"></p></div>
79
  <div class="cnb-price-plans">
80
  <div class="currency-box currency-box-eur cnb-flexbox<?php if($active_currency !== 'usd') {?> currency-box-active<?php }?>">
 
 
 
 
 
 
 
 
 
81
  <?php $plan = cnb_get_plan($plans, 'powered-by-eur-yearly'); ?>
82
  <div class="pricebox">
83
- <h3 class="yearly">Yearly Plan</h3>
84
- <div class="benefit">All branding removed</div>
85
  <div class="plan-amount"><span class="currency">€</span><span class="euros">2</span><span class="cents">.49</span><span class="timeframe">/month</span></div>
86
  <div class="billingprice">
87
  Billed at €29.88 annually
88
  </div>
89
- <?php getProfileEditModal('button button-primary', 'Next', 'Verify your information', 'powered-by-eur-yearly'); ?>
90
  <a class="button button-primary button-upgrade powered-by-eur-yearly" href="#" onclick="cnb_get_checkout('<?php _e($plan->id) ?>')">Upgrade</a>
91
  </div>
92
 
93
  <?php $plan = cnb_get_plan($plans, 'powered-by-eur-monthly'); ?>
94
  <div class="pricebox">
95
- <h3 class="">Monthly Plan</h3>
96
- <div class="benefit">All branding removed</div>
97
  <div class="plan-amount"><span class="currency">€</span><span class="euros">4</span><span class="cents">.98</span><span class="timeframe">/month</span></div>
98
  <div class="billingprice">
99
- Billed at €4.98 monthly
100
  </div>
101
- <?php getProfileEditModal('button button-secondary', 'Next', 'Verify your information', 'powered-by-eur-monthly'); ?>
102
  <a class="button button-secondary button-upgrade powered-by-eur-monthly" href="#" onclick="cnb_get_checkout('<?php _e($plan->id) ?>')">Upgrade</a>
103
  </div>
104
  </div>
105
  <div class="currency-box currency-box-usd cnb-flexbox<?php if($active_currency === 'usd') {?> currency-box-active<?php }?>">
 
 
 
 
 
 
 
 
 
106
  <?php $plan = cnb_get_plan($plans, 'powered-by-usd-yearly'); ?>
107
  <div class="pricebox">
108
- <h3 class="yearly">Yearly Plan</h3>
109
- <div class="benefit">All branding removed</div>
110
  <div class="plan-amount"><span class="currency">$</span><span class="euros">2</span><span class="cents">.99</span><span class="timeframe">/month</span></div>
111
  <div class="billingprice">
112
  Billed at $34.88 annually
113
  </div>
114
- <?php getProfileEditModal('button button-primary', 'Next', 'Verify your information', 'powered-by-usd-yearly'); ?>
115
  <a class="button button-primary button-upgrade powered-by-usd-yearly" href="#" onclick="cnb_get_checkout('<?php _e($plan->id) ?>')">Upgrade</a>
116
  </div>
117
  <?php $plan = cnb_get_plan($plans, 'powered-by-usd-monthly'); ?>
118
  <div class="pricebox">
119
- <h3 class="">Monthly Plan</h3>
120
- <div class="benefit">All branding removed</div>
121
  <div class="plan-amount"><span class="currency">$</span><span class="euros">5</span><span class="cents">.98</span><span class="timeframe">/month</span></div>
122
  <div class="billingprice">
123
- Billed at $5.98 monthly
124
  </div>
125
- <?php getProfileEditModal('button button-secondary', 'Next', 'Verify your information', 'powered-by-usd-monthly'); ?>
126
  <a class="button button-secondary button-upgrade powered-by-usd-monthly" href="#" onclick="cnb_get_checkout('<?php _e($plan->id) ?>')">Upgrade</a>
127
  </div>
128
  </div>
129
  </div>
130
  </form>
131
 
132
- <p class="cnb-center">All <u>Premium</u> plans (free and paid) contain the following features:</p>
 
 
133
  <div class="cnb-center" style="margin-bottom:50px;">
134
  <div><b>&check;</b> Phone, Email, Location, WhatsApp, Links</div>
135
  <div><b>&check;</b> Multiple buttons</div>
18
  'height' => '800'),
19
  $url );
20
  printf(
21
+ '<a href="%1$s" title="%2$s" class="thickbox open-profile-details-modal %4$s" onclick="cnb_btn=\'%5$s\'">%3$s</a>',
22
  $full_url,
23
  __(esc_html($modal_header)),
24
  __(esc_html($link_text)),
39
  if ($user && !is_wp_error($user) && isset($user->address) && !empty($user->address->country)) {
40
  $profile_set = true;
41
  }
42
+
43
  ?>
44
  <script>
45
  <?php if (!$profile_set) { ?>
46
  // Unless a profile hasn't been set yet, in which case, ensure we ask customers for that first
47
  jQuery(function() {
48
  jQuery('.button-upgrade').hide();
 
 
 
 
49
  });
50
  <?php } else { ?>
51
  // Hide the "Next" buttons, we already have a profile
61
  });
62
  <?php } ?>
63
  </script>
64
+ <p>Your domain is currently on the Premium <code><?php esc_html_e($domain->type) ?></code> plan.</p>
65
 
66
  <form id="wp_domain_upgrade" method="post">
67
  <input type="hidden" name="cnb_domain_id" id="cnb_domain_id" value="<?php esc_attr_e($domain->id) ?>">
68
 
69
+ <h2>Select a plan that works best for <strong><?php esc_html_e($domain->name) ?></strong></h2>
70
 
71
  <h2 class="nav-tab-wrapper">
72
  <a href="#" data-cnb-currency="eur" class="cnb-currency-select cnb-currency-eur nav-tab<?php if($active_currency !== 'usd') {?> nav-tab-active<?php }?>">Euro (&euro;)</a>
75
  <div class="cnb-message notice"><p class="cnb-error-message"></p></div>
76
  <div class="cnb-price-plans">
77
  <div class="currency-box currency-box-eur cnb-flexbox<?php if($active_currency !== 'usd') {?> currency-box-active<?php }?>">
78
+ <?php if($domain->type === 'FREE') { ?>
79
+ <div class="pricebox cnb-premium-free">
80
+ <h3 class="free">Premium Free</h3>
81
+ <div class="benefit">Shows "Powered by" branding<br>Up to 20k monthly pageviews</div>
82
+ <div class="plan-amount"><span class="currency"></span><span class="euros">&nbsp;</span><span class="cents"></span><span class="timeframe"></span></div>
83
+ <div class="billingprice">&nbsp;</div>
84
+ <button class="button button-disabled" disabled="disabled">Currently active</button>
85
+ </div>
86
+ <?php } ?>
87
  <?php $plan = cnb_get_plan($plans, 'powered-by-eur-yearly'); ?>
88
  <div class="pricebox">
89
+ <h3 class="yearly"><span class="cnb-premium-label">Premium </span>Yearly</h3>
90
+ <div class="benefit">No "Powered by" branding<br>Up to 50k monthly pageviews</div>
91
  <div class="plan-amount"><span class="currency">€</span><span class="euros">2</span><span class="cents">.49</span><span class="timeframe">/month</span></div>
92
  <div class="billingprice">
93
  Billed at €29.88 annually
94
  </div>
95
+ <?php getProfileEditModal('button button-primary', 'Upgrade', 'Verify your information', 'powered-by-eur-yearly'); ?>
96
  <a class="button button-primary button-upgrade powered-by-eur-yearly" href="#" onclick="cnb_get_checkout('<?php _e($plan->id) ?>')">Upgrade</a>
97
  </div>
98
 
99
  <?php $plan = cnb_get_plan($plans, 'powered-by-eur-monthly'); ?>
100
  <div class="pricebox">
101
+ <h3 class="monthly"><span class="cnb-premium-label">Premium </span>Monthly</h3>
102
+ <div class="benefit">No "Powered by" branding<br>Up to 50k monthly pageviews</div>
103
  <div class="plan-amount"><span class="currency">€</span><span class="euros">4</span><span class="cents">.98</span><span class="timeframe">/month</span></div>
104
  <div class="billingprice">
105
+ Billed monthly
106
  </div>
107
+ <?php getProfileEditModal('button button-secondary', 'Upgrade', 'Verify your information', 'powered-by-eur-monthly'); ?>
108
  <a class="button button-secondary button-upgrade powered-by-eur-monthly" href="#" onclick="cnb_get_checkout('<?php _e($plan->id) ?>')">Upgrade</a>
109
  </div>
110
  </div>
111
  <div class="currency-box currency-box-usd cnb-flexbox<?php if($active_currency === 'usd') {?> currency-box-active<?php }?>">
112
+ <?php if($domain->type === 'FREE') { ?>
113
+ <div class="pricebox cnb-premium-free">
114
+ <h3 class="free">Premium Free</h3>
115
+ <div class="benefit">Shows "Powered by" branding<br>Up to 20k monthly pageviews</div>
116
+ <div class="plan-amount"><span class="currency"></span><span class="euros">&nbsp;</span><span class="cents"></span><span class="timeframe"></span></div>
117
+ <div class="billingprice">&nbsp;</div>
118
+ <button class="button button-disabled" disabled="disabled">Currently active</button>
119
+ </div>
120
+ <?php } ?>
121
  <?php $plan = cnb_get_plan($plans, 'powered-by-usd-yearly'); ?>
122
  <div class="pricebox">
123
+ <h3 class="yearly"><span class="cnb-premium-label">Premium </span>Yearly</h3>
124
+ <div class="benefit">No "Powered by" branding<br>Up to 50k monthly pageviews</div>
125
  <div class="plan-amount"><span class="currency">$</span><span class="euros">2</span><span class="cents">.99</span><span class="timeframe">/month</span></div>
126
  <div class="billingprice">
127
  Billed at $34.88 annually
128
  </div>
129
+ <?php getProfileEditModal('button button-primary', 'Upgrade', 'Verify your information', 'powered-by-usd-yearly'); ?>
130
  <a class="button button-primary button-upgrade powered-by-usd-yearly" href="#" onclick="cnb_get_checkout('<?php _e($plan->id) ?>')">Upgrade</a>
131
  </div>
132
  <?php $plan = cnb_get_plan($plans, 'powered-by-usd-monthly'); ?>
133
  <div class="pricebox">
134
+ <h3 class="monthly"><span class="cnb-premium-label">Premium </span>Monthly</h3>
135
+ <div class="benefit">No "Powered by" branding<br>Up to 50k monthly pageviews</div>
136
  <div class="plan-amount"><span class="currency">$</span><span class="euros">5</span><span class="cents">.98</span><span class="timeframe">/month</span></div>
137
  <div class="billingprice">
138
+ Billed monthly
139
  </div>
140
+ <?php getProfileEditModal('button button-secondary', 'Upgrade', 'Verify your information', 'powered-by-usd-monthly'); ?>
141
  <a class="button button-secondary button-upgrade powered-by-usd-monthly" href="#" onclick="cnb_get_checkout('<?php _e($plan->id) ?>')">Upgrade</a>
142
  </div>
143
  </div>
144
  </div>
145
  </form>
146
 
147
+ <div class="cnb-callout-bar"><p>Is your website enjoying more than 50k monthly pageviews?</p> <a class="button button-primary" href="https://callnowbutton.com/support/wordpress/contact/sales/" target="_blank">Contact us</a></div>
148
+
149
+ <h3 class="cnb-center">Premium plans contain the following features:</h3>
150
  <div class="cnb-center" style="margin-bottom:50px;">
151
  <div><b>&check;</b> Phone, Email, Location, WhatsApp, Links</div>
152
  <div><b>&check;</b> Multiple buttons</div>
src/admin/settings-profile.php CHANGED
@@ -437,10 +437,7 @@ function cnb_admin_page_profile_edit_render_form($modal = false) {
437
  </tr>
438
 
439
  <tr class="cnb_vat_companies_show" style="display:none">
440
- <th scope="row"><label for="cnb_profile_vat">VAT number<span class="cnb_required">*</span></label>
441
- <a href="https://callnowbutton.com/support/vat/" target="_blank" class="cnb-nounderscore">
442
- <span class="dashicons dashicons-editor-help"></span>
443
- </a>
444
  </th>
445
  <td>
446
  <input id="cnb_profile_vat" type="text" name="user[taxIds][0][value]"
@@ -448,7 +445,7 @@ function cnb_admin_page_profile_edit_render_form($modal = false) {
448
  class="regular-text ltr cnb_vat_companies_required cnb_eu_values_only">
449
  <input id="cnb_user_taxids_type" type="hidden" name="user[taxIds][0][type]" value="eu_vat"
450
  class="regular-text ltr cnb_vat_companies_required cnb_eu_values_only">
451
- <p class="description">Required for EU based companies outside the Netherlands that are registered for
452
  VAT.</p>
453
  <?php
454
  if ($cnb_user_stripe_verified) {
@@ -460,7 +457,7 @@ function cnb_admin_page_profile_edit_render_form($modal = false) {
460
  </td>
461
  </tr>
462
 
463
- <tr><th></th><td><?php submit_button() ?></td></tr>
464
  </tbody>
465
  </table>
466
  </form>
437
  </tr>
438
 
439
  <tr class="cnb_vat_companies_show" style="display:none">
440
+ <th scope="row"><label for="cnb_profile_vat">VAT number<span class="cnb_required">*</span></label>
 
 
 
441
  </th>
442
  <td>
443
  <input id="cnb_profile_vat" type="text" name="user[taxIds][0][value]"
445
  class="regular-text ltr cnb_vat_companies_required cnb_eu_values_only">
446
  <input id="cnb_user_taxids_type" type="hidden" name="user[taxIds][0][type]" value="eu_vat"
447
  class="regular-text ltr cnb_vat_companies_required cnb_eu_values_only">
448
+ <p class="description">Required for EU based companies who are registered for
449
  VAT.</p>
450
  <?php
451
  if ($cnb_user_stripe_verified) {
457
  </td>
458
  </tr>
459
 
460
+ <tr><th></th><td><?php submit_button('Next','primary large') ?></td></tr>
461
  </tbody>
462
  </table>
463
  </form>
src/admin/settings.php CHANGED
@@ -13,15 +13,18 @@ function cnb_add_header_settings() {
13
  echo 'Settings';
14
  }
15
 
16
- function cnb_settings_create_tab_url($tab) {
17
  $url = admin_url('admin.php');
18
  $tab_link =
19
  add_query_arg(
20
- array(
21
- 'page' => 'call-now-button-settings',
22
- 'tab' => $tab),
23
- $url );
24
- return esc_url( $tab_link );
 
 
 
25
  }
26
 
27
  /**
@@ -111,6 +114,8 @@ function cnb_settings_options_validate($input) {
111
  }
112
  }
113
 
 
 
114
  // Check for legacy button
115
  $check = cnb_settings_disallow_active_without_phone_number($updated_options);
116
  if (is_wp_error($check)) {
@@ -124,6 +129,8 @@ function cnb_settings_options_validate($input) {
124
  // But just in case, this is here for other unseen errors..
125
  $messages[] = CnbAdminCloud::cnb_admin_get_error_message( 'save', 'settings', $check );
126
  }
 
 
127
  } else {
128
  $messages[] = new CnbNotice( 'success', '<p>Your settings have been updated!</p>' );
129
  }
@@ -185,25 +192,60 @@ function cnb_admin_setting_migrate() {
185
  }
186
 
187
  function cnb_admin_settings_page() {
188
- global $cnb_options, $use_cloud;
189
 
190
  add_action('cnb_header_name', 'cnb_add_header_settings');
191
 
192
  // Fix for https://github.com/callnowbutton/wp-plugin/issues/263
193
  $cnb_options['cloud_enabled'] = isset($cnb_options['cloud_enabled']) ? $cnb_options['cloud_enabled'] : 0;
194
 
195
- // Parse special header
196
- $api_key = filter_input(INPUT_GET, 'api_key', FILTER_SANITIZE_STRING);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
197
  if (empty($cnb_options['api_key']) && $api_key) {
198
- $options = array();
199
  // This also enabled the cloud
200
  $options['cloud_enabled'] = 1;
201
  $options['api_key'] = $api_key;
202
  update_option('cnb', $options);
203
- $reload_url = cnb_settings_create_tab_url('basic_options');
204
- echo '<script>window.location.href = "'.$reload_url.'";</script>';
 
 
 
 
 
 
 
 
 
 
205
  }
206
 
 
 
 
207
  $cnb_cloud_domain = null;
208
  $cnb_cloud_domains = array();
209
  $cnb_clean_site_url = null;
@@ -221,31 +263,78 @@ function cnb_admin_settings_page() {
221
  }
222
  }
223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  do_action('cnb_header');
225
  $show_advanced_view_only = array_key_exists('advanced_view', $cnb_options) && $cnb_options['advanced_view'] === 1;
226
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  <div class="cnb-two-column-section">
228
  <div class="cnb-body-column">
229
  <div class="cnb-body-content">
230
 
231
  <h2 class="nav-tab-wrapper">
232
- <a href="<?php echo cnb_settings_create_tab_url('basic_options') ?>"
233
  class="nav-tab <?php echo cnb_is_active_tab('basic_options') ?>">General</a>
234
  <?php if ($use_cloud) { ?>
235
- <a href="<?php echo cnb_settings_create_tab_url('account_options') ?>"
236
  class="nav-tab <?php echo cnb_is_active_tab('account_options') ?>">Account</a>
237
- <a href="<?php echo cnb_settings_create_tab_url('advanced_options') ?>"
238
  class="nav-tab <?php echo cnb_is_active_tab('advanced_options') ?>">Advanced</a>
239
  <?php } ?>
240
  </h2>
241
  <form method="post" action="<?php echo esc_url( admin_url('options.php') ); ?>" class="cnb-container">
242
  <?php settings_fields('cnb_options'); ?>
243
- <table class="form-table <?php echo cnb_is_active_tab('basic_options'); ?>">
244
  <tr><th colspan="2"></th></tr>
245
  <tr>
246
- <th scope="row">Plugin type<a href="<?php echo cnb_legacy_upgrade_page(); ?>" class="cnb-nounderscore">
 
 
 
247
  <span class="dashicons dashicons-editor-help"></span>
248
- </a></th>
 
 
249
  <td>
250
  <div class="cnb-radio-item">
251
  <input type="radio" name="cnb[cloud_enabled]" id="cnb_cloud_disabled" value="0" <?php checked('0', $cnb_options['cloud_enabled']); ?>>
@@ -255,11 +344,13 @@ function cnb_admin_settings_page() {
255
  <div class="cnb-radio-item">
256
  <input type="radio" name="cnb[cloud_enabled]" id="cnb_cloud_enabled" value="1" <?php checked('1', $cnb_options['cloud_enabled']); ?>>
257
  <label for="cnb_cloud_enabled">Premium</label>
 
258
  <?php if ($cnb_options['cloud_enabled'] == 0) { ?>
259
- <p class="description">Paid and free options. <a href="<?php echo cnb_legacy_upgrade_page(); ?>">Learn more</a></p>
260
  <?php } ?>
 
261
  <?php if ($cnb_options['cloud_enabled'] == 1 && isset($cnb_cloud_domain) && !is_wp_error($cnb_cloud_domain) && $cnb_cloud_domain->type !== 'PRO') { ?>
262
- <p class="description">Paid and free options. <a href="<?php echo get_cnb_domain_upgrade($cnb_cloud_domain); ?>">Learn more</a></p>
263
  <?php } ?>
264
  </div>
265
  </td>
@@ -292,14 +383,14 @@ function cnb_admin_settings_page() {
292
  <?php
293
  }
294
  }
295
- if($cnb_options['status'] === 'cloud' && isset($cnb_cloud_domain) && !($cnb_cloud_domain instanceof WP_Error)) {
296
- cnb_admin_page_domain_edit_render_form_plan_details($cnb_cloud_domain);
297
- cnb_admin_page_domain_edit_render_form_tracking($cnb_cloud_domain);
298
- cnb_admin_page_domain_edit_render_form_button_display($cnb_cloud_domain);
299
- } ?>
300
  </table>
301
  <?php if ($cnb_options['status'] === 'cloud') { ?>
302
- <table class="form-table <?php echo cnb_is_active_tab('account_options'); ?>">
303
  <tr><th colspan="2"></th></tr>
304
  <tr>
305
  <th scope="row">API key</th>
@@ -329,7 +420,7 @@ function cnb_admin_settings_page() {
329
  <?php } ?>
330
  </table>
331
  <?php } ?>
332
- <table class="form-table <?php echo cnb_is_active_tab('advanced_options'); ?>">
333
  <?php if(isset($cnb_cloud_domain) && !($cnb_cloud_domain instanceof WP_Error) && $cnb_options['status'] === 'cloud') {
334
  ?>
335
  <tr>
13
  echo 'Settings';
14
  }
15
 
16
+ function cnb_settings_create_tab_url($tab, $additional_query_args = array()) {
17
  $url = admin_url('admin.php');
18
  $tab_link =
19
  add_query_arg(
20
+ array_merge(
21
+ array(
22
+ 'page' => 'call-now-button-settings',
23
+ 'tab' => $tab),
24
+ $additional_query_args
25
+ ),
26
+ $url );
27
+ return esc_url_raw( $tab_link );
28
  }
29
 
30
  /**
114
  }
115
  }
116
 
117
+ $version_upgrade = $original_settings['version'] != $updated_options['version'];
118
+
119
  // Check for legacy button
120
  $check = cnb_settings_disallow_active_without_phone_number($updated_options);
121
  if (is_wp_error($check)) {
129
  // But just in case, this is here for other unseen errors..
130
  $messages[] = CnbAdminCloud::cnb_admin_get_error_message( 'save', 'settings', $check );
131
  }
132
+ } else if ($version_upgrade) {
133
+ // NOOP - Do nothing for a version upgrade
134
  } else {
135
  $messages[] = new CnbNotice( 'success', '<p>Your settings have been updated!</p>' );
136
  }
192
  }
193
 
194
  function cnb_admin_settings_page() {
195
+ global $cnb_options;
196
 
197
  add_action('cnb_header_name', 'cnb_add_header_settings');
198
 
199
  // Fix for https://github.com/callnowbutton/wp-plugin/issues/263
200
  $cnb_options['cloud_enabled'] = isset($cnb_options['cloud_enabled']) ? $cnb_options['cloud_enabled'] : 0;
201
 
202
+ // Parse special header(s)
203
+ $api_key = null;
204
+ $api_key_ott = filter_input(INPUT_GET, 'api_key_ott', FILTER_SANITIZE_STRING);
205
+ if (!empty($api_key_ott)) {
206
+ $api_key_obj = CnbAppRemote::cnb_remote_get_apikey_via_ott($api_key_ott);
207
+ if ($api_key_obj !== null) {
208
+ if (!is_wp_error($api_key_obj)) {
209
+ $api_key = $api_key_obj->key;
210
+ } else {
211
+ if (empty($cnb_options['api_key'])) {
212
+ $error_details = CnbAdminCloud::cnb_admin_get_error_message_details( $api_key_obj );
213
+ $message = '<p>We could not enable <strong>Premium</strong> with the <em>one-time token</em> <code>' . esc_html( $api_key_ott ) . '</code> :-(.' . $error_details . '</p>';
214
+ $notice = new CnbNotice( 'error', $message );
215
+ CnbAdminNotices::get_instance()->renderNotice( $notice );
216
+ }
217
+ }
218
+ }
219
+ }
220
+
221
+ // If the API key was not passed via api_key_ott, see if it was passed directly via api_key
222
+ if (!$api_key) {
223
+ $api_key = filter_input( INPUT_GET, 'api_key', FILTER_SANITIZE_STRING );
224
+ }
225
+
226
+ $options = array();
227
  if (empty($cnb_options['api_key']) && $api_key) {
 
228
  // This also enabled the cloud
229
  $options['cloud_enabled'] = 1;
230
  $options['api_key'] = $api_key;
231
  update_option('cnb', $options);
232
+
233
+ $cnb_options['cloud_enabled'] = 1;
234
+ $cnb_options['api_key'] = $api_key;
235
+ cnb_reset_options();
236
+ // In case a token is provided (api_key[_ott]) but there already is an API key (so no need to update)
237
+ } else if (!empty($cnb_options['api_key']) && ($api_key || $api_key_ott) && $cnb_options['cloud_enabled'] != 1) {
238
+ CnbAdminNotices::get_instance()->warning("<p>You have followed a link, but an API key is already present or the token has expired.</p><p>We have enabled <strong>Premium</strong>, but did not change the already present API key.</p>");
239
+ $options['cloud_enabled'] = 1;
240
+ update_option('cnb', $options);
241
+
242
+ $cnb_options['cloud_enabled'] = 1;
243
+ cnb_reset_options();
244
  }
245
 
246
+ /**
247
+ * @type CnbDomain
248
+ */
249
  $cnb_cloud_domain = null;
250
  $cnb_cloud_domains = array();
251
  $cnb_clean_site_url = null;
263
  }
264
  }
265
 
266
+ wp_enqueue_script(
267
+ CNB_SLUG . '-settings',
268
+ plugins_url( '../../resources/js/settings.js', __FILE__ ),
269
+ array('jquery'),
270
+ CNB_VERSION,
271
+ true);
272
+
273
+ wp_enqueue_script(
274
+ CNB_SLUG . '-timezone-picker-fix',
275
+ plugins_url( '../../resources/js/timezone-picker-fix.js', __FILE__ ),
276
+ array('jquery'),
277
+ CNB_VERSION,
278
+ true);
279
+
280
  do_action('cnb_header');
281
  $show_advanced_view_only = array_key_exists('advanced_view', $cnb_options) && $cnb_options['advanced_view'] === 1;
282
+ $use_cloud = is_use_cloud($cnb_options);
283
+
284
+ $cloud_successful = $cnb_options['status'] === 'cloud' && isset($cnb_cloud_domain) && !($cnb_cloud_domain instanceof WP_Error);
285
+ if ($cloud_successful) { ?>
286
+ <script>
287
+ jQuery(() => {
288
+ const counter = jQuery("#cnb-nav-counter")
289
+ if (counter.length && counter.text() === '!') {
290
+ counter.hide();
291
+ }
292
+ });
293
+ </script>
294
+ <?php
295
+ // Also warning if timezone is not yet set
296
+ $domain_timezone = $cnb_cloud_domain->timezone;
297
+ if (empty($domain_timezone)) {
298
+ $url = admin_url( 'admin.php' );
299
+ $redirect_link =
300
+ add_query_arg(
301
+ array(
302
+ 'page' => 'call-now-button-settings',
303
+ 'tab' => 'advanced_options#domain_timezone',
304
+
305
+ ),
306
+ $url );
307
+ $redirect_url = esc_url( $redirect_link );
308
+ CnbAdminNotices::get_instance()->renderWarning("<p>Please set your timezone in the <a href=\"". $redirect_url . "\">Advanced settings</a> tab to avoid unpredictable behavior when using the scheduler.</p>");
309
+ }
310
+ } ?>
311
  <div class="cnb-two-column-section">
312
  <div class="cnb-body-column">
313
  <div class="cnb-body-content">
314
 
315
  <h2 class="nav-tab-wrapper">
316
+ <a data-tab-name="basic_options" href="<?php echo cnb_settings_create_tab_url('basic_options') ?>"
317
  class="nav-tab <?php echo cnb_is_active_tab('basic_options') ?>">General</a>
318
  <?php if ($use_cloud) { ?>
319
+ <a data-tab-name="account_options" href="<?php echo cnb_settings_create_tab_url('account_options') ?>"
320
  class="nav-tab <?php echo cnb_is_active_tab('account_options') ?>">Account</a>
321
+ <a data-tab-name="advanced_options" href="<?php echo cnb_settings_create_tab_url('advanced_options') ?>"
322
  class="nav-tab <?php echo cnb_is_active_tab('advanced_options') ?>">Advanced</a>
323
  <?php } ?>
324
  </h2>
325
  <form method="post" action="<?php echo esc_url( admin_url('options.php') ); ?>" class="cnb-container">
326
  <?php settings_fields('cnb_options'); ?>
327
+ <table data-tab-name="basic_options" class="form-table <?php echo cnb_is_active_tab('basic_options'); ?>">
328
  <tr><th colspan="2"></th></tr>
329
  <tr>
330
+ <th scope="row">
331
+ Plugin type
332
+ <?php if ($cnb_options['cloud_enabled'] == 0) { ?>
333
+ <a href="<?php echo cnb_legacy_upgrade_page(); ?>" class="cnb-nounderscore">
334
  <span class="dashicons dashicons-editor-help"></span>
335
+ </a>
336
+ <?php } ?>
337
+ </th>
338
  <td>
339
  <div class="cnb-radio-item">
340
  <input type="radio" name="cnb[cloud_enabled]" id="cnb_cloud_disabled" value="0" <?php checked('0', $cnb_options['cloud_enabled']); ?>>
344
  <div class="cnb-radio-item">
345
  <input type="radio" name="cnb[cloud_enabled]" id="cnb_cloud_enabled" value="1" <?php checked('1', $cnb_options['cloud_enabled']); ?>>
346
  <label for="cnb_cloud_enabled">Premium</label>
347
+
348
  <?php if ($cnb_options['cloud_enabled'] == 0) { ?>
349
+ <p class="description">Paid and free options. <a href="<?php echo cnb_legacy_upgrade_page(); ?>">Learn more</a></p>
350
  <?php } ?>
351
+
352
  <?php if ($cnb_options['cloud_enabled'] == 1 && isset($cnb_cloud_domain) && !is_wp_error($cnb_cloud_domain) && $cnb_cloud_domain->type !== 'PRO') { ?>
353
+ <p class="description">Paid and free options. <a href="<?php echo get_cnb_domain_upgrade($cnb_cloud_domain); ?>">Learn more</a></p>
354
  <?php } ?>
355
  </div>
356
  </td>
383
  <?php
384
  }
385
  }
386
+ if($cloud_successful) {
387
+ cnb_admin_page_domain_edit_render_form_plan_details($cnb_cloud_domain);
388
+ cnb_admin_page_domain_edit_render_form_tracking($cnb_cloud_domain);
389
+ cnb_admin_page_domain_edit_render_form_button_display($cnb_cloud_domain);
390
+ } ?>
391
  </table>
392
  <?php if ($cnb_options['status'] === 'cloud') { ?>
393
+ <table data-tab-name="account_options" class="form-table <?php echo cnb_is_active_tab('account_options'); ?>">
394
  <tr><th colspan="2"></th></tr>
395
  <tr>
396
  <th scope="row">API key</th>
420
  <?php } ?>
421
  </table>
422
  <?php } ?>
423
+ <table data-tab-name="advanced_options" class="form-table <?php echo cnb_is_active_tab('advanced_options'); ?>">
424
  <?php if(isset($cnb_cloud_domain) && !($cnb_cloud_domain instanceof WP_Error) && $cnb_options['status'] === 'cloud') {
425
  ?>
426
  <tr>
src/call-now-button.php CHANGED
@@ -5,28 +5,15 @@ require_once dirname( __FILE__ ) . '/admin/admin-ajax.php';
5
  require_once dirname( __FILE__ ) . '/utils/CnbAdminNotices.class.php';
6
  require_once dirname( __FILE__ ) . '/admin/partials/admin-header.php';
7
 
8
- // Grabbing the settings and checking for latest version
9
- // OR creating the options file for first time installations
10
- $cnb_settings = cnb_get_options();
11
- $cnb_options = $cnb_settings['options'];
12
  $cnb_slug_base = CNB_SLUG;
13
-
14
- $cnb_options['active'] = isset($cnb_options['active']) && $cnb_options['active'] == 1 ? 1 : 0;
15
- $cnb_options['classic'] = isset($cnb_options['classic']) && $cnb_options['classic'] == 1 ? 1 : 0;
16
- $cnb_options['hideIcon'] = isset($cnb_options['hideIcon']) && $cnb_options['hideIcon'] == 1 ? 1 : 0;
17
- $cnb_options['frontpage'] = isset($cnb_options['frontpage']) && $cnb_options['frontpage'] == 1 ? 1 : 0;
18
- $cnb_options['advanced_view'] = isset($cnb_options['advanced_view']) && $cnb_options['advanced_view'] == 1 ? 1 : 0;
19
- $cnb_options['show_all_buttons_for_domain'] = isset($cnb_options['show_all_buttons_for_domain']) && $cnb_options['show_all_buttons_for_domain'] == 1 ? 1 : 0;
20
- $cnb_options['footer_show_traces'] = isset($cnb_options['footer_show_traces']) && $cnb_options['footer_show_traces'] == 1 ? 1 : 0;
21
- $cnb_options['api_caching'] = isset($cnb_options['api_caching']) && $cnb_options['api_caching'] == 1 ? 1 : 0;
22
-
23
  $plugin_title = apply_filters('cnb_plugin_title', CNB_NAME);
24
- $cnb_cloud_hosting = isset($cnb_options['cloud_enabled']) && $cnb_options['cloud_enabled'] == 1;
25
- $cloud_use_id = isset($cnb_options['cloud_use_id']) && !empty($cnb_options['cloud_use_id']) ? $cnb_options['cloud_use_id'] : 0;
26
- $use_cloud = $cnb_cloud_hosting && $cloud_use_id !== 0;
27
 
28
- // Used by settings
29
- $cnb_options['status'] = $cnb_cloud_hosting ? 'cloud' : ($cnb_options['active'] ? 'enabled' : 'disabled');
 
 
 
 
30
 
31
  /**
32
  * Used by cnb_register_admin_page
@@ -89,10 +76,26 @@ function cnb_register_admin_pages() {
89
 
90
  $menu_page_function = $cnb_cloud_hosting ? 'cnb_admin_button_overview' : 'cnb_admin_page_legacy_edit';
91
 
92
- // $menu_page_title = $cnb_cloud_hosting ? 'Buttons' : 'Call Now Button';
93
- $menu_page_title = 'Call Now Button';
94
  $menu_page_position = $cnb_cloud_hosting ? 30 : 66;
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  // Oldest WordPress only has "smartphone", no "phone" (this is added in a later version)
97
  $icon_url = version_compare($wp_version, '5.5.0', '<') ? 'dashicons-smartphone' : 'dashicons-phone';
98
  $menu_page = add_menu_page(
@@ -165,7 +168,12 @@ add_action('admin_menu', 'cnb_register_admin_pages');
165
 
166
  function cnb_enqueue_color_picker() {
167
  wp_enqueue_style('wp-color-picker');
168
- wp_enqueue_script('cnb-script-handle', plugins_url('../resources/js/call-now-button.js', __FILE__), array('wp-color-picker'), CNB_VERSION, true);
 
 
 
 
 
169
  }
170
 
171
  add_action('admin_enqueue_scripts', 'cnb_enqueue_color_picker'); // add the color picker
@@ -203,12 +211,9 @@ function cnb_plugin_meta($links, $file) {
203
  $settings_url = esc_url($settings_link);
204
 
205
  $cnb_new_links = array(
206
- sprintf(
207
- '<a href="%s">%s</a>', $button_url, __($link_name)),
208
- sprintf(
209
- '<a href="%s">%s</a>', $settings_url, __('Settings')),
210
- sprintf(
211
- '<a href="%s">%s</a>', CNB_SUPPORT, __('Support'))
212
  );
213
  array_push(
214
  $links,
@@ -224,8 +229,8 @@ add_filter('plugin_row_meta', 'cnb_plugin_meta', 10, 2);
224
 
225
  function cnb_plugin_add_action_link($links) {
226
  global $cnb_cloud_hosting;
227
- $link_name = $cnb_cloud_hosting ? 'All buttons' : 'My button';
228
 
 
229
  $url = admin_url( 'admin.php' );
230
  $button_link =
231
  add_query_arg(
@@ -234,17 +239,27 @@ function cnb_plugin_add_action_link($links) {
234
  ),
235
  $url );
236
  $button_url = esc_url( $button_link );
 
 
237
 
 
 
 
 
 
 
 
 
 
 
 
 
238
 
239
- $button = sprintf(
240
- '<a href="%s">%s</a>', $button_url, __( $link_name ) );
241
- array_unshift($links, $button);
242
  return $links;
243
  }
244
 
245
  add_filter('plugin_action_links_' . CNB_BASENAME, 'cnb_plugin_add_action_link');
246
 
247
-
248
  function cnb_options_validate($input) {
249
  require_once dirname( __FILE__ ) . '/admin/settings.php';
250
  return cnb_settings_options_validate($input);
@@ -374,17 +389,15 @@ add_action( 'cnb_in_admin_header', 'cnb_admin_header_no_args' );
374
  add_action('cnb_header', 'cnb_admin_header');
375
  add_action( 'cnb_footer', 'cnb_admin_footer');
376
 
377
- /**
378
- * Initialize the permanent is-dismissible notices code
379
- */
380
- $adminNotices = CnbAdminNotices::get_instance();
381
 
382
  // Render the Frontend
383
  if (!is_admin() && isButtonActive($cnb_options)) {
384
  $cnb_has_text = ($cnb_options['text'] == '') ? false : true;
385
  $cnb_is_classic = $cnb_options['classic'] == 1 && !$cnb_has_text;
386
 
387
- $renderer = $use_cloud ? 'cloud' : ($cnb_is_classic ? 'classic' : 'modern');
388
 
389
  require_once dirname( __FILE__ ) . "/renderers/$renderer/wp_head.php";
390
  require_once dirname( __FILE__ ) . "/renderers/$renderer/wp_foot.php";
5
  require_once dirname( __FILE__ ) . '/utils/CnbAdminNotices.class.php';
6
  require_once dirname( __FILE__ ) . '/admin/partials/admin-header.php';
7
 
 
 
 
 
8
  $cnb_slug_base = CNB_SLUG;
 
 
 
 
 
 
 
 
 
 
9
  $plugin_title = apply_filters('cnb_plugin_title', CNB_NAME);
 
 
 
10
 
11
+ // Globals
12
+ $cnb_settings = array();
13
+ $cnb_options = array();
14
+ $cnb_cloud_hosting = false;
15
+ $cloud_use_id = 0;
16
+ cnb_reset_options();
17
 
18
  /**
19
  * Used by cnb_register_admin_page
76
 
77
  $menu_page_function = $cnb_cloud_hosting ? 'cnb_admin_button_overview' : 'cnb_admin_page_legacy_edit';
78
 
79
+ $counter = 0;
80
+ $menu_page_title = 'Call Now Button<span class="awaiting-mod" id="cnb-nav-counter" style="display: none">'.$counter.'</span>';
81
  $menu_page_position = $cnb_cloud_hosting ? 30 : 66;
82
 
83
+ $has_changelog = has_changelog($cnb_options);
84
+ if ($has_changelog) $counter++;
85
+
86
+ $has_welcome_panel = cnb_show_welcome_panel() && !$cnb_cloud_hosting;
87
+ if ($has_welcome_panel) $counter++;
88
+
89
+ // Detect errors (specific, - Premium enabled, but API key is not present yet)
90
+ if ($cnb_cloud_hosting && !array_key_exists('api_key', $cnb_options)) {
91
+ $counter = '!';
92
+ }
93
+
94
+ if ($counter) {
95
+ $menu_page_title = 'Call Now Bu...<span class="awaiting-mod" id="cnb-nav-counter">'.$counter.'</span>';
96
+ }
97
+
98
+
99
  // Oldest WordPress only has "smartphone", no "phone" (this is added in a later version)
100
  $icon_url = version_compare($wp_version, '5.5.0', '<') ? 'dashicons-smartphone' : 'dashicons-phone';
101
  $menu_page = add_menu_page(
168
 
169
  function cnb_enqueue_color_picker() {
170
  wp_enqueue_style('wp-color-picker');
171
+ wp_enqueue_script(
172
+ CNB_SLUG,
173
+ plugins_url('../resources/js/call-now-button.js', __FILE__),
174
+ array('wp-color-picker'),
175
+ CNB_VERSION,
176
+ true);
177
  }
178
 
179
  add_action('admin_enqueue_scripts', 'cnb_enqueue_color_picker'); // add the color picker
211
  $settings_url = esc_url($settings_link);
212
 
213
  $cnb_new_links = array(
214
+ sprintf( '<a href="%s">%s</a>', $button_url, __($link_name)),
215
+ sprintf( '<a href="%s">%s</a>', $settings_url, __('Settings')),
216
+ sprintf( '<a href="%s">%s</a>', CNB_SUPPORT, __('Support'))
 
 
 
217
  );
218
  array_push(
219
  $links,
229
 
230
  function cnb_plugin_add_action_link($links) {
231
  global $cnb_cloud_hosting;
 
232
 
233
+ $link_name = $cnb_cloud_hosting ? 'All buttons' : 'My button';
234
  $url = admin_url( 'admin.php' );
235
  $button_link =
236
  add_query_arg(
239
  ),
240
  $url );
241
  $button_url = esc_url( $button_link );
242
+ $button = sprintf( '<a href="%s">%s</a>', $button_url, __( $link_name ) );
243
+ array_unshift($links, $button);
244
 
245
+ if (!$cnb_cloud_hosting) {
246
+ $link_name = 'Get Premium';
247
+ $upgrade_link =
248
+ add_query_arg(
249
+ array(
250
+ 'page' => 'call-now-button-upgrade'
251
+ ),
252
+ $url );
253
+ $upgrade_url = esc_url( $upgrade_link );
254
+ $upgrade = sprintf( '<a style="font-weight: bold;" href="%s">%s</a>', $upgrade_url, __( $link_name ) );
255
+ array_unshift($links, $upgrade);
256
+ }
257
 
 
 
 
258
  return $links;
259
  }
260
 
261
  add_filter('plugin_action_links_' . CNB_BASENAME, 'cnb_plugin_add_action_link');
262
 
 
263
  function cnb_options_validate($input) {
264
  require_once dirname( __FILE__ ) . '/admin/settings.php';
265
  return cnb_settings_options_validate($input);
389
  add_action('cnb_header', 'cnb_admin_header');
390
  add_action( 'cnb_footer', 'cnb_admin_footer');
391
 
392
+ // This updates the internal version number, called by CnbAdminNotices::action_admin_init
393
+ add_action('cnb_update_'.CNB_VERSION, 'cnb_update_version');
 
 
394
 
395
  // Render the Frontend
396
  if (!is_admin() && isButtonActive($cnb_options)) {
397
  $cnb_has_text = ($cnb_options['text'] == '') ? false : true;
398
  $cnb_is_classic = $cnb_options['classic'] == 1 && !$cnb_has_text;
399
 
400
+ $renderer = is_use_cloud($cnb_options) ? 'cloud' : ($cnb_is_classic ? 'classic' : 'modern');
401
 
402
  require_once dirname( __FILE__ ) . "/renderers/$renderer/wp_head.php";
403
  require_once dirname( __FILE__ ) . "/renderers/$renderer/wp_foot.php";
src/utils/CnbAdminNotices.class.php CHANGED
@@ -56,6 +56,7 @@ class CnbAdminNotices {
56
  $dismiss_option = filter_input( INPUT_GET, CNB_SLUG . '_dismiss', FILTER_SANITIZE_STRING );
57
  if ( is_string( $dismiss_option ) ) {
58
  update_option( CNB_SLUG . '_dismissed_' . $dismiss_option, true );
 
59
  wp_die(
60
  __( 'Dismissed notice: ' . $dismiss_option, CNB_NAME), __( 'Dismissed notice', CNB_NAME),
61
  array(
@@ -68,10 +69,11 @@ class CnbAdminNotices {
68
  public function action_admin_enqueue_scripts() {
69
  wp_enqueue_script( 'jquery' );
70
  wp_enqueue_script(
71
- CNB_SLUG . '-notify',
72
  plugins_url( '../../resources/js/dismiss.js', __FILE__ ),
73
- array( 'jquery' )
74
- );
 
75
  }
76
 
77
  /**
@@ -98,16 +100,28 @@ class CnbAdminNotices {
98
  $dismiss_classes .= ' is-dismissible';
99
  }
100
 
101
- echo '<div class="notice notice-' . CNB_SLUG . ' notice-' . $notice->type . $dismiss_classes . '"'.$dismiss_data_url.'>';
102
- echo $notice->message;
103
- echo '</div>';
 
 
 
 
 
 
 
 
 
 
 
 
104
  }
105
 
106
  public function action_admin_notices() {
107
  foreach ( explode( ',', self::TYPES ) as $type ) {
108
  foreach ( $this->admin_notices->{$type} as $admin_notice ) {
109
- $option = CNB_SLUG . '_dismissed_' . $admin_notice->dismiss_option;
110
- if ( !$admin_notice->dismiss_option || !get_option( $option ) ) {
111
  $this->renderNotice($admin_notice);
112
  }
113
  }
@@ -165,6 +179,7 @@ class CnbAdminNotices {
165
  $notice = $this->createNotice( 'info', $message, false, $dismiss_option );
166
  $this->addNotice($notice);
167
  }
 
168
  public function renderInfo( $message, $dismiss_option = false ) {
169
  $notice = $this->createNotice( 'info', $message, false, $dismiss_option );
170
  $this->renderNotice($notice);
56
  $dismiss_option = filter_input( INPUT_GET, CNB_SLUG . '_dismiss', FILTER_SANITIZE_STRING );
57
  if ( is_string( $dismiss_option ) ) {
58
  update_option( CNB_SLUG . '_dismissed_' . $dismiss_option, true );
59
+ do_action($dismiss_option);
60
  wp_die(
61
  __( 'Dismissed notice: ' . $dismiss_option, CNB_NAME), __( 'Dismissed notice', CNB_NAME),
62
  array(
69
  public function action_admin_enqueue_scripts() {
70
  wp_enqueue_script( 'jquery' );
71
  wp_enqueue_script(
72
+ CNB_SLUG . '-dismiss',
73
  plugins_url( '../../resources/js/dismiss.js', __FILE__ ),
74
+ array('jquery'),
75
+ CNB_VERSION,
76
+ true);
77
  }
78
 
79
  /**
100
  $dismiss_classes .= ' is-dismissible';
101
  }
102
 
103
+ // Check if this particular Notice has already been dismissed
104
+ $option = CNB_SLUG . '_dismissed_' . $notice->dismiss_option;
105
+ if ( !$notice->dismiss_option || !get_option( $option ) ) {
106
+ echo '<div class="notice notice-' . CNB_SLUG . ' notice-' . $notice->type . $dismiss_classes . '"'.$dismiss_data_url.'>';
107
+ echo $notice->message;
108
+ echo '</div>';
109
+ }
110
+ }
111
+
112
+ public function get_dismiss_option_name($name) {
113
+ return CNB_SLUG . '_dismissed_' . $name;
114
+ }
115
+
116
+ public function is_dismissed($name) {
117
+ return get_option( $name );
118
  }
119
 
120
  public function action_admin_notices() {
121
  foreach ( explode( ',', self::TYPES ) as $type ) {
122
  foreach ( $this->admin_notices->{$type} as $admin_notice ) {
123
+ $option = $this->get_dismiss_option_name($admin_notice->dismiss_option);
124
+ if ( !$admin_notice->dismiss_option || !$this->is_dismissed( $option ) ) {
125
  $this->renderNotice($admin_notice);
126
  }
127
  }
179
  $notice = $this->createNotice( 'info', $message, false, $dismiss_option );
180
  $this->addNotice($notice);
181
  }
182
+
183
  public function renderInfo( $message, $dismiss_option = false ) {
184
  $notice = $this->createNotice( 'info', $message, false, $dismiss_option );
185
  $this->renderNotice($notice);
src/utils/notices.php CHANGED
@@ -3,10 +3,14 @@
3
  require_once dirname( __FILE__ ) . '/CnbAdminNotices.class.php';
4
  require_once dirname( __FILE__ ) . '/../admin/api/CnbAdminCloud.php';
5
 
6
- function cnb_upgrade_notice($cnb_old_version, $cnb_changelog) {
7
-
8
- $message = '<h3>' . CNB_NAME . ' has been updated!</h3><h4>What\'s new?</h4>';
9
- // Only on first run after update show list of changes since last update
 
 
 
 
10
  foreach ( $cnb_changelog as $key => $value ) {
11
  if ( $key > $cnb_old_version ) {
12
  $message .= '<h3>' . esc_html($key) . '</h3>';
@@ -19,22 +23,52 @@ function cnb_upgrade_notice($cnb_old_version, $cnb_changelog) {
19
  }
20
  }
21
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  $adminNotices = CnbAdminNotices::get_instance();
24
- $adminNotices->warning($message, 'cnb_update_'.$cnb_old_version);
 
 
 
 
 
 
 
 
 
25
 
 
26
  }
27
 
28
  function cnb_settings_get_account_missing_notice() {
29
  $message = '<h3 class="title">Activating Premium</h3>
30
- <p>To activate Call Now Button Premium, you\'ll need an account at
31
- <a href="https://app.callnowbutton.com?utm_source=wp-plugin&utm_medium=referral&utm_campaign=beta_tester&utm_term=sign-up-for-api">https://app.callnowbutton.com</a>, generate a unique key and paste that into the field below. There\'s 2 ways to do this:</p>
32
- <h4>Option 1: The fast track</h4>
33
- <a class="button button-primary" href="' . get_cnb_wordpress_upgrade_link() .'">Take the fast track</a>
34
- <p class="nonessential">This shares your WordPress admin email and this page\'s URL with callnowbutton.com so it can prefill your email and return you to this page when the process is done. None of this data is stored! When you click the "Activate Premium" button on the next page, your email will be used for creating an account.</p>
35
- <p>In the fast track we\'ve tried to automate as much as possible of the process and make this as easy as possible.</p>
36
-
37
- <h4>Option 2: The manual process</h4>
38
  <ol>
39
  <li>Create your account at <a href="https://app.callnowbutton.com?utm_source=wp-plugin&utm_medium=referral&utm_campaign=beta_tester&utm_term=sign-up-for-api">https://app.callnowbutton.com</a></li>
40
  <li>Go to your profile info by clicking on the user icon in the top right corner and then click <strong>Create new API key</strong>.</li>
@@ -61,11 +95,15 @@ function cnb_settings_api_key_invalid_notice() {
61
  $adminNotices->warning($message);
62
  }
63
 
64
- function cnb_generic_error_notice($user) {
65
- $message = '<h3 class="title">Something went wrong!</h3>
66
  <p>Something has gone wrong and we do not know why...</p>
67
  <p>As unlikely as it is, our service might be experiencing issues (check <a href="https://status.callnowbutton.com">our status page</a>).</p>
68
  <p>If you think you\'ve found a bug, please report it at our <a href="https://callnowbutton.com/support/" target="_blank">Help Center</a>.';
 
 
 
 
69
  $message .= CnbAdminCloud::cnb_admin_get_error_message_details($user);
70
 
71
  $adminNotices = CnbAdminNotices::get_instance();
@@ -73,24 +111,16 @@ function cnb_generic_error_notice($user) {
73
  }
74
 
75
  function cnb_settings_api_key_input() {
76
- // Create URL
77
- $url = admin_url('admin.php');
78
- $settings_url = esc_url( $url );
79
-
80
  $message = '<form method="post" action="' . esc_url( admin_url('options.php') ) . '" class="cnb-container">';
81
  ob_start();
82
  settings_fields('cnb_options');
83
  $message .= ob_get_clean();
84
  $message .= '<input type="hidden" name="page" value="call-now-button-settings" />
85
- <table class="form-table">
86
- <tr class="when-cloud-enabled">
87
- <th scope="row">API key</th>
88
- <td>
89
- <input type="text" class="regular-text" name="cnb[api_key]"
90
- placeholder="e.g. b52c3f83-38dc-4493-bc90-642da5be7e39"/>
91
- '. get_submit_button(__('Save API key'), 'primary', 'submit', false).'
92
- </td>
93
- </table>
94
  </form>';
95
  return $message;
96
  }
@@ -200,3 +230,68 @@ function cnb_caching_plugin_warning_notice($caching_plugin_name) {
200
  $adminNotices = CnbAdminNotices::get_instance();
201
  $adminNotices->error($message);
202
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/CnbAdminNotices.class.php';
4
  require_once dirname( __FILE__ ) . '/../admin/api/CnbAdminCloud.php';
5
 
6
+ /**
7
+ * @param $cnb_changelog
8
+ * @param $cnb_old_version "$cnb_options['changelog_version']" most likely
9
+ *
10
+ * @return string
11
+ */
12
+ function cnb_get_changelog_message($cnb_changelog, $cnb_old_version) {
13
+ $message = '';
14
  foreach ( $cnb_changelog as $key => $value ) {
15
  if ( $key > $cnb_old_version ) {
16
  $message .= '<h3>' . esc_html($key) . '</h3>';
23
  }
24
  }
25
  }
26
+ return $message;
27
+ }
28
+
29
+ function cnb_get_upgrade_notice_dismiss_name() {
30
+ return 'cnb_update_'.CNB_VERSION;
31
+ }
32
+ /**
33
+ * Create a dismissable notice to inform users about changes
34
+ * @param $cnb_options
35
+ * @param $cnb_changelog
36
+ *
37
+ * @return void
38
+ */
39
+ function cnb_upgrade_notice($cnb_options, $cnb_changelog) {
40
+ $changelog = cnb_get_changelog_message($cnb_changelog, get_changelog_version($cnb_options));
41
+
42
+ if (empty($changelog)) return;
43
+
44
+ $message = '<h3 id="cnb_is_updated">' . CNB_NAME . ' has been updated!</h3><h4>What\'s new?</h4>';
45
+ $message .= $changelog;
46
 
47
  $adminNotices = CnbAdminNotices::get_instance();
48
+ $adminNotices->warning($message, cnb_get_upgrade_notice_dismiss_name());
49
+ }
50
+
51
+ function cnb_settings_email_activation_input() {
52
+ $message = '<div id="cnb_email_activation_alternate_formd">';
53
+ $message .= '<input type="text" class="regular-text" name="cnb_email_activation_alternate_address" id="cnb_email_activation_alternate_address" placeholder="email@example.com" value="' . esc_attr(get_bloginfo('admin_email')) . '"/>';
54
+ $message .= get_submit_button(__('Activate Premium'), 'primary', 'cnb_email_activation_alternate', false, array('onclick' => 'return cnb_email_activation_alternate()'));
55
+ $message .= '</div>';
56
+ $message .= '<p id="cnb_email_activation"></p>';
57
+ $message .= '<p class="nonessential">By clicking <u>Activate Premium</u> an account will be created with your email address on callnowbutton.com and you agree to our <a href="https://callnowbutton.com/terms.html" target="_blank">Terms & Conditions</a> and <a href="https://callnowbutton.com/privacy.html" target="_blank">Privacy statement</a>.</p>';
58
 
59
+ return $message;
60
  }
61
 
62
  function cnb_settings_get_account_missing_notice() {
63
  $message = '<h3 class="title">Activating Premium</h3>
64
+ <p>To activate Premium, you\'ll need a <a href="https://app.callnowbutton.com/register" target="_blank">callnowbutton.com</a> account and an API key. There\'s 2 ways to do this:</p>
65
+
66
+ <h4>Option 1: Email activation (easy and fast!)</h4>';
67
+ $message .= cnb_settings_email_activation_input();
68
+
69
+ $message .= '
70
+ <hr>
71
+ <h4>Option 2: Web activation (manual process)</h4>
72
  <ol>
73
  <li>Create your account at <a href="https://app.callnowbutton.com?utm_source=wp-plugin&utm_medium=referral&utm_campaign=beta_tester&utm_term=sign-up-for-api">https://app.callnowbutton.com</a></li>
74
  <li>Go to your profile info by clicking on the user icon in the top right corner and then click <strong>Create new API key</strong>.</li>
95
  $adminNotices->warning($message);
96
  }
97
 
98
+ function get_cnb_generic_error_notice() {
99
+ return '<h3 class="title">Something went wrong!</h3>
100
  <p>Something has gone wrong and we do not know why...</p>
101
  <p>As unlikely as it is, our service might be experiencing issues (check <a href="https://status.callnowbutton.com">our status page</a>).</p>
102
  <p>If you think you\'ve found a bug, please report it at our <a href="https://callnowbutton.com/support/" target="_blank">Help Center</a>.';
103
+ }
104
+
105
+ function cnb_generic_error_notice($user) {
106
+ $message = get_cnb_generic_error_notice();
107
  $message .= CnbAdminCloud::cnb_admin_get_error_message_details($user);
108
 
109
  $adminNotices = CnbAdminNotices::get_instance();
111
  }
112
 
113
  function cnb_settings_api_key_input() {
 
 
 
 
114
  $message = '<form method="post" action="' . esc_url( admin_url('options.php') ) . '" class="cnb-container">';
115
  ob_start();
116
  settings_fields('cnb_options');
117
  $message .= ob_get_clean();
118
  $message .= '<input type="hidden" name="page" value="call-now-button-settings" />
119
+ <div>
120
+ <input type="text" class="regular-text" name="cnb[api_key]"
121
+ placeholder="Paste API key here"/>
122
+ '. get_submit_button(__('Activate Premium'), 'primary', 'submit', false).'
123
+ </div>
 
 
 
 
124
  </form>';
125
  return $message;
126
  }
230
  $adminNotices = CnbAdminNotices::get_instance();
231
  $adminNotices->error($message);
232
  }
233
+
234
+ function cnb_show_welcome_panel() {
235
+ $dimiss_value = 'welcome-panel';
236
+ $dismissed_option = CnbAdminNotices::get_instance()->get_dismiss_option_name($dimiss_value);
237
+ $is_dismissed = CnbAdminNotices::get_instance()->is_dismissed($dismissed_option);
238
+ return !$is_dismissed;
239
+ }
240
+
241
+ function cnb_get_welcome_panel() {
242
+ if (!cnb_show_welcome_panel()) return;
243
+ $dimiss_value = 'welcome-panel';
244
+
245
+ $url = admin_url('admin.php');
246
+ $upgrade_link =
247
+ add_query_arg(
248
+ array('page' => 'call-now-button-upgrade'),
249
+ $url );
250
+ $upgrade_url = esc_url( $upgrade_link );
251
+
252
+ $dismiss_data_url = '';
253
+ $dismiss_url = add_query_arg( array(
254
+ CNB_SLUG . '_dismiss' => $dimiss_value
255
+ ), $url );
256
+
257
+ $dismiss_data_url .= ' data-dismiss-url="' . esc_url( $dismiss_url ) . '"';
258
+
259
+ ?>
260
+ <div id="welcome-panel" class="welcome-panel is-dismissible notice-call-now-button" <?php echo $dismiss_data_url ?>>
261
+ <button type="button" class="welcome-panel-close notice-dismiss">Dismiss<span class="screen-reader-text">Dismiss this notice.</span></button>
262
+
263
+ <div class="welcome-panel-content">
264
+ <h2>Welcome to Call Now Button verson 1.0</h2>
265
+ <p class="about-description">After 10 years we have finally reached v1!</p>
266
+ <div class="welcome-panel-column-container">
267
+ <div class="welcome-panel-column">
268
+ <h3>Here's why</h3>
269
+ <div class="welcome-column-box">
270
+ <p class="only-in-columns">Why we promoted the plugin from the zeros to a 1:</p>
271
+
272
+ <p class="cnb-mobile-inline">🎉 The Call Now Button is turning 10!</p>
273
+ <p class="cnb-mobile-inline">❤️ 200k+ active installs and rated 4.9!</p>
274
+ <p class="cnb-mobile-inline">💎 Premium went live!</p>
275
+ </div>
276
+ </div>
277
+ <div class="welcome-panel-column">
278
+ <h3>What's in Premium?</h3>
279
+ <p class="cnb-mobile-inline">+ Create multiple buttons</p>
280
+ <p class="cnb-mobile-inline">+ WhatsApp, Email, Maps and Links</p>
281
+ <p class="cnb-mobile-inline">+ Multibutton&trade; and Buttonbar&trade;</p>
282
+ <p class="cnb-mobile-inline">+ Button scheduler</p>
283
+ <p class="cnb-mobile-inline">+ Advanced page targeting</p>
284
+ </div>
285
+ <div class="welcome-panel-column">
286
+ <a class="button button-primary button-hero" href="<?php echo $upgrade_url ?>">Activate Premium</a>
287
+ <p>Or, <a href="<?php echo $upgrade_url ?>">learn more.</a></p>
288
+ <h3>Other resources</h3>
289
+ <p>
290
+ <a href="<?php echo CNB_SUPPORT; ?>wordpress-free/">The new help center</a><br>
291
+ <a href="<?php echo CNB_SUPPORT; ?>wordpress-free/#faq">FAQ</a>
292
+ </p>
293
+ </div>
294
+ </div>
295
+ </div>
296
+ </div>
297
+ <?php }
src/utils/utils.php CHANGED
@@ -22,13 +22,14 @@ function cnb_get_defaults() {
22
  'z-index' => 10,
23
  'tracking' => 0,
24
  'show' => '',
25
- 'version' => CNB_VERSION
 
26
  );
27
  }
28
 
29
  /**
30
  * Returns the most current set of options
31
- * Will update the Wordpress Options if they are missing or outdated
32
  *
33
  * @return array
34
  */
@@ -36,12 +37,11 @@ function cnb_get_options() { // Grabbing existing settings and creating them if
36
  if(!get_option('cnb')) { // Doesn't exist -> set defaults
37
  add_option('cnb', cnb_get_defaults());
38
  } else { // Does exist -> see if update is needed
39
- $updated = cnb_update_options();
40
  }
 
 
41
  $cnb_options['options'] = get_option('cnb');
42
- // Format = options['updated'] = array(true/false [true for "there is an update", false for "CNB is up-to-date" , 0.5.5)
43
- // Debug example: $cnb_options['updated'] = array(true, '0.0.0');
44
- $cnb_options['updated'] = isset($updated) ? $updated : array(false, substr(CNB_VERSION, 0, 3));
45
  return $cnb_options;
46
  }
47
 
@@ -52,16 +52,17 @@ function cnb_get_options() { // Grabbing existing settings and creating them if
52
  * @return bool true if there has been an update, false otherwise
53
  */
54
  function cnb_update_needed($cnb_options) {
55
- $setupVersion = array_key_exists('version', $cnb_options) ? $cnb_options['version'] : "0.1.0";
56
 
57
  // 1 if version in DB is lower, 0 if the same, -1 if DB is higher than defined plugin (should never happen..)
58
  $compare = version_compare(CNB_VERSION, $setupVersion);
 
59
  return $compare === 1;
60
  }
61
 
62
  /**
63
  * Gets the result of the DB settings combined with the default settings if any setting is missing
64
- * @return array
65
  */
66
  function cnb_update_options() {
67
  $cnb_options = get_option('cnb');
@@ -115,16 +116,47 @@ function cnb_update_options() {
115
  )
116
  );
117
 
118
- if(array_key_exists('classic', $cnb_options) && $cnb_options['classic'] == 1 ) {
119
- $default_options['classic'] = 1;
120
- }
121
-
122
  update_option('cnb', $updated_options);
123
- $updated = array(true, $cnb_options['version']); // Updated and previous version number
124
- } else {
125
- $updated = array(false, $cnb_options['version']); // Not updated and current version number
126
  }
127
- return $updated;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
  }
129
 
130
  /**
@@ -199,13 +231,15 @@ function zindexToOrder($zindex) {
199
 
200
  function cnb_actiontype_to_icontext($actionType) {
201
  switch ($actionType) {
202
- case 'PHONE': return 'call';
203
  case 'ANCHOR': return 'anchor';
204
  case 'WHATSAPP': return 'whatsapp';
205
  case 'EMAIL': return 'email';
206
  case 'LINK': return 'link';
207
  case 'MAP': return 'directions';
208
  case 'HOURS': return 'access_time';
 
 
 
209
  }
210
  }
211
 
@@ -224,7 +258,7 @@ function cnb_check_for_caching() {
224
  'wp-fastest-cache/wpFastestCache.php',
225
  'wp-super-cache/wp-cache.php'
226
  );
227
- $active = FALSE; //Default is false
228
  $name = 'none'; // Default name is none
229
  foreach ($caching_plugins as $plugin) {
230
  if ( is_plugin_active( $plugin ) ) {
@@ -417,8 +451,11 @@ function cnb_array_column($array, $column_key, $index_key = null) {
417
  }
418
 
419
  function cnb_timestamp_to_string($timestamp){
 
420
  if ( $timestamp instanceof stdClass ) {
421
  return date("r", $timestamp->seconds);
 
 
422
  }
423
  return $timestamp;
424
  }
@@ -426,7 +463,7 @@ function cnb_timestamp_to_string($timestamp){
426
  /***
427
  * To ensure arrays are properly sanitized to WordPress Codex standards,
428
  * they encourage usage of sanitize_text_field(). That only works with a single
429
- * variable (string). This function allows for a full blown array to get sanitized
430
  * properly, while sanitizing each individual value in a key -> value pair.
431
  *
432
  * Source: https://wordpress.stackexchange.com/questions/24736/wordpress-sanitize-array
@@ -434,7 +471,7 @@ function cnb_timestamp_to_string($timestamp){
434
  * Via: https://developer.wordpress.org/reference/functions/sanitize_text_field/
435
  */
436
  function cnb_wporg_recursive_sanitize_text_field( $array ) {
437
- foreach ( $array as $key => &$value ) {
438
  if ( is_array( $value ) ) {
439
  $value = cnb_wporg_recursive_sanitize_text_field( $value );
440
  } else {
@@ -477,3 +514,20 @@ function get_cnb_domain_upgrade($cnb_cloud_domain) {
477
  }
478
  return null;
479
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  'z-index' => 10,
23
  'tracking' => 0,
24
  'show' => '',
25
+ 'version' => CNB_VERSION,
26
+ 'changelog_version' => CNB_VERSION,
27
  );
28
  }
29
 
30
  /**
31
  * Returns the most current set of options
32
+ * Will update the WordPress Options if they are missing or outdated
33
  *
34
  * @return array
35
  */
37
  if(!get_option('cnb')) { // Doesn't exist -> set defaults
38
  add_option('cnb', cnb_get_defaults());
39
  } else { // Does exist -> see if update is needed
40
+ cnb_update_options();
41
  }
42
+
43
+ $cnb_options = array();
44
  $cnb_options['options'] = get_option('cnb');
 
 
 
45
  return $cnb_options;
46
  }
47
 
52
  * @return bool true if there has been an update, false otherwise
53
  */
54
  function cnb_update_needed($cnb_options) {
55
+ $setupVersion = array_key_exists('version', $cnb_options) ? $cnb_options['version'] : '0.1.0';
56
 
57
  // 1 if version in DB is lower, 0 if the same, -1 if DB is higher than defined plugin (should never happen..)
58
  $compare = version_compare(CNB_VERSION, $setupVersion);
59
+
60
  return $compare === 1;
61
  }
62
 
63
  /**
64
  * Gets the result of the DB settings combined with the default settings if any setting is missing
65
+ * @return void
66
  */
67
  function cnb_update_options() {
68
  $cnb_options = get_option('cnb');
116
  )
117
  );
118
 
 
 
 
 
119
  update_option('cnb', $updated_options);
 
 
 
120
  }
121
+ }
122
+
123
+ /**
124
+ * After the upgrade (changelog) dialog is dismissed, the "cnb_update_<version>" action is fired.
125
+ *
126
+ * This action updates the internal version number, so we're ready for the next update.
127
+ *
128
+ * @see admin-functions.php -> set_changelog_version()
129
+ *
130
+ * @return void
131
+ */
132
+ function cnb_update_version() {
133
+ set_changelog_version();
134
+ }
135
+
136
+ function cnb_reset_options() {
137
+ global $cnb_settings, $cnb_options, $cnb_cloud_hosting, $cloud_use_id;
138
+
139
+ // Grabbing the settings and checking for latest version
140
+ // OR creating the options file for first time installations
141
+ $cnb_settings = cnb_get_options();
142
+ $cnb_options = $cnb_settings['options'];
143
+
144
+ $cnb_options['active'] = isset($cnb_options['active']) && $cnb_options['active'] == 1 ? 1 : 0;
145
+ $cnb_options['classic'] = isset($cnb_options['classic']) && $cnb_options['classic'] == 1 ? 1 : 0;
146
+ $cnb_options['hideIcon'] = isset($cnb_options['hideIcon']) && $cnb_options['hideIcon'] == 1 ? 1 : 0;
147
+ $cnb_options['frontpage'] = isset($cnb_options['frontpage']) && $cnb_options['frontpage'] == 1 ? 1 : 0;
148
+ $cnb_options['advanced_view'] = isset($cnb_options['advanced_view']) && $cnb_options['advanced_view'] == 1 ? 1 : 0;
149
+ $cnb_options['show_all_buttons_for_domain'] = isset($cnb_options['show_all_buttons_for_domain']) && $cnb_options['show_all_buttons_for_domain'] == 1 ? 1 : 0;
150
+ $cnb_options['footer_show_traces'] = isset($cnb_options['footer_show_traces']) && $cnb_options['footer_show_traces'] == 1 ? 1 : 0;
151
+ $cnb_options['api_caching'] = isset($cnb_options['api_caching']) && $cnb_options['api_caching'] == 1 ? 1 : 0;
152
+
153
+ $cnb_cloud_hosting = isset($cnb_options['cloud_enabled']) && $cnb_options['cloud_enabled'] == 1;
154
+ $cloud_use_id = isset($cnb_options['cloud_use_id']) && !empty($cnb_options['cloud_use_id']) ? $cnb_options['cloud_use_id'] : 0;
155
+
156
+ // Used by settings
157
+ $cnb_options['status'] = $cnb_cloud_hosting ? 'cloud' : ($cnb_options['active'] ? 'enabled' : 'disabled');
158
+
159
+ return $cnb_options;
160
  }
161
 
162
  /**
231
 
232
  function cnb_actiontype_to_icontext($actionType) {
233
  switch ($actionType) {
 
234
  case 'ANCHOR': return 'anchor';
235
  case 'WHATSAPP': return 'whatsapp';
236
  case 'EMAIL': return 'email';
237
  case 'LINK': return 'link';
238
  case 'MAP': return 'directions';
239
  case 'HOURS': return 'access_time';
240
+ case 'PHONE':
241
+ default:
242
+ return 'call';
243
  }
244
  }
245
 
258
  'wp-fastest-cache/wpFastestCache.php',
259
  'wp-super-cache/wp-cache.php'
260
  );
261
+ $active = false; //Default is false
262
  $name = 'none'; // Default name is none
263
  foreach ($caching_plugins as $plugin) {
264
  if ( is_plugin_active( $plugin ) ) {
451
  }
452
 
453
  function cnb_timestamp_to_string($timestamp){
454
+ $timestamp_parsed = strtotime($timestamp);
455
  if ( $timestamp instanceof stdClass ) {
456
  return date("r", $timestamp->seconds);
457
+ } else if ($timestamp_parsed) {
458
+ return date("r", $timestamp_parsed);
459
  }
460
  return $timestamp;
461
  }
463
  /***
464
  * To ensure arrays are properly sanitized to WordPress Codex standards,
465
  * they encourage usage of sanitize_text_field(). That only works with a single
466
+ * variable (string). This function allows for a full-blown array to get sanitized
467
  * properly, while sanitizing each individual value in a key -> value pair.
468
  *
469
  * Source: https://wordpress.stackexchange.com/questions/24736/wordpress-sanitize-array
471
  * Via: https://developer.wordpress.org/reference/functions/sanitize_text_field/
472
  */
473
  function cnb_wporg_recursive_sanitize_text_field( $array ) {
474
+ foreach ( $array as &$value ) {
475
  if ( is_array( $value ) ) {
476
  $value = cnb_wporg_recursive_sanitize_text_field( $value );
477
  } else {
514
  }
515
  return null;
516
  }
517
+
518
+ function is_use_cloud($cnb_options) {
519
+ $cnb_cloud_hosting = isset($cnb_options['cloud_enabled']) && $cnb_options['cloud_enabled'] == 1;
520
+ $cloud_use_id = isset($cnb_options['cloud_use_id']) && !empty($cnb_options['cloud_use_id']) ? $cnb_options['cloud_use_id'] : 0;
521
+ return $cnb_cloud_hosting && $cloud_use_id !== 0;
522
+ }
523
+
524
+ function is_valid_timezone_string($timezone_string) {
525
+ // Do not allow: +00:00 variants
526
+ $plus_variants_domain = strripos($timezone_string, '+') !== false;
527
+ // Do not allow: utc variants
528
+ $utc_variants_domain = strripos($timezone_string, 'utc') !== false;
529
+
530
+ $has_slash = strripos($timezone_string, '/') !== false;
531
+
532
+ return !($plus_variants_domain || $utc_variants_domain) && $has_slash;
533
+ }