Call Now Button - Version 1.0.8

Version Description

= * WhatsApp chat modal (Premium) * Multiple buttons on a single page (Premium) * Icon selection (Premium) * Drag and drop action sorting (Premium) * Time selector in the preview (Premium) * Button animations (Premium) * Set link target (Premium) * Display setting shown in button overview (Premium)

Download this release

Release Info

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

Code changes from version 1.0.7 to 1.0.8

Files changed (48) hide show
  1. call-now-button.php +2 -2
  2. readme.txt +11 -1
  3. resources/js/action-edit-scheduler.js +23 -6
  4. resources/js/action-edit.js +76 -0
  5. resources/js/action-type-to-icon-text.js +144 -11
  6. resources/js/call-now-button.js +23 -8
  7. resources/js/domain-upgrade.js +2 -1
  8. resources/js/jquery.ui.touch-punch.js +244 -0
  9. resources/js/preview.js +134 -19
  10. resources/js/settings.js +20 -10
  11. resources/style/call-now-button.css +208 -20
  12. src/admin/action-edit.php +312 -147
  13. src/admin/action-overview.php +32 -8
  14. src/admin/admin-ajax.php +12 -5
  15. src/admin/api/CnbAdminCloud.php +115 -78
  16. src/admin/api/CnbAppRemote.php +106 -111
  17. src/admin/api/CnbAppRemotePayment.php +1 -0
  18. src/admin/api/RemoteTrace.php +2 -0
  19. src/admin/api/RemoteTracer.php +1 -0
  20. src/admin/apikey-overview.php +3 -0
  21. src/admin/button-edit.php +448 -228
  22. src/admin/button-overview.php +101 -62
  23. src/admin/condition-edit.php +97 -107
  24. src/admin/condition-overview.php +8 -3
  25. src/admin/domain-edit.php +32 -8
  26. src/admin/domain-overview.php +4 -1
  27. src/admin/domain-upgrade.php +4 -0
  28. src/admin/legacy-edit.php +38 -36
  29. src/admin/legacy-upgrade.php +11 -7
  30. src/admin/models/CnbAction.class.php +215 -9
  31. src/admin/models/CnbApiKey.class.php +51 -1
  32. src/admin/models/CnbButton.class.php +212 -43
  33. src/admin/models/CnbCondition.class.php +52 -1
  34. src/admin/models/CnbDomain.class.php +100 -8
  35. src/admin/models/CnbUser.class.php +3 -1
  36. src/admin/partials/admin-footer.php +2 -0
  37. src/admin/partials/admin-functions.php +14 -4
  38. src/admin/partials/admin-header.php +1 -1
  39. src/admin/partials/domain-upgrade/overview.php +37 -41
  40. src/admin/partials/domain-upgrade/upgraded.php +4 -2
  41. src/admin/settings-profile.php +11 -10
  42. src/admin/settings.php +64 -48
  43. src/call-now-button.php +20 -1
  44. src/cli/CNB_CLI_Button.class.php +7 -7
  45. src/renderers/cloud/wp_head.php +3 -0
  46. src/utils/CnbUtils.php +30 -0
  47. src/utils/notices.php +24 -12
  48. src/utils/utils.php +10 -2
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.7
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.7');
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.8
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.8');
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.9
8
- Stable tag: 1.0.7
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -111,6 +111,16 @@ Yes, you can upgrade to Premium to enable tons of extra features. Checkout [call
111
 
112
 
113
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
114
  = 1.0.7 =
115
  * Bugfix for Localization
116
 
5
  Requires at least: 3.9
6
  Requires PHP: 5.4
7
  Tested up to: 5.9
8
+ Stable tag: 1.0.8
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.8 =
115
+ * WhatsApp chat modal (Premium)
116
+ * Multiple buttons on a single page (Premium)
117
+ * Icon selection (Premium)
118
+ * Drag and drop action sorting (Premium)
119
+ * Time selector in the preview (Premium)
120
+ * Button animations (Premium)
121
+ * Set link target (Premium)
122
+ * Display setting shown in button overview (Premium)
123
+
124
  = 1.0.7 =
125
  * Bugfix for Localization
126
 
resources/js/action-edit-scheduler.js CHANGED
@@ -41,8 +41,13 @@ function fromFormattedToMinutes(time) {
41
  * @param {string} stop Formatted 24h time ("14:50")
42
  */
43
  function cnbUpdateTime(start, stop) {
44
- jQuery('#actions-schedule-start').val(start)
45
- jQuery('#actions-schedule-stop').val(stop)
 
 
 
 
 
46
  }
47
 
48
  function cnbUpdateColors() {
@@ -53,21 +58,33 @@ function cnbUpdateColors() {
53
  jQuery('#cnb-schedule-range.ui-widget-content').css({"background": widgetColor});
54
  }
55
 
 
 
56
  function cnbAjaxTimeFormat(start, stop) {
 
 
57
  const data = {
58
  'action': 'cnb_time_format',
59
  'start': start,
60
  'stop': stop
61
  };
62
 
63
- jQuery.post(ajaxurl, data, function(response) {
64
- cnbUpdateTimeText(response.start, response.stop)
 
 
 
 
 
 
 
65
  });
66
  }
67
 
68
  function cnbUpdateTimeText(start, stop) {
69
- const reverse1 = jQuery('#actions_schedule_outside_hours').prop('checked') ? 'Before': 'From';
70
- const reverse2 = jQuery('#actions_schedule_outside_hours').prop('checked') ? 'and after': 'till';
 
71
 
72
  jQuery( "#cnb-schedule-range-text" ).html( reverse1+" <strong>" + start + "</strong> "+reverse2+" <strong>" + stop + "</strong>")
73
  }
41
  * @param {string} stop Formatted 24h time ("14:50")
42
  */
43
  function cnbUpdateTime(start, stop) {
44
+ const startEle = jQuery('#actions-schedule-start')
45
+ const stopEle = jQuery('#actions-schedule-stop')
46
+ startEle.val(start)
47
+ stopEle.val(stop)
48
+
49
+ // This ensures that a rerender is triggered
50
+ startEle.trigger('change')
51
  }
52
 
53
  function cnbUpdateColors() {
58
  jQuery('#cnb-schedule-range.ui-widget-content').css({"background": widgetColor});
59
  }
60
 
61
+ let cnb_api_counter = 0;
62
+ let cnb_api_in_progress;
63
  function cnbAjaxTimeFormat(start, stop) {
64
+ const local_counter = cnb_api_counter + 1
65
+ cnb_api_counter = local_counter
66
  const data = {
67
  'action': 'cnb_time_format',
68
  'start': start,
69
  'stop': stop
70
  };
71
 
72
+ if (cnb_api_in_progress) {
73
+ cnb_api_in_progress.abort();
74
+ }
75
+ cnb_api_in_progress = jQuery.post(ajaxurl, data, function(response) {
76
+ // If we have another counter request already, ignore this one
77
+ if (local_counter === cnb_api_counter) {
78
+ cnbUpdateTimeText(response.start, response.stop)
79
+ }
80
+ cnb_api_in_progress = null;
81
  });
82
  }
83
 
84
  function cnbUpdateTimeText(start, stop) {
85
+ const outsideHoursEle = jQuery('#actions_schedule_outside_hours')
86
+ const reverse1 = outsideHoursEle.prop('checked') ? 'Before': 'From';
87
+ const reverse2 = outsideHoursEle.prop('checked') ? 'and after': 'till';
88
 
89
  jQuery( "#cnb-schedule-range-text" ).html( reverse1+" <strong>" + start + "</strong> "+reverse2+" <strong>" + stop + "</strong>")
90
  }
resources/js/action-edit.js ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // If the modal is enabled, we need to clear and disable the "Default message"
2
+
3
+ /**
4
+ * This sets the various Whatsapp Modal fields to appear only when needed.
5
+ *
6
+ * When the
7
+ */
8
+ function cnb_set_action_modal_fields() {
9
+ const ele = jQuery('#cnb-action-modal')
10
+
11
+ // messageRow contains just the message (the non-modal message)
12
+ const messageRow = jQuery("#action-properties-message-row")
13
+ const messageEle = jQuery('#action-properties-message')
14
+ const modalElements = jQuery('.cnb-action-properties-whatsapp-modal')
15
+
16
+ const isVisible = ele.is(":visible")
17
+ const isChecked = ele.prop('checked')
18
+ if (!isVisible) {
19
+ messageRow.hide()
20
+ modalElements.hide()
21
+ } else if (isChecked) {
22
+ messageEle.attr('disabled', 'disabled')
23
+ messageRow.hide()
24
+ modalElements.show()
25
+ } else {
26
+ messageEle.removeAttr('disabled')
27
+ messageRow.show()
28
+ modalElements.hide()
29
+ }
30
+ }
31
+
32
+ function cnb_clear_default_on_modal() {
33
+ const ele = jQuery('#cnb-action-modal')
34
+ ele.on('click', () => {
35
+ cnb_set_action_modal_fields()
36
+ })
37
+ }
38
+
39
+ function cnb_refresh_on_action_change() {
40
+ const ele = jQuery('#cnb_action_type')
41
+ ele.on('change', () => {
42
+ cnb_set_action_modal_fields()
43
+ })
44
+ }
45
+
46
+ function cnb_add_sortable_to_action_table() {
47
+ // Only add sortable if the table exists (otherwise ".sortable()" might not even exist
48
+ jQuery('table.cnb_list_actions #the-list').each(function(){
49
+ const ele = jQuery(this)
50
+
51
+ // Only set sortable if >1 item in the table
52
+ // And if there are 0 or 1 item, hide the draggable item, to avoid confusion
53
+ const childCount = jQuery('tr', ele).length
54
+
55
+ if (childCount > 1) {
56
+ ele.sortable({
57
+ stop: function () {
58
+ livePreview()
59
+ },
60
+ placeholder: 'ui-state-highlight'
61
+ })
62
+ } else {
63
+ jQuery('.column-draggable', ele.parentElement).hide()
64
+ }
65
+ })
66
+
67
+ }
68
+
69
+ jQuery(() => {
70
+ // These 2 set up action handler to process changes on the form
71
+ cnb_clear_default_on_modal()
72
+ cnb_refresh_on_action_change()
73
+ // This ensures that the default state matches the state of the page when it is loaded
74
+ cnb_set_action_modal_fields()
75
+ cnb_add_sortable_to_action_table()
76
+ })
resources/js/action-type-to-icon-text.js CHANGED
@@ -5,35 +5,168 @@
5
  *
6
  * @param {string} actionType
7
  *
8
- * @returns {string}
9
  */
10
  function cnbActiontypeToIcontext(actionType) {
11
  switch (actionType) {
12
- case 'ANCHOR': return 'anchor';
13
- case 'EMAIL': return 'email';
14
- case 'HOURS': return 'access_time';
15
- case 'LINK': return 'link';
16
- case 'MAP': return 'directions';
17
- case 'PHONE': return 'call';
18
- case 'SMS': return 'chat';
19
- case 'WHATSAPP': return 'whatsapp';
20
  default:
21
- return 'call';
22
  }
23
  }
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  function updateIconText() {
26
  const type = jQuery('#cnb_action_type').val();
27
  const iconText = cnbActiontypeToIcontext(type)
28
  jQuery('#cnb_action_icon_text').val(iconText);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  }
30
 
31
  function initUpdateIconText() {
32
- jQuery('form.cnb-container :input').on('change input', function() {
 
33
  updateIconText()
 
 
34
  });
 
 
 
 
 
 
 
 
 
 
35
  }
36
 
37
  jQuery(() => {
38
  initUpdateIconText()
 
 
39
  })
5
  *
6
  * @param {string} actionType
7
  *
8
+ * @returns {string} the default iconText for the given action
9
  */
10
  function cnbActiontypeToIcontext(actionType) {
11
  switch (actionType) {
12
+ case 'ANCHOR': return 'anchor'
13
+ case 'EMAIL': return 'email'
14
+ case 'HOURS': return 'access_time'
15
+ case 'LINK': return 'link'
16
+ case 'MAP': return 'directions'
17
+ case 'PHONE': return 'call'
18
+ case 'SMS': return 'chat'
19
+ case 'WHATSAPP': return 'whatsapp'
20
  default:
21
+ return 'call'
22
  }
23
  }
24
 
25
+ function cnb_trigger_rerender(jEle) {
26
+ jEle.trigger('change')
27
+
28
+ }
29
+ /**
30
+ * Updates the iconText property (and rerenders the preview)
31
+ *
32
+ * @param ele {HTMLElement} the icon clicked
33
+ * @returns {boolean} false, to prevent the page from changing scroll position
34
+ */
35
+ function cnb_change_icon_text(ele) {
36
+ const jEle = jQuery(ele)
37
+ const val = jEle.text()
38
+
39
+ // this is to update the action-edit icons!
40
+ const findIcontextEle = jEle.closest("[data-icon-text-target]").data('iconTextTarget')
41
+ const cnb_action_icon_text = jQuery('#' + findIcontextEle)
42
+ if (cnb_action_icon_text.length) {
43
+ cnb_action_icon_text.val(val)
44
+
45
+ // Since we support multiple icon-type's, we take the correct one from the element's metadata
46
+ const findIcontypeEle = jEle.closest("[data-icon-type-target]").data('iconTypeTarget')
47
+ const cnb_action_icon_type = jQuery('#' + findIcontypeEle)
48
+ cnb_action_icon_type.val(jQuery(ele).data('icon-type'))
49
+
50
+ // Force an update to the preview
51
+ cnb_trigger_rerender(cnb_action_icon_text)
52
+ } else {
53
+ // Maybe it's the button-edit multibutton options
54
+ // If so, get the parent and find if the 2 data attributes are set
55
+ const parent = jQuery(ele.parentElement)
56
+ const iconText = parent.data('icon-text')
57
+ const iconType = parent.data('icon-type')
58
+ if (iconText && iconType) {
59
+ const iconTextEle = jQuery('#' + iconText)
60
+ const iconTypeEle = jQuery('#' + iconType)
61
+ iconTypeEle.val(jQuery(ele).data('icon-type'))
62
+ iconTextEle.val(val)
63
+ iconTextEle.trigger('change')
64
+ }
65
+ }
66
+ return false
67
+ }
68
+
69
  function updateIconText() {
70
  const type = jQuery('#cnb_action_type').val();
71
  const iconText = cnbActiontypeToIcontext(type)
72
  jQuery('#cnb_action_icon_text').val(iconText);
73
+
74
+ // Also reset the iconType to default
75
+ jQuery('#cnb_action_icon_type').val('FONT')
76
+ }
77
+
78
+ /**
79
+ * When changing Button/Action type, the examples also need to be updated
80
+ */
81
+ function updateIconTextExamples() {
82
+ // Show the examples
83
+ const type = jQuery('#cnb_action_type').val();
84
+
85
+ if (type) {
86
+ jQuery('.icon-text-options').hide();
87
+ jQuery('#icon-text-' + type).show();
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Unused for now
93
+ *
94
+ * Shows the advanced view for iconText. Basically - swaps the hidden iconText input to text.
95
+ *
96
+ * @returns {boolean} false, to prevent the page from changing scroll position
97
+ */
98
+ function cnb_show_icon_text_advanced(ele) {
99
+ const jEle = jQuery(ele)
100
+
101
+ const iconText = jEle.data('icon-text')
102
+ const iconType = jEle.data('icon-type')
103
+ const iconDescription = jEle.data('description')
104
+ if (iconText && iconType) {
105
+ const iconTextEle = jQuery('#' + iconText)
106
+ const iconTypeEle = jQuery('#' + iconType)
107
+ const iconDescriptionEle = jQuery('#' + iconDescription)
108
+ iconTextEle.attr('type', 'text')
109
+ iconTypeEle.attr('type', 'text')
110
+ iconTypeEle.val('FONT_MATERIAL')
111
+ iconDescriptionEle.show()
112
+
113
+ cnb_trigger_rerender(iconTextEle)
114
+ }
115
+ jEle.hide()
116
+ return false;
117
+ }
118
+
119
+ /**
120
+ *
121
+ * @param {HTMLElement} ele the font icon clicked (can be empty in case of action-edit)
122
+ */
123
+ function cnb_hightlight_selected_icon_all(ele = null) {
124
+ const all = jQuery("[data-icon-text-target]")
125
+ all.each(function() {
126
+ const findIcontextEle = jQuery(this).data('iconTextTarget')
127
+ const findIcontypeEle = jQuery(this).data('iconTypeTarget')
128
+ const iconTextEle = jQuery('#' + findIcontextEle)
129
+ const iconTypeEle = jQuery('#' + findIcontypeEle)
130
+ cnb_hightlight_selected_icon_each(iconTextEle, iconTypeEle)
131
+ })
132
+ }
133
+
134
+ function cnb_hightlight_selected_icon_each(iconTextEle, iconTypeEle) {
135
+ // In case of "DEFAULT", we should match that to FONT
136
+ const iconTextVal = iconTextEle.val()
137
+ const iconTypeVal = iconTypeEle.val() === 'DEFAULT' ? 'FONT' : iconTypeEle.val()
138
+
139
+ const selector = '.cnb-font-icon[data-icon-text="' + iconTextVal + '"][data-icon-type="' + iconTypeVal + '"]'
140
+ const current = jQuery(selector)
141
+
142
+ const iconsInSeries = current.closest("[data-icon-text-target]").find('.cnb-font-icon')
143
+ iconsInSeries.parent().removeClass('cnb_icon_active')
144
+ if (current.length) {
145
+ current.parent().addClass('cnb_icon_active')
146
+ }
147
  }
148
 
149
  function initUpdateIconText() {
150
+ // When the "Button/Action type" is changed, we need to update the icon as well as the examples
151
+ jQuery('#cnb_action_type').on('change', function() {
152
  updateIconText()
153
+ updateIconTextExamples()
154
+ cnb_hightlight_selected_icon_all()
155
  });
156
+
157
+ jQuery('#cnb_action_icon_text').on('input', () => {
158
+ cnb_hightlight_selected_icon_all()
159
+ })
160
+
161
+ // Attach on click handler for the custom icons
162
+ jQuery('.cnb-font-icon').on('click', function (event) {
163
+ cnb_change_icon_text(event.target)
164
+ cnb_hightlight_selected_icon_all()
165
+ })
166
  }
167
 
168
  jQuery(() => {
169
  initUpdateIconText()
170
+ updateIconTextExamples()
171
+ cnb_hightlight_selected_icon_all()
172
  })
resources/js/call-now-button.js CHANGED
@@ -75,13 +75,13 @@ function cnb_hide_on_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');
@@ -92,6 +92,7 @@ function cnb_hide_on_show_always() {
92
  }
93
  }
94
  }
 
95
  return false;
96
  }
97
 
@@ -107,7 +108,7 @@ function cnb_disable_api_key_when_cloud_hosting_is_disabled() {
107
  }
108
 
109
  function cnb_animate_saving() {
110
- jQuery('.call-now-button #submit').on('click', function (event) {
111
  // if value is saving, skip...
112
  if (jQuery(this).prop('value') === 'Saving...') {
113
  event.preventDefault();
@@ -136,7 +137,7 @@ function cnb_animate_saving() {
136
  const notification = jQuery('<div />', {class: "cnb-form-validation-notice notice notice-warning"}).append(inner);
137
  const label = node.labels.length > 0 ? node.labels[0].innerText + ': ' : '';
138
  inner.text(label + node.validationMessage);
139
- notification.insertAfter(form.find('#submit'));
140
  })
141
  }
142
  })
@@ -326,6 +327,7 @@ function cnb_action_appearance() {
326
 
327
  function cnb_action_update_appearance(value) {
328
  const emailEle = jQuery('.cnb-action-properties-email');
 
329
  const emailExtraEle = jQuery('.cnb-action-properties-email-extra');
330
  const whatsappEle = jQuery('.cnb-action-properties-whatsapp');
331
  const whatsappExtraEle = jQuery('.cnb-action-properties-whatsapp-extra');
@@ -344,6 +346,7 @@ function cnb_action_update_appearance(value) {
344
  smsEle.hide();
345
  smsExtraEle.hide();
346
  propertiesEle.hide();
 
347
 
348
  valueEle.show();
349
  valueTextEle.prop( 'disabled', false );
@@ -368,6 +371,7 @@ function cnb_action_update_appearance(value) {
368
  case 'LINK':
369
  valuelabelEle.text('Full URL');
370
  valueTextEle.attr("required", "required");
 
371
  break
372
  case 'MAP':
373
  valuelabelEle.text('Address');
@@ -395,6 +399,7 @@ function cnb_action_update_appearance(value) {
395
  valuelabelEle.text('Action value');
396
  valueTextEle.attr("required", "required");
397
  }
 
398
  }
399
 
400
  function cnb_action_update_map_link(element) {
@@ -422,10 +427,21 @@ function cnb_hide_on_modal() {
422
  jQuery('.cnb_hide_on_modal input').removeAttr('required');
423
  }
424
 
 
 
 
425
  function show_advanced_view_only() {
426
  jQuery('.cnb_advanced_view').show();
427
  }
428
 
 
 
 
 
 
 
 
 
429
  function cnb_strip_beta_from_referrer() {
430
  const referer = jQuery('input[name="_wp_http_referer"]');
431
  if (referer && referer.val()) {
@@ -662,9 +678,8 @@ jQuery( function() {
662
  // Allow for tab switching to be dynamic
663
  cnb_init_tabs();
664
 
665
- if (typeof show_advanced_view_only_set !== 'undefined' && show_advanced_view_only_set && show_advanced_view_only_set === 1) {
666
- show_advanced_view_only()
667
- }
668
  // This needs to go AFTER the "advanced_view" check so a modal does not get additional (unneeded) "advanced" items
669
  if (typeof cnb_hide_on_modal_set !== 'undefined' && cnb_hide_on_modal_set === 1) {
670
  cnb_hide_on_modal();
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').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
84
+ jQuery('.cnb_hide_on_show_always').show();
85
 
86
  // Show Domain Timezone notice (and move to the correct place)
87
  const domainTimezoneNotice = jQuery('#cnb-notice-domain-timezone-unsupported').parent('.notice');
92
  }
93
  }
94
  }
95
+ cnb_clean_up_advanced_view();
96
  return false;
97
  }
98
 
108
  }
109
 
110
  function cnb_animate_saving() {
111
+ jQuery('.call-now-button-plugin form.cnb-validation #submit').on('click', function (event) {
112
  // if value is saving, skip...
113
  if (jQuery(this).prop('value') === 'Saving...') {
114
  event.preventDefault();
137
  const notification = jQuery('<div />', {class: "cnb-form-validation-notice notice notice-warning"}).append(inner);
138
  const label = node.labels.length > 0 ? node.labels[0].innerText + ': ' : '';
139
  inner.text(label + node.validationMessage);
140
+ notification.insertBefore(form.find('#submit'));
141
  })
142
  }
143
  })
327
 
328
  function cnb_action_update_appearance(value) {
329
  const emailEle = jQuery('.cnb-action-properties-email');
330
+ const linkEle = jQuery('.cnb-action-properties-link');
331
  const emailExtraEle = jQuery('.cnb-action-properties-email-extra');
332
  const whatsappEle = jQuery('.cnb-action-properties-whatsapp');
333
  const whatsappExtraEle = jQuery('.cnb-action-properties-whatsapp-extra');
346
  smsEle.hide();
347
  smsExtraEle.hide();
348
  propertiesEle.hide();
349
+ linkEle.hide()
350
 
351
  valueEle.show();
352
  valueTextEle.prop( 'disabled', false );
371
  case 'LINK':
372
  valuelabelEle.text('Full URL');
373
  valueTextEle.attr("required", "required");
374
+ linkEle.show()
375
  break
376
  case 'MAP':
377
  valuelabelEle.text('Address');
399
  valuelabelEle.text('Action value');
400
  valueTextEle.attr("required", "required");
401
  }
402
+ cnb_clean_up_advanced_view();
403
  }
404
 
405
  function cnb_action_update_map_link(element) {
427
  jQuery('.cnb_hide_on_modal input').removeAttr('required');
428
  }
429
 
430
+ function cnb_is_advanced_view() {
431
+ return typeof show_advanced_view_only_set !== 'undefined' && show_advanced_view_only_set && show_advanced_view_only_set === 1;
432
+ }
433
  function show_advanced_view_only() {
434
  jQuery('.cnb_advanced_view').show();
435
  }
436
 
437
+ function cnb_clean_up_advanced_view() {
438
+ const advanced_views = jQuery('.cnb_advanced_view')
439
+ advanced_views.hide()
440
+ if(cnb_is_advanced_view()) {
441
+ show_advanced_view_only()
442
+ }
443
+ }
444
+
445
  function cnb_strip_beta_from_referrer() {
446
  const referer = jQuery('input[name="_wp_http_referer"]');
447
  if (referer && referer.val()) {
678
  // Allow for tab switching to be dynamic
679
  cnb_init_tabs();
680
 
681
+ cnb_clean_up_advanced_view();
682
+
 
683
  // This needs to go AFTER the "advanced_view" check so a modal does not get additional (unneeded) "advanced" items
684
  if (typeof cnb_hide_on_modal_set !== 'undefined' && cnb_hide_on_modal_set === 1) {
685
  cnb_hide_on_modal();
resources/js/domain-upgrade.js CHANGED
@@ -107,7 +107,8 @@ function do_cnb_ajax_submit_profile() {
107
  showMessage('error', e.message);
108
  }
109
  } else {
110
- // Noop, errors are shown in the form itself
 
111
  }
112
  return false;
113
  }
107
  showMessage('error', e.message);
108
  }
109
  } else {
110
+ // Noop, show errors in the form itself
111
+ form[0].reportValidity()
112
  }
113
  return false;
114
  }
resources/js/jquery.ui.touch-punch.js ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * jQuery UI Touch Punch 1.0.8 as modified by RWAP Software
3
+ * based on original touchpunch v0.2.3 which has not been updated since 2014
4
+ *
5
+ * Updates by RWAP Software to take account of various suggested changes on the original code issues
6
+ *
7
+ * Original: https://github.com/furf/jquery-ui-touch-punch
8
+ * Copyright 2011–2014, Dave Furfero
9
+ * Dual licensed under the MIT or GPL Version 2 licenses.
10
+ *
11
+ * Fork: https://github.com/RWAP/jquery-ui-touch-punch
12
+ *
13
+ * Depends:
14
+ * jquery.ui.widget.js
15
+ * jquery.ui.mouse.js
16
+ */
17
+
18
+ (function( factory ) {
19
+ if ( typeof define === "function" && define.amd ) {
20
+
21
+ // AMD. Register as an anonymous module.
22
+ define([ "jquery", "jquery.ui" ], factory );
23
+ } else {
24
+
25
+ // Browser globals
26
+ factory( jQuery );
27
+ }
28
+ }(function ($) {
29
+
30
+ // Detect touch support - Windows Surface devices and other touch devices
31
+ $.support.mspointer = window.navigator.msPointerEnabled;
32
+ $.support.touch = ( 'ontouchstart' in document
33
+ || 'ontouchstart' in window
34
+ || window.TouchEvent
35
+ || (window.DocumentTouch && document instanceof DocumentTouch)
36
+ || navigator.maxTouchPoints > 0
37
+ || navigator.msMaxTouchPoints > 0
38
+ );
39
+
40
+ // Ignore browsers without touch or mouse support
41
+ if ((!$.support.touch && !$.support.mspointer) || !$.ui.mouse) {
42
+ return;
43
+ }
44
+
45
+ var mouseProto = $.ui.mouse.prototype,
46
+ _mouseInit = mouseProto._mouseInit,
47
+ _mouseDestroy = mouseProto._mouseDestroy,
48
+ touchHandled;
49
+
50
+ /**
51
+ * Get the x,y position of a touch event
52
+ * @param {Object} event A touch event
53
+ */
54
+ function getTouchCoords (event) {
55
+ return {
56
+ x: event.originalEvent.changedTouches[0].pageX,
57
+ y: event.originalEvent.changedTouches[0].pageY
58
+ };
59
+ }
60
+
61
+ /**
62
+ * Simulate a mouse event based on a corresponding touch event
63
+ * @param {Object} event A touch event
64
+ * @param {String} simulatedType The corresponding mouse event
65
+ */
66
+ function simulateMouseEvent (event, simulatedType) {
67
+
68
+ // Ignore multi-touch events
69
+ if (event.originalEvent.touches.length > 1) {
70
+ return;
71
+ }
72
+
73
+ // Prevent "Ignored attempt to cancel a touchmove event with cancelable=false" errors
74
+ if (event.cancelable) {
75
+ event.preventDefault();
76
+ }
77
+
78
+ var touch = event.originalEvent.changedTouches[0],
79
+ simulatedEvent = document.createEvent('MouseEvents');
80
+
81
+ // Initialize the simulated mouse event using the touch event's coordinates
82
+ simulatedEvent.initMouseEvent(
83
+ simulatedType, // type
84
+ true, // bubbles
85
+ true, // cancelable
86
+ window, // view
87
+ 1, // detail
88
+ touch.screenX, // screenX
89
+ touch.screenY, // screenY
90
+ touch.clientX, // clientX
91
+ touch.clientY, // clientY
92
+ false, // ctrlKey
93
+ false, // altKey
94
+ false, // shiftKey
95
+ false, // metaKey
96
+ 0, // button
97
+ null // relatedTarget
98
+ );
99
+
100
+ // Dispatch the simulated event to the target element
101
+ event.target.dispatchEvent(simulatedEvent);
102
+ }
103
+
104
+ /**
105
+ * Handle the jQuery UI widget's touchstart events
106
+ * @param {Object} event The widget element's touchstart event
107
+ */
108
+ mouseProto._touchStart = function (event) {
109
+
110
+ var self = this;
111
+
112
+ // Interaction time
113
+ this._startedMove = event.timeStamp;
114
+
115
+ // Track movement to determine if interaction was a click
116
+ self._startPos = getTouchCoords(event);
117
+
118
+ // Ignore the event if another widget is already being handled
119
+ if (touchHandled || !self._mouseCapture(event.originalEvent.changedTouches[0])) {
120
+ return;
121
+ }
122
+
123
+ // Set the flag to prevent other widgets from inheriting the touch event
124
+ touchHandled = true;
125
+
126
+ // Track movement to determine if interaction was a click
127
+ self._touchMoved = false;
128
+
129
+ // Simulate the mouseover event
130
+ simulateMouseEvent(event, 'mouseover');
131
+
132
+ // Simulate the mousemove event
133
+ simulateMouseEvent(event, 'mousemove');
134
+
135
+ // Simulate the mousedown event
136
+ simulateMouseEvent(event, 'mousedown');
137
+ };
138
+
139
+ /**
140
+ * Handle the jQuery UI widget's touchmove events
141
+ * @param {Object} event The document's touchmove event
142
+ */
143
+ mouseProto._touchMove = function (event) {
144
+
145
+ // Ignore event if not handled
146
+ if (!touchHandled) {
147
+ return;
148
+ }
149
+
150
+ // Interaction was moved
151
+ this._touchMoved = true;
152
+
153
+ // Simulate the mousemove event
154
+ simulateMouseEvent(event, 'mousemove');
155
+ };
156
+
157
+ /**
158
+ * Handle the jQuery UI widget's touchend events
159
+ * @param {Object} event The document's touchend event
160
+ */
161
+ mouseProto._touchEnd = function (event) {
162
+
163
+ // Ignore event if not handled
164
+ if (!touchHandled) {
165
+ return;
166
+ }
167
+
168
+ // Simulate the mouseup event
169
+ simulateMouseEvent(event, 'mouseup');
170
+
171
+ // Simulate the mouseout event
172
+ simulateMouseEvent(event, 'mouseout');
173
+
174
+ // If the touch interaction did not move, it should trigger a click
175
+ // Check for this in two ways - length of time of simulation and distance moved
176
+ // Allow for Apple Stylus to be used also
177
+ var timeMoving = event.timeStamp - this._startedMove;
178
+ if (!this._touchMoved || timeMoving < 500) {
179
+ // Simulate the click event
180
+ simulateMouseEvent(event, 'click');
181
+ } else {
182
+ var endPos = getTouchCoords(event);
183
+ if ((Math.abs(endPos.x - this._startPos.x) < 10) && (Math.abs(endPos.y - this._startPos.y) < 10)) {
184
+
185
+ // If the touch interaction did not move, it should trigger a click
186
+ if (!this._touchMoved || event.originalEvent.changedTouches[0].touchType === 'stylus') {
187
+ // Simulate the click event
188
+ simulateMouseEvent(event, 'click');
189
+ }
190
+ }
191
+ }
192
+
193
+ // Unset the flag to determine the touch movement stopped
194
+ this._touchMoved = false;
195
+
196
+ // Unset the flag to allow other widgets to inherit the touch event
197
+ touchHandled = false;
198
+ };
199
+
200
+ /**
201
+ * A duck punch of the $.ui.mouse _mouseInit method to support touch events.
202
+ * This method extends the widget with bound touch event handlers that
203
+ * translate touch events to mouse events and pass them to the widget's
204
+ * original mouse event handling methods.
205
+ */
206
+ mouseProto._mouseInit = function () {
207
+
208
+ var self = this;
209
+
210
+ // Microsoft Surface Support = remove original touch Action
211
+ if ($.support.mspointer) {
212
+ self.element[0].style.msTouchAction = 'none';
213
+ }
214
+
215
+ // Delegate the touch handlers to the widget's element
216
+ self.element.on({
217
+ touchstart: $.proxy(self, '_touchStart'),
218
+ touchmove: $.proxy(self, '_touchMove'),
219
+ touchend: $.proxy(self, '_touchEnd')
220
+ });
221
+
222
+ // Call the original $.ui.mouse init method
223
+ _mouseInit.call(self);
224
+ };
225
+
226
+ /**
227
+ * Remove the touch event handlers
228
+ */
229
+ mouseProto._mouseDestroy = function () {
230
+
231
+ var self = this;
232
+
233
+ // Delegate the touch handlers to the widget's element
234
+ self.element.off({
235
+ touchstart: $.proxy(self, '_touchStart'),
236
+ touchmove: $.proxy(self, '_touchMove'),
237
+ touchend: $.proxy(self, '_touchEnd')
238
+ });
239
+
240
+ // Call the original $.ui.mouse destroy method
241
+ _mouseDestroy.call(self);
242
+ };
243
+
244
+ }));
resources/js/preview.js CHANGED
@@ -27,16 +27,17 @@ function createButtonFromData(formData) {
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
  }
@@ -44,6 +45,7 @@ function createButtonFromData(formData) {
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 = {};
@@ -63,6 +65,16 @@ function livePreview() {
63
  parsedData.cnb = cnb_button
64
  }
65
 
 
 
 
 
 
 
 
 
 
 
66
  // Ensure it is always visible
67
  parsedData.cnb.options.displayMode = 'ALWAYS';
68
 
@@ -74,6 +86,13 @@ function livePreview() {
74
  });
75
  }
76
 
 
 
 
 
 
 
 
77
  // Ensure a Multi button / Buttonbar gets its actions
78
  if (typeof cnb_actions !== 'undefined') {
79
  if (parsedData &&
@@ -81,12 +100,50 @@ function livePreview() {
81
  && ((parsedData.actions[Object.keys(parsedData.actions)[0]]
82
  && parsedData.actions[Object.keys(parsedData.actions)[0]].actionType)
83
  || parsedData.actions.new)) {
 
84
  parsedData.actions = Object.assign(convertArrayToObject(cnb_actions, 'id'), parsedData.actions)
 
 
 
 
85
  } else {
 
86
  parsedData.actions = convertArrayToObject(cnb_actions, 'id')
87
  }
88
  }
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
  // Fix iconenabled (should be true/false instead of 0/1)
92
  if (parsedData.action_id && parsedData.actions &&
@@ -99,11 +156,6 @@ function livePreview() {
99
  parsedData.domain = cnb_domain;
100
  }
101
 
102
- // Ensure a "new" Action (in case of a new SINGLE) gets an ID to work with
103
- if (parsedData && parsedData.actions && parsedData.actions.new) {
104
- parsedData.actions.new.id = "new"
105
- }
106
-
107
  // Ensure WhatsApp works
108
  if (parsedData.action_id && parsedData.actions &&
109
  parsedData.actions[parsedData.action_id] && parsedData.actions[parsedData.action_id].actionType === 'WHATSAPP') {
@@ -116,28 +168,88 @@ function livePreview() {
116
  jQuery('.cnb-single.call-now-button').remove()
117
  jQuery('.cnb-full.call-now-button').remove()
118
  jQuery('.cnb-multi.call-now-button').remove()
119
- // And ensure that the actual WordPress editing screen does not disappear with the Button
120
- jQuery('.call-now-button').css('display', 'block');
121
 
122
- window.CNB_DATA = createButtonFromData(parsedData);
 
 
123
  if (typeof CNB !== 'undefined') {
124
- const result = CNB.render();
125
- // If there is a Multibutton, expand it
126
- const multiButton = jQuery('.cnb-multi.call-now-button .cnb-floating-main')
 
 
 
 
 
 
 
 
 
 
 
127
  if (multiButton.length > 0) {
128
  multiButton[0].dispatchEvent(new window.CustomEvent('toggle'));
129
  }
130
 
131
  // Move the result into a new special div (if found)
132
  const button = jQuery('.cnb-single.call-now-button, .cnb-full.call-now-button, .cnb-multi.call-now-button').detach()
133
- const previewContainer = jQuery('#cnb-button-preview')
134
  if (previewContainer.length > 0) {
135
  previewContainer.append(button)
136
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  return result
138
  }
139
  }
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  function initButtonEdit() {
142
  jQuery(() => {
143
  const idElement = jQuery('form.cnb-container :input[name="cnb[id]"]');
@@ -157,9 +269,12 @@ function initButtonEdit() {
157
  })
158
  }
159
 
160
-
161
  jQuery(() => {
162
- // Default, we show all actions
163
- window.cnb_ignore_schedule = true;
 
164
  initButtonEdit()
 
 
 
165
  })
27
  "name": "Live preview",
28
  "type": formData.cnb.type,
29
  "options": formData.cnb.options,
30
+ "multiButtonOptions": formData.cnb.multiButtonOptions,
31
+ "actions": Object.values(formData.actions_ordered),
32
  "conditions": []
33
  }
34
  ],
35
  "actions": Object.values(formData.actions),
36
  "conditions": [],
37
  "options": {
38
+ "debugMode": false,
39
+ "cssLocation": formData.cnb_css_root + "/css/main.css",
40
+ ...formData.options
41
  }
42
  }
43
  }
45
  /**
46
  * Via https://dev.to/afewminutesofcode/how-to-convert-an-array-into-an-object-in-javascript-25a4
47
  *
48
+ * NOTE that this does not work for "daysOfWeek", since the proper order of the array is lost.
49
  */
50
  function convertArrayToObject (array, key) {
51
  const initialValue = {};
65
  parsedData.cnb = cnb_button
66
  }
67
 
68
+ if (typeof cnb_options !== 'undefined') {
69
+ parsedData.options = cnb_options
70
+ }
71
+
72
+ // Find the correct static base URL for the Client CSS file
73
+ parsedData.cnb_css_root = 'https://static.callnowbutton.com';
74
+ if (typeof cnb_css_root !== 'undefined') {
75
+ parsedData.cnb_css_root = cnb_css_root
76
+ }
77
+
78
  // Ensure it is always visible
79
  parsedData.cnb.options.displayMode = 'ALWAYS';
80
 
86
  });
87
  }
88
 
89
+ if (!cnb_ignore_schedule) {
90
+ jQuery('#phone-preview').addClass('using-scheduler')
91
+ }
92
+
93
+ // This ensures we keep the order in the table
94
+ parsedData.actions_ordered = Object.values(parsedData.actions).map((item) => item.id)
95
+
96
  // Ensure a Multi button / Buttonbar gets its actions
97
  if (typeof cnb_actions !== 'undefined') {
98
  if (parsedData &&
100
  && ((parsedData.actions[Object.keys(parsedData.actions)[0]]
101
  && parsedData.actions[Object.keys(parsedData.actions)[0]].actionType)
102
  || parsedData.actions.new)) {
103
+ // Editing Multi & Full Button
104
  parsedData.actions = Object.assign(convertArrayToObject(cnb_actions, 'id'), parsedData.actions)
105
+
106
+ // Since we're editing, we need to do this a bit different. Also see 'new' logic below
107
+ parsedData.actions_ordered = Object.values(parsedData.actions).map((item) => item.id)
108
+
109
  } else {
110
+ // Overview Multi & Full Button
111
  parsedData.actions = convertArrayToObject(cnb_actions, 'id')
112
  }
113
  }
114
 
115
+ // Ensure a "new" Action (in case of a new SINGLE) gets an ID to work with
116
+ if (parsedData && parsedData.actions && parsedData.actions.new) {
117
+ parsedData.actions.new.id = 'new'
118
+ parsedData.actions_ordered.pop()
119
+ parsedData.actions_ordered.push('new')
120
+ }
121
+
122
+ if (typeof cnb_actions !== 'undefined') {
123
+ cnb_actions = cnb_actions.map((item) => {
124
+ item.schedule.showAlways = item.schedule.showAlways || item.schedule.showAlways === 'true'
125
+ item.schedule.daysOfWeek = item.schedule.daysOfWeek.map((daysOfWeek) =>
126
+ daysOfWeek
127
+ )
128
+ return item
129
+ });
130
+ }
131
+
132
+ // Fix: Force all booleans for schedule (and force daysOfWeek into array)
133
+ if (!cnb_ignore_schedule && parsedData.action_id && parsedData.actions &&
134
+ parsedData.actions[parsedData.action_id]) {
135
+
136
+ const showAlways = parsedData.actions[parsedData.action_id].schedule.showAlways;
137
+ parsedData.actions[parsedData.action_id].schedule.showAlways = showAlways !== "false";
138
+
139
+ const daysOfWeek = [0,1,2,3,4,5,6]
140
+ let newDaysOfWeek = []
141
+ for (const day in daysOfWeek) {
142
+ const ele = jQuery('#cnb_weekday_' + day)
143
+ newDaysOfWeek[day] = ele.prop('checked')
144
+ }
145
+ parsedData.actions[parsedData.action_id].schedule.daysOfWeek = newDaysOfWeek
146
+ }
147
 
148
  // Fix iconenabled (should be true/false instead of 0/1)
149
  if (parsedData.action_id && parsedData.actions &&
156
  parsedData.domain = cnb_domain;
157
  }
158
 
 
 
 
 
 
159
  // Ensure WhatsApp works
160
  if (parsedData.action_id && parsedData.actions &&
161
  parsedData.actions[parsedData.action_id] && parsedData.actions[parsedData.action_id].actionType === 'WHATSAPP') {
168
  jQuery('.cnb-single.call-now-button').remove()
169
  jQuery('.cnb-full.call-now-button').remove()
170
  jQuery('.cnb-multi.call-now-button').remove()
171
+ jQuery('.cnb-message-modal').remove()
 
172
 
173
+ const cnbData = createButtonFromData(parsedData);
174
+ const previewContainer = jQuery('#cnb-button-preview')
175
+ previewContainer.text('')
176
  if (typeof CNB !== 'undefined') {
177
+ // pass "false" to ensure we do NOT add the client's native observers
178
+ const result = CNB.render(cnbData, false);
179
+
180
+ // If there is a modal, trigger it
181
+ // The "parsedData.action_id" check is to ensure it does not expand on a FULL or MULTI overview page
182
+ if (parsedData.action_id) {
183
+ const whatsappButton = jQuery('.call-now-button a[data-action-type="WHATSAPP"]')
184
+ if (whatsappButton.length > 0) {
185
+ whatsappButton[0].dispatchEvent(new window.CustomEvent('toggle'));
186
+ }
187
+ }
188
+
189
+ // If there is a Multibutton, expand it (test this AFTER the modal, so we only toggle if it isn't ALREADY expanded)
190
+ const multiButton = jQuery('.cnb-multi.call-now-button:not(.cnb-expand) .cnb-floating-main')
191
  if (multiButton.length > 0) {
192
  multiButton[0].dispatchEvent(new window.CustomEvent('toggle'));
193
  }
194
 
195
  // Move the result into a new special div (if found)
196
  const button = jQuery('.cnb-single.call-now-button, .cnb-full.call-now-button, .cnb-multi.call-now-button').detach()
 
197
  if (previewContainer.length > 0) {
198
  previewContainer.append(button)
199
  }
200
+
201
+ // There are no actions to work with...
202
+ const previewMoment = jQuery('.cnb-preview-moment')
203
+ previewMoment.show()
204
+ if (parsedData.actions && Object.keys(parsedData.actions).length === 0) {
205
+ let message = '<h3 class="cnb_inscreen_notification">Nothing to show yet...</h3><p class="cnb_inscreen_notification">Once you add an Action, a preview of your Button will be shown here..</p>'
206
+ previewContainer.html(message)
207
+ previewMoment.hide()
208
+ } else if (result.length === 0 && !cnb_ignore_schedule) {
209
+ let message = '<h3 class="cnb_inscreen_notification">Nothing to show...</h3><p class="cnb_inscreen_notification">Following your schedule there\'s <strong>nothing to display at the current time</strong>.</p>'
210
+ message += '<p class="cnb_inscreen_notification">You can adjust the day and time at the top of this screen to preview what your visitors will see at the selected time.</p>'
211
+ previewContainer.html(message)
212
+ }
213
+
214
  return result
215
  }
216
  }
217
 
218
+ /*** Scheduler: Day and Time selector **/
219
+
220
+ function updateScheduler(day, hour, minute) {
221
+ const date = new Date()
222
+ date.setHours(hour)
223
+ date.setMinutes(minute)
224
+ date.setSeconds(0)
225
+
226
+ // Settings day is weird...
227
+ const currentDay = date.getDay();
228
+ const distance = day - currentDay;
229
+ date.setDate(date.getDate() + distance);
230
+
231
+ cnb_options.date = date.getTime()
232
+
233
+ // Trigger a rerender
234
+ livePreview()
235
+ }
236
+
237
+ function updateSchedulerCall() {
238
+ const day = jQuery('#call-now-button-preview-selector-day').val()
239
+ const hour = jQuery('#call-now-button-preview-selector-hour').val()
240
+ const minute = jQuery('#call-now-button-preview-selector-minute').val()
241
+ updateScheduler(day, hour, minute)
242
+
243
+ }
244
+
245
+ function initPreviewDayAndTimeSelector() {
246
+ jQuery('.call-now-button-preview-selector').on('change', () => {
247
+ updateSchedulerCall()
248
+ })
249
+ }
250
+ /*** END: Scheduler: Day and Time selector **/
251
+
252
+
253
  function initButtonEdit() {
254
  jQuery(() => {
255
  const idElement = jQuery('form.cnb-container :input[name="cnb[id]"]');
269
  })
270
  }
271
 
 
272
  jQuery(() => {
273
+ // This enables the scheduler (which can be disabled on a per-screen basis)
274
+ window.cnb_ignore_schedule = false;
275
+
276
  initButtonEdit()
277
+
278
+ initPreviewDayAndTimeSelector();
279
+
280
  })
resources/js/settings.js CHANGED
@@ -1,9 +1,13 @@
1
- function cnb_email_activation_reenable_fields() {
2
- const errorMessage = '<h3 class="title">Something went wrong!</h3>' +
3
- '<p>Something has gone wrong and we do not know why...</p>' +
4
- '<p>As unlikely as it is, our service might be experiencing issues (check <a href="https://status.callnowbutton.com">our status page</a>).</p>' +
5
- '<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>.';
6
- const errorDetails = '<p>Technical details:</p><p style="color:red"><span id="cnb_email_activation_details"></span></p>';
 
 
 
 
7
 
8
  jQuery('#cnb_email_activation_alternate_address').removeAttr("disabled")
9
  jQuery('#cnb_email_activation_alternate').removeAttr("disabled")
@@ -57,9 +61,15 @@ function cnb_email_activation(admin_email) {
57
 
58
  if (result && result.errors) {
59
  clearTimeout(takingTooLongTimer)
60
- cnb_email_activation_reenable_fields()
61
-
62
  const keys = Object.keys(result.errors)
 
 
 
 
 
 
 
 
63
  keys.forEach((key) => {
64
  // Create Text Nodes to ensure escaping of the content
65
  const codeMsg = document.createTextNode(key)
@@ -90,14 +100,14 @@ function cnb_email_activation_alternate() {
90
 
91
  // Note: IDE marks this as unused, but it is used by settings.php ("Delete API key")
92
  function cnb_delete_apikey() {
93
- const apiKeyField = jQuery(".call-now-button #cnb_api_key")
94
  apiKeyField.prop("type", "hidden");
95
  apiKeyField.prop("value", "delete_me");
96
  apiKeyField.removeAttr("disabled");
97
 
98
  // Ensure we use the exact verbiage of the Submit button
99
  const saveVal = apiKeyField.parents('.cnb-container').find('#submit').val();
100
- jQuery('.call-now-button #cnb_api_key_delete').replaceWith("<p>Click <strong>"+saveVal+"</strong> to disconnect your account.</p>")
101
 
102
  // Present the default behavior of this submit button (since it needs to be actioned on by the *actual* submit button
103
  return false;
1
+ function cnb_email_activation_reenable_fields(showSomethingWentWrong = true) {
2
+ let errorMessage = ''
3
+ if (showSomethingWentWrong) {
4
+ errorMessage = '<h3 class="title">Something went wrong!</h3>' +
5
+ '<p>Something has gone wrong and we do not know why...</p>' +
6
+ '<p>As unlikely as it is, our service might be experiencing issues (check <a href="https://status.callnowbutton.com">our status page</a>).</p>' +
7
+ '<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>.' +
8
+ '<p>Technical details:</p>';
9
+ }
10
+ const errorDetails = '<p style="color:red"><span id="cnb_email_activation_details"></span></p>';
11
 
12
  jQuery('#cnb_email_activation_alternate_address').removeAttr("disabled")
13
  jQuery('#cnb_email_activation_alternate').removeAttr("disabled")
61
 
62
  if (result && result.errors) {
63
  clearTimeout(takingTooLongTimer)
 
 
64
  const keys = Object.keys(result.errors)
65
+
66
+ let showSomethingWentWrong = true
67
+ if (keys.length === 1 && (keys[0] === 'CNB_EMAIL_INVALID'|| keys[0] === 'CNB_EMAIL_EMPTY')) {
68
+ // Skip showing the big block with links, since we know exactly what's going on
69
+ showSomethingWentWrong = false
70
+ }
71
+ cnb_email_activation_reenable_fields(showSomethingWentWrong)
72
+
73
  keys.forEach((key) => {
74
  // Create Text Nodes to ensure escaping of the content
75
  const codeMsg = document.createTextNode(key)
100
 
101
  // Note: IDE marks this as unused, but it is used by settings.php ("Delete API key")
102
  function cnb_delete_apikey() {
103
+ const apiKeyField = jQuery(".call-now-button-plugin #cnb_api_key")
104
  apiKeyField.prop("type", "hidden");
105
  apiKeyField.prop("value", "delete_me");
106
  apiKeyField.removeAttr("disabled");
107
 
108
  // Ensure we use the exact verbiage of the Submit button
109
  const saveVal = apiKeyField.parents('.cnb-container').find('#submit').val();
110
+ jQuery('.call-now-button-plugin #cnb_api_key_delete').replaceWith("<p>Click <strong>"+saveVal+"</strong> to disconnect your account.</p>")
111
 
112
  // Present the default behavior of this submit button (since it needs to be actioned on by the *actual* submit button
113
  return false;
resources/style/call-now-button.css CHANGED
@@ -138,6 +138,10 @@ table.form-table.nav-tab-active,
138
  padding: 2px;
139
  }
140
 
 
 
 
 
141
  #TB_window .cnb-button-name-field,
142
  .cnb-button-name-field.nav-tab-active {
143
  display: block;
@@ -191,6 +195,14 @@ table.form-table.nav-tab-only {
191
  .cnb-radio-item {
192
  margin: 10px 0;
193
  }
 
 
 
 
 
 
 
 
194
  .cnb-extra-placement {
195
  display: none;
196
  }
@@ -238,7 +250,6 @@ input[type='range'] {
238
  @media screen and (max-width: 630px) {
239
  .wp-admin #TB_window {
240
  width: auto !important;
241
- margin-left: auto !important;
242
  left: auto !important;
243
  margin-left: 10px !important;
244
  margin-right: 10px !important;
@@ -311,7 +322,7 @@ input[type='range'] {
311
  justify-content:center;
312
  }
313
  .cnb-flexbox > * {
314
- flex: 1 1 0px;
315
  }
316
  /* Pricing page */
317
  .cnb-price-plans {
@@ -344,7 +355,7 @@ input[type='range'] {
344
  .cnb-price-plans .billingprice,
345
  .cnb-price-plans .timeframe {
346
  margin: 20px 0;
347
- color:#999;
348
  font-size:80%;
349
  font-weight: normal;
350
  }
@@ -360,6 +371,42 @@ input[type='range'] {
360
  display: flex;
361
  }
362
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  .cnb-callout-bar {
364
  padding: 10px 5px 3px;
365
  border: 1px solid #c3c4c7;
@@ -437,7 +484,7 @@ input[type='range'] {
437
  h1 span.cnb_button_name {
438
  display: inline-block;
439
  color: #777;
440
- padding: 0px 5px;
441
  border-radius: 5px;
442
  border: 2px solid #999;
443
  }
@@ -461,7 +508,6 @@ label.cnb_toggle_label {
461
  width: 40px;
462
  height: 23px;
463
  background: #b3afaf;
464
- display: block;
465
  border-radius: 25px;
466
  position: relative;
467
  display: inline-block;
@@ -722,10 +768,27 @@ input[type=checkbox].cnb_day_selector:checked + label.cnb_day_selector {
722
  /*
723
  Preview phone and button placement
724
  */
725
- #phone-preview {
726
- margin-bottom: 50px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
727
  }
728
- #phone-preview .phone-outside:after {
 
729
  content: '*The preview ignores the scheduler';
730
  bottom: -25px;
731
  position: absolute;
@@ -755,8 +818,8 @@ Preview phone and button placement
755
  }
756
  #phone-preview .phone-inside {
757
  width: 320px;
758
- height: 548px;
759
- top: 84px;
760
  left: 11px;
761
  background: #fff;
762
  }
@@ -782,6 +845,54 @@ Preview phone and button placement
782
  overflow: hidden;
783
  }
784
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
785
  /*
786
  Enforce mobile viewport for previews via overwrites:
787
  */
@@ -814,6 +925,25 @@ Enforce mobile viewport for previews via overwrites:
814
  max-width: 100%;
815
  }
816
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
817
 
818
  /*
819
  Welcome banner styling
@@ -886,7 +1016,7 @@ Welcome banner styling
886
  .only-in-columns {
887
  display: none;
888
  }
889
- .call-now-button .welcome-banner-column .button {
890
  margin-top:22px !important;
891
  }
892
  }
@@ -917,6 +1047,16 @@ a.cnb-nav-tab:hover {
917
  background-color: #fff;
918
  color: #3c434a;
919
  }
 
 
 
 
 
 
 
 
 
 
920
  /* Message when email activation was initiated */
921
  input.cnb_activation_input_field {
922
  width:calc(100% - 158px);
@@ -979,14 +1119,6 @@ span.cnb_check_email_message {
979
  .cnb-scheduler-slider p:first-child {
980
  margin-bottom:1em;
981
  }
982
- .cnb-promobox-action-left #cnb_email_activation_alternate_formd:before {
983
- content: '*The Premium Free plan is for websites with up to 20k pageviews per month. More popular websites can try it out but are required to upgrade to a PRO plan once the limit gets hit.';
984
- display: block;
985
- padding-left: 12px;
986
- padding-bottom: 16px;
987
- color: #646970;
988
- }
989
-
990
 
991
  .iti__flag {
992
  background-image: url("../images/flags.png") !important;
@@ -996,4 +1128,60 @@ span.cnb_check_email_message {
996
  .iti__flag {
997
  background-image: url("../images/flags@2x.png") !important;
998
  }
999
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  padding: 2px;
139
  }
140
 
141
+ p.submit .cnb-form-validation-notice {
142
+
143
+ }
144
+
145
  #TB_window .cnb-button-name-field,
146
  .cnb-button-name-field.nav-tab-active {
147
  display: block;
195
  .cnb-radio-item {
196
  margin: 10px 0;
197
  }
198
+ .cnb-container textarea {
199
+ max-width: 400px;
200
+ width: 100%;
201
+ }
202
+ .cnb-container input::placeholder,
203
+ .cnb-container textarea::placeholder {
204
+ color: #777771;
205
+ }
206
  .cnb-extra-placement {
207
  display: none;
208
  }
250
  @media screen and (max-width: 630px) {
251
  .wp-admin #TB_window {
252
  width: auto !important;
 
253
  left: auto !important;
254
  margin-left: 10px !important;
255
  margin-right: 10px !important;
322
  justify-content:center;
323
  }
324
  .cnb-flexbox > * {
325
+ flex: 1 1 0;
326
  }
327
  /* Pricing page */
328
  .cnb-price-plans {
355
  .cnb-price-plans .billingprice,
356
  .cnb-price-plans .timeframe {
357
  margin: 20px 0;
358
+ color:#6c6c6c;
359
  font-size:80%;
360
  font-weight: normal;
361
  }
371
  display: flex;
372
  }
373
 
374
+ @media screen and (max-width:599px) {
375
+ .cnb-price-plans .cnb-plan-features {
376
+ flex-direction: column;
377
+ max-width: 400px;
378
+ padding: 0 20px;
379
+ margin: 0 auto;
380
+ }
381
+ .cnb-price-plans .cnb-plan-features ul:first-child li {
382
+ display: inline-block;
383
+ width: 30%;
384
+ }
385
+ }
386
+ @media screen and (min-width:600px) {
387
+ .cnb-price-plans .cnb-plan-features ul:first-child {
388
+ max-width:130px;
389
+ }
390
+ }
391
+ @media screen and (min-width:1100px) {
392
+ .cnb-price-plans .cnb-plan-features ul:first-child {
393
+ max-width:170px;
394
+ }
395
+ }
396
+ .cnb-checklist li:before {
397
+ content:"✓";
398
+ font-weight: bold;
399
+ margin-right:10px;
400
+ color:#2271b1;
401
+ }
402
+ .cnb-checklist {
403
+ color: #6c6c6c;
404
+ }
405
+ .cnb-checklist strong {
406
+ font-size: 15px;
407
+ color:#3c434A;
408
+ }
409
+
410
  .cnb-callout-bar {
411
  padding: 10px 5px 3px;
412
  border: 1px solid #c3c4c7;
484
  h1 span.cnb_button_name {
485
  display: inline-block;
486
  color: #777;
487
+ padding: 0 5px;
488
  border-radius: 5px;
489
  border: 2px solid #999;
490
  }
508
  width: 40px;
509
  height: 23px;
510
  background: #b3afaf;
 
511
  border-radius: 25px;
512
  position: relative;
513
  display: inline-block;
768
  /*
769
  Preview phone and button placement
770
  */
771
+ #phone-preview .phone-outside {
772
+ margin: 0 auto 50px;
773
+ }
774
+ @media (min-width:851px) and (max-width:1100px) {
775
+ #phone-preview {
776
+ transform-origin: top center;
777
+ transform: scale(0.8);
778
+ }
779
+ }
780
+ @media (max-width:450px) {
781
+ #phone-preview {
782
+ transform-origin: top center;
783
+ transform: scale(0.8);
784
+ }
785
+ }
786
+
787
+ #phone-preview.using-scheduler .phone-outside:after {
788
+ content: '*The preview is using the scheduler';
789
  }
790
+
791
+ #phone-preview .phone-outside:after {
792
  content: '*The preview ignores the scheduler';
793
  bottom: -25px;
794
  position: absolute;
818
  }
819
  #phone-preview .phone-inside {
820
  width: 320px;
821
+ height: 517px;
822
+ top: 115px;
823
  left: 11px;
824
  background: #fff;
825
  }
845
  overflow: hidden;
846
  }
847
 
848
+ .cnb-preview-moment {
849
+ background-color: #000;
850
+ color: #fff;
851
+ text-align: center;
852
+ font-weight: 600;
853
+ top: -32px;
854
+ position: absolute;
855
+ width: 100%;
856
+ left: -1px;
857
+ border: 1px solid #000;
858
+ border-bottom: 0;
859
+ }
860
+ .cnb-preview-moment select {
861
+ background: #000;
862
+ border: 0;
863
+ color: #fff;
864
+ -moz-appearance: none;
865
+ -webkit-appearance: none;
866
+ appearance: auto;
867
+ padding: 0;
868
+ font-size: small;
869
+ text-align: right;
870
+ }
871
+ .cnb-preview-moment select:hover,
872
+ .cnb-preview-moment select:focus {
873
+ color: #fff;
874
+ border-color: #fff;
875
+ outline: none;
876
+ box-shadow: 0 0 0 0;
877
+ }
878
+
879
+ #cnb-button-preview .cnb_inscreen_notification {
880
+ padding: 0 15px;
881
+ color:#666;
882
+ font-weight: 200;
883
+ }
884
+
885
+ #cnb-button-preview p.cnb_inscreen_notification {
886
+ font-size:20px;
887
+ font-weight: 200;
888
+ }
889
+ #cnb-button-preview h3.cnb_inscreen_notification {
890
+ font-weight: 300;
891
+ font-size:28px
892
+ }
893
+ #cnb-button-preview .cnb_inscreen_notification strong {
894
+ font-weight: 400;
895
+ }
896
  /*
897
  Enforce mobile viewport for previews via overwrites:
898
  */
925
  max-width: 100%;
926
  }
927
  }
928
+ @media (min-width: 450px) {
929
+ #cnb-button-preview .cnb-full.cnb-items-1,
930
+ #cnb-button-preview .cnb-full.cnb-items-2,
931
+ #cnb-button-preview .cnb-full.cnb-items-3,
932
+ #cnb-button-preview .cnb-full.cnb-items-4,
933
+ #cnb-button-preview .cnb-full.cnb-items-5 {
934
+ max-width: 100%;
935
+ left:0;
936
+ }
937
+ }
938
+
939
+ .cnb-message-modal .cnb-message-heading h3 {
940
+ color: #fff;
941
+ font-size: 18px;
942
+ font-weight: bold;
943
+ margin: 0;
944
+ line-height: 1;
945
+ padding: 10px;
946
+ }
947
 
948
  /*
949
  Welcome banner styling
1016
  .only-in-columns {
1017
  display: none;
1018
  }
1019
+ .call-now-button-plugin .welcome-banner-column .button {
1020
  margin-top:22px !important;
1021
  }
1022
  }
1047
  background-color: #fff;
1048
  color: #3c434a;
1049
  }
1050
+ @media screen and (max-width: 600px) {
1051
+ h2 .cnb-nav-tab {
1052
+ margin: 10px 10px 0 0;
1053
+ border-bottom: 1px solid #c3c4c7;
1054
+ }
1055
+ }
1056
+
1057
+
1058
+
1059
+
1060
  /* Message when email activation was initiated */
1061
  input.cnb_activation_input_field {
1062
  width:calc(100% - 158px);
1119
  .cnb-scheduler-slider p:first-child {
1120
  margin-bottom:1em;
1121
  }
 
 
 
 
 
 
 
 
1122
 
1123
  .iti__flag {
1124
  background-image: url("../images/flags.png") !important;
1128
  .iti__flag {
1129
  background-image: url("../images/flags@2x.png") !important;
1130
  }
1131
+ }
1132
+ .cnb-button-icon {
1133
+ display: flex;
1134
+ align-items: center;
1135
+ justify-content: center;
1136
+ width: 35px;
1137
+ height: 35px;
1138
+ border-radius: 3px;
1139
+ float: left;
1140
+ margin-right: 10px;
1141
+ margin-bottom: 10px;
1142
+ background-color: #ddd;
1143
+ color: #555;
1144
+ }
1145
+ .cnb-button-icon.cnb_icon_active {
1146
+ background-color: #2271b1;
1147
+ color: #fff;
1148
+ }
1149
+ .cnb-button-icon:not(.cnb_icon_active):hover {
1150
+ color: #2271b1;
1151
+ background: #d6e0e8;
1152
+ }
1153
+ .cnb-button-icon i {
1154
+ cursor: pointer;
1155
+ }
1156
+ .icon-text-options:after {
1157
+ content: '';
1158
+ display: block;
1159
+ clear: both;
1160
+ }
1161
+
1162
+ /** Below if for the sortable/draggable state of the Action overview inside a Button overview **/
1163
+ th#draggable,
1164
+ td.draggable.column-draggable{
1165
+ width: 24px;
1166
+ vertical-align: middle;
1167
+ }
1168
+ td.draggable.column-draggable {
1169
+ cursor:move;
1170
+ }
1171
+ td.draggable svg {
1172
+ fill:#929292;
1173
+ }
1174
+ .ui-state-highlight {
1175
+ height: 58px;
1176
+ background-color: #3582c4 !important;
1177
+ }
1178
+
1179
+ /* This prevents the table from shrinking, see https://stackoverflow.com/q/11146000 & https://stackoverflow.com/a/62883995*/
1180
+ .ui-sortable-helper {
1181
+ display: table;
1182
+ background-color: #fff;
1183
+ border:2px dashed #ccc;
1184
+ }
1185
+ .ui-sortable-placeholder td:first-of-type{
1186
+ display: none;
1187
+ }
src/admin/action-edit.php CHANGED
@@ -1,5 +1,11 @@
1
  <?php
2
 
 
 
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
5
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
@@ -31,6 +37,8 @@ function cnb_add_header_action_edit($action) {
31
  * via `call-now-button.php#cnb_create_action`
32
  */
33
  function cnb_admin_page_action_create_process() {
 
 
34
  $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING );
35
  if( isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $nonce, 'cnb-action-edit') ) {
36
 
@@ -40,40 +48,23 @@ function cnb_admin_page_action_create_process() {
40
  FILTER_SANITIZE_STRING,
41
  FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES);
42
  $action_id = filter_input( INPUT_POST, 'action_id', FILTER_SANITIZE_STRING );
43
- $action = $actions[$action_id];
44
 
45
  // Do the processing
46
- $cnb_cloud_notifications = array();
47
- if (isset($action['schedule']['daysOfWeek']) &&
48
- $action['schedule']['daysOfWeek'] !== null &&
49
- is_array($action['schedule']['daysOfWeek'])) {
50
- $action['schedule']['daysOfWeek'] = cnb_create_days_of_week_array($action['schedule']['daysOfWeek']);
51
- }
52
-
53
- // "Fix" the WHATSAPP values
54
- if ($action['actionType'] === 'WHATSAPP'
55
- && isset($action['actionValueWhatsappHidden'])
56
- && !empty($action['actionValueWhatsappHidden'])) {
57
- $action['actionValue'] = $action['actionValueWhatsappHidden'];
58
- }
59
-
60
- // Remove the "display" value
61
- unset($action['actionValueWhatsapp']);
62
- unset($action['actionValueWhatsappHidden']);
63
-
64
  $new_action = CnbAdminCloud::cnb_create_action( $cnb_cloud_notifications, $action );
65
  $new_action_id = $new_action->id;
66
 
67
  $bid = filter_input( INPUT_POST, 'bid', FILTER_SANITIZE_STRING );
68
  if (!empty($bid)) {
69
  // Tie this new Action to the provided Button
70
- $button = CnbAppRemote::cnb_remote_get_button( $bid );
71
  if (!($button instanceof WP_Error)) {
72
- $button->actions[] = $new_action_id;
73
- $button_array = json_decode(json_encode($button), true);
74
- CnbAdminCloud::cnb_update_button( $cnb_cloud_notifications, $button_array );
75
  } else {
76
- // TODO Add error to $cnb_cloud_notifications
 
77
  }
78
  }
79
 
@@ -129,35 +120,6 @@ function cnb_admin_page_action_create_process() {
129
  }
130
  }
131
 
132
- /**
133
- * @param $action CnbAction
134
- *
135
- * @return array
136
- */
137
- function cnb_admin_process_action($action) {
138
- if (isset($action['schedule']['daysOfWeek']) && $action['schedule']['daysOfWeek'] !== null && is_array($action['schedule']['daysOfWeek'])) {
139
- $action['schedule']['daysOfWeek'] = cnb_create_days_of_week_array($action['schedule']['daysOfWeek']);
140
- }
141
-
142
- // "Fix" the WHATSAPP values
143
- if (isset($action['actionType']) && $action['actionType'] === 'WHATSAPP'
144
- && isset($action['actionValueWhatsappHidden'])
145
- && !empty($action['actionValueWhatsappHidden'])) {
146
- $action['actionValue'] = $action['actionValueWhatsappHidden'];
147
- }
148
-
149
- // Remove the "display" value
150
- unset($action['actionValueWhatsapp']);
151
- unset($action['actionValueWhatsappHidden']);
152
-
153
- // Set the correct iconText
154
- if (isset($action['iconText']) && !empty($action['iconText'])) {
155
- // Reset the iconText based on type
156
- $action['iconText'] = cnb_actiontype_to_icontext($action['actionType']);
157
- }
158
-
159
- return $action;
160
- }
161
  /**
162
  * This is called to update the action
163
  * via `call-now-button.php#cnb_update_action`
@@ -176,7 +138,7 @@ function cnb_admin_page_action_edit_process() {
176
  $cnb_cloud_notifications = array();
177
 
178
  foreach($actions as $action) {
179
- $processed_action = cnb_admin_process_action($action);
180
  // do the processing
181
  $result = CnbAdminCloud::cnb_update_action( $cnb_cloud_notifications, $processed_action );
182
  }
@@ -309,8 +271,12 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
309
  if (empty($action->actionType)) {
310
  $action->actionType = 'PHONE';
311
  }
312
- $action->iconText = cnb_actiontype_to_icontext($action->actionType);
313
- $action->iconType = 'DEFAULT';
 
 
 
 
314
 
315
  wp_enqueue_style(CNB_SLUG . '-jquery-ui');
316
  wp_enqueue_script(CNB_SLUG . '-timezone-picker-fix');
@@ -325,21 +291,21 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
325
  $action_tz_different_from_domain = isset($domain) && !empty($domain->timezone) && $domain->timezone !== $timezone;
326
  cnb_domain_timezone_check( $domain );
327
  $timezone_set_correctly = cnb_warn_about_timezone($domain);
 
328
  ?>
329
  <input type="hidden" name="actions[<?php echo esc_attr($action->id) ?>][id]" value="<?php if ($action->id !== null && $action->id !== 'new') { echo esc_attr($action->id); } ?>" />
330
  <input type="hidden" name="actions[<?php echo esc_attr($action->id) ?>][delete]" id="cnb_action_<?php echo esc_attr($action->id) ?>_delete" value="" />
331
- <input type="hidden" name="actions[<?php echo esc_attr($action->id) ?>][iconText]" value="<?php if (isset($action->iconText)) { echo esc_attr($action->iconText); } ?>" id="cnb_action_icon_text" />
332
- <input type="hidden" name="actions[<?php echo esc_attr($action->id) ?>][iconType]" value="<?php if (isset($action->iconType)) { echo esc_attr($action->iconType); } ?>" />
333
- <?php if ($show_table) { ?>
334
- <table data-tab-name="actions" class="form-table nav-tab-active">
335
- <?php } ?>
336
  <?php if (!$button) { ?>
337
  <tr>
338
  <th colspan="2"><h2>Action Settings</h2>
339
  </th>
340
  </tr>
341
  <?php } ?>
342
-
 
 
 
343
  <tr class="cnb_hide_on_modal">
344
  <th scope="row"><label for="cnb_action_type">Button type</label></th>
345
  <td>
@@ -350,6 +316,7 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
350
  </option>
351
  <?php } ?>
352
  </select>
 
353
  </tr>
354
  <tr class="cnb-action-value cnb_hide_on_modal">
355
  <th scope="row">
@@ -373,80 +340,152 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
373
  </td>
374
  </tr>
375
  <tr class="button-text cnb_hide_on_modal">
376
- <th scope="row"><label for="buttonTextField">Button label</label></th>
 
 
 
 
377
  <td>
378
  <input id="buttonTextField" type="text" name="actions[<?php echo esc_attr($action->id) ?>][labelText]"
379
- value="<?php echo esc_attr($action->labelText) ?>" maxlength="30" placeholder="optional" />
380
- <p class="description">Leave this field empty to only show an icon.</p>
381
  </td>
382
  </tr>
383
- <tr class="cnb-action-properties-email">
384
- <th></th>
385
- <td><a class="cnb_cursor_pointer" onclick="jQuery('.cnb-action-properties-email-extra').show();jQuery(this).parent().parent().hide()">Extra email settings...</a></td>
386
- </tr>
387
- <tr class="cnb-action-properties-email-extra">
388
- <th colspan="2"><hr /></th>
389
- </tr>
390
- <tr class="cnb-action-properties-email-extra">
391
- <th scope="row"><label for="action-properties-subject">Subject</label></th>
392
- <td><input id="action-properties-subject" name="actions[<?php echo esc_attr($action->id) ?>][properties][subject]" type="text" value="<?php if (isset($action->properties) && isset($action->properties->subject)) { echo esc_attr($action->properties->subject); } ?>" /></td>
393
- </tr>
394
- <tr class="cnb-action-properties-email-extra">
395
- <th scope="row"><label for="action-properties-body">Body</label></th>
396
- <td><textarea id="action-properties-body" name="actions[<?php echo esc_attr($action->id) ?>][properties][body]" class="large-text code" rows="3"><?php if (isset($action->properties) && isset($action->properties->body)) { echo esc_textarea($action->properties->body); } ?></textarea></td>
397
-
398
- </tr>
399
- <tr class="cnb-action-properties-email-extra">
400
- <th scope="row"><label for="action-properties-cc">CC</label></th>
401
- <td><input id="action-properties-cc" name="actions[<?php echo esc_attr($action->id) ?>][properties][cc]" type="text" value="<?php if (isset($action->properties) && isset($action->properties->cc)) { echo esc_attr($action->properties->cc); } ?>" /></td>
402
- </tr>
403
- <tr class="cnb-action-properties-email-extra">
404
- <th scope="row"><label for="action-properties-bcc">BCC</label></th>
405
- <td><input id="action-properties-bcc" name="actions[<?php echo esc_attr($action->id) ?>][properties][bcc]" type="text" value="<?php if (isset($action->properties) && isset($action->properties->bcc)) { echo esc_attr($action->properties->bcc); } ?>" /></td>
406
- </tr>
407
- <tr class="cnb-action-properties-email-extra">
408
- <th colspan="2"><hr /></th>
409
- </tr>
410
 
411
- <tr class="cnb-action-properties-sms">
412
- <th></th>
413
- <td><a class="cnb_cursor_pointer" onclick="jQuery('.cnb-action-properties-sms-extra').show();jQuery(this).parent().parent().hide()">Extra SMS settings...</a></td>
414
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
415
 
416
- <tr class="cnb-action-properties-whatsapp">
417
- <th></th>
418
- <td><a class="cnb_cursor_pointer" onclick="jQuery('.cnb-action-properties-whatsapp-extra').show();jQuery(this).parent().parent().hide()">Extra Whatsapp settings...</a></td>
419
- </tr>
420
- <tr class="cnb-action-properties-whatsapp-extra cnb-action-properties-sms-extra">
421
- <th colspan="2"><hr /></th>
422
- </tr>
423
- <tr class="cnb-action-properties-whatsapp-extra cnb-action-properties-sms-extra">
424
- <th scope="row"><label for="action-properties-message">Default message</label></th>
425
- <td>
426
- <textarea id="action-properties-message" name="actions[<?php echo esc_attr($action->id) ?>][properties][message]" class="large-text code" rows="3"><?php if (isset($action->properties) && isset($action->properties->message)) { echo esc_textarea($action->properties->message); } ?></textarea>
 
 
 
 
 
 
 
 
 
 
 
 
 
427
  </td>
428
- </tr>
429
- <tr class="cnb-action-properties-whatsapp-extra cnb-action-properties-sms-extra">
430
- <th colspan="2"><hr /></th>
431
- </tr>
432
 
433
- <?php if ($button && $button->type === 'SINGLE') { ?>
434
  <tr class="cnb_hide_on_modal cnb_advanced_view">
435
  <th colspan="2">
436
- <h2>Colors for a Single button are defined on the Button, not the action.</h2>
437
- <input name="actions[<?php echo esc_attr($action->id) ?>][backgroundColor]" type="hidden" value="<?php echo esc_attr($action->backgroundColor) ?>" />
438
- <input name="actions[<?php echo esc_attr($action->id) ?>][iconColor]" type="hidden" value="<?php echo esc_attr($action->iconColor) ?>" />
439
- <!-- We always enable the icon when the type if SINGLE, original value is "<?php echo esc_attr($action->iconEnabled) ?>" -->
440
- <input name="actions[<?php echo esc_attr($action->id) ?>][iconEnabled]" type="hidden" value="1" />
441
  </th>
442
  </tr>
443
  <?php } else { ?>
444
- <tr class="cnb_hide_on_modal">
445
- <th></th>
446
- <td></td>
447
- </tr>
448
  <tr>
449
- <th scope="row"><label for="actions[<?php echo esc_attr($action->id) ?>][backgroundColor]">Background color</label></th>
450
  <td>
451
  <input name="actions[<?php echo esc_attr($action->id) ?>][backgroundColor]" id="actions[<?php echo esc_attr($action->id) ?>][backgroundColor]" type="text" value="<?php echo esc_attr($action->backgroundColor) ?>"
452
  class="cnb-color-field" data-default-color="#009900"/>
@@ -459,7 +498,7 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
459
  class="cnb-iconcolor-field" data-default-color="#FFFFFF"/>
460
  </td>
461
  </tr>
462
- <?php if ($button && $button->type === 'MULTI') { ?>
463
  <input name="actions[<?php echo esc_attr($action->id) ?>][iconEnabled]" type="hidden" value="1" />
464
  <?php } else { ?>
465
  <tr>
@@ -475,29 +514,149 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
475
  <?php } // End Multi/Buttonbar ?>
476
  <?php } ?>
477
 
478
- <tr class="cnb_hide_on_modal">
479
- <th scope="row">Show at all times</th>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
480
  <td>
481
- <?php $showAlwaysValue = $action->id === 'new' || $action->schedule->showAlways; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
482
  <input name="actions[<?php echo esc_attr($action->id) ?>][schedule][showAlways]" type="hidden" value="false" />
483
  <input id="actions_schedule_show_always" class="cnb_toggle_checkbox" onchange="return cnb_hide_on_show_always();" name="actions[<?php echo esc_attr($action->id) ?>][schedule][showAlways]" type="checkbox"
484
- value="true" <?php checked(true, $showAlwaysValue); ?>
485
- <?php if (!$timezone_set_correctly) { ?>disabled="disabled" <?php } ?>/>
486
  <label for="actions_schedule_show_always" class="cnb_toggle_label">Toggle</label>
487
- <span data-cnb_toggle_state_label="actions_schedule_show_always" class="cnb_toggle_state cnb_toggle_true">Yes <?php if (!$timezone_set_correctly) { ?>(disabled)<?php } ?></span>
488
- <?php if (!$timezone_set_correctly && $showAlwaysValue){ ?>
489
- <p class="description"><span class="dashicons dashicons-warning"></span>The scheduler is disabled because your timezone is not set correctly yet.</p>
490
- <?php } ?>
491
- <?php if (!$timezone_set_correctly && !$showAlwaysValue){ ?>
492
- <p class="description"><span class="dashicons dashicons-warning"></span>Please set your timezone before making any more changes. See the notice at the top of the page for more information.</p>
493
- <?php } ?>
494
- </td>
495
- </tr>
496
- <tr>
497
- <td colspan="2" class="cnb_padding_0">
498
  <span id="domain-timezone-notice-placeholder"></span>
499
- </td>
500
- </tr>
501
  <tr class="cnb_hide_on_show_always">
502
  <th>Set days</th>
503
  <td>
@@ -523,6 +682,8 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
523
  <input id="actions_schedule_outside_hours" class="cnb_toggle_checkbox" name="actions[<?php echo esc_attr($action->id) ?>][schedule][outsideHours]" type="checkbox"
524
  value="true" <?php checked(true, isset($action->schedule) && $action->schedule->outsideHours); ?> />
525
  <label for="actions_schedule_outside_hours" class="cnb_toggle_label">Toggle</label>
 
 
526
  </td>
527
  </tr>
528
  <tr class="cnb_hide_on_show_always">
@@ -562,9 +723,7 @@ function cnb_render_form_action($action, $button=null, $domain=null, $show_table
562
  <?php } ?>
563
  </td>
564
  </tr>
565
- <?php if ($show_table) { ?>
566
  </table>
567
- <?php } ?>
568
  <?php
569
  }
570
 
@@ -648,6 +807,7 @@ function cnb_admin_page_action_edit_render() {
648
  wp_enqueue_script(CNB_SLUG . '-form-to-json');
649
  wp_enqueue_script(CNB_SLUG . '-preview');
650
  wp_enqueue_script(CNB_SLUG . '-client');
 
651
 
652
  do_action('cnb_header');
653
 
@@ -657,20 +817,25 @@ function cnb_admin_page_action_edit_render() {
657
  <div class="cnb-body-content">
658
 
659
  <?php if ($bid !== null) { ?>
660
- <!-- These are FAKE buttons -->
661
  <h2 class="nav-tab-wrapper">
662
  <a href="<?php echo $back_to_button_link; ?>" class="cnb-nav-tab"><span class="dashicons dashicons-arrow-left-alt"></span></a>
663
- <a data-tab-name="actions" href="<?php echo cnb_action_edit_create_tab_url($button, 'basic_options') ?>"
664
- class="nav-tab nav-tab-active">Action</a>
665
  </h2>
666
  <?php } ?>
 
667
  <script>
668
  let cnb_button = <?php echo json_encode($button); ?>;
669
  let cnb_actions = <?php echo json_encode($button->actions); ?>;
670
  let cnb_domain = <?php echo json_encode($button->domain) ?>;
 
 
 
 
671
  </script>
 
672
 
673
- <form class="cnb-container" action="<?php echo $redirect_link; ?>" method="post">
674
  <input type="hidden" name="page" value="call-now-button-actions" />
675
  <input type="hidden" name="action" value="<?php echo $action->id === 'new' ? 'cnb_create_action' :'cnb_update_action' ?>" />
676
  <?php
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAdminCloud;
4
+ use cnb\admin\api\CnbAppRemote;
5
+ use cnb\admin\models\CnbAction;
6
+ use cnb\admin\models\CnbButton;
7
+ use cnb\admin\models\CnbDomain;
8
+
9
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
10
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
11
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
37
  * via `call-now-button.php#cnb_create_action`
38
  */
39
  function cnb_admin_page_action_create_process() {
40
+ $cnb_cloud_notifications = array();
41
+
42
  $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING );
43
  if( isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $nonce, 'cnb-action-edit') ) {
44
 
48
  FILTER_SANITIZE_STRING,
49
  FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES);
50
  $action_id = filter_input( INPUT_POST, 'action_id', FILTER_SANITIZE_STRING );
51
+ $action = CnbAction::fromObject($actions[$action_id]);
52
 
53
  // Do the processing
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  $new_action = CnbAdminCloud::cnb_create_action( $cnb_cloud_notifications, $action );
55
  $new_action_id = $new_action->id;
56
 
57
  $bid = filter_input( INPUT_POST, 'bid', FILTER_SANITIZE_STRING );
58
  if (!empty($bid)) {
59
  // Tie this new Action to the provided Button
60
+ $button = CnbAppRemote::cnb_remote_get_button_full( $bid );
61
  if (!($button instanceof WP_Error)) {
62
+ $button->actions[] = $new_action;
63
+
64
+ CnbAdminCloud::cnb_update_button( $cnb_cloud_notifications, $button );
65
  } else {
66
+ $message = CnbAdminCloud::cnb_admin_get_error_message( 'create', 'action', $button );
67
+ array_push( $cnb_cloud_notifications, $message );
68
  }
69
  }
70
 
120
  }
121
  }
122
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  /**
124
  * This is called to update the action
125
  * via `call-now-button.php#cnb_update_action`
138
  $cnb_cloud_notifications = array();
139
 
140
  foreach($actions as $action) {
141
+ $processed_action = CnbAction::fromObject($action);
142
  // do the processing
143
  $result = CnbAdminCloud::cnb_update_action( $cnb_cloud_notifications, $processed_action );
144
  }
271
  if (empty($action->actionType)) {
272
  $action->actionType = 'PHONE';
273
  }
274
+ if (empty($action->iconText)) {
275
+ $action->iconText = cnb_actiontype_to_icontext( $action->actionType );
276
+ }
277
+ if (empty($action->iconType)) {
278
+ $action->iconType = 'DEFAULT';
279
+ }
280
 
281
  wp_enqueue_style(CNB_SLUG . '-jquery-ui');
282
  wp_enqueue_script(CNB_SLUG . '-timezone-picker-fix');
291
  $action_tz_different_from_domain = isset($domain) && !empty($domain->timezone) && $domain->timezone !== $timezone;
292
  cnb_domain_timezone_check( $domain );
293
  $timezone_set_correctly = cnb_warn_about_timezone($domain);
294
+
295
  ?>
296
  <input type="hidden" name="actions[<?php echo esc_attr($action->id) ?>][id]" value="<?php if ($action->id !== null && $action->id !== 'new') { echo esc_attr($action->id); } ?>" />
297
  <input type="hidden" name="actions[<?php echo esc_attr($action->id) ?>][delete]" id="cnb_action_<?php echo esc_attr($action->id) ?>_delete" value="" />
298
+ <table data-tab-name="basic_options" class="form-table <?php echo cnb_is_active_tab('basic_options') ?>">
 
 
 
 
299
  <?php if (!$button) { ?>
300
  <tr>
301
  <th colspan="2"><h2>Action Settings</h2>
302
  </th>
303
  </tr>
304
  <?php } ?>
305
+ <tr class="cnb_hide_on_modal">
306
+ <th></th>
307
+ <td></td>
308
+ </tr>
309
  <tr class="cnb_hide_on_modal">
310
  <th scope="row"><label for="cnb_action_type">Button type</label></th>
311
  <td>
316
  </option>
317
  <?php } ?>
318
  </select>
319
+ </td>
320
  </tr>
321
  <tr class="cnb-action-value cnb_hide_on_modal">
322
  <th scope="row">
340
  </td>
341
  </tr>
342
  <tr class="button-text cnb_hide_on_modal">
343
+ <th scope="row"><label for="buttonTextField">Button label text <a
344
+ href="<?php echo CNB_SUPPORT; ?>wordpress/buttons/button-label/<?php cnb_utm_params("question-mark", "button-label"); ?>"
345
+ target="_blank" class="cnb-nounderscore">
346
+ <span class="dashicons dashicons-editor-help"></span>
347
+ </a></label></th>
348
  <td>
349
  <input id="buttonTextField" type="text" name="actions[<?php echo esc_attr($action->id) ?>][labelText]"
350
+ value="<?php echo esc_attr($action->labelText) ?>" maxlength="30" placeholder="Optional" />
 
351
  </td>
352
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
 
354
+ <tr class="cnb_hide_on_modal">
355
+ <th scope="row"><label for="actions-<?php echo esc_attr($action->id) ?>-iconText">Icon</label></th>
356
+ <td data-icon-text-target="cnb_action_icon_text" data-icon-type-target="cnb_action_icon_type">
357
+ <div class="icon-text-options" id="icon-text-ANCHOR">
358
+ <div class="cnb-button-icon">
359
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="anchor">anchor</i>
360
+ </div>
361
+ <div class="cnb-button-icon">
362
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="close_down">close_down</i>
363
+ </div>
364
+ </div>
365
+ <div class="icon-text-options" id="icon-text-EMAIL">
366
+ <div class="cnb-button-icon">
367
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="email">email</i>
368
+ </div>
369
+ <div class="cnb-button-icon">
370
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="mail2">mail2</i>
371
+ </div>
372
+ <div class="cnb-button-icon">
373
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="mail3">mail3</i>
374
+ </div>
375
+ </div>
376
+ <div class="icon-text-options" id="icon-text-HOURS">
377
+ <div class="cnb-button-icon">
378
+ <i class="cnb-font-icon family-material" data-icon-type="FONT_MATERIAL" data-icon-text="access_time">access_time</i>
379
+ </div>
380
+ <div class="cnb-button-icon">
381
+ <i class="cnb-font-icon family-material" data-icon-type="FONT_MATERIAL" data-icon-text="access_time_filled">access_time_filled</i>
382
+ </div>
383
+ </div>
384
+ <div class="icon-text-options" id="icon-text-LINK">
385
+ <div class="cnb-button-icon">
386
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="link">link</i>
387
+ </div>
388
+ <div class="cnb-button-icon">
389
+ <i class="cnb-font-icon family-material" data-icon-type="FONT_MATERIAL" data-icon-text="link">link</i>
390
+ </div>
391
+ <div class="cnb-button-icon">
392
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="link2">link2</i>
393
+ </div>
394
+ <div class="cnb-button-icon">
395
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="link3">link3</i>
396
+ </div>
397
+ <div class="cnb-button-icon">
398
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="link4">link4</i>
399
+ </div>
400
+ <div class="cnb-button-icon">
401
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="link5">link5</i>
402
+ </div>
403
+ </div>
404
+ <div class="icon-text-options" id="icon-text-MAP">
405
+ <div class="cnb-button-icon">
406
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="directions">directions</i>
407
+ </div>
408
+ <div class="cnb-button-icon">
409
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="directions2">directions2</i>
410
+ </div>
411
+ <div class="cnb-button-icon">
412
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="directions3">directions3</i>
413
+ </div>
414
+ <div class="cnb-button-icon">
415
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="directions4">directions4</i>
416
+ </div>
417
+ <div class="cnb-button-icon">
418
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="directions5">directions5</i>
419
+ </div>
420
+ <div class="cnb-button-icon">
421
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="directions6">directions6</i>
422
+ </div>
423
+ </div>
424
+ <div class="icon-text-options" id="icon-text-PHONE">
425
+ <div class="cnb-button-icon">
426
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="call">call</i>
427
+ </div>
428
+ <div class="cnb-button-icon">
429
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="call2">call2</i>
430
+ </div>
431
+ <div class="cnb-button-icon">
432
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="call3">call3</i>
433
+ </div>
434
+ <div class="cnb-button-icon">
435
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="call4">call4</i>
436
+ </div>
437
+ </div>
438
+ <div class="icon-text-options" id="icon-text-SMS">
439
+ <div class="cnb-button-icon">
440
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="chat">chat</i>
441
+ </div>
442
+ <div class="cnb-button-icon">
443
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="sms">sms</i>
444
+ </div>
445
+ </div>
446
+ <div class="icon-text-options" id="icon-text-WHATSAPP">
447
+ <div class="cnb-button-icon">
448
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="whatsapp">whatsapp</i>
449
+ </div>
450
+ </div>
451
 
452
+ <a
453
+ href="#"
454
+ onclick="return cnb_show_icon_text_advanced(this)"
455
+ data-icon-text="cnb_action_icon_text"
456
+ data-icon-type="cnb_action_icon_type"
457
+ data-description="cnb_action_icon_text_description"
458
+ class="cnb_advanced_view">Use a custom icon</a>
459
+ <input
460
+ type="hidden"
461
+ name="actions[<?php echo esc_attr( $action->id ) ?>][iconText]"
462
+ value="<?php if ( isset( $action->iconText ) ) {
463
+ echo esc_attr( $action->iconText );
464
+ } ?>"
465
+ id="cnb_action_icon_text" />
466
+ <input
467
+ type="hidden"
468
+ readonly="readonly"
469
+ name="actions[<?php echo esc_attr($action->id) ?>][iconType]"
470
+ value="<?php if (isset($action->iconType)) { echo esc_attr($action->iconType); } ?>"
471
+ id="cnb_action_icon_type" />
472
+ <p class="description" id="cnb_action_icon_text_description" style="display: none">
473
+ You can enter a custom Material Design font code here. Search the full library at <a
474
+ href="https://fonts.google.com/icons" target="_blank">Google Fonts</a>.<br/>
475
+ The Call Now Button uses the <code>filled</code> version of icons.</p>
476
  </td>
477
+ </tr>
 
 
 
478
 
479
+ <?php if ($button && $button->type === 'SINGLE') { ?>
480
  <tr class="cnb_hide_on_modal cnb_advanced_view">
481
  <th colspan="2">
482
+ <h3>Colors for a Single button are defined on the Presentation tab.</h3>
 
 
 
 
483
  </th>
484
  </tr>
485
  <?php } else { ?>
486
+
 
 
 
487
  <tr>
488
+ <th scope="row"><label for="actions[<?php echo esc_attr($action->id) ?>][backgroundColor]">Button color</label></th>
489
  <td>
490
  <input name="actions[<?php echo esc_attr($action->id) ?>][backgroundColor]" id="actions[<?php echo esc_attr($action->id) ?>][backgroundColor]" type="text" value="<?php echo esc_attr($action->backgroundColor) ?>"
491
  class="cnb-color-field" data-default-color="#009900"/>
498
  class="cnb-iconcolor-field" data-default-color="#FFFFFF"/>
499
  </td>
500
  </tr>
501
+ <?php if ($button && $button->type === 'MULTI') { ?>
502
  <input name="actions[<?php echo esc_attr($action->id) ?>][iconEnabled]" type="hidden" value="1" />
503
  <?php } else { ?>
504
  <tr>
514
  <?php } // End Multi/Buttonbar ?>
515
  <?php } ?>
516
 
517
+ <tr class="cnb-action-properties-whatsapp">
518
+ <th colspan="2"><hr /></th>
519
+ </tr>
520
+
521
+ <tr class="cnb-action-properties-whatsapp">
522
+ <th scope="row">Show WhatsApp modal <a
523
+ href="<?php echo CNB_SUPPORT; ?>wordpress/buttons/whatsapp-modal/<?php cnb_utm_params("question-mark", "whatsapp-modal"); ?>"
524
+ target="_blank" class="cnb-nounderscore">
525
+ <span class="dashicons dashicons-editor-help"></span>
526
+ </a></th>
527
+ <td class="appearance">
528
+ <input type="hidden" name="actions[<?php echo esc_attr($action->id) ?>][properties][whatsapp-dialog-type]" value="" />
529
+ <input id="cnb-action-modal" class="cnb_toggle_checkbox" type="checkbox" name="actions[<?php echo esc_attr($action->id) ?>][properties][whatsapp-dialog-type]"
530
+ value="popout"
531
+ <?php checked(true, isset($action->properties) && isset($action->properties->{'whatsapp-dialog-type'}) && $action->properties->{'whatsapp-dialog-type'}); ?> />
532
+ <label for="cnb-action-modal" class="cnb_toggle_label">Toggle</label>
533
+ <span data-cnb_toggle_state_label="cnb-action-modal" class="cnb_toggle_state cnb_toggle_false">(Off)</span>
534
+ <span data-cnb_toggle_state_label="cnb-action-modal" class="cnb_toggle_state cnb_toggle_true">Yes</span>
535
+ </td>
536
+ </tr>
537
+ <tr id="action-properties-message-row" class="cnb-action-properties-sms">
538
+ <th scope="row"><label for="action-properties-message">Message template <a
539
+ href="<?php echo CNB_SUPPORT; ?>wordpress/buttons/message-template/<?php cnb_utm_params("question-mark", "message-template"); ?>"
540
+ target="_blank" class="cnb-nounderscore">
541
+ <span class="dashicons dashicons-editor-help"></span>
542
+ </a></label></th>
543
+ <td>
544
+ <textarea id="action-properties-message" name="actions[<?php echo esc_attr($action->id) ?>][properties][message]" class="code" rows="3" placeholder="Optional"><?php if (isset($action->properties) && isset($action->properties->message)) { echo esc_textarea($action->properties->message); } ?></textarea>
545
+ </td>
546
+ </tr>
547
+
548
+ <tr class="cnb-action-properties-whatsapp-modal">
549
+ <th scope="row"><label for="actionWhatsappTitle">Modal title</label></th>
550
+ <td>
551
+ <input id="actionWhatsappTitle" type="text" name="actions[<?php echo esc_attr($action->id) ?>][properties][whatsapp-title]"
552
+ value="<?php if (isset($action->properties) && isset($action->properties->{'whatsapp-title'})) { echo esc_attr($action->properties->{'whatsapp-title'}); } ?>" maxlength="30" placeholder="optional" />
553
+ <p class="description">If left empty, the "Button label text" entered above will be used.</p>
554
+ </td>
555
+ </tr>
556
+ <tr class="cnb-action-properties-whatsapp-modal">
557
+ <th scope="row"><label for="actionWhatsappWelcomeMessage">Welcome message</label></th>
558
  <td>
559
+ <input id="actionWhatsappWelcomeMessage" type="text" name="actions[<?php echo esc_attr($action->id) ?>][properties][whatsapp-welcomeMessage]"
560
+ value="<?php if (isset($action->properties) && isset($action->properties->{'whatsapp-welcomeMessage'})) { echo esc_attr($action->properties->{'whatsapp-welcomeMessage'}); } ?>" placeholder="How can we help?" />
561
+ </td>
562
+ </tr>
563
+ <tr class="cnb-action-properties-whatsapp-modal">
564
+ <th scope="row"><label for="actionWhatsappPlaceholderMessage">Placeholder message</label></th>
565
+ <td>
566
+ <input id="actionWhatsappPlaceholderMessage" type="text" name="actions[<?php echo esc_attr($action->id) ?>][properties][whatsapp-placeholderMessage]"
567
+ value="<?php if (isset($action->properties) && isset($action->properties->{'whatsapp-placeholderMessage'})) { echo esc_attr($action->properties->{'whatsapp-placeholderMessage'}); } ?>" placeholder="Type a message" />
568
+ </td>
569
+ </tr>
570
+ <tr class="cnb-action-properties-email">
571
+ <th colspan="2"><hr /></th>
572
+ </tr>
573
+ <tr class="cnb-action-properties-email">
574
+ <th scope="row"><label for="action-properties-subject">Subject</label></th>
575
+ <td><input placeholder="Optional" id="action-properties-subject" name="actions[<?php echo esc_attr($action->id) ?>][properties][subject]" type="text" value="<?php if (isset($action->properties) && isset($action->properties->subject)) { echo esc_attr($action->properties->subject); } ?>" /></td>
576
+ </tr>
577
+ <tr class="cnb-action-properties-email">
578
+ <th scope="row"><label for="action-properties-body">Message template <a
579
+ href="<?php echo CNB_SUPPORT; ?>wordpress/buttons/message-template/<?php cnb_utm_params("question-mark", "message-template"); ?>"
580
+ target="_blank" class="cnb-nounderscore">
581
+ <span class="dashicons dashicons-editor-help"></span>
582
+ </a></label></th>
583
+ <td><textarea placeholder="Optional" id="action-properties-body" name="actions[<?php echo esc_attr($action->id) ?>][properties][body]" class="large-text code" rows="3"><?php if (isset($action->properties) && isset($action->properties->body)) { echo esc_textarea($action->properties->body); } ?></textarea></td>
584
+
585
+ </tr>
586
+ <tr class="cnb-action-properties-email">
587
+ <th scope="row"><label for="action-properties-cc">CC</label></th>
588
+ <td><input placeholder="Optional" id="action-properties-cc" name="actions[<?php echo esc_attr($action->id) ?>][properties][cc]" type="text" value="<?php if (isset($action->properties) && isset($action->properties->cc)) { echo esc_attr($action->properties->cc); } ?>" /></td>
589
+ </tr>
590
+ <tr class="cnb-action-properties-email">
591
+ <th scope="row"><label for="action-properties-bcc">BCC</label></th>
592
+ <td><input placeholder="Optional" id="action-properties-bcc" name="actions[<?php echo esc_attr($action->id) ?>][properties][bcc]" type="text" value="<?php if (isset($action->properties) && isset($action->properties->bcc)) { echo esc_attr($action->properties->bcc); } ?>" /></td>
593
+ </tr>
594
+ <tr class="cnb-action-properties-link">
595
+ <th colspan="2"><hr /></th>
596
+ </tr>
597
+ <tr class="cnb-action-properties-link cnb_hide_on_modal">
598
+ <th scope="row"><label for="actionLinkTargetSelect">Open link in</label></th>
599
+ <td>
600
+ <?php $action_link_target = isset($action->properties) && isset($action->properties->{'link-target'}) ? $action->properties->{'link-target'} : null; ?>
601
+ <select id="actionLinkTargetSelect" name="actions[<?php echo esc_attr($action->id) ?>][properties][link-target]">
602
+ <option value="_blank" <?php selected('_blank', $action_link_target) ?>>New window</option>
603
+ <option value="_self" <?php selected('_self', $action_link_target) ?>>Current window</option>
604
+ </select>
605
+ </td>
606
+ </tr>
607
+ <tr class="cnb-action-properties-link cnb_advanced_view cnb_hide_on_modal">
608
+ <th scope="row"><label for="actionLinkDownload">Download</label></th>
609
+ <td>
610
+ <?php
611
+ $action_download_enabled = isset($action->properties) && isset($action->properties->{'link-download-enabled'}) ? $action->properties->{'link-download-enabled'} : false;
612
+ $action_download_value = isset($action->properties) && isset($action->properties->{'link-download'}) ? $action->properties->{'link-download'} : null;
613
+ ?>
614
+ <p><input type="hidden" name="actions[<?php echo esc_attr($action->id) ?>][properties][link-download-enabled]" value="0" />
615
+ <input id="cnb-action-link-download-enabled" class="cnb_toggle_checkbox" type="checkbox" name="actions[<?php echo esc_attr($action->id) ?>][properties][link-download-enabled]" value="true" <?php checked(true, $action_download_enabled); ?>>
616
+ <label for="cnb-action-link-download-enabled" class="cnb_toggle_label">Toggle</label>
617
+ <span data-cnb_toggle_state_label="cnb-action-link-download-enabled" class="cnb_toggle_state cnb_toggle_false">(No)</span>
618
+ <span data-cnb_toggle_state_label="cnb-action-link-download-enabled" class="cnb_toggle_state cnb_toggle_true">Yes</span></p>
619
+ <p><input id="actionLinkDownload" type="text" name="actions[<?php echo esc_attr($action->id) ?>][properties][link-download]"
620
+ value="<?php echo esc_attr($action_download_value) ?>" placeholder="Download filename" /></p>
621
+ </td>
622
+ </tr>
623
+ </table>
624
+ <table data-tab-name="scheduler" class="form-table <?php echo cnb_is_active_tab('scheduler'); ?>">
625
+ <tr class="cnb_hide_on_modal">
626
+ <th></th>
627
+ <td></td>
628
+ </tr>
629
+ <tr class="cnb_hide_on_modal">
630
+ <th scope="row">Show at all times</th>
631
+ <td>
632
+ <?php $showAlwaysValue = $action->id === 'new' || $action->schedule->showAlways; ?>
633
+ <?php if ($timezone_set_correctly) { ?>
634
+ <input name="actions[<?php echo esc_attr($action->id) ?>][schedule][showAlways]" type="hidden" value="false" />
635
+ <input id="actions_schedule_show_always" class="cnb_toggle_checkbox" onchange="return cnb_hide_on_show_always();" name="actions[<?php echo esc_attr($action->id) ?>][schedule][showAlways]" type="checkbox"
636
+ value="true" <?php checked(true, $showAlwaysValue); ?>
637
+ />
638
+ <label for="actions_schedule_show_always" class="cnb_toggle_label">Toggle</label>
639
+ <span data-cnb_toggle_state_label="actions_schedule_show_always" class="cnb_toggle_state cnb_toggle_true">Yes</span>
640
+ <span data-cnb_toggle_state_label="actions_schedule_show_always" class="cnb_toggle_state cnb_toggle_false">(No)</span>
641
+ <?php } else if ( $showAlwaysValue ){ ?>
642
+ <p class="description"><span class="dashicons dashicons-warning"></span>The scheduler is disabled because your timezone is not set correctly yet.</p>
643
+ <input id="actions_schedule_show_always" class="cnb_toggle_checkbox" name="actions[<?php echo esc_attr($action->id) ?>][schedule][showAlways]" type="checkbox" value="true" checked="checked" />
644
+ <?php } else { ?>
645
  <input name="actions[<?php echo esc_attr($action->id) ?>][schedule][showAlways]" type="hidden" value="false" />
646
  <input id="actions_schedule_show_always" class="cnb_toggle_checkbox" onchange="return cnb_hide_on_show_always();" name="actions[<?php echo esc_attr($action->id) ?>][schedule][showAlways]" type="checkbox"
647
+ value="true" />
 
648
  <label for="actions_schedule_show_always" class="cnb_toggle_label">Toggle</label>
649
+ <span data-cnb_toggle_state_label="actions_schedule_show_always" class="cnb_toggle_state cnb_toggle_true">Yes</span>
650
+ <span data-cnb_toggle_state_label="actions_schedule_show_always" class="cnb_toggle_state cnb_toggle_false">(No)</span>
651
+ <p class="description"><span class="dashicons dashicons-warning"></span>Please set your timezone before making any more changes. See the notice at the top of the page for more information.</p>
652
+ <?php } ?>
653
+ </td>
654
+ </tr>
655
+ <tr>
656
+ <td colspan="2" class="cnb_padding_0">
 
 
 
657
  <span id="domain-timezone-notice-placeholder"></span>
658
+ </td>
659
+ </tr>
660
  <tr class="cnb_hide_on_show_always">
661
  <th>Set days</th>
662
  <td>
682
  <input id="actions_schedule_outside_hours" class="cnb_toggle_checkbox" name="actions[<?php echo esc_attr($action->id) ?>][schedule][outsideHours]" type="checkbox"
683
  value="true" <?php checked(true, isset($action->schedule) && $action->schedule->outsideHours); ?> />
684
  <label for="actions_schedule_outside_hours" class="cnb_toggle_label">Toggle</label>
685
+ <span data-cnb_toggle_state_label="actions_schedule_outside_hours" class="cnb_toggle_state cnb_toggle_true">Active</span>
686
+ <span data-cnb_toggle_state_label="actions_schedule_outside_hours" class="cnb_toggle_state cnb_toggle_false">(Off)</span>
687
  </td>
688
  </tr>
689
  <tr class="cnb_hide_on_show_always">
723
  <?php } ?>
724
  </td>
725
  </tr>
 
726
  </table>
 
727
  <?php
728
  }
729
 
807
  wp_enqueue_script(CNB_SLUG . '-form-to-json');
808
  wp_enqueue_script(CNB_SLUG . '-preview');
809
  wp_enqueue_script(CNB_SLUG . '-client');
810
+ wp_enqueue_script(CNB_SLUG . '-action-edit');
811
 
812
  do_action('cnb_header');
813
 
817
  <div class="cnb-body-content">
818
 
819
  <?php if ($bid !== null) { ?>
 
820
  <h2 class="nav-tab-wrapper">
821
  <a href="<?php echo $back_to_button_link; ?>" class="cnb-nav-tab"><span class="dashicons dashicons-arrow-left-alt"></span></a>
822
+ <a data-tab-name="basic_options" href="<?php echo cnb_action_edit_create_tab_url($button, 'basic_options') ?>" class="nav-tab <?php echo cnb_is_active_tab('basic_options') ?>">Basics</a>
823
+ <a data-tab-name="scheduler" href="<?php echo cnb_action_edit_create_tab_url($button, 'scheduler') ?>" class="nav-tab <?php echo cnb_is_active_tab('scheduler') ?>">Scheduling</a>
824
  </h2>
825
  <?php } ?>
826
+ <?php if($button) { ?>
827
  <script>
828
  let cnb_button = <?php echo json_encode($button); ?>;
829
  let cnb_actions = <?php echo json_encode($button->actions); ?>;
830
  let cnb_domain = <?php echo json_encode($button->domain) ?>;
831
+ let cnb_css_root = '<?php echo esc_js(CnbAppRemote::cnb_get_static_base()) ?>';
832
+ let cnb_options = <?php echo json_encode(new stdClass()) ?>;
833
+ // disable scheduler for the action-edit screen
834
+ let cnb_ignore_schedule = true
835
  </script>
836
+ <?php } ?>
837
 
838
+ <form class="cnb-container cnb-validation" action="<?php echo $redirect_link; ?>" method="post">
839
  <input type="hidden" name="page" value="call-now-button-actions" />
840
  <input type="hidden" name="action" value="<?php echo $action->id === 'new' ? 'cnb_create_action' :'cnb_update_action' ?>" />
841
  <?php
src/admin/action-overview.php CHANGED
@@ -1,5 +1,9 @@
1
  <?php
2
 
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
5
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
@@ -72,13 +76,18 @@ class Cnb_Action_List_Table extends WP_List_Table {
72
  global $cnb_options;
73
  $columns = array(
74
  'cb' => '<input type="checkbox">',
 
75
  'id' => __('ID'),
76
  'actionType' => __('Type'),
77
  'actionValue' => __('Value'),
78
  'labelText' => __('Label'),
79
  'schedule' => __('Schedule'),
80
  );
81
- if ($this->button) { unset($columns['cb']); }
 
 
 
 
82
 
83
  if ($cnb_options['advanced_view'] === 1) {
84
  $columns['actionButton'] = __('Button');
@@ -87,6 +96,11 @@ class Cnb_Action_List_Table extends WP_List_Table {
87
  }
88
 
89
  function get_sortable_columns() {
 
 
 
 
 
90
  return array(
91
  'actionType' => array('actionType', false),
92
  'actionValue' => array('actionValue', false),
@@ -111,7 +125,9 @@ class Cnb_Action_List_Table extends WP_List_Table {
111
 
112
  /* -- Ordering parameters -- */
113
  //Parameters that are going to be used to order the result
114
- usort( $data, array( &$this, 'sort_data' ) );
 
 
115
 
116
  /* -- Pagination parameters -- */
117
  //Number of elements in your table?
@@ -154,6 +170,13 @@ class Cnb_Action_List_Table extends WP_List_Table {
154
  function column_default( $item, $column_name ) {
155
  switch( $column_name ) {
156
  case 'id':
 
 
 
 
 
 
 
157
  case 'actionValue':
158
  case 'labelText':
159
  return !empty($item[$column_name]) ? esc_html($item[$column_name]) : '<em>No value</em>';
@@ -180,7 +203,7 @@ class Cnb_Action_List_Table extends WP_List_Table {
180
  }
181
  }
182
  }
183
- break;
184
  default:
185
  return '<em>Unknown column ' .esc_html($column_name) . '</em>';
186
  }
@@ -319,12 +342,12 @@ class Cnb_Action_List_Table extends WP_List_Table {
319
  $hour = explode(':', $start)[0];
320
  $min = explode(':', $start)[1];
321
  $date->setTime($hour, $min);
322
- $wp_start = $date->format($wp_time_format);
323
 
324
  $hour = explode(':', $stop)[0];
325
  $min = explode(':', $stop)[1];
326
  $date->setTime($hour, $min);
327
- $wp_stop = $date->format($wp_time_format);
328
 
329
  // print time
330
  $time = '';
@@ -347,7 +370,7 @@ class Cnb_Action_List_Table extends WP_List_Table {
347
  function column_actionType($item) {
348
  $column_name = 'actionType';
349
  $bid = $this->button !== null ? $this->button->id : null;
350
- $tab = $this->button !== null ? 'actions' : null;
351
 
352
  $actions = array();
353
  // Let's build a link
@@ -416,8 +439,9 @@ class Cnb_Action_List_Table extends WP_List_Table {
416
  switch ($this->current_action()) {
417
  case 'delete':
418
  foreach ($actionIds as $actionId) {
419
- $action = array('id' => $actionId);
420
- CnbAppRemote::cnb_remote_delete_action( $action );
 
421
  }
422
  CnbAdminNotices::get_instance()->renderSuccess(count($actionIds) . ' Action(s) deleted.');
423
  break;
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAdminCloud;
4
+ use cnb\admin\api\CnbAppRemote;
5
+ use cnb\admin\models\CnbAction;
6
+
7
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
8
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
9
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
76
  global $cnb_options;
77
  $columns = array(
78
  'cb' => '<input type="checkbox">',
79
+ 'draggable' => '',
80
  'id' => __('ID'),
81
  'actionType' => __('Type'),
82
  'actionValue' => __('Value'),
83
  'labelText' => __('Label'),
84
  'schedule' => __('Schedule'),
85
  );
86
+ if ($this->button) {
87
+ unset($columns['cb']);
88
+ } else {
89
+ unset($columns['draggable']);
90
+ }
91
 
92
  if ($cnb_options['advanced_view'] === 1) {
93
  $columns['actionButton'] = __('Button');
96
  }
97
 
98
  function get_sortable_columns() {
99
+ // No sorting for the actions list for buttons
100
+ // since they are returned in /actual/ order they appear in, we do not allow changing
101
+ // that via sortable columns
102
+ if ($this->button) return array();
103
+
104
  return array(
105
  'actionType' => array('actionType', false),
106
  'actionValue' => array('actionValue', false),
125
 
126
  /* -- Ordering parameters -- */
127
  //Parameters that are going to be used to order the result
128
+ if (key_exists('orderby', $_GET)) {
129
+ usort($data, array(&$this, 'sort_data'));
130
+ }
131
 
132
  /* -- Pagination parameters -- */
133
  //Number of elements in your table?
170
  function column_default( $item, $column_name ) {
171
  switch( $column_name ) {
172
  case 'id':
173
+ // Also add the ID input
174
+ $id = '<input type="hidden" name="actions[][id]" value="'. esc_attr($item['id']) . '" />';
175
+ $value = !empty($item[$column_name]) ? esc_html($item[$column_name]) : '<em>No value</em>';
176
+
177
+ return $id . $value;
178
+ case 'draggable':
179
+ return '<svg height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></svg>';
180
  case 'actionValue':
181
  case 'labelText':
182
  return !empty($item[$column_name]) ? esc_html($item[$column_name]) : '<em>No value</em>';
203
  }
204
  }
205
  }
206
+ return '<em>N/A</em>';
207
  default:
208
  return '<em>Unknown column ' .esc_html($column_name) . '</em>';
209
  }
342
  $hour = explode(':', $start)[0];
343
  $min = explode(':', $start)[1];
344
  $date->setTime($hour, $min);
345
+ $wp_start = date_i18n($wp_time_format, $date->getTimestamp());
346
 
347
  $hour = explode(':', $stop)[0];
348
  $min = explode(':', $stop)[1];
349
  $date->setTime($hour, $min);
350
+ $wp_stop = date_i18n($wp_time_format, $date->getTimestamp());
351
 
352
  // print time
353
  $time = '';
370
  function column_actionType($item) {
371
  $column_name = 'actionType';
372
  $bid = $this->button !== null ? $this->button->id : null;
373
+ $tab = $this->button !== null ? 'basic_options' : null;
374
 
375
  $actions = array();
376
  // Let's build a link
439
  switch ($this->current_action()) {
440
  case 'delete':
441
  foreach ($actionIds as $actionId) {
442
+ $cnbAction = new CnbAction();
443
+ $cnbAction->id = $actionId;
444
+ CnbAppRemote::cnb_remote_delete_action( $cnbAction );
445
  }
446
  CnbAdminNotices::get_instance()->renderSuccess(count($actionIds) . ' Action(s) deleted.');
447
  break;
src/admin/admin-ajax.php CHANGED
@@ -1,4 +1,8 @@
1
  <?php
 
 
 
 
2
  require_once dirname( __FILE__ ) . '/api/CnbAppRemotePayment.php';
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/action-overview.php';
@@ -63,7 +67,7 @@ function cnb_admin_button_delete_actions() {
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
 
@@ -81,14 +85,17 @@ function cnb_admin_settings_profile_save() {
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
 
1
  <?php
2
+
3
+ use cnb\admin\api\CnbAppRemote;
4
+ use cnb\admin\api\CnbAppRemotePayment;
5
+
6
  require_once dirname( __FILE__ ) . '/api/CnbAppRemotePayment.php';
7
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
8
  require_once dirname( __FILE__ ) . '/action-overview.php';
67
  // We sent both the result and an updated button so the preview code can re-render the button
68
  $return = array(
69
  'result' => $result,
70
+ 'button' => CnbAppRemote::cnb_remote_get_button_full( $button_id )->toArray(false)
71
  );
72
  wp_send_json($return);
73
 
85
  add_action('wp_ajax_cnb_settings_profile_save', 'cnb_admin_settings_profile_save');
86
 
87
  function cnb_admin_cnb_email_activation() {
 
88
  $admin_url = esc_url( admin_url('admin.php') );
89
 
90
  $custom_email = trim(filter_input( INPUT_POST, 'admin_email', FILTER_SANITIZE_STRING ));
91
+ if (is_email($custom_email)) {
92
+ $data = CnbAppRemote::cnb_remote_email_activation( $custom_email, $admin_url );
93
+ } else {
94
+ $data = new WP_Error('CNB_EMAIL_INVALID', __('Please enter a valid e-mail address.'));
95
+ if (empty($custom_email)) {
96
+ $data = new WP_Error('CNB_EMAIL_EMPTY', __('Please enter a valid e-mail address.'));
97
+ }
98
  }
 
99
  wp_send_json($data);
100
  }
101
 
src/admin/api/CnbAdminCloud.php CHANGED
@@ -1,4 +1,14 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
2
 
3
  require_once dirname( __FILE__ ) . '/../../utils/CnbAdminNotices.class.php';
4
 
@@ -75,41 +85,40 @@ class CnbAdminCloud {
75
  }
76
 
77
  /**
78
- * @param $button array
79
- * @param $actions array Should ONLY contain Ids, not full objects
80
- * @param $conditions array
81
  *
82
  * @return array
83
  */
84
  public static function cnb_update_button_and_conditions( $button, $actions = array(), $conditions = array() ) {
85
  $cnb_cloud_notifications = array();
86
- // No need to update the Condition, this is done via the Button for now
87
 
88
- // 2: Update the Condition(s)
89
  $new_conditions = array();
90
  foreach ( $conditions as $condition ) {
91
- if ( $condition['delete'] === 'true' ) {
92
  // 2.1 Delete now unused Conditions
93
  CnbAppRemote::cnb_remote_delete_condition( $condition );
94
- } else if ( $condition['id'] === '' ) {
95
  // 2.2 Create new Conditions
96
  $new_conditions[] = self::cnb_create_condition( $cnb_cloud_notifications, $condition );
97
- } else if ( $condition['id'] !== '' ) {
98
  // 2.3 Update existing Conditions
99
  $new_conditions[] = self::cnb_update_condition( $cnb_cloud_notifications, $condition );
100
  }
101
  }
102
 
103
- // 3: Update the Action(s)
104
  $new_actions = array();
105
  foreach ( $actions as $action ) {
106
- if ( isset( $action['delete'] ) && $action['delete'] === 'true' ) {
107
  // 2.1 Delete now unused Action
108
  CnbAppRemote::cnb_remote_delete_action( $action );
109
- } else if ( $action['id'] === '' ) {
110
  // 2.2 Create new Action
111
  $new_actions[] = self::cnb_create_action( $cnb_cloud_notifications, $action );
112
- } else if ( $action['id'] !== '' && isset( $action['actionType'] ) ) {
113
  // 2.3 Update existing Action (but only if it is provided fully, which is why "actionType" is tested for presence
114
  $new_actions[] = self::cnb_update_action( $cnb_cloud_notifications, $action );
115
  } else {
@@ -118,34 +127,24 @@ class CnbAdminCloud {
118
  }
119
  }
120
 
121
- // 4: Update the Button
122
- self::cnb_update_button_actions_conditions( $cnb_cloud_notifications, $button, $new_actions, $new_conditions );
 
 
 
 
123
 
124
  return $cnb_cloud_notifications;
125
  }
126
 
127
  /**
128
  * @param $cnb_cloud_notifications
129
- * @param $button array Single Button object
130
- * @param $actions array Action objects
131
- * @param $conditions array Condition objects
132
  *
133
  * @return mixed|WP_Error
134
  */
135
- public static function cnb_update_button_actions_conditions( &$cnb_cloud_notifications, $button, $actions, $conditions ) {
136
- $result = CnbAppRemote::cnb_remote_update_wp_button( $button, $actions, $conditions );
137
- if ( $result instanceof WP_Error ) {
138
- $message = self::cnb_admin_get_error_message( 'update', 'button', $result );
139
- } else {
140
- $message = self::cnb_admin_get_success_message( 'updated', 'button', $result->name );
141
- }
142
- array_push( $cnb_cloud_notifications, $message );
143
-
144
- return $result;
145
- }
146
-
147
- public static function cnb_update_button( &$cnb_cloud_notifications, $button ) {
148
- $result = CnbAppRemote::cnb_remote_update_button( $button );
149
  if ( $result instanceof WP_Error ) {
150
  $message = self::cnb_admin_get_error_message( 'update', 'button', $result );
151
  } else {
@@ -156,6 +155,12 @@ class CnbAdminCloud {
156
  return $result;
157
  }
158
 
 
 
 
 
 
 
159
  public static function cnb_update_action( &$cnb_cloud_notifications, $action ) {
160
  $result = CnbAppRemote::cnb_remote_update_action( $action );
161
  if ( $result instanceof WP_Error ) {
@@ -166,6 +171,12 @@ class CnbAdminCloud {
166
  return $result;
167
  }
168
 
 
 
 
 
 
 
169
  public static function cnb_update_condition( &$cnb_cloud_notifications, $condition ) {
170
  $result = CnbAppRemote::cnb_remote_update_condition( $condition );
171
  if ( $result instanceof WP_Error ) {
@@ -190,7 +201,7 @@ class CnbAdminCloud {
190
 
191
  /**
192
  * @param $cnb_cloud_notifications
193
- * @param $button array Single Button object
194
  *
195
  * @return CnbButton|WP_Error The created Button
196
  */
@@ -250,7 +261,9 @@ class CnbAdminCloud {
250
  * @return mixed|WP_Error
251
  */
252
  public static function cnb_delete_action( &$cnb_cloud_notifications, $action_id ) {
253
- $result = CnbAppRemote::cnb_remote_delete_action( array( 'id' => $action_id ) );
 
 
254
  if ( $result instanceof WP_Error ) {
255
  $message = self::cnb_admin_get_error_message( 'delete', 'action', $result, 'with ID <code>' . esc_html( $action_id ) . '</code>' );
256
  array_push( $cnb_cloud_notifications, $message );
@@ -266,7 +279,9 @@ class CnbAdminCloud {
266
  * @return mixed|WP_Error
267
  */
268
  public static function cnb_delete_condition( &$cnb_cloud_notifications, $condition_id ) {
269
- $result = CnbAppRemote::cnb_remote_delete_condition( array( 'id' => $condition_id ) );
 
 
270
  if ( $result instanceof WP_Error ) {
271
  $message = self::cnb_admin_get_error_message( 'delete', 'condition', $result, 'with ID <code>' . esc_html( $condition_id ) . '</code>' );
272
  array_push( $cnb_cloud_notifications, $message );
@@ -305,6 +320,12 @@ class CnbAdminCloud {
305
  return $result;
306
  }
307
 
 
 
 
 
 
 
308
  public static function cnb_create_action( &$cnb_cloud_notifications, $action ) {
309
  $result = CnbAppRemote::cnb_remote_create_action( $action );
310
  if ( $result instanceof WP_Error ) {
@@ -317,6 +338,12 @@ class CnbAdminCloud {
317
  return $result;
318
  }
319
 
 
 
 
 
 
 
320
  public static function cnb_create_condition( &$cnb_cloud_notifications, $condition ) {
321
  $result = CnbAppRemote::cnb_remote_create_condition( $condition );
322
  if ( $result instanceof WP_Error ) {
@@ -385,7 +412,7 @@ class CnbAdminCloud {
385
  * @param $extra_info string Allows for some extra details to be added to the error message.
386
  * This contains HTML and should be escaped already when passed through.
387
  *
388
- * @return CnbNotice A Wordpress error notice with all details filled out (Content has been escaped already)
389
  */
390
  public static function cnb_admin_get_error_message( $verb, $type, $result, $extra_info = '' ) {
391
  $error_details = self::cnb_admin_get_error_message_details( $result );
@@ -543,45 +570,58 @@ class CnbAdminCloud {
543
  return $cnb_cloud_notifications;
544
  }
545
 
 
 
 
 
 
 
 
 
546
  public static function cnb_wp_create_action( &$cnb_cloud_notifications, $options ) {
547
- $action = array(
548
- 'actionType' => 'PHONE',
549
- 'actionValue' => $options['number'],
550
- 'labelText' => $options['text'],
551
- 'backgroundColor' => $options['color'],
552
- 'iconColor' => $options['iconcolor'],
553
- 'iconEnabled' => isset( $options['hideIcon'] ) && $options['hideIcon'] == 1 ? false : true,
554
- 'schedule' => array(
555
- 'showAlways' => true
556
- )
557
- );
558
 
559
  return self::cnb_create_action( $cnb_cloud_notifications, $action );
560
  }
561
 
 
 
 
 
 
 
 
 
562
  public static function cnb_wp_create_condition( &$cnb_cloud_notifications, $options ) {
563
  // frontpage (if == 1, condition: don't show on /)
564
  if ( ! isset( $options['frontpage'] ) || $options['frontpage'] != 1 ) {
565
  return null;
566
  }
567
 
568
- $condition = array(
569
- 'conditionType' => 'URL',
570
- 'filterType' => 'EXCLUDE',
571
- 'matchType' => 'EXACT',
572
- 'matchValue' => get_home_url(),
573
- );
574
 
575
  return self::cnb_create_condition( $cnb_cloud_notifications, $condition );
576
  }
577
 
578
  /**
579
  *
580
- * @param $cnb_cloud_notifications CnbNotice[]
581
- * @param $domain
582
- * @param $action
583
- * @param $condition
584
- * @param $options
585
  *
586
  * @return CnbButton|WP_Error
587
  */
@@ -631,14 +671,12 @@ class CnbAdminCloud {
631
 
632
  $conditions = array();
633
  if ( $condition != null && isset( $condition->id ) ) {
634
- $condition_array = json_decode( json_encode( $condition ), true );
635
- array_push( $conditions, $condition_array );
636
  }
637
 
638
  $actions = array();
639
  if ( $action != null && isset( $action->id ) ) {
640
- $action_array = json_decode( json_encode( $action ), true );
641
- array_push( $actions, $action_array );
642
 
643
  $iconBackgroundColor = $action->backgroundColor;
644
  $iconColor = $action->iconColor;
@@ -647,19 +685,18 @@ class CnbAdminCloud {
647
  // 'active' is based on the status of enabled and if the number has a value
648
  $has_a_number = !empty($action->actionValue);
649
  $is_enabled = $options && array_key_exists('active', $options) && $options['active'] == 1;
650
- $button = array(
651
- 'name' => 'Button created via Wordpress plugin',
652
- 'domain' => $domain->id,
653
- 'active' => ($is_enabled && $has_a_number),
654
- 'actions' => $actions,
655
- 'conditions' => $conditions,
656
- 'type' => $type,
657
- 'options' => array(
658
- 'placement' => $appearance,
659
- 'iconBackgroundColor' => $iconBackgroundColor,
660
- 'iconColor' => $iconColor
661
- )
662
- );
663
 
664
  return self::cnb_create_button( $cnb_cloud_notifications, $button );
665
  }
@@ -667,15 +704,15 @@ class CnbAdminCloud {
667
  /**
668
  * NOTE: Currently only be called via button-overview, for a specific listing use case
669
  *
670
- * @param $button array The button array as created by the button-overview table class
671
  * @param $max int (optional) The maximum amount of Actions to retrieve
672
  *
673
  * @return array Array of Action objects, between 0 and $max items
674
  */
675
  public static function cnb_wp_get_actions_for_button( $button, $max = 3 ) {
676
  $count = 0;
677
- if ( $button['actions'] ) {
678
- $count = count( $button['actions'] );
679
  }
680
  $actionCount = min( $count, $max );
681
  $result = array();
@@ -684,7 +721,7 @@ class CnbAdminCloud {
684
  }
685
 
686
  for ( $i = 0; $i < $actionCount; $i ++ ) {
687
- $result[] = $button['actions'][ $i ];
688
  }
689
 
690
  return $result;
1
  <?php
2
+ namespace cnb\admin\api;
3
+
4
+ use cnb\admin\models\CnbAction;
5
+ use cnb\admin\models\CnbActionSchedule;
6
+ use cnb\admin\models\CnbButton;
7
+ use cnb\admin\models\CnbButtonOptions;
8
+ use cnb\admin\models\CnbCondition;
9
+ use cnb\admin\models\CnbDomain;
10
+ use CnbNotice;
11
+ use WP_Error;
12
 
13
  require_once dirname( __FILE__ ) . '/../../utils/CnbAdminNotices.class.php';
14
 
85
  }
86
 
87
  /**
88
+ * @param $button CnbButton
89
+ * @param $actions CnbAction[]
90
+ * @param $conditions CnbCondition[]
91
  *
92
  * @return array
93
  */
94
  public static function cnb_update_button_and_conditions( $button, $actions = array(), $conditions = array() ) {
95
  $cnb_cloud_notifications = array();
 
96
 
97
+ // 1: Update the Condition(s)
98
  $new_conditions = array();
99
  foreach ( $conditions as $condition ) {
100
+ if ( $condition->delete == 'true' ) {
101
  // 2.1 Delete now unused Conditions
102
  CnbAppRemote::cnb_remote_delete_condition( $condition );
103
+ } else if ( $condition->id === '' ) {
104
  // 2.2 Create new Conditions
105
  $new_conditions[] = self::cnb_create_condition( $cnb_cloud_notifications, $condition );
106
+ } else if ( $condition->id !== '' ) {
107
  // 2.3 Update existing Conditions
108
  $new_conditions[] = self::cnb_update_condition( $cnb_cloud_notifications, $condition );
109
  }
110
  }
111
 
112
+ // 2: Update the Action(s)
113
  $new_actions = array();
114
  foreach ( $actions as $action ) {
115
+ if ( $action->delete == 'true' ) {
116
  // 2.1 Delete now unused Action
117
  CnbAppRemote::cnb_remote_delete_action( $action );
118
+ } else if ( $action->id === '' ) {
119
  // 2.2 Create new Action
120
  $new_actions[] = self::cnb_create_action( $cnb_cloud_notifications, $action );
121
+ } else if ( $action->id !== '' && isset( $action->actionType ) ) {
122
  // 2.3 Update existing Action (but only if it is provided fully, which is why "actionType" is tested for presence
123
  $new_actions[] = self::cnb_update_action( $cnb_cloud_notifications, $action );
124
  } else {
127
  }
128
  }
129
 
130
+ $button->actions = $new_actions;
131
+ $button->conditions = $new_conditions;
132
+
133
+
134
+ // 3: Update the Button
135
+ self::cnb_update_button( $cnb_cloud_notifications, $button);
136
 
137
  return $cnb_cloud_notifications;
138
  }
139
 
140
  /**
141
  * @param $cnb_cloud_notifications
142
+ * @param $button CnbButton Single Button object
 
 
143
  *
144
  * @return mixed|WP_Error
145
  */
146
+ public static function cnb_update_button( &$cnb_cloud_notifications, $button) {
147
+ $result = CnbAppRemote::cnb_remote_update_wp_button( $button);
 
 
 
 
 
 
 
 
 
 
 
 
148
  if ( $result instanceof WP_Error ) {
149
  $message = self::cnb_admin_get_error_message( 'update', 'button', $result );
150
  } else {
155
  return $result;
156
  }
157
 
158
+ /**
159
+ * @param $cnb_cloud_notifications array
160
+ * @param $action CnbAction
161
+ *
162
+ * @return CnbAction|WP_Error
163
+ */
164
  public static function cnb_update_action( &$cnb_cloud_notifications, $action ) {
165
  $result = CnbAppRemote::cnb_remote_update_action( $action );
166
  if ( $result instanceof WP_Error ) {
171
  return $result;
172
  }
173
 
174
+ /**
175
+ * @param $cnb_cloud_notifications array
176
+ * @param $condition CnbCondition
177
+ *
178
+ * @return CnbCondition|WP_Error
179
+ */
180
  public static function cnb_update_condition( &$cnb_cloud_notifications, $condition ) {
181
  $result = CnbAppRemote::cnb_remote_update_condition( $condition );
182
  if ( $result instanceof WP_Error ) {
201
 
202
  /**
203
  * @param $cnb_cloud_notifications
204
+ * @param $button CnbButton Single Button object
205
  *
206
  * @return CnbButton|WP_Error The created Button
207
  */
261
  * @return mixed|WP_Error
262
  */
263
  public static function cnb_delete_action( &$cnb_cloud_notifications, $action_id ) {
264
+ $action = new CnbAction();
265
+ $action->id = $action_id;
266
+ $result = CnbAppRemote::cnb_remote_delete_action( $action );
267
  if ( $result instanceof WP_Error ) {
268
  $message = self::cnb_admin_get_error_message( 'delete', 'action', $result, 'with ID <code>' . esc_html( $action_id ) . '</code>' );
269
  array_push( $cnb_cloud_notifications, $message );
279
  * @return mixed|WP_Error
280
  */
281
  public static function cnb_delete_condition( &$cnb_cloud_notifications, $condition_id ) {
282
+ $condition = new CnbCondition();
283
+ $condition->id = $condition_id;
284
+ $result = CnbAppRemote::cnb_remote_delete_condition( $condition );
285
  if ( $result instanceof WP_Error ) {
286
  $message = self::cnb_admin_get_error_message( 'delete', 'condition', $result, 'with ID <code>' . esc_html( $condition_id ) . '</code>' );
287
  array_push( $cnb_cloud_notifications, $message );
320
  return $result;
321
  }
322
 
323
+ /**
324
+ * @param $cnb_cloud_notifications array
325
+ * @param $action CnbAction
326
+ *
327
+ * @return CnbAction|WP_Error
328
+ */
329
  public static function cnb_create_action( &$cnb_cloud_notifications, $action ) {
330
  $result = CnbAppRemote::cnb_remote_create_action( $action );
331
  if ( $result instanceof WP_Error ) {
338
  return $result;
339
  }
340
 
341
+ /**
342
+ * @param $cnb_cloud_notifications
343
+ * @param $condition CnbCondition
344
+ *
345
+ * @return CnbCondition|WP_Error
346
+ */
347
  public static function cnb_create_condition( &$cnb_cloud_notifications, $condition ) {
348
  $result = CnbAppRemote::cnb_remote_create_condition( $condition );
349
  if ( $result instanceof WP_Error ) {
412
  * @param $extra_info string Allows for some extra details to be added to the error message.
413
  * This contains HTML and should be escaped already when passed through.
414
  *
415
+ * @return CnbNotice A WordPress error notice with all details filled out (Content has been escaped already)
416
  */
417
  public static function cnb_admin_get_error_message( $verb, $type, $result, $extra_info = '' ) {
418
  $error_details = self::cnb_admin_get_error_message_details( $result );
570
  return $cnb_cloud_notifications;
571
  }
572
 
573
+ /**
574
+ * Used to convert the "legacy" button into a functional CnbAction
575
+ *
576
+ * @param $cnb_cloud_notifications array
577
+ * @param $options array
578
+ *
579
+ * @return CnbAction|WP_Error
580
+ */
581
  public static function cnb_wp_create_action( &$cnb_cloud_notifications, $options ) {
582
+ $action = new CnbAction();
583
+ $action->actionType = 'PHONE';
584
+ $action->actionValue = $options['number'];
585
+ $action->labelText = $options['text'];
586
+ $action->backgroundColor = $options['color'];
587
+ $action->iconColor = $options['iconcolor'];
588
+ $action->iconEnabled = isset( $options['hideIcon'] ) && $options['hideIcon'] == 1 ? false : true;
589
+ $action->schedule = new CnbActionSchedule();
590
+ $action->schedule->showAlways = true;
 
 
591
 
592
  return self::cnb_create_action( $cnb_cloud_notifications, $action );
593
  }
594
 
595
+ /**
596
+ * Used to convert the "legacy" button into a functional CnbCondition
597
+ *
598
+ * @param $cnb_cloud_notifications array
599
+ * @param $options array
600
+ *
601
+ * @return CnbCondition|WP_Error|null
602
+ */
603
  public static function cnb_wp_create_condition( &$cnb_cloud_notifications, $options ) {
604
  // frontpage (if == 1, condition: don't show on /)
605
  if ( ! isset( $options['frontpage'] ) || $options['frontpage'] != 1 ) {
606
  return null;
607
  }
608
 
609
+ $condition = new CnbCondition();
610
+ $condition->conditionType = 'URL';
611
+ $condition->filterType = 'EXCLUDE';
612
+ $condition->matchType = 'EXACT';
613
+ $condition->matchValue = get_home_url();
 
614
 
615
  return self::cnb_create_condition( $cnb_cloud_notifications, $condition );
616
  }
617
 
618
  /**
619
  *
620
+ * @param $cnb_cloud_notifications CnbNotice[] (likely ignored, but passed for good measure)
621
+ * @param $domain CnbDomain
622
+ * @param $action CnbAction
623
+ * @param $condition CnbCondition
624
+ * @param $options array the global cnb_options array
625
  *
626
  * @return CnbButton|WP_Error
627
  */
671
 
672
  $conditions = array();
673
  if ( $condition != null && isset( $condition->id ) ) {
674
+ $conditions[] = $condition;
 
675
  }
676
 
677
  $actions = array();
678
  if ( $action != null && isset( $action->id ) ) {
679
+ $actions[] = $action;
 
680
 
681
  $iconBackgroundColor = $action->backgroundColor;
682
  $iconColor = $action->iconColor;
685
  // 'active' is based on the status of enabled and if the number has a value
686
  $has_a_number = !empty($action->actionValue);
687
  $is_enabled = $options && array_key_exists('active', $options) && $options['active'] == 1;
688
+
689
+ $button = new CnbButton();
690
+ $button->name = 'Button created via Wordpress plugin';
691
+ $button->domain = $domain;
692
+ $button->active = ($is_enabled && $has_a_number);
693
+ $button->actions = $actions;
694
+ $button->conditions = $conditions;
695
+ $button->type = $type;
696
+ $button->options = new CnbButtonOptions();
697
+ $button->options->placement = $appearance;
698
+ $button->options->iconBackgroundColor = $iconBackgroundColor;
699
+ $button->options->iconColor = $iconColor;
 
700
 
701
  return self::cnb_create_button( $cnb_cloud_notifications, $button );
702
  }
704
  /**
705
  * NOTE: Currently only be called via button-overview, for a specific listing use case
706
  *
707
+ * @param $button CnbButton The button array as created by the button-overview table class
708
  * @param $max int (optional) The maximum amount of Actions to retrieve
709
  *
710
  * @return array Array of Action objects, between 0 and $max items
711
  */
712
  public static function cnb_wp_get_actions_for_button( $button, $max = 3 ) {
713
  $count = 0;
714
+ if ( $button->actions ) {
715
+ $count = count( $button->actions );
716
  }
717
  $actionCount = min( $count, $max );
718
  $result = array();
721
  }
722
 
723
  for ( $i = 0; $i < $actionCount; $i ++ ) {
724
+ $result[] = $button->actions[ $i ];
725
  }
726
 
727
  return $result;
src/admin/api/CnbAppRemote.php CHANGED
@@ -1,6 +1,14 @@
1
  <?php
 
2
 
3
  use cnb\admin\models\Cnb_User;
 
 
 
 
 
 
 
4
 
5
  require_once dirname( __FILE__ ) . '/RemoteTrace.php';
6
 
@@ -72,43 +80,13 @@ class CnbAppRemoteHelper {
72
  'iconColor' => !empty( $action['iconColor'] ) ? $action['iconColor'] : '#ffffff',
73
  // phpcs:ignore
74
  'iconEnabled' => isset( $action['iconEnabled'] ) ? boolval( $action['iconEnabled'] ) : false,
 
75
  'labelText' => isset($action['labelText']) ? $action['labelText'] : null,
76
- // 'iconText' => isset($action['iconText']) ? $action['iconText'] : null,
77
- 'iconText' => cnb_actiontype_to_icontext($action['actionType']),
78
  'properties' => self::cnb_remote_cleanup_properties($action)
79
  );
80
  }
81
 
82
- public function convertButton($button, $actions=null, $conditions=null) {
83
- if ($actions != null) {
84
- $button['actions'] = is_array( $actions ) ? cnb_array_column( $actions, 'id' ) : array();
85
- } else if (isset($button['actions']) && $button['actions'] != null) {
86
- $button['actions'] = is_array( $button['actions'] ) ? cnb_array_column( $button['actions'], 'id' ) : array();
87
- }
88
-
89
- if ($conditions != null) {
90
- $button['conditions'] = is_array( $conditions ) ? cnb_array_column( $conditions, 'id' ) : array();
91
- } else if (isset($button['conditions']) && $button['conditions'] != null) {
92
- $button['conditions'] = is_array( $button['conditions'] ) ? cnb_array_column( $button['conditions'], 'id' ) : array();
93
- }
94
-
95
- if (!isset($button['id'])) {
96
- $button['id'] = null;
97
- }
98
-
99
- return array(
100
- 'id' => $button['id'],
101
- // phpcs:ignore
102
- 'active' => isset( $button['active'] ) ? boolval( $button['active'] ) : false,
103
- 'name' => ! empty( $button['name'] ) ? $button['name'] : 'Button created via Wordpress plugin',
104
- 'domain' => $button['domain'],
105
- 'actions' => isset( $button['actions'] ) && is_array( $button['actions'] ) ? $button['actions'] : array(),
106
- 'conditions' => isset( $button['conditions'] ) && is_array( $button['conditions'] ) ? $button['conditions'] : array(),
107
- 'type' => $button['type'],
108
- 'options' => $button['options']
109
- );
110
- }
111
-
112
  public function convertDomain($domain) {
113
  return array(
114
  'name' => $domain['name'],
@@ -120,16 +98,6 @@ class CnbAppRemoteHelper {
120
  );
121
  }
122
 
123
- public function convertCondition($condition) {
124
- return array(
125
- 'id' => isset($condition['id']) ? $condition['id'] : null,
126
- 'conditionType' => $condition['conditionType'],
127
- 'filterType' => $condition['filterType'],
128
- 'matchType' => $condition['matchType'],
129
- 'matchValue' => $condition['matchValue'],
130
- );
131
- }
132
-
133
  public function convertApiKey($apikey) {
134
  return array(
135
  'name' => $apikey['name'],
@@ -203,6 +171,13 @@ class CnbAppRemote {
203
  return str_replace('api', 'user', CnbAppRemote::cnb_get_api_base());
204
  }
205
 
 
 
 
 
 
 
 
206
  /**
207
  * @return int 0 if not found, otherwise the current cache key
208
  */
@@ -329,6 +304,12 @@ class CnbAppRemote {
329
  return self::cnb_wp_request( $url, $parsed_args );
330
  }
331
 
 
 
 
 
 
 
332
  public static function cnb_remote_patch( $rest_endpoint, $body ) {
333
  $args = self::cnb_remote_get_args();
334
  if ( $args instanceof WP_Error ) {
@@ -415,19 +396,24 @@ class CnbAppRemote {
415
 
416
  /**
417
  * This returns the domain matching the WordPress domain
418
- * @return mixed|WP_Error
419
  */
420
  public static function cnb_remote_get_wp_domain() {
421
  $cnbAppRemote = new CnbAppRemote();
422
  $rest_endpoint = '/v1/domain/byName/' . $cnbAppRemote->cnb_clean_site_url();
423
 
424
- return self::cnb_remote_get( $rest_endpoint );
425
  }
426
 
 
 
 
 
 
427
  public static function cnb_remote_get_domain( $id ) {
428
  $rest_endpoint = '/v1/domain/' . $id;
429
 
430
- return self::cnb_remote_get( $rest_endpoint );
431
  }
432
 
433
  public static function cnb_remote_get_domains() {
@@ -436,16 +422,27 @@ class CnbAppRemote {
436
  return self::cnb_remote_get( $rest_endpoint );
437
  }
438
 
 
 
 
 
 
 
439
  public static function cnb_remote_get_button( $id ) {
440
  $rest_endpoint = '/v1/button/' . $id;
441
 
442
  return self::cnb_remote_get( $rest_endpoint );
443
  }
444
 
 
 
 
 
 
445
  public static function cnb_remote_get_button_full( $id ) {
446
  $rest_endpoint = '/v1/button/' . $id . '/full';
447
 
448
- return self::cnb_remote_get( $rest_endpoint );
449
  }
450
 
451
  /**
@@ -456,13 +453,13 @@ class CnbAppRemote {
456
  public static function cnb_remote_get_buttons() {
457
  $rest_endpoint = '/v1/button';
458
 
459
- return self::cnb_remote_get( $rest_endpoint );
460
  }
461
 
462
  public static function cnb_remote_get_buttons_full() {
463
  $rest_endpoint = '/v1/button/full';
464
 
465
- return self::cnb_remote_get( $rest_endpoint );
466
  }
467
 
468
  public static function cnb_remote_get_action( $id ) {
@@ -518,17 +515,20 @@ class CnbAppRemote {
518
  return self::cnb_remote_get( $rest_endpoint );
519
  }
520
 
 
 
 
 
 
521
  public static function cnb_remote_update_button( $button ) {
522
  // Find the ID in the options
523
- $buttonId = $button['id'];
524
-
525
- if ( ! $buttonId ) {
526
  return new WP_Error( 'CNB_BUTTON_ID_MISSING', 'buttonId expected, but not found' );
527
  }
528
 
529
- $rest_endpoint = '/v1/button/' . $buttonId;
530
 
531
- return self::cnb_remote_patch( $rest_endpoint, $button );
532
  }
533
 
534
  public static function cnb_remote_update_domain( $domain ) {
@@ -575,28 +575,34 @@ class CnbAppRemote {
575
  return self::cnb_remote_delete( $rest_endpoint );
576
  }
577
 
 
 
 
 
 
578
  public static function cnb_remote_delete_condition( $condition ) {
579
  // Find the ID in the options
580
- $entityId = $condition['id'];
581
-
582
- if ( ! $entityId ) {
583
  return new WP_Error( 'CNB_CONDITION_ID_MISSING', 'conditionId expected, but not found' );
584
  }
585
 
586
- $rest_endpoint = '/v1/condition/' . $entityId;
587
 
588
- return self::cnb_remote_delete( $rest_endpoint );
589
  }
590
 
 
 
 
 
 
591
  public static function cnb_remote_delete_action( $action ) {
592
  // Find the ID in the options
593
- $entityId = $action['id'];
594
-
595
- if ( ! $entityId ) {
596
  return new WP_Error( 'CNB_ACTION_ID_MISSING', 'actionId expected, but not found' );
597
  }
598
 
599
- $rest_endpoint = '/v1/action/' . $entityId;
600
 
601
  return self::cnb_remote_delete( $rest_endpoint );
602
  }
@@ -614,41 +620,33 @@ class CnbAppRemote {
614
  return self::cnb_remote_delete( $rest_endpoint );
615
  }
616
 
 
 
 
 
 
617
  public static function cnb_remote_update_action( $action ) {
618
  // Find the action ID in the options
619
- $actionId = $action['id'];
620
-
621
- if ( ! $actionId ) {
622
  return new WP_Error( 'CNB_ACTION_ID_MISSING', 'actionId expected, but not found' );
623
  }
624
 
625
- $helper = new CnbAppRemoteHelper();
626
- $body = $helper->convertAction($action);
627
 
628
- $rest_endpoint = '/v1/action/' . $actionId;
629
- return self::cnb_remote_patch( $rest_endpoint, $body );
630
  }
631
 
632
  /**
633
- * TODO See if we can make this cleaner (without actions/conditions passed in?)
634
- *
635
- * @param $button array Single Button object
636
- * @param $actions array Action objects
637
- * @param $conditions array Conditions objects
638
  *
639
- * @return mixed|WP_Error
640
  */
641
- public static function cnb_remote_update_wp_button( $button, $actions, $conditions ) {
642
- $buttonId = $button['id'];
643
-
644
- if ( ! $buttonId ) {
645
  return new WP_Error( 'CNB_BUTTON_ID_MISSING', 'buttonId expected, but not found' );
646
  }
647
 
648
- $helper = new CnbAppRemoteHelper();
649
- $body = $helper->convertButton($button, $actions, $conditions);
650
-
651
- return self::cnb_remote_update_button( $body );
652
  }
653
 
654
  public static function cnb_remote_create_domain( $domain ) {
@@ -667,66 +665,63 @@ class CnbAppRemote {
667
  }
668
 
669
  /**
670
- * @param $button array Single Button object
671
  *
672
  * @return CnbButton|WP_Error
673
  */
674
  public static function cnb_remote_create_button( $button ) {
675
- $buttonId = isset($button['id']) && $button['id'];
676
-
677
- if ( $buttonId ) {
678
  return new WP_Error( 'CNB_BUTTON_ID_FOUND', 'no buttonId expected, but one was given' );
679
  }
680
 
681
- $helper = new CnbAppRemoteHelper();
682
- $body = $helper->convertButton($button);
683
-
684
  $rest_endpoint = '/v1/button';
685
 
686
- return self::cnb_remote_post( $rest_endpoint, $body );
687
  }
688
 
 
 
 
 
 
689
  public static function cnb_remote_create_action( $action ) {
690
- $actionId = isset($action['id']) && $action['id'];
691
-
692
- if ( $actionId ) {
693
  return new WP_Error( 'CNB_ACTION_ID_FOUND', 'no actionId expected, but one was given' );
694
  }
695
 
696
- $helper = new CnbAppRemoteHelper();
697
- $body = $helper->convertAction($action);
698
-
699
  $rest_endpoint = '/v1/action';
700
 
701
- return self::cnb_remote_post( $rest_endpoint, $body );
702
  }
703
 
 
 
 
 
 
704
  public static function cnb_remote_create_condition( $condition ) {
705
- $conditionId = isset($condition['id']) && $condition['id'];
706
-
707
- if ( $conditionId ) {
708
  return new WP_Error( 'CNB_CONDITION_ID_FOUND', 'no conditionId expected, but one was given' );
709
  }
710
 
711
- $helper = new CnbAppRemoteHelper();
712
- $body = $helper->convertCondition($condition);
713
-
714
  $rest_endpoint = '/v1/condition';
715
 
716
- return self::cnb_remote_post( $rest_endpoint, $body );
717
  }
718
 
 
 
 
 
 
719
  public static function cnb_remote_update_condition( $condition ) {
720
- if ( ! $condition['id'] ) {
721
  return new WP_Error( 'CNB_CONDITION_ID_MISSING', 'conditionId expected, but not found' );
722
  }
723
 
724
- $helper = new CnbAppRemoteHelper();
725
- $body = $helper->convertCondition($condition);
726
-
727
- $rest_endpoint = '/v1/condition/' . $condition['id'];
728
 
729
- return self::cnb_remote_patch( $rest_endpoint, $body );
730
  }
731
 
732
  public static function cnb_remote_create_apikey( $apikey ) {
1
  <?php
2
+ namespace cnb\admin\api;
3
 
4
  use cnb\admin\models\Cnb_User;
5
+ use cnb\admin\models\CnbAction;
6
+ use cnb\admin\models\CnbApiKey;
7
+ use cnb\admin\models\CnbButton;
8
+ use cnb\admin\models\CnbCondition;
9
+ use cnb\admin\models\CnbDomain;
10
+ use JsonSerializable;
11
+ use WP_Error;
12
 
13
  require_once dirname( __FILE__ ) . '/RemoteTrace.php';
14
 
80
  'iconColor' => !empty( $action['iconColor'] ) ? $action['iconColor'] : '#ffffff',
81
  // phpcs:ignore
82
  'iconEnabled' => isset( $action['iconEnabled'] ) ? boolval( $action['iconEnabled'] ) : false,
83
+ 'iconType' => isset( $action['iconType'] ) ? $action['iconType'] : 'DEFAULT',
84
  'labelText' => isset($action['labelText']) ? $action['labelText'] : null,
85
+ 'iconText' => isset($action['iconText']) ? $action['iconText'] : cnb_actiontype_to_icontext($action['actionType']),
 
86
  'properties' => self::cnb_remote_cleanup_properties($action)
87
  );
88
  }
89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  public function convertDomain($domain) {
91
  return array(
92
  'name' => $domain['name'],
98
  );
99
  }
100
 
 
 
 
 
 
 
 
 
 
 
101
  public function convertApiKey($apikey) {
102
  return array(
103
  'name' => $apikey['name'],
171
  return str_replace('api', 'user', CnbAppRemote::cnb_get_api_base());
172
  }
173
 
174
+ /**
175
+ * @return string usually "https://static.callnowbutton.com"
176
+ */
177
+ public static function cnb_get_static_base() {
178
+ return str_replace('api', 'static', CnbAppRemote::cnb_get_api_base());
179
+ }
180
+
181
  /**
182
  * @return int 0 if not found, otherwise the current cache key
183
  */
304
  return self::cnb_wp_request( $url, $parsed_args );
305
  }
306
 
307
+ /**
308
+ * @param $rest_endpoint
309
+ * @param $body array|JsonSerializable will be JSON encoded, can be array (or class with JsonSerializable?)
310
+ *
311
+ * @return mixed|WP_Error
312
+ */
313
  public static function cnb_remote_patch( $rest_endpoint, $body ) {
314
  $args = self::cnb_remote_get_args();
315
  if ( $args instanceof WP_Error ) {
396
 
397
  /**
398
  * This returns the domain matching the WordPress domain
399
+ * @return CnbDomain|WP_Error
400
  */
401
  public static function cnb_remote_get_wp_domain() {
402
  $cnbAppRemote = new CnbAppRemote();
403
  $rest_endpoint = '/v1/domain/byName/' . $cnbAppRemote->cnb_clean_site_url();
404
 
405
+ return CnbDomain::fromObject(self::cnb_remote_get( $rest_endpoint ));
406
  }
407
 
408
+ /**
409
+ * @param $id
410
+ *
411
+ * @return CnbDomain|WP_Error
412
+ */
413
  public static function cnb_remote_get_domain( $id ) {
414
  $rest_endpoint = '/v1/domain/' . $id;
415
 
416
+ return CnbDomain::fromObject(self::cnb_remote_get( $rest_endpoint ));
417
  }
418
 
419
  public static function cnb_remote_get_domains() {
422
  return self::cnb_remote_get( $rest_endpoint );
423
  }
424
 
425
+ /**
426
+ * @param $id
427
+ *
428
+ * @return mixed|WP_Error
429
+ * @deprecated use cnb_remote_get_button_full( $id )
430
+ */
431
  public static function cnb_remote_get_button( $id ) {
432
  $rest_endpoint = '/v1/button/' . $id;
433
 
434
  return self::cnb_remote_get( $rest_endpoint );
435
  }
436
 
437
+ /**
438
+ * @param $id
439
+ *
440
+ * @return CnbButton|WP_Error
441
+ */
442
  public static function cnb_remote_get_button_full( $id ) {
443
  $rest_endpoint = '/v1/button/' . $id . '/full';
444
 
445
+ return CnbButton::fromObject(self::cnb_remote_get( $rest_endpoint ));
446
  }
447
 
448
  /**
453
  public static function cnb_remote_get_buttons() {
454
  $rest_endpoint = '/v1/button';
455
 
456
+ return CnbButton::fromObjects(self::cnb_remote_get( $rest_endpoint ));
457
  }
458
 
459
  public static function cnb_remote_get_buttons_full() {
460
  $rest_endpoint = '/v1/button/full';
461
 
462
+ return CnbButton::fromObjects(self::cnb_remote_get( $rest_endpoint ));
463
  }
464
 
465
  public static function cnb_remote_get_action( $id ) {
515
  return self::cnb_remote_get( $rest_endpoint );
516
  }
517
 
518
+ /**
519
+ * @param $button CnbButton
520
+ *
521
+ * @return CnbButton|WP_Error
522
+ */
523
  public static function cnb_remote_update_button( $button ) {
524
  // Find the ID in the options
525
+ if ( ! $button->id ) {
 
 
526
  return new WP_Error( 'CNB_BUTTON_ID_MISSING', 'buttonId expected, but not found' );
527
  }
528
 
529
+ $rest_endpoint = '/v1/button/' . $button->id;
530
 
531
+ return CnbButton::fromObject(self::cnb_remote_patch( $rest_endpoint, $button ));
532
  }
533
 
534
  public static function cnb_remote_update_domain( $domain ) {
575
  return self::cnb_remote_delete( $rest_endpoint );
576
  }
577
 
578
+ /**
579
+ * @param $condition CnbCondition
580
+ *
581
+ * @return CnbCondition|WP_Error
582
+ */
583
  public static function cnb_remote_delete_condition( $condition ) {
584
  // Find the ID in the options
585
+ if ( ! $condition->id ) {
 
 
586
  return new WP_Error( 'CNB_CONDITION_ID_MISSING', 'conditionId expected, but not found' );
587
  }
588
 
589
+ $rest_endpoint = '/v1/condition/' . $condition->id;
590
 
591
+ return CnbCondition::fromObject(self::cnb_remote_delete( $rest_endpoint ));
592
  }
593
 
594
+ /**
595
+ * @param $action CnbAction
596
+ *
597
+ * @return mixed|WP_Error
598
+ */
599
  public static function cnb_remote_delete_action( $action ) {
600
  // Find the ID in the options
601
+ if ( ! $action->id ) {
 
 
602
  return new WP_Error( 'CNB_ACTION_ID_MISSING', 'actionId expected, but not found' );
603
  }
604
 
605
+ $rest_endpoint = '/v1/action/' . $action->id;
606
 
607
  return self::cnb_remote_delete( $rest_endpoint );
608
  }
620
  return self::cnb_remote_delete( $rest_endpoint );
621
  }
622
 
623
+ /**
624
+ * @param $action CnbAction
625
+ *
626
+ * @return CnbAction|WP_Error
627
+ */
628
  public static function cnb_remote_update_action( $action ) {
629
  // Find the action ID in the options
630
+ if ( ! $action->id ) {
 
 
631
  return new WP_Error( 'CNB_ACTION_ID_MISSING', 'actionId expected, but not found' );
632
  }
633
 
634
+ $rest_endpoint = '/v1/action/' . $action->id;
 
635
 
636
+ return CnbAction::fromObject(self::cnb_remote_patch( $rest_endpoint, $action ));
 
637
  }
638
 
639
  /**
640
+ * @param $button CnbButton Single Button object
 
 
 
 
641
  *
642
+ * @return CnbButton|WP_Error
643
  */
644
+ public static function cnb_remote_update_wp_button( $button ) {
645
+ if ( ! $button->id ) {
 
 
646
  return new WP_Error( 'CNB_BUTTON_ID_MISSING', 'buttonId expected, but not found' );
647
  }
648
 
649
+ return CnbButton::fromObject(self::cnb_remote_update_button( $button ));
 
 
 
650
  }
651
 
652
  public static function cnb_remote_create_domain( $domain ) {
665
  }
666
 
667
  /**
668
+ * @param $button CnbButton Single Button object
669
  *
670
  * @return CnbButton|WP_Error
671
  */
672
  public static function cnb_remote_create_button( $button ) {
673
+ if ( $button->id ) {
 
 
674
  return new WP_Error( 'CNB_BUTTON_ID_FOUND', 'no buttonId expected, but one was given' );
675
  }
676
 
 
 
 
677
  $rest_endpoint = '/v1/button';
678
 
679
+ return CnbButton::fromObject(self::cnb_remote_post( $rest_endpoint, $button ));
680
  }
681
 
682
+ /**
683
+ * @param $action CnbAction
684
+ *
685
+ * @return CnbAction|WP_Error
686
+ */
687
  public static function cnb_remote_create_action( $action ) {
688
+ if ( $action->id ) {
 
 
689
  return new WP_Error( 'CNB_ACTION_ID_FOUND', 'no actionId expected, but one was given' );
690
  }
691
 
 
 
 
692
  $rest_endpoint = '/v1/action';
693
 
694
+ return CnbAction::fromObject(self::cnb_remote_post( $rest_endpoint, $action ));
695
  }
696
 
697
+ /**
698
+ * @param $condition CnbCondition
699
+ *
700
+ * @return CnbCondition|WP_Error
701
+ */
702
  public static function cnb_remote_create_condition( $condition ) {
703
+ if ( $condition->id ) {
 
 
704
  return new WP_Error( 'CNB_CONDITION_ID_FOUND', 'no conditionId expected, but one was given' );
705
  }
706
 
 
 
 
707
  $rest_endpoint = '/v1/condition';
708
 
709
+ return CnbCondition::fromObject(self::cnb_remote_post( $rest_endpoint, $condition ));
710
  }
711
 
712
+ /**
713
+ * @param $condition CnbCondition
714
+ *
715
+ * @return CnbCondition|WP_Error
716
+ */
717
  public static function cnb_remote_update_condition( $condition ) {
718
+ if ( ! $condition->id ) {
719
  return new WP_Error( 'CNB_CONDITION_ID_MISSING', 'conditionId expected, but not found' );
720
  }
721
 
722
+ $rest_endpoint = '/v1/condition/' . $condition->id;
 
 
 
723
 
724
+ return CnbCondition::fromObject(self::cnb_remote_patch( $rest_endpoint, $condition ));
725
  }
726
 
727
  public static function cnb_remote_create_apikey( $apikey ) {
src/admin/api/CnbAppRemotePayment.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
 
3
  require_once dirname( __FILE__ ) . '/CnbAppRemote.php';
4
 
1
  <?php
2
+ namespace cnb\admin\api;
3
 
4
  require_once dirname( __FILE__ ) . '/CnbAppRemote.php';
5
 
src/admin/api/RemoteTrace.php CHANGED
@@ -1,4 +1,6 @@
1
  <?php
 
 
2
  require_once dirname( __FILE__ ) . '/RemoteTracer.php';
3
 
4
  class RemoteTrace {
1
  <?php
2
+ namespace cnb\admin\api;
3
+
4
  require_once dirname( __FILE__ ) . '/RemoteTracer.php';
5
 
6
  class RemoteTrace {
src/admin/api/RemoteTracer.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
 
3
  /**
4
  * Used to keep track of all traces
1
  <?php
2
+ namespace cnb\admin\api;
3
 
4
  /**
5
  * Used to keep track of all traces
src/admin/apikey-overview.php CHANGED
@@ -1,5 +1,8 @@
1
  <?php
2
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
5
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAdminCloud;
4
+ use cnb\admin\api\CnbAppRemote;
5
+
6
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
7
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
8
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
src/admin/button-edit.php CHANGED
@@ -1,5 +1,14 @@
1
  <?php
2
 
 
 
 
 
 
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
5
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
@@ -25,7 +34,7 @@ function cnb_add_header_button_edit($button = null) {
25
  }
26
  $buttonTypes = cnb_get_button_types();
27
  $typeName = $buttonTypes[$type];
28
- echo 'Editing ' . esc_html($typeName) . ' <span class="cnb_button_name">' . esc_html($name) . '</span>';
29
  }
30
 
31
  function cnb_create_tab_url_button($button, $tab) {
@@ -42,26 +51,36 @@ function cnb_create_tab_url_button($button, $tab) {
42
  return esc_url( $tab_link );
43
  }
44
 
45
- /**
46
- * This is called to update the button
47
- * via `call-now-button.php#cnb_create_<type>_button`
48
- */
49
- function cnb_admin_create_button() {
50
  $nonce = filter_input( INPUT_POST, '_wpnonce_button', FILTER_SANITIZE_STRING );
51
  if( isset( $_REQUEST['_wpnonce_button'] ) && wp_verify_nonce( $nonce, 'cnb-button-edit') ) {
52
 
53
  // sanitize the input
54
  $button = filter_input(
55
- INPUT_POST,
56
- 'cnb',
57
- FILTER_SANITIZE_STRING,
58
- FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
 
60
  // ensure the position is valid for FULL
61
  if (strtoupper($button['type']) === 'FULL') {
62
  if (!empty($button['options']) && !empty($button['options']['placement'])) {
63
  $placement = $button['options']['placement'];
64
- if ($placement !== 'BOTTOM_CENTER' && $placement !== 'TOP_CENTER') {
65
  $button['options']['placement'] = 'BOTTOM_CENTER';
66
  }
67
  } else {
@@ -69,21 +88,62 @@ function cnb_admin_create_button() {
69
  }
70
  }
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  // Do the processing
73
  $cnb_cloud_notifications = array();
74
- $new_button = CnbAdminCloud::cnb_create_button( $cnb_cloud_notifications, $button );
75
 
76
  // redirect the user to the appropriate page
77
  $tab = filter_input( INPUT_POST, 'tab', FILTER_SANITIZE_STRING );
78
  $transient_id = 'cnb-' . wp_generate_uuid4();
79
  set_transient( $transient_id, $cnb_cloud_notifications, HOUR_IN_SECONDS );
80
 
81
- if ($new_button instanceof WP_Error) {
82
  $new_button_type = null;
83
- $new_button_id = null;
84
  } else {
85
  $new_button_type = strtolower( $new_button->type );
86
- $new_button_id = $new_button->id;
87
  }
88
 
89
  // Create link
@@ -102,12 +162,8 @@ function cnb_admin_create_button() {
102
  $redirect_url = esc_url_raw( $redirect_link );
103
  wp_safe_redirect( $redirect_url );
104
  exit;
105
- } else {
106
- wp_die( __( 'Invalid nonce specified', CNB_NAME), __( 'Error', CNB_NAME), array(
107
- 'response' => 403,
108
- 'back_link' => 'admin.php?page=' . CNB_SLUG,
109
- ) );
110
- }
111
  }
112
 
113
  /**
@@ -115,80 +171,53 @@ function cnb_admin_create_button() {
115
  * via `call-now-button.php#cnb_update_<type>_button`
116
  */
117
  function cnb_admin_update_button() {
118
- $nonce = filter_input( INPUT_POST, '_wpnonce_button', FILTER_SANITIZE_STRING );
119
- if( isset( $_REQUEST['_wpnonce_button'] ) && wp_verify_nonce( $nonce, 'cnb-button-edit') ) {
120
-
121
- // sanitize the input
122
- $button = filter_input(
123
- INPUT_POST,
124
- 'cnb',
125
- FILTER_SANITIZE_STRING,
126
- FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES);
127
- $actions = filter_input(
128
- INPUT_POST,
129
- 'actions',
130
- FILTER_SANITIZE_STRING,
131
- FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES);
132
- $conditions = filter_input(
133
- INPUT_POST,
134
- 'condition',
135
- FILTER_SANITIZE_STRING,
136
- FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES);
137
-
138
- if ($conditions === null) {
139
- $conditions = array();
140
- }
141
-
142
- // ensure the position is valid for FULL
143
- if (strtoupper($button['type']) === 'FULL') {
144
- if (!empty($button['options']) && !empty($button['options']['placement'])) {
145
- $placement = $button['options']['placement'];
146
- if ( $placement !== 'BOTTOM_CENTER' && $placement !== 'TOP_CENTER' ) {
147
- $button['options']['placement'] = 'BOTTOM_CENTER';
148
- }
149
- } else {
150
- $button['options']['placement'] = 'BOTTOM_CENTER';
151
- }
152
- }
153
-
154
- // do the processing
155
- $processed_actions = array();
156
- if (is_array($actions)) {
157
- foreach ( $actions as $action ) {
158
- $processed_actions[] = cnb_admin_process_action( $action );
159
- }
160
- }
161
- $result = CnbAdminCloud::cnb_update_button_and_conditions( $button, $processed_actions, $conditions );
162
-
163
- // redirect the user to the appropriate page
164
- $tab = filter_input( INPUT_POST, 'tab', FILTER_SANITIZE_STRING );
165
- $transient_id = 'cnb-' . wp_generate_uuid4();
166
- set_transient($transient_id, $result, HOUR_IN_SECONDS);
167
-
168
- // Create link
169
- $url = admin_url('admin.php');
170
- $redirect_link =
171
- add_query_arg(
172
- array(
173
- 'page' => 'call-now-button',
174
- 'action' => 'edit',
175
- 'type' => strtolower($button['type']),
176
- 'id' => $button['id'],
177
- 'tid' => $transient_id,
178
- 'tab' => $tab),
179
- $url );
180
- $redirect_url = esc_url_raw( $redirect_link );
181
- wp_safe_redirect($redirect_url);
182
- exit;
183
- }
184
- else {
185
- wp_die( __( 'Invalid nonce specified', CNB_NAME), __( 'Error', CNB_NAME), array(
186
- 'response' => 403,
187
- 'back_link' => 'admin.php?page=' . CNB_SLUG,
188
- ) );
189
- }
190
  }
191
 
 
 
 
 
 
 
 
 
 
 
 
192
  function cnb_button_edit_form($button_id, $button, $default_domain, $options=array()) {
193
  $domains = CnbAppRemote::cnb_remote_get_domains();
194
 
@@ -210,23 +239,31 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
210
  'page' => 'call-now-button-actions',
211
  'action' => 'new',
212
  'id' => 'new',
213
- 'tab' => 'actions',
214
  'bid' => $button->id),
215
  $url);
216
  $new_action_url = esc_url($new_action_link);
217
 
218
  // In case the API isn't working properly
219
  if ($default_domain instanceof WP_Error) {
220
- $default_domain = array();
221
- $default_domain['id'] = 0;
222
  }
223
 
 
 
224
  wp_enqueue_script(CNB_SLUG . '-action-type-to-icon-text');
225
  wp_enqueue_script(CNB_SLUG . '-form-to-json');
226
  wp_enqueue_script(CNB_SLUG . '-preview');
227
  wp_enqueue_script(CNB_SLUG . '-client');
 
 
228
  ?>
229
- <form action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post" class="cnb-container">
 
 
 
 
230
  <input type="hidden" name="page" value="call-now-button" />
231
  <input type="hidden" name="action" value="<?php echo $button_id === 'new' ? 'cnb_create_'.strtolower($button->type).'_button' :'cnb_update_'.esc_attr(strtolower($button->type)).'_button' ?>" />
232
  <input type="hidden" name="_wpnonce_button" value="<?php echo wp_create_nonce('cnb-button-edit')?>" />
@@ -236,48 +273,45 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
236
  <input type="hidden" name="cnb[type]" value="<?php echo esc_attr($button->type) ?>" id="cnb_type" />
237
  <input type="hidden" name="cnb[active]" value="<?php echo esc_attr($button->active) ?>" />
238
  <input type="hidden" name="cnb[domain]" value="<?php echo esc_attr($default_domain->id) ?>" />
239
- <?php
240
- // Show all the current actions (needed to submit the form)
241
- foreach($button->actions as $action) { ?>
242
- <input type="hidden" name="actions[<?php echo esc_attr($action->id) ?>][id]" value="<?php echo esc_attr($action->id) ?>" />
243
- <?php } ?>
244
 
245
  <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">
246
- <tr class="cnb_hide_on_modal">
247
- <th></th>
248
- <td></td>
249
- </tr>
250
- <tr>
251
- <th scope="row"><label for="cnb[name]">Button name</label></th>
252
-
253
- <td class="activated">
254
- <label for="cnb[name]"><input type="text" name="cnb[name]" id="cnb[name]" required="required" value="<?php echo esc_attr($button->name); ?>" /></label>
255
- </td>
256
- </tr>
257
- <tr class="cnb_hide_on_modal">
258
- <th scope="row"><label for="cnb-enable">Button status</label></th>
259
-
260
- <td class="activated">
261
  <input type="hidden" name="cnb[active]" value="0" />
262
  <input id="cnb-enable" class="cnb_toggle_checkbox" type="checkbox" name="cnb[active]" value="1" <?php checked(true, $button->active); ?> />
263
  <label for="cnb-enable" class="cnb_toggle_label">Toggle</label>
264
- <span data-cnb_toggle_state_label="cnb-enable" class="cnb_toggle_state cnb_toggle_false">Inactive</span>
265
  <span data-cnb_toggle_state_label="cnb-enable" class="cnb_toggle_state cnb_toggle_true">Active</span>
266
- </td>
267
- </tr>
268
- <tr class="cnb_hide_on_modal cnb_advanced_view">
269
- <th scope="row"><label for="cnb[domain]">Domain</label></th>
270
- <td>
271
  <select name="cnb[domain]" id="cnb[domain]">
272
  <?php
273
  foreach ($domains as $domain) { ?>
274
- <option value="<?php echo esc_attr($domain->id) ?>"<?php selected($domain->id, $button->domain->id) ?>>
275
- <?php echo esc_html($domain->name) ?>
 
 
276
  <?php if ($domain->id == $default_domain->id) { echo ' (current Wordpress domain)'; } ?>
277
  </option>
278
  <?php } ?>
279
  </select>
280
- </td>
281
  </tr>
282
  <?php if ($button->type !== 'SINGLE') { ?>
283
  <tr class="cnb_hide_on_modal">
@@ -300,27 +334,37 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
300
  $action->labelText = '';
301
  $action->properties = new CnbActionProperties();
302
  }
 
 
 
 
 
 
 
303
  cnb_admin_page_action_edit_render_main($action, $button, $default_domain, false);
304
- } else {
305
- ?>
 
 
 
306
  </table>
307
 
308
  <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"'; } ?>>
309
  <?php cnb_admin_page_action_overview_render_form(array('button' => $button)); ?>
310
  <script>
311
  let cnb_actions = <?php echo json_encode($button->actions) ?>;
312
- let cnb_domain = <?php echo json_encode($default_domain) ?>;
313
  </script>
314
  </div>
315
  <table class="form-table <?php if(!$hide_on_modal) { echo cnb_is_active_tab('basic_options'); } else { echo 'nav-tab-only'; } ?>"><?php
316
  } ?>
317
  <?php if ($button_id === 'new') { ?>
318
- <tr>
319
- <th scope="row">Select button type</th>
320
- </tr>
321
- <tr>
322
- <td scope="row" colspan="2" class="cnb_type_selector">
323
- <div class="cnb-flexbox">
324
  <div class="cnb_type_selector_item cnb_type_selector_single cnb_type_selector_active" data-cnb-selection="single">
325
  <img style="max-width:100%;" alt="Choose a Single button type" src="<?php echo $cnb_single_image ?>">
326
  <div style="text-align:center">Single button</div>
@@ -333,45 +377,162 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
333
  <img style="max-width:100%;" alt="Choose a Full button type" src="<?php echo $cnb_full_image ?>">
334
  <div style="text-align:center">Buttonbar</div>
335
  </div>
336
- </div>
337
- </td>
338
- </tr>
339
  <?php } ?>
340
  </table>
341
  <table class="form-table <?php echo cnb_is_active_tab('extra_options') ?>" data-tab-name="extra_options">
342
  <?php if ($button->type === 'FULL') { ?>
343
- <tr>
344
- <th colspan="2">
345
- <h2>Colors for the Buttonbar are defined via the Actions.</h2>
346
- <input name="cnb[options][iconBackgroundColor]" type="hidden" value="<?php echo esc_attr($button->options->iconBackgroundColor); ?>" />
347
- <input name="cnb[options][iconColor]" type="hidden" value="<?php echo esc_attr($button->options->iconColor); ?>" />
348
- </th>
349
- </tr>
350
- <?php } else { ?>
351
- <tr class="cnb_hide_on_modal">
352
- <th></th>
353
- <td></td>
354
- </tr>
355
- <tr>
356
- <th scope="row"><label for="cnb[options][iconBackgroundColor]">Background color</label></th>
357
- <td>
358
- <input name="cnb[options][iconBackgroundColor]" id="cnb[options][iconBackgroundColor]" type="text" value="<?php echo esc_attr($button->options->iconBackgroundColor); ?>"
359
- class="cnb-iconcolor-field" data-default-color="#009900"/>
360
- <?php if ($button->type === 'MULTI') { ?>
361
- <p class="description"><span class="dashicons dashicons-info"></span>This color applies to the collapsable button only.</p>
362
- <?php } ?>
363
- </td>
364
- </tr>
365
- <tr>
366
- <th scope="row"><label for="cnb[options][iconColor]">Icon color</label></th>
367
- <td>
368
- <input name="cnb[options][iconColor]" id="cnb[options][iconColor]" type="text" value="<?php echo esc_attr($button->options->iconColor); ?>"
369
- class="cnb-iconcolor-field" data-default-color="#FFFFFF"/>
370
- <?php if ($button->type === 'MULTI') { ?>
371
- <p class="description"><span class="dashicons dashicons-info"></span>This color applies to the collapsable button only.</p>
372
- <?php } ?>
373
- </td>
374
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
  <?php } ?>
376
  <tr>
377
  <th scope="row">Position <a
@@ -409,7 +570,6 @@ 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
- <?php if ($button->type !== 'MULTI') { ?>
413
  <!-- Extra placement options -->
414
  <br class="cnb-extra-placement">
415
  <div class="cnb-radio-item cnb-extra-placement <?php echo $button->options->placement == "MIDDLE_RIGHT" ? "cnb-extra-active" : ""; ?>">
@@ -440,11 +600,26 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
440
  </div>
441
  <a href="#" id="cnb-more-placements">More placement options...</a>
442
  <!-- END extra placement options -->
443
- <?php } ?>
444
  <?php } ?>
445
  </div>
446
  </td>
447
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  </table>
449
  <table class="form-table <?php echo cnb_is_active_tab('visibility') ?>" data-tab-name="visibility">
450
  <tbody id="cnb_form_table_visibility">
@@ -471,9 +646,9 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
471
  <span data-cnb_toggle_state_label="conditions_show_on_all_pages" class="cnb_toggle_state cnb_toggle_true">Yes</span>
472
  </td>
473
  </tr>
474
- <tr class="cnb_hide_on_show_on_all_pages">
475
- <th><input type="button" onclick="return cnb_add_condition();" value="Add page rule" class="button button-secondary page-title-action"></th>
476
- </tr>
477
  <?php if (empty($button->conditions)) { ?>
478
  <tr class="cnb_hide_on_show_on_all_pages">
479
  <td colspan="2">
@@ -483,23 +658,23 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
483
  </tr>
484
  <?php } else { ?>
485
  <?php foreach ($button->conditions as $condition) { ?>
486
- <tr class="appearance cnb-condition" id="cnb_condition_<?php echo esc_attr($condition->id) ?>">
487
  <td colspan="2" style="padding: 0;">
488
  <table class="cnb_condition_rule">
489
- <tbody>
490
- <tr>
491
- <td>
492
- <input type="hidden" name="condition[<?php echo esc_attr($condition->id) ?>][id]" value="<?php echo esc_attr($condition->id) ?>" />
493
- <input type="hidden" name="condition[<?php echo esc_attr($condition->id) ?>][conditionType]" value="<?php echo esc_attr($condition->conditionType) ?>" />
494
- <input type="hidden" name="condition[<?php echo esc_attr($condition->id) ?>][delete]" id="cnb_condition_<?php echo esc_attr($condition->id) ?>_delete" value="" />
495
- <label for="condition[<?php echo esc_attr($condition->id) ?>][filterType]">
496
- <select name="condition[<?php echo esc_attr($condition->id) ?>][filterType]" id="condition[<?php echo esc_attr($condition->id) ?>][filterType]">
497
- <option value="INCLUDE"<?php selected('INCLUDE', $condition->filterType) ?>>Include</option>
498
- <option value="EXCLUDE"<?php selected('EXCLUDE', $condition->filterType) ?>>Exclude</option>
499
- </select>
500
- </label>
501
- </td>
502
- <td>
503
  <select name="condition[<?php echo esc_attr($condition->id) ?>][matchType]">
504
  <?php foreach (cnb_get_condition_match_types() as $condition_match_type_key => $condition_match_type_value) { ?>
505
  <option value="<?php echo esc_attr($condition_match_type_key) ?>"<?php selected($condition_match_type_key, $condition->matchType) ?>>
@@ -507,30 +682,33 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
507
  </option>
508
  <?php } ?>
509
  </select>
510
- </td>
511
- <td class="max_width_column">
 
 
512
  <input type="text" name="condition[<?php echo esc_attr($condition->id) ?>][matchValue]" value="<?php echo esc_attr($condition->matchValue); ?>"/>
513
- <a onclick="return cnb_remove_condition('<?php echo esc_js($condition->id) ?>');" title="Remove Condition" class="button-link button-link-delete"><span class="dashicons dashicons-no"></span></a>
514
- </td>
515
- </tr>
516
- <?php // Match old "Hide button on front page"
517
- if ($condition->conditionType === 'URL' && $condition->filterType === 'EXCLUDE' && $condition->matchType === 'EXACT' && $condition->matchValue === get_home_url()) { ?>
518
- <tr>
519
- <td colspan="3"><p class="description" style="text-align: center;"><span class="dashicons dashicons-info"></span> This condition matches the plugin's "<strong>Hide button on front page</strong>" checkbox.</p></td>
520
- </tr>
521
- <?php } ?>
522
- <tr class="cnb_advanced_view">
523
- <td colspan="3" style="padding: 5px 10px"><div class="cnb_font_normal cnb_font_90">ID: <code class="cnb_font_90"><?php echo esc_html($condition->id) ?></code></div></td>
524
- </tr>
525
- </tbody>
 
526
  </table>
527
  </td>
528
  </tr>
529
  <?php } } ?>
530
- <tr id="cnb_form_table_add_condition">
531
- <th></th>
532
- <td></td>
533
- </tr>
534
  </tbody>
535
  </table>
536
 
@@ -544,27 +722,25 @@ function cnb_button_edit_form($button_id, $button, $default_domain, $options=arr
544
  * Main entrypoint, used by `call-now-button.php`.
545
  */
546
  function cnb_admin_page_edit_render() {
 
547
  global $cnb_options;
548
 
549
  $button_id = cnb_get_button_id();
550
  $button = new CnbButton();
551
 
552
  // Get the various supported domains
553
- $default_domain = CnbAppRemote::cnb_remote_get_wp_domain();
554
 
555
  if (strlen($button_id) > 0 && $button_id !== 'new') {
556
  $button = CnbAppRemote::cnb_remote_get_button_full( $button_id );
557
  } elseif ($button_id === 'new') {
558
  $button->type = strtoupper(filter_input(INPUT_GET, 'type', FILTER_SANITIZE_STRING));
559
- $button->domain = $default_domain;
560
  }
561
  if ($button->actions === null) {
562
  $button->actions = array();
563
  }
564
 
565
- // Set some sane defaults
566
- CnbButton::setSaneDefault($button);
567
-
568
  // Create options
569
  $options = array();
570
  $options['advanced_view'] = $cnb_options['advanced_view'];
@@ -574,13 +750,25 @@ function cnb_admin_page_edit_render() {
574
  });
575
 
576
  do_action('cnb_header');
577
- cnb_warn_about_timezone($default_domain);
 
 
 
 
 
 
 
 
 
 
 
 
 
578
  ?>
579
 
580
  <div class="cnb-two-column-section-preview">
581
  <div class="cnb-body-column">
582
  <div class="cnb-body-content">
583
-
584
  <h2 class="nav-tab-wrapper">
585
  <a href="<?php echo cnb_create_tab_url_button($button, 'basic_options') ?>"
586
  class="nav-tab <?php echo cnb_is_active_tab('basic_options') ?>" data-tab-name="basic_options">Basics</a>
@@ -589,26 +777,58 @@ function cnb_admin_page_edit_render() {
589
  class="nav-tab <?php echo cnb_is_active_tab('extra_options') ?>" data-tab-name="extra_options">Presentation</a>
590
  <a href="<?php echo cnb_create_tab_url_button($button, 'visibility') ?>"
591
  class="nav-tab <?php echo cnb_is_active_tab('visibility') ?>" data-tab-name="visibility">Visibility</a>
 
 
 
 
592
  <?php } else { ?>
593
  <a class="nav-tab"><i>Additional options available after saving</i></a>
594
  <?php } ?>
595
  </h2>
596
-
597
- <?php
598
- cnb_button_edit_form($button_id, $button, $default_domain, $options);
599
- ?>
600
- <!-- <div id="cnb-button-preview"></div> -->
601
- </div>
602
- </div>
603
  <div class="cnb-side-column">
604
  <div id="phone-preview">
605
- <div class="phone-outside double">
606
- <div class="speaker single"></div>
607
- <div class="phone-inside single">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
608
  <div id="cnb-button-preview"></div>
609
  </div>
610
- <div class="mic double"></div>
611
- </div>
612
  </div>
613
  </div>
614
  </div>
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAdminCloud;
4
+ use cnb\admin\api\CnbAppRemote;
5
+ use cnb\admin\models\CnbAction;
6
+ use cnb\admin\models\CnbActionProperties;
7
+ use cnb\admin\models\CnbButton;
8
+ use cnb\admin\models\CnbButtonOptions;
9
+ use cnb\admin\models\CnbCondition;
10
+ use cnb\admin\models\CnbDomain;
11
+
12
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
13
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
14
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
34
  }
35
  $buttonTypes = cnb_get_button_types();
36
  $typeName = $buttonTypes[$type];
37
+ echo __('Editing ') . esc_html($typeName) . ' <span class="cnb_button_name">' . esc_html($name) . '</span>';
38
  }
39
 
40
  function cnb_create_tab_url_button($button, $tab) {
51
  return esc_url( $tab_link );
52
  }
53
 
54
+ function cnb_process_create_and_update_button($closure) {
 
 
 
 
55
  $nonce = filter_input( INPUT_POST, '_wpnonce_button', FILTER_SANITIZE_STRING );
56
  if( isset( $_REQUEST['_wpnonce_button'] ) && wp_verify_nonce( $nonce, 'cnb-button-edit') ) {
57
 
58
  // sanitize the input
59
  $button = filter_input(
60
+ INPUT_POST,
61
+ 'cnb',
62
+ FILTER_SANITIZE_STRING,
63
+ FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES);
64
+ $actions = filter_input(
65
+ INPUT_POST,
66
+ 'actions',
67
+ FILTER_SANITIZE_STRING,
68
+ FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES);
69
+ $conditions = filter_input(
70
+ INPUT_POST,
71
+ 'condition',
72
+ FILTER_SANITIZE_STRING,
73
+ FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES);
74
+
75
+ if ($conditions === null) {
76
+ $conditions = array();
77
+ }
78
 
79
  // ensure the position is valid for FULL
80
  if (strtoupper($button['type']) === 'FULL') {
81
  if (!empty($button['options']) && !empty($button['options']['placement'])) {
82
  $placement = $button['options']['placement'];
83
+ if ( $placement !== 'BOTTOM_CENTER' && $placement !== 'TOP_CENTER' ) {
84
  $button['options']['placement'] = 'BOTTOM_CENTER';
85
  }
86
  } else {
88
  }
89
  }
90
 
91
+ /** @var CnbAction[] */
92
+ $processed_actions = array();
93
+ if (is_array($actions)) {
94
+ foreach ( $actions as $action ) {
95
+ $processed_actions[] = CnbAction::fromObject($action);
96
+ }
97
+ }
98
+
99
+ $processed_conditions = array();
100
+ if (is_array($conditions)) {
101
+ foreach ( $conditions as $condition ) {
102
+ $processed_conditions[] = CnbCondition::fromObject($condition);
103
+ }
104
+ }
105
+
106
+ $button['actions'] = $processed_actions;
107
+ $button['conditions'] = $processed_conditions;
108
+ $processed_button = CnbButton::fromObject($button);
109
+
110
+ // processing
111
+ $closure($processed_button, $processed_actions, $processed_conditions);
112
+ // end processing
113
+ } else {
114
+ wp_die( __( 'Invalid nonce specified', CNB_NAME), __( 'Error', CNB_NAME), array(
115
+ 'response' => 403,
116
+ 'back_link' => 'admin.php?page=' . CNB_SLUG,
117
+ ) );
118
+ }
119
+
120
+ }
121
+ /**
122
+ * This is called to update the button
123
+ * via `call-now-button.php#cnb_create_<type>_button`
124
+ */
125
+ function cnb_admin_create_button() {
126
+ /**
127
+ * @param $button CnbButton
128
+ *
129
+ * @return void
130
+ */
131
+ $inner = function($button) {
132
  // Do the processing
133
  $cnb_cloud_notifications = array();
134
+ $new_button = CnbAdminCloud::cnb_create_button( $cnb_cloud_notifications, $button );
135
 
136
  // redirect the user to the appropriate page
137
  $tab = filter_input( INPUT_POST, 'tab', FILTER_SANITIZE_STRING );
138
  $transient_id = 'cnb-' . wp_generate_uuid4();
139
  set_transient( $transient_id, $cnb_cloud_notifications, HOUR_IN_SECONDS );
140
 
141
+ if ( $new_button instanceof WP_Error ) {
142
  $new_button_type = null;
143
+ $new_button_id = null;
144
  } else {
145
  $new_button_type = strtolower( $new_button->type );
146
+ $new_button_id = $new_button->id;
147
  }
148
 
149
  // Create link
162
  $redirect_url = esc_url_raw( $redirect_link );
163
  wp_safe_redirect( $redirect_url );
164
  exit;
165
+ };
166
+ cnb_process_create_and_update_button($inner);
 
 
 
 
167
  }
168
 
169
  /**
171
  * via `call-now-button.php#cnb_update_<type>_button`
172
  */
173
  function cnb_admin_update_button() {
174
+ /**
175
+ * @param $button CnbButton
176
+ * @param $actions CnbAction[]
177
+ * @param $conditions CnbCondition[]
178
+ *
179
+ * @return void
180
+ */
181
+ $inner = function($button, $actions, $conditions) {
182
+ // do the processing
183
+ $result = CnbAdminCloud::cnb_update_button_and_conditions( $button, $actions, $conditions );
184
+
185
+ // redirect the user to the appropriate page
186
+ $tab = filter_input( INPUT_POST, 'tab', FILTER_SANITIZE_STRING );
187
+ $transient_id = 'cnb-' . wp_generate_uuid4();
188
+ set_transient( $transient_id, $result, HOUR_IN_SECONDS );
189
+
190
+ // Create link
191
+ $url = admin_url( 'admin.php' );
192
+ $redirect_link =
193
+ add_query_arg(
194
+ array(
195
+ 'page' => 'call-now-button',
196
+ 'action' => 'edit',
197
+ 'type' => strtolower( $button->type ),
198
+ 'id' => $button->id,
199
+ 'tid' => $transient_id,
200
+ 'tab' => $tab
201
+ ),
202
+ $url );
203
+ $redirect_url = esc_url_raw( $redirect_link );
204
+ wp_safe_redirect( $redirect_url );
205
+ exit;
206
+ };
207
+ cnb_process_create_and_update_button($inner);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
208
  }
209
 
210
+ /**
211
+ *
212
+ * This renders JUST the form (no tabs, preview phone, etc.) and is also used in button-overview for the "Add new" modal.
213
+ *
214
+ * @param $button_id int
215
+ * @param $button CnbButton
216
+ * @param $default_domain CnbDomain|WP_Error
217
+ * @param $options array
218
+ *
219
+ * @return void
220
+ */
221
  function cnb_button_edit_form($button_id, $button, $default_domain, $options=array()) {
222
  $domains = CnbAppRemote::cnb_remote_get_domains();
223
 
239
  'page' => 'call-now-button-actions',
240
  'action' => 'new',
241
  'id' => 'new',
242
+ 'tab' => 'basic_options',
243
  'bid' => $button->id),
244
  $url);
245
  $new_action_url = esc_url($new_action_link);
246
 
247
  // In case the API isn't working properly
248
  if ($default_domain instanceof WP_Error) {
249
+ $default_domain = new CnbDomain();
250
+ $default_domain->id = 0;
251
  }
252
 
253
+ wp_enqueue_script('jquery-ui-sortable');
254
+ wp_enqueue_script(CNB_SLUG . '-jquery-ui-touch-punch');
255
  wp_enqueue_script(CNB_SLUG . '-action-type-to-icon-text');
256
  wp_enqueue_script(CNB_SLUG . '-form-to-json');
257
  wp_enqueue_script(CNB_SLUG . '-preview');
258
  wp_enqueue_script(CNB_SLUG . '-client');
259
+ wp_enqueue_script(CNB_SLUG . '-action-edit');
260
+ wp_enqueue_style(CNB_SLUG . '-client');
261
  ?>
262
+ <script>
263
+ let cnb_css_root = '<?php echo esc_js(CnbAppRemote::cnb_get_static_base()) ?>';
264
+ let cnb_options = <?php echo json_encode(new stdClass()) ?>;
265
+ </script>
266
+ <form class="cnb-container <?php if (!$hide_on_modal) { ?>cnb-validation<?php } ?>" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" method="post">
267
  <input type="hidden" name="page" value="call-now-button" />
268
  <input type="hidden" name="action" value="<?php echo $button_id === 'new' ? 'cnb_create_'.strtolower($button->type).'_button' :'cnb_update_'.esc_attr(strtolower($button->type)).'_button' ?>" />
269
  <input type="hidden" name="_wpnonce_button" value="<?php echo wp_create_nonce('cnb-button-edit')?>" />
273
  <input type="hidden" name="cnb[type]" value="<?php echo esc_attr($button->type) ?>" id="cnb_type" />
274
  <input type="hidden" name="cnb[active]" value="<?php echo esc_attr($button->active) ?>" />
275
  <input type="hidden" name="cnb[domain]" value="<?php echo esc_attr($default_domain->id) ?>" />
 
 
 
 
 
276
 
277
  <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">
278
+ <tr class="cnb_hide_on_modal">
279
+ <th></th>
280
+ <td></td>
281
+ </tr>
282
+ <tr>
283
+ <th scope="row"><label for="cnb[name]">Button name</label></th>
284
+
285
+ <td class="activated">
286
+ <label for="cnb[name]"><input type="text" name="cnb[name]" id="cnb[name]" required="required" value="<?php echo esc_attr($button->name); ?>" /></label>
287
+ </td>
288
+ </tr>
289
+ <tr class="cnb_hide_on_modal">
290
+ <th scope="row"><label for="cnb-enable">Button status</label></th>
291
+
292
+ <td class="activated">
293
  <input type="hidden" name="cnb[active]" value="0" />
294
  <input id="cnb-enable" class="cnb_toggle_checkbox" type="checkbox" name="cnb[active]" value="1" <?php checked(true, $button->active); ?> />
295
  <label for="cnb-enable" class="cnb_toggle_label">Toggle</label>
296
+ <span data-cnb_toggle_state_label="cnb-enable" class="cnb_toggle_state cnb_toggle_false">(Inactive)</span>
297
  <span data-cnb_toggle_state_label="cnb-enable" class="cnb_toggle_state cnb_toggle_true">Active</span>
298
+ </td>
299
+ </tr>
300
+ <tr class="cnb_hide_on_modal cnb_advanced_view">
301
+ <th scope="row"><label for="cnb[domain]">Domain</label></th>
302
+ <td>
303
  <select name="cnb[domain]" id="cnb[domain]">
304
  <?php
305
  foreach ($domains as $domain) { ?>
306
+ <option
307
+ <?php selected($domain->id, $button->domain->id) ?>
308
+ value="<?php echo esc_attr($domain->id) ?>">
309
+ <?php echo esc_html($domain->name) ?>
310
  <?php if ($domain->id == $default_domain->id) { echo ' (current Wordpress domain)'; } ?>
311
  </option>
312
  <?php } ?>
313
  </select>
314
+ </td>
315
  </tr>
316
  <?php if ($button->type !== 'SINGLE') { ?>
317
  <tr class="cnb_hide_on_modal">
334
  $action->labelText = '';
335
  $action->properties = new CnbActionProperties();
336
  }
337
+ // Start workaround: This table below (<tr>...</tr>) needs to be there for the modal to work!
338
+ if ($hide_on_modal) { ?>
339
+ <tr class="cnb_hide_on_modal">
340
+ <th></th>
341
+ <td>
342
+ <input type="hidden" name="actions[<?php echo esc_attr($action->id) ?>][id]" value="<?php echo esc_attr($action->id) ?>" />
343
+ <?php }
344
  cnb_admin_page_action_edit_render_main($action, $button, $default_domain, false);
345
+ if ($hide_on_modal) { ?>
346
+ </td>
347
+ </tr>
348
+ <?php } // End workaround
349
+ } else { ?>
350
  </table>
351
 
352
  <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"'; } ?>>
353
  <?php cnb_admin_page_action_overview_render_form(array('button' => $button)); ?>
354
  <script>
355
  let cnb_actions = <?php echo json_encode($button->actions) ?>;
356
+ let cnb_domain = <?php echo json_encode($button->domain) ?>;
357
  </script>
358
  </div>
359
  <table class="form-table <?php if(!$hide_on_modal) { echo cnb_is_active_tab('basic_options'); } else { echo 'nav-tab-only'; } ?>"><?php
360
  } ?>
361
  <?php if ($button_id === 'new') { ?>
362
+ <tr>
363
+ <th scope="row">Select button type</th>
364
+ </tr>
365
+ <tr>
366
+ <td colspan="2">
367
+ <div class="cnb-flexbox cnb_type_selector">
368
  <div class="cnb_type_selector_item cnb_type_selector_single cnb_type_selector_active" data-cnb-selection="single">
369
  <img style="max-width:100%;" alt="Choose a Single button type" src="<?php echo $cnb_single_image ?>">
370
  <div style="text-align:center">Single button</div>
377
  <img style="max-width:100%;" alt="Choose a Full button type" src="<?php echo $cnb_full_image ?>">
378
  <div style="text-align:center">Buttonbar</div>
379
  </div>
380
+ </div>
381
+ </td>
382
+ </tr>
383
  <?php } ?>
384
  </table>
385
  <table class="form-table <?php echo cnb_is_active_tab('extra_options') ?>" data-tab-name="extra_options">
386
  <?php if ($button->type === 'FULL') { ?>
387
+ <tr>
388
+ <th colspan="2">
389
+ <h3>Colors for the Buttonbar are defined via the individual Action(s).</h3>
390
+ <input name="cnb[options][iconBackgroundColor]" type="hidden" value="<?php echo esc_attr($button->options->iconBackgroundColor); ?>" />
391
+ <input name="cnb[options][iconColor]" type="hidden" value="<?php echo esc_attr($button->options->iconColor); ?>" />
392
+ </th>
393
+ </tr>
394
+ <?php } else if ($button->type === 'SINGLE') {
395
+ // Migration note:
396
+ //- we move from button.options.iconBackgroundColor to action.backgroundColor
397
+ //- we move from button.options.iconColor to action.iconColor
398
+ // So for now, "button" take priority, but once the new value is saved, we blank the button options
399
+ $backgroundColor = ($button && $button->options && $button->options->iconBackgroundColor) ? $button->options->iconBackgroundColor : ($action->backgroundColor ?: '#009900');
400
+ $iconColor = ($button && $button->options && $button->options->iconColor) ? $button->options->iconColor : ($action->iconColor ?: '#FFFFFF');
401
+ ?>
402
+ <tr class="cnb_hide_on_modal">
403
+ <th></th>
404
+ <td>
405
+ <input name="cnb[options][iconBackgroundColor]" type="hidden" value="" />
406
+ <input name="cnb[options][iconColor]" type="hidden" value="" />
407
+ <!-- We always enable the icon when the type if SINGLE, original value is "<?php echo esc_attr($action->iconEnabled) ?>" -->
408
+ <input name="actions[<?php echo esc_attr($action->id) ?>][iconEnabled]" type="hidden" value="1" />
409
+ </td>
410
+ </tr>
411
+ <tr>
412
+ <th scope="row"><label for="actions-options-iconBackgroundColor">Button color</label></th>
413
+ <td>
414
+ <input name="actions[<?php echo esc_attr($action->id) ?>][backgroundColor]" id="actions-options-iconBackgroundColor" type="text" value="<?php echo esc_attr($backgroundColor); ?>" class="cnb-iconcolor-field" data-default-color="#009900"/>
415
+ </td>
416
+ </tr>
417
+ <tr>
418
+ <th scope="row"><label for="actions-options-iconColor">Icon color</label></th>
419
+ <td>
420
+ <input name="actions[<?php echo esc_attr($action->id) ?>][iconColor]" id="actions-options-iconColor" type="text" value="<?php echo esc_attr($iconColor); ?>" class="cnb-iconcolor-field" data-default-color="#FFFFFF"/>
421
+ </td>
422
+ </tr>
423
+
424
+ <?php } else if ($button->type === 'MULTI') {
425
+ $backgroundColor = ($button->options && $button->options->iconBackgroundColor) ? $button->options->iconBackgroundColor : ($button->multiButtonOptions->iconBackgroundColor ?: '#009900');
426
+ $iconColor = ($button->options && $button->options->iconColor) ? $button->options->iconColor : ($button->multiButtonOptions->iconColor ?: '#FFFFFF');
427
+ $iconTextOpen = ($button->multiButtonOptions && $button->multiButtonOptions->iconTextOpen) ? $button->multiButtonOptions->iconTextOpen : 'more_vert';
428
+ $iconTypeOpen = ($button->multiButtonOptions && $button->multiButtonOptions->iconTypeOpen) ? $button->multiButtonOptions->iconTypeOpen : 'FONT';
429
+ $iconTextClose = ($button->multiButtonOptions && $button->multiButtonOptions->iconTextClose) ? $button->multiButtonOptions->iconTextClose : 'close';
430
+ $iconTypeClose = ($button->multiButtonOptions && $button->multiButtonOptions->iconTypeClose) ? $button->multiButtonOptions->iconTypeClose : 'FONT';
431
+ $labelText = ($button->multiButtonOptions && $button->multiButtonOptions->iconTypeClose) ? $button->multiButtonOptions->labelText : null;
432
+ $labelBackgroundColor = ($button->multiButtonOptions && $button->multiButtonOptions->iconTypeClose) ? $button->multiButtonOptions->labelBackgroundColor : null;
433
+ ?>
434
+ <tr class="cnb_hide_on_modal">
435
+ <th></th>
436
+ <td></td>
437
+ </tr>
438
+ <tr>
439
+ <th scope="row"><label for="cnb-multiButtonOptions-iconBackgroundColor">Main button color</label></th>
440
+ <td>
441
+ <input name="cnb[multiButtonOptions][id]" type="hidden" value="<?php echo esc_attr($button->multiButtonOptions->id); ?>" />
442
+ <input name="cnb[multiButtonOptions][iconBackgroundColor]" id="cnb-multiButtonOptions-iconBackgroundColor" type="text" value="<?php echo esc_attr($backgroundColor); ?>"
443
+ class="cnb-iconcolor-field" data-default-color="#009900" />
444
+ </td>
445
+ </tr>
446
+ <tr>
447
+ <th scope="row"><label for="cnb-multiButtonOptions-iconColor">Main icon color</label></th>
448
+ <td>
449
+ <input name="cnb[multiButtonOptions][iconColor]" id="cnb-multiButtonOptions-iconColor" type="text" value="<?php echo esc_attr($iconColor); ?>"
450
+ class="cnb-iconcolor-field" data-default-color="#FFFFFF"/>
451
+ </td>
452
+ </tr>
453
+ <tr>
454
+ <th scope="row"><label for="cnb-multiButtonOptions-iconTextOpen">Main icon</label></th>
455
+ <td>
456
+ <div class="icon-text-options" id="icon-text-open" data-icon-text-target="cnb-multiButtonOptions-iconTextOpen" data-icon-type-target="cnb-multiButtonOptions-iconTypeOpen">
457
+ <div class="cnb-button-icon">
458
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="more_vert">more_vert</i>
459
+ </div>
460
+ <div class="cnb-button-icon">
461
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="menu">menu</i>
462
+ </div>
463
+ <div class="cnb-button-icon">
464
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="support">support</i>
465
+ </div>
466
+ <div class="cnb-button-icon">
467
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="communicate">communicate</i>
468
+ </div>
469
+ <div class="cnb-button-icon">
470
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="more_info">more_info</i>
471
+ </div>
472
+ <div class="cnb-button-icon">
473
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="conversation">conversation</i>
474
+ </div>
475
+ </div>
476
+ <div class="cnb_advanced_view">
477
+ <a
478
+ href="#"
479
+ onclick="return cnb_show_icon_text_advanced(this)"
480
+ data-icon-text="cnb-multiButtonOptions-iconTextOpen"
481
+ data-icon-type="cnb-multiButtonOptions-iconTypeOpen"
482
+ data-description="cnb-multiButtonOptions-iconTextOpen-description"
483
+ class="cnb_advanced_view">Use a custom icon</a>
484
+ <input name="cnb[multiButtonOptions][iconTextOpen]" id="cnb-multiButtonOptions-iconTextOpen" type="hidden" value="<?php echo esc_attr($iconTextOpen); ?>" />
485
+ <input name="cnb[multiButtonOptions][iconTypeOpen]" id="cnb-multiButtonOptions-iconTypeOpen" type="hidden" value="<?php echo esc_attr($iconTypeOpen); ?>" />
486
+ <p class="description" id="cnb-multiButtonOptions-iconTextOpen-description" style="display: none">
487
+ You can enter a custom Material Design font code here. Search the full library at <a href="https://fonts.google.com/icons" target="_blank">Google Fonts</a>.<br />
488
+ The Call Now Button uses the <code>filled</code> version of icons.</p>
489
+ </div>
490
+ </td>
491
+ </tr>
492
+ <tr class="cnb_advanced_view">
493
+ <th scope="row"><label for="cnb-multiButtonOptions-iconTextClose">Close Icon</label></th>
494
+ <td>
495
+ <div class="icon-text-options" id="icon-text-close" data-icon-text-target="cnb-multiButtonOptions-iconTextClose" data-icon-type-target="cnb-multiButtonOptions-iconTypeClose">
496
+ <div class="cnb-button-icon">
497
+ <i class="cnb-font-icon" data-icon-type="FONT" data-icon-text="close">close</i>
498
+ </div>
499
+ <div class="cnb-button-icon">
500
+ <i class="cnb-font-icon family-material" data-icon-type="FONT_MATERIAL" data-icon-text="cancel">cancel</i>
501
+ </div>
502
+ <div class="cnb-button-icon">
503
+ <i class="cnb-font-icon family-material" data-icon-type="FONT_MATERIAL" data-icon-text="close">close</i>
504
+ </div>
505
+ <div class="cnb-button-icon">
506
+ <i class="cnb-font-icon family-material" data-icon-type="FONT_MATERIAL" data-icon-text="zoom_in_map">zoom_in_map</i>
507
+ </div>
508
+ </div>
509
+ <a
510
+ href="#"
511
+ onclick="return cnb_show_icon_text_advanced(this)"
512
+ data-icon-text="cnb-multiButtonOptions-iconTextClose"
513
+ data-icon-type="cnb-multiButtonOptions-iconTypeClose"
514
+ data-description="cnb-multiButtonOptions-iconTextClose-description"
515
+ class="cnb_advanced_view">Use a custom icon</a>
516
+ <input name="cnb[multiButtonOptions][iconTextClose]" id="cnb-multiButtonOptions-iconTextClose" type="hidden" value="<?php echo esc_attr($iconTextClose); ?>" />
517
+ <input name="cnb[multiButtonOptions][iconTypeClose]" id="cnb-multiButtonOptions-iconTypeClose" type="hidden" value="<?php echo esc_attr($iconTypeClose); ?>" />
518
+ <p class="description" id="cnb-multiButtonOptions-iconTextClose-description" style="display: none">
519
+ You can enter a custom Material Design font code here. Search the full library at <a href="https://fonts.google.com/icons" target="_blank">Google Fonts</a>.<br />
520
+ The Call Now Button uses the <code>filled</code> version of icons.</p>
521
+ </td>
522
+ </tr>
523
+ <tr class="cnb_advanced_view">
524
+ <th scope="row"><label for="cnb-multiButtonOptions-labelText">Label text (when open)</label></th>
525
+ <td>
526
+ <input name="cnb[multiButtonOptions][labelText]" id="cnb-multiButtonOptions-labelText" type="text" value="<?php echo esc_attr($labelText); ?>" />
527
+ </td>
528
+ </tr>
529
+ <tr class="cnb_advanced_view">
530
+ <th scope="row"><label for="cnb-multiButtonOptions-labelBackgroundColor">Label background color</label></th>
531
+ <td>
532
+ <input name="cnb[multiButtonOptions][labelBackgroundColor]" id="cnb-multiButtonOptions-labelBackgroundColor" type="text" value="<?php echo esc_attr($labelBackgroundColor); ?>"
533
+ class="cnb-iconcolor-field" data-default-color="#3c434a"/>
534
+ </td>
535
+ </tr>
536
  <?php } ?>
537
  <tr>
538
  <th scope="row">Position <a
570
  <label title="bottom-center" for="appearance3">Center</label>
571
  </div>
572
 
 
573
  <!-- Extra placement options -->
574
  <br class="cnb-extra-placement">
575
  <div class="cnb-radio-item cnb-extra-placement <?php echo $button->options->placement == "MIDDLE_RIGHT" ? "cnb-extra-active" : ""; ?>">
600
  </div>
601
  <a href="#" id="cnb-more-placements">More placement options...</a>
602
  <!-- END extra placement options -->
 
603
  <?php } ?>
604
  </div>
605
  </td>
606
  </tr>
607
+ <?php if ($button->type !== 'FULL') { ?>
608
+ <tr>
609
+ <th scope="row"><label for="cnb_button_options_animation">Button animation <a
610
+ href="<?php echo CNB_SUPPORT; ?>wordpress/buttons/button-animation/<?php cnb_utm_params("question-mark", "button-animation"); ?>"
611
+ target="_blank" class="cnb-nounderscore">
612
+ <span class="dashicons dashicons-editor-help"></span>
613
+ </a></label></th>
614
+ <td>
615
+ <select name="cnb[options][animation]" id="cnb_button_options_animation">
616
+ <?php foreach ( CnbButtonOptions::getAnimationTypes() as $animation_type_key => $animation_type_value) { ?>
617
+ <option value="<?php echo esc_attr($animation_type_key) ?>"<?php selected($animation_type_key, $button->options->animation) ?>><?php echo esc_html($animation_type_value) ?></option>
618
+ <?php } ?>
619
+ </select>
620
+ </td>
621
+ </tr>
622
+ <?php } ?>
623
  </table>
624
  <table class="form-table <?php echo cnb_is_active_tab('visibility') ?>" data-tab-name="visibility">
625
  <tbody id="cnb_form_table_visibility">
646
  <span data-cnb_toggle_state_label="conditions_show_on_all_pages" class="cnb_toggle_state cnb_toggle_true">Yes</span>
647
  </td>
648
  </tr>
649
+ <tr class="cnb_hide_on_show_on_all_pages">
650
+ <th><input type="button" onclick="return cnb_add_condition();" value="Add page rule" class="button button-secondary page-title-action"></th>
651
+ </tr>
652
  <?php if (empty($button->conditions)) { ?>
653
  <tr class="cnb_hide_on_show_on_all_pages">
654
  <td colspan="2">
658
  </tr>
659
  <?php } else { ?>
660
  <?php foreach ($button->conditions as $condition) { ?>
661
+ <tr class="appearance cnb-condition" id="cnb_condition_<?php echo esc_attr($condition->id) ?>">
662
  <td colspan="2" style="padding: 0;">
663
  <table class="cnb_condition_rule">
664
+ <tr>
665
+ <td>
666
+ <input type="hidden" name="condition[<?php echo esc_attr($condition->id) ?>][id]" value="<?php echo esc_attr($condition->id) ?>" />
667
+ <input type="hidden" name="condition[<?php echo esc_attr($condition->id) ?>][conditionType]" value="<?php echo esc_attr($condition->conditionType) ?>" />
668
+ <input type="hidden" name="condition[<?php echo esc_attr($condition->id) ?>][delete]" id="cnb_condition_<?php echo esc_attr($condition->id) ?>_delete" value="" />
669
+ <label for="condition[<?php echo esc_attr($condition->id) ?>][filterType]">
670
+ <select name="condition[<?php echo esc_attr($condition->id) ?>][filterType]" id="condition[<?php echo esc_attr($condition->id) ?>][filterType]">
671
+ <option value="INCLUDE"<?php selected('INCLUDE', $condition->filterType) ?>>Include</option>
672
+ <option value="EXCLUDE"<?php selected('EXCLUDE', $condition->filterType) ?>>Exclude</option>
673
+ </select>
674
+ </label>
675
+ </td>
676
+ <td>
677
+ <label>
678
  <select name="condition[<?php echo esc_attr($condition->id) ?>][matchType]">
679
  <?php foreach (cnb_get_condition_match_types() as $condition_match_type_key => $condition_match_type_value) { ?>
680
  <option value="<?php echo esc_attr($condition_match_type_key) ?>"<?php selected($condition_match_type_key, $condition->matchType) ?>>
682
  </option>
683
  <?php } ?>
684
  </select>
685
+ </label>
686
+ </td>
687
+ <td class="max_width_column">
688
+ <label>
689
  <input type="text" name="condition[<?php echo esc_attr($condition->id) ?>][matchValue]" value="<?php echo esc_attr($condition->matchValue); ?>"/>
690
+ </label>
691
+ <a onclick="return cnb_remove_condition('<?php echo esc_js($condition->id) ?>');" title="Remove Condition" class="button-link button-link-delete"><span class="dashicons dashicons-no"></span></a>
692
+ </td>
693
+ </tr>
694
+ <?php
695
+ // Match old "Hide button on front page"
696
+ if ($condition->conditionType === 'URL' && $condition->filterType === 'EXCLUDE' && $condition->matchType === 'EXACT' && $condition->matchValue === get_home_url()) { ?>
697
+ <tr>
698
+ <td colspan="3"><p class="description" style="text-align: center;"><span class="dashicons dashicons-info"></span> This condition matches the plugin's "<strong>Hide button on front page</strong>" checkbox.</p></td>
699
+ </tr>
700
+ <?php } ?>
701
+ <tr class="cnb_advanced_view">
702
+ <td colspan="3" style="padding: 5px 10px"><div class="cnb_font_normal cnb_font_90">ID: <code class="cnb_font_90"><?php echo esc_html($condition->id) ?></code></div></td>
703
+ </tr>
704
  </table>
705
  </td>
706
  </tr>
707
  <?php } } ?>
708
+ <tr id="cnb_form_table_add_condition">
709
+ <th></th>
710
+ <td></td>
711
+ </tr>
712
  </tbody>
713
  </table>
714
 
722
  * Main entrypoint, used by `call-now-button.php`.
723
  */
724
  function cnb_admin_page_edit_render() {
725
+ global $wp_locale;
726
  global $cnb_options;
727
 
728
  $button_id = cnb_get_button_id();
729
  $button = new CnbButton();
730
 
731
  // Get the various supported domains
732
+ $domain = CnbAppRemote::cnb_remote_get_wp_domain();
733
 
734
  if (strlen($button_id) > 0 && $button_id !== 'new') {
735
  $button = CnbAppRemote::cnb_remote_get_button_full( $button_id );
736
  } elseif ($button_id === 'new') {
737
  $button->type = strtoupper(filter_input(INPUT_GET, 'type', FILTER_SANITIZE_STRING));
738
+ $button->domain = $domain;
739
  }
740
  if ($button->actions === null) {
741
  $button->actions = array();
742
  }
743
 
 
 
 
744
  // Create options
745
  $options = array();
746
  $options['advanced_view'] = $cnb_options['advanced_view'];
750
  });
751
 
752
  do_action('cnb_header');
753
+ cnb_warn_about_timezone($domain);
754
+
755
+ // Preview date picker details
756
+ // "w": 0 (for Sunday) through 6 (for Saturday)
757
+ $currentDayOfWeek = current_time('w');
758
+ $currentHourOfDay = current_time('H');
759
+ $currentMinuteOfHour = current_time('i');
760
+
761
+ // Round to the nearest 15 in an extremely lazy way
762
+ $currentMinuteOfHour = ($currentMinuteOfHour < 45) ? '30' : '45';
763
+ $currentMinuteOfHour = ($currentMinuteOfHour < 30) ? '15' : $currentMinuteOfHour;
764
+ $currentMinuteOfHour = ($currentMinuteOfHour < 15) ? '00' : $currentMinuteOfHour;
765
+ // END Preview date picker details
766
+
767
  ?>
768
 
769
  <div class="cnb-two-column-section-preview">
770
  <div class="cnb-body-column">
771
  <div class="cnb-body-content">
 
772
  <h2 class="nav-tab-wrapper">
773
  <a href="<?php echo cnb_create_tab_url_button($button, 'basic_options') ?>"
774
  class="nav-tab <?php echo cnb_is_active_tab('basic_options') ?>" data-tab-name="basic_options">Basics</a>
777
  class="nav-tab <?php echo cnb_is_active_tab('extra_options') ?>" data-tab-name="extra_options">Presentation</a>
778
  <a href="<?php echo cnb_create_tab_url_button($button, 'visibility') ?>"
779
  class="nav-tab <?php echo cnb_is_active_tab('visibility') ?>" data-tab-name="visibility">Visibility</a>
780
+ <?php if ($button->type === 'SINGLE') { ?>
781
+ <a href="<?php echo cnb_action_edit_create_tab_url($button, 'scheduler') ?>"
782
+ class="nav-tab <?php echo cnb_is_active_tab('scheduler') ?>" data-tab-name="scheduler">Schedule</a>
783
+ <?php } ?>
784
  <?php } else { ?>
785
  <a class="nav-tab"><i>Additional options available after saving</i></a>
786
  <?php } ?>
787
  </h2>
788
+ <?php cnb_button_edit_form($button_id, $button, $domain, $options); ?>
789
+ </div> <!-- /cnb-body-content -->
790
+ </div> <!-- /cnb-body-column -->
 
 
 
 
791
  <div class="cnb-side-column">
792
  <div id="phone-preview">
793
+ <div class="phone-outside double">
794
+ <div class="speaker single"></div>
795
+ <div class="phone-inside single">
796
+ <div class="cnb-preview-moment">
797
+ <label>
798
+ <select class="call-now-button-preview-selector" id="call-now-button-preview-selector-day">
799
+ <?php $days = array(1,2,3,4,5,6,0); foreach ($days as $day) {
800
+ echo '<option value="'.$day.'" ' . selected( $currentDayOfWeek, $day ) . '>' . $wp_locale->get_weekday( $day ) . '</option>';
801
+ }
802
+ ?>
803
+ </select>
804
+ </label>
805
+
806
+ <label>
807
+ <select class="call-now-button-preview-selector" id="call-now-button-preview-selector-hour">
808
+ <?php
809
+ foreach (range(0, 24) as $number) {
810
+ $number = $number < 10 ? '0' . $number : $number;
811
+ echo '<option '.selected($currentHourOfDay, $number).'>'.$number.'</option>';
812
+ }
813
+ ?>
814
+ </select>
815
+ </label>
816
+ :
817
+ <label>
818
+ <select class="call-now-button-preview-selector" id="call-now-button-preview-selector-minute">
819
+ <?php
820
+ foreach (range(0, 45, 15) as $number) {
821
+ $number = $number < 10 ? '0' . $number : $number;
822
+ echo '<option '.selected($currentMinuteOfHour, $number).'>'.$number.'</option>';
823
+ }
824
+ ?>
825
+ </select>
826
+ </label>
827
+ </div>
828
  <div id="cnb-button-preview"></div>
829
  </div>
830
+ <div class="mic double"></div>
831
+ </div>
832
  </div>
833
  </div>
834
  </div>
src/admin/button-overview.php CHANGED
@@ -1,5 +1,9 @@
1
  <?php
2
 
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
5
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
@@ -24,7 +28,7 @@ function cnb_get_new_button_link() {
24
  array(
25
  'TB_inline' => 'true',
26
  'inlineId' => 'cnb-add-new-modal',
27
- 'height' => '500', // 405 is ideal -> To hide the scrollbar
28
  'page' => 'call-now-button',
29
  'action' => 'new',
30
  'type' => 'single',
@@ -56,7 +60,7 @@ class Cnb_Button_List_Table extends WP_List_Table {
56
  /**
57
  * Used as a local caching variable to avoid multiple calls to the external datasource (i.e. API calls)
58
  *
59
- * @var array of Buttons
60
  */
61
  private $data;
62
 
@@ -91,6 +95,7 @@ class Cnb_Button_List_Table extends WP_List_Table {
91
  'name' => __('Name'),
92
  'type' => __('Type'),
93
  'actions' => __('Actions'),
 
94
  );
95
  }
96
 
@@ -106,6 +111,11 @@ class Cnb_Button_List_Table extends WP_List_Table {
106
  return array('id');
107
  }
108
 
 
 
 
 
 
109
  function get_views() {
110
  // Let's count
111
  $data = $this->get_data();
@@ -114,7 +124,7 @@ class Cnb_Button_List_Table extends WP_List_Table {
114
  if ($data instanceof WP_Error) return array();
115
  $all_count = count($data);
116
  $all_count_str = '<span class="count">('.$all_count.')</span>';
117
- $active_count = count(array_filter($data, function($el) { return $el['status'] === true; }));
118
  $active_count_str = '<span class="count">('.$active_count.')</span>';
119
 
120
  // Let's build a link
@@ -135,10 +145,11 @@ class Cnb_Button_List_Table extends WP_List_Table {
135
  $active_url = esc_url( $active_link );
136
 
137
  return array(
138
- 'all' => "<a href='" . $all_url . "' " . (!$current_view_is_active ? "class='current'" : '') . ">" . __('All') . $all_count_str."</a>",
139
- 'active' => "<a href='" . $active_url . "' " . ($current_view_is_active ? "class='current'" : '') . "'>" . __('Active') .$active_count_str."</a>"
140
  );
141
  }
 
142
  function prepare_items() {
143
  // Process any Bulk actions before gathering data
144
  $this->process_bulk_action();
@@ -153,7 +164,7 @@ class Cnb_Button_List_Table extends WP_List_Table {
153
  /* -- Filtering parameters -- */
154
  $current_view_is_active = isset( $_REQUEST['view'] ) && $_REQUEST['view'] === 'active';
155
  if ($current_view_is_active) {
156
- $data = array_filter($data, function($el) { return $el['status'] === true; });
157
  }
158
 
159
  /* -- Ordering parameters -- */
@@ -198,31 +209,51 @@ class Cnb_Button_List_Table extends WP_List_Table {
198
  return null;
199
  }
200
 
 
 
 
 
 
 
201
  function column_default( $item, $column_name )
202
  {
203
  switch( $column_name ) {
204
  case 'id':
205
- return '<code>' . esc_html($item[ $column_name ]) . '</code>';
206
  case 'name':
207
  case 'type':
208
- switch ($item[ $column_name ]) {
209
  case 'SINGLE':
210
  case 'FULL':
211
  case 'MULTI':
212
  $button_types = cnb_get_button_types();
213
- return $button_types[$item[ $column_name ]];
214
  default:
215
- return esc_html($item[$column_name]);
216
  }
217
  case 'actions':
218
  // Moved to column_actions
219
  break;
220
-
 
 
 
 
 
 
 
 
 
221
  default:
222
  return '<em>Unknown column ' .esc_html($column_name) . '</em>';
223
  }
224
  }
225
 
 
 
 
 
 
226
  function column_actions( $item ) {
227
  global $cnb_options;
228
 
@@ -232,8 +263,8 @@ class Cnb_Button_List_Table extends WP_List_Table {
232
  $count = 0;
233
 
234
  // Action info
235
- if ($item['actions']) {
236
- $count = count( $item['actions'] );
237
  }
238
 
239
  if ($count === 0) {
@@ -255,12 +286,15 @@ class Cnb_Button_List_Table extends WP_List_Table {
255
 
256
  // Domain info
257
  if ($cnb_options['advanced_view'] === 1) {
258
- $domain = '<br />Domain: <code>' . esc_html($item['domain']->name) . '</code>';
259
  }
260
 
261
  return "$items$actionMsg$domain";
262
  }
263
 
 
 
 
264
  private function get_data() {
265
  if (is_array($this->data)) return $this->data;
266
  $buttons = CnbAppRemote::cnb_remote_get_buttons_full();
@@ -273,32 +307,20 @@ class Cnb_Button_List_Table extends WP_List_Table {
273
  $buttons = array();
274
  }
275
 
276
- $data = array();
277
- foreach ($buttons as $button) {
278
- $data[] = array(
279
- 'id' => $button->id,
280
- 'name' => $button->name,
281
- 'type' => $button->type,
282
- 'actions' => $button->actions,
283
- 'status' => $button->active,
284
- 'domain' => $button->domain
285
- );
286
- }
287
-
288
  // Filter for current or all domains
289
  $filterOnDomainId = $this->options['filter_buttons_for_domain'];
290
  if ($filterOnDomainId) {
291
- $data = array_filter($data, function($el) use ( $filterOnDomainId ) { return $el['domain']->id === $filterOnDomainId; });
292
  }
293
 
294
- $this->data = $data;
295
- return $data;
296
  }
297
 
298
  /**
299
  * Allows you to sort the data by the variables set in the $_GET
300
  *
301
- * @return Mixed
302
  */
303
  private function sort_data( $a, $b ) {
304
  // If orderby is set, use this as the sort column
@@ -306,7 +328,7 @@ class Cnb_Button_List_Table extends WP_List_Table {
306
  // If order is set use this as the order
307
  $order = !empty($_GET['order']) ? sanitize_text_field($_GET['order']) : 'asc';
308
 
309
- $result = strcmp( $a[$orderby], $b[$orderby] );
310
 
311
  if($order === 'asc') {
312
  return $result;
@@ -317,70 +339,76 @@ class Cnb_Button_List_Table extends WP_List_Table {
317
  /**
318
  * Custom action for `cb` columns (checkboxes)
319
  *
320
- * @param array|object $item
321
- * @return string|void
 
322
  */
323
  function column_cb($item) {
324
  return sprintf(
325
  '<input type="checkbox" name="%1$s[]" value="%2$s" />',
326
  $this->_args['singular'],
327
- $item['id']
328
  );
329
  }
330
 
 
 
 
 
 
331
  function column_name($item) {
332
  // Let's build a link
333
  $url = admin_url('admin.php');
334
  $edit_link =
335
  add_query_arg(
336
- array( 'page' => 'call-now-button', 'action' => 'edit', 'type' => strtolower($item['type']), 'id' => $item['id'] ),
337
  $url );
338
  $edit_url = esc_url( $edit_link );
339
 
340
  $actions = array(
341
- 'edit' => '<a href="'.$edit_url.'">Edit</a>',
342
  );
343
  $enable_disable_link = wp_nonce_url(
344
  add_query_arg(
345
  array(
346
  'page' => 'call-now-button',
347
- 'action' => $item['status'] == true ? 'cnb_disable_button' : 'cnb_enable_button',
348
- 'id' => $item['id'] ),
349
  $url ),
350
  'cnb_enable_disable_button' );
351
  $enable_disable_url = esc_url( $enable_disable_link );
352
 
353
- if ($item['status'] == true) {
354
- $actions['disable'] = '<a href="'.$enable_disable_url.'">Disable</a>';
355
  } else {
356
- $actions['enable'] = '<a href="'.$enable_disable_url.'">Enable</a>';
357
  }
358
  $delete_link = wp_nonce_url(
359
  add_query_arg( array(
360
  'page' => 'call-now-button',
361
  'action' => 'cnb_delete_button',
362
- 'id' => $item['id'] ),
363
  $url ),
364
  'cnb_delete_button' );
365
  $delete_url = esc_url( $delete_link );
366
- $actions['delete'] = '<a href="'.$delete_url.'">Delete</a>';
367
 
368
  $inactive_str = '';
369
- if (!$item['status']) {
370
- $inactive_str = ' — <span class="post-state">Inactive</span>';
371
  }
372
  return sprintf(
373
  '%1$s %2$s',
374
- '<strong><a class="row-title" href="'.$edit_url.'">'.esc_html($item['name']) . '</a>' . $inactive_str . '</strong>',
375
  $this->row_actions($actions)
376
  );
377
  }
378
 
379
  function get_bulk_actions() {
380
  return array(
381
- 'enable' => 'Enable',
382
- 'disable' => 'Disable',
383
- 'delete' => 'Delete',
384
  );
385
  }
386
 
@@ -395,7 +423,9 @@ class Cnb_Button_List_Table extends WP_List_Table {
395
  case 'enable':
396
  case 'disable':
397
  foreach ($buttonIds as $buttonId) {
398
- $button = array('id' => $buttonId, 'active' => $this->current_action() === 'enable');
 
 
399
  CnbAppRemote::cnb_remote_update_button( $button );
400
  }
401
  CnbAdminNotices::get_instance()->renderSuccess('<p>' . count($buttonIds) . ' Buttons updated.</p>');
@@ -418,6 +448,11 @@ class Cnb_Button_List_Table extends WP_List_Table {
418
  }
419
  }
420
 
 
 
 
 
 
421
  function cnb_enable_disable_button($action) {
422
  if ( isset( $_REQUEST['_wpnonce'] ) && ! empty( $_REQUEST['_wpnonce'] ) ) {
423
  $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_STRING );
@@ -426,8 +461,11 @@ function cnb_enable_disable_button($action) {
426
  if ( wp_verify_nonce( $nonce, 'cnb_enable_disable_button' ) ) {
427
  $active = $action === 'cnb_enable_button';
428
  $action_verb = $active ? 'enable' : 'disable';
429
- $action_name = $action_verb . 'd';
430
- $button = array( 'id' => $id, 'active' => $active );
 
 
 
431
  $updated_button = CnbAppRemote::cnb_remote_update_button( $button );
432
 
433
  if (!is_wp_error($updated_button)) {
@@ -440,6 +478,11 @@ function cnb_enable_disable_button($action) {
440
  }
441
  }
442
 
 
 
 
 
 
443
  function cnb_delete_button($action) {
444
  if ( isset( $_REQUEST['_wpnonce'] ) && ! empty( $_REQUEST['_wpnonce'] ) ) {
445
  $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_STRING );
@@ -448,10 +491,7 @@ function cnb_delete_button($action) {
448
  if ( wp_verify_nonce( $nonce, $action ) ) {
449
  $cnb_cloud_notifications = array();
450
  CnbAdminCloud::cnb_delete_button( $cnb_cloud_notifications, $id );
451
- // TODO Should we be rendering ALL notices?!
452
- foreach ($cnb_cloud_notifications as $cnb_cloud_notification) {
453
- CnbAdminNotices::get_instance()->renderNotice($cnb_cloud_notification);
454
- }
455
  }
456
  }
457
  }
@@ -578,23 +618,22 @@ function cnb_admin_page_overview_render_list() {
578
  do_action('cnb_footer');
579
  }
580
 
581
- function cnb_admin_page_render_thickbox($default_domain = null) {
582
  add_thickbox();
583
  echo '<div id="cnb-add-new-modal" style="display:none;"><div>';
584
 
585
- if (!$default_domain) {
586
  // Get the various supported domains
587
- $default_domain = CnbAppRemote::cnb_remote_get_wp_domain();
588
  }
589
 
590
  $button_id = 'new';
591
 
592
  // Create a dummy button
593
- $button = CnbButton::createDummyButton($default_domain);
594
- CnbButton::setSaneDefault($button);
595
 
596
  $options = array('modal_view' => true, 'submit_button_text' => 'Next');
597
- cnb_button_edit_form($button_id, $button, $default_domain, $options);
598
  echo '</div></div>';
599
 
600
  }
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAdminCloud;
4
+ use cnb\admin\api\CnbAppRemote;
5
+ use cnb\admin\models\CnbButton;
6
+
7
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
8
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
9
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
28
  array(
29
  'TB_inline' => 'true',
30
  'inlineId' => 'cnb-add-new-modal',
31
+ 'height' => '433', // 433 seems ideal -> To hide the scrollbar. 500 to include validation errors
32
  'page' => 'call-now-button',
33
  'action' => 'new',
34
  'type' => 'single',
60
  /**
61
  * Used as a local caching variable to avoid multiple calls to the external datasource (i.e. API calls)
62
  *
63
+ * @var CnbButton[]
64
  */
65
  private $data;
66
 
95
  'name' => __('Name'),
96
  'type' => __('Type'),
97
  'actions' => __('Actions'),
98
+ 'displaymode' => __('Display'),
99
  );
100
  }
101
 
111
  return array('id');
112
  }
113
 
114
+ /**
115
+ * "views" is the top selector of a List Table (all, active, pending) etc
116
+ *
117
+ * @return string[]
118
+ */
119
  function get_views() {
120
  // Let's count
121
  $data = $this->get_data();
124
  if ($data instanceof WP_Error) return array();
125
  $all_count = count($data);
126
  $all_count_str = '<span class="count">('.$all_count.')</span>';
127
+ $active_count = count(array_filter($data, function($el) { return $el->active === true; }));
128
  $active_count_str = '<span class="count">('.$active_count.')</span>';
129
 
130
  // Let's build a link
145
  $active_url = esc_url( $active_link );
146
 
147
  return array(
148
+ 'all' => "<a href='" . $all_url . "' " . (!$current_view_is_active ? "class='current'" : '') . "'>" . __('All') . $all_count_str . '</a>',
149
+ 'active' => "<a href='" . $active_url . "' " . ($current_view_is_active ? "class='current'" : '') . "'>" . __('Active') . $active_count_str . '</a>'
150
  );
151
  }
152
+
153
  function prepare_items() {
154
  // Process any Bulk actions before gathering data
155
  $this->process_bulk_action();
164
  /* -- Filtering parameters -- */
165
  $current_view_is_active = isset( $_REQUEST['view'] ) && $_REQUEST['view'] === 'active';
166
  if ($current_view_is_active) {
167
+ $data = array_filter($data, function($el) { return $el->active === true; });
168
  }
169
 
170
  /* -- Ordering parameters -- */
209
  return null;
210
  }
211
 
212
+ /**
213
+ * @param $item CnbButton
214
+ * @param $column_name string
215
+ *
216
+ * @return string|void
217
+ */
218
  function column_default( $item, $column_name )
219
  {
220
  switch( $column_name ) {
221
  case 'id':
222
+ return '<code>' . esc_html($item->id) . '</code>';
223
  case 'name':
224
  case 'type':
225
+ switch ($item->type) {
226
  case 'SINGLE':
227
  case 'FULL':
228
  case 'MULTI':
229
  $button_types = cnb_get_button_types();
230
+ return $button_types[$item->type];
231
  default:
232
+ return esc_html($item->type);
233
  }
234
  case 'actions':
235
  // Moved to column_actions
236
  break;
237
+ case 'displaymode':
238
+ switch ($item->options->displayMode) {
239
+ case 'MOBILE_ONLY':
240
+ return __('Mobile only');
241
+ case 'DESKTOP_ONLY':
242
+ return __('Desktop only');
243
+ case 'ALWAYS':
244
+ default:
245
+ return __('All screens');
246
+ }
247
  default:
248
  return '<em>Unknown column ' .esc_html($column_name) . '</em>';
249
  }
250
  }
251
 
252
+ /**
253
+ * @param $item CnbButton
254
+ *
255
+ * @return string
256
+ */
257
  function column_actions( $item ) {
258
  global $cnb_options;
259
 
263
  $count = 0;
264
 
265
  // Action info
266
+ if ($item->actions) {
267
+ $count = count( $item->actions );
268
  }
269
 
270
  if ($count === 0) {
286
 
287
  // Domain info
288
  if ($cnb_options['advanced_view'] === 1) {
289
+ $domain = '<br />Domain: <code>' . esc_html($item->domain->name) . '</code>';
290
  }
291
 
292
  return "$items$actionMsg$domain";
293
  }
294
 
295
+ /**
296
+ * @return CnbButton[]|WP_Error
297
+ */
298
  private function get_data() {
299
  if (is_array($this->data)) return $this->data;
300
  $buttons = CnbAppRemote::cnb_remote_get_buttons_full();
307
  $buttons = array();
308
  }
309
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  // Filter for current or all domains
311
  $filterOnDomainId = $this->options['filter_buttons_for_domain'];
312
  if ($filterOnDomainId) {
313
+ $buttons = array_filter($buttons, function($el) use ( $filterOnDomainId ) { return $el->domain->id === $filterOnDomainId; });
314
  }
315
 
316
+ $this->data = $buttons;
317
+ return $buttons;
318
  }
319
 
320
  /**
321
  * Allows you to sort the data by the variables set in the $_GET
322
  *
323
+ * @return int
324
  */
325
  private function sort_data( $a, $b ) {
326
  // If orderby is set, use this as the sort column
328
  // If order is set use this as the order
329
  $order = !empty($_GET['order']) ? sanitize_text_field($_GET['order']) : 'asc';
330
 
331
+ $result = strcmp( $a->$orderby, $b->$orderby );
332
 
333
  if($order === 'asc') {
334
  return $result;
339
  /**
340
  * Custom action for `cb` columns (checkboxes)
341
  *
342
+ * @param CnbButton $item
343
+ *
344
+ * @return string
345
  */
346
  function column_cb($item) {
347
  return sprintf(
348
  '<input type="checkbox" name="%1$s[]" value="%2$s" />',
349
  $this->_args['singular'],
350
+ $item->id
351
  );
352
  }
353
 
354
+ /**
355
+ * @param $item CnbButton
356
+ *
357
+ * @return string
358
+ */
359
  function column_name($item) {
360
  // Let's build a link
361
  $url = admin_url('admin.php');
362
  $edit_link =
363
  add_query_arg(
364
+ array( 'page' => 'call-now-button', 'action' => 'edit', 'type' => strtolower($item->type), 'id' => $item->id ),
365
  $url );
366
  $edit_url = esc_url( $edit_link );
367
 
368
  $actions = array(
369
+ 'edit' => '<a href="'.$edit_url.'">'.__('Edit').'</a>',
370
  );
371
  $enable_disable_link = wp_nonce_url(
372
  add_query_arg(
373
  array(
374
  'page' => 'call-now-button',
375
+ 'action' => $item->active == true ? 'cnb_disable_button' : 'cnb_enable_button',
376
+ 'id' => $item->id ),
377
  $url ),
378
  'cnb_enable_disable_button' );
379
  $enable_disable_url = esc_url( $enable_disable_link );
380
 
381
+ if ($item->active == true) {
382
+ $actions['disable'] = '<a href="'.$enable_disable_url.'">'.__('Disable').'</a>';
383
  } else {
384
+ $actions['enable'] = '<a href="'.$enable_disable_url.'">'.__('Enable').'</a>';
385
  }
386
  $delete_link = wp_nonce_url(
387
  add_query_arg( array(
388
  'page' => 'call-now-button',
389
  'action' => 'cnb_delete_button',
390
+ 'id' => $item->id ),
391
  $url ),
392
  'cnb_delete_button' );
393
  $delete_url = esc_url( $delete_link );
394
+ $actions['delete'] = '<a href="'.$delete_url.'">'.__('Delete').'</a>';
395
 
396
  $inactive_str = '';
397
+ if (!$item->active) {
398
+ $inactive_str = ' — <span class="post-state">'.__('Inactive').'</span>';
399
  }
400
  return sprintf(
401
  '%1$s %2$s',
402
+ '<strong><a class="row-title" href="'.$edit_url.'">'.esc_html($item->name) . '</a>' . $inactive_str . '</strong>',
403
  $this->row_actions($actions)
404
  );
405
  }
406
 
407
  function get_bulk_actions() {
408
  return array(
409
+ 'enable' => __('Enable'),
410
+ 'disable' => __('Disable'),
411
+ 'delete' => __('Delete'),
412
  );
413
  }
414
 
423
  case 'enable':
424
  case 'disable':
425
  foreach ($buttonIds as $buttonId) {
426
+ $button = CnbAppRemote::cnb_remote_get_button_full($buttonId);
427
+ $button->active = $this->current_action() === 'enable';
428
+
429
  CnbAppRemote::cnb_remote_update_button( $button );
430
  }
431
  CnbAdminNotices::get_instance()->renderSuccess('<p>' . count($buttonIds) . ' Buttons updated.</p>');
448
  }
449
  }
450
 
451
+ /**
452
+ * @param $action string "cnb_enable_button" or "cnb_disable_button"
453
+ *
454
+ * @return void
455
+ */
456
  function cnb_enable_disable_button($action) {
457
  if ( isset( $_REQUEST['_wpnonce'] ) && ! empty( $_REQUEST['_wpnonce'] ) ) {
458
  $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_STRING );
461
  if ( wp_verify_nonce( $nonce, 'cnb_enable_disable_button' ) ) {
462
  $active = $action === 'cnb_enable_button';
463
  $action_verb = $active ? 'enable' : 'disable';
464
+ $action_name = __($action_verb . 'd');
465
+
466
+ $button = CnbAppRemote::cnb_remote_get_button_full($id);
467
+ $button->active = $active;
468
+
469
  $updated_button = CnbAppRemote::cnb_remote_update_button( $button );
470
 
471
  if (!is_wp_error($updated_button)) {
478
  }
479
  }
480
 
481
+ /**
482
+ * @param $action string cnb_delete_button (always) used to verify the nonce
483
+ *
484
+ * @return void
485
+ */
486
  function cnb_delete_button($action) {
487
  if ( isset( $_REQUEST['_wpnonce'] ) && ! empty( $_REQUEST['_wpnonce'] ) ) {
488
  $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_STRING );
491
  if ( wp_verify_nonce( $nonce, $action ) ) {
492
  $cnb_cloud_notifications = array();
493
  CnbAdminCloud::cnb_delete_button( $cnb_cloud_notifications, $id );
494
+ CnbAdminNotices::get_instance()->notices($cnb_cloud_notifications);
 
 
 
495
  }
496
  }
497
  }
618
  do_action('cnb_footer');
619
  }
620
 
621
+ function cnb_admin_page_render_thickbox($domain = null) {
622
  add_thickbox();
623
  echo '<div id="cnb-add-new-modal" style="display:none;"><div>';
624
 
625
+ if (!$domain) {
626
  // Get the various supported domains
627
+ $domain = CnbAppRemote::cnb_remote_get_wp_domain();
628
  }
629
 
630
  $button_id = 'new';
631
 
632
  // Create a dummy button
633
+ $button = CnbButton::createDummyButton($domain);
 
634
 
635
  $options = array('modal_view' => true, 'submit_button_text' => 'Next');
636
+ cnb_button_edit_form($button_id, $button, $domain, $options);
637
  echo '</div></div>';
638
 
639
  }
src/admin/condition-edit.php CHANGED
@@ -1,5 +1,9 @@
1
  <?php
2
 
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
5
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
@@ -24,135 +28,121 @@ function cnb_add_header_condition_edit($condition) {
24
  }
25
  }
26
 
27
- /**
28
- * This is called to create the condition
29
- * via `call-now-button.php#cnb_admin_create_condition`
30
- */
31
- function cnb_admin_page_condition_create_process() {
32
- $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING );
33
- if( isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $nonce, 'cnb_create_condition') ) {
34
 
35
  // sanitize the input
36
- $conditions = filter_input(
37
  INPUT_POST,
38
  'conditions',
39
  FILTER_SANITIZE_STRING,
40
- FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES);
41
 
42
- $result = '';
43
- $cnb_cloud_notifications = array();
44
- foreach($conditions as $condition) {
45
- // do the processing
46
- $result = CnbAdminCloud::cnb_create_condition( $cnb_cloud_notifications, $condition );
47
  }
48
 
49
- // redirect the user to the appropriate page
50
- $transient_id = 'cnb-' . wp_generate_uuid4();
51
- set_transient($transient_id, $cnb_cloud_notifications, HOUR_IN_SECONDS);
52
-
53
- // Create link
54
- $bid = !empty($_GET['bid']) ? sanitize_text_field($_GET['bid']) : null;
55
- $url = admin_url('admin.php');
56
- if (!empty($bid)) {
57
- $redirect_link =
58
- add_query_arg(
59
- array(
60
- 'page' => 'call-now-button',
61
- 'action' => 'edit',
62
- 'id' => $bid,
63
- 'tid' => $transient_id,
64
- 'tab' => 'visibility',
65
- ),
66
- $url);
67
- $redirect_url = esc_url_raw($redirect_link);
68
- wp_safe_redirect($redirect_url);
69
- exit;
70
- } else {
71
- $redirect_link =
72
- add_query_arg(
73
- array(
74
- 'page' => 'call-now-button-conditions',
75
- 'action' => 'edit',
76
- 'id' => $result->id,
77
- 'tid' => $transient_id,
78
- 'bid' => $bid),
79
- $url);
80
- $redirect_url = esc_url_raw($redirect_link);
81
- wp_safe_redirect($redirect_url);
82
- exit;
83
- }
84
- }
85
- else {
86
- wp_die( __( 'Invalid nonce specified', CNB_NAME), __( 'Error', CNB_NAME), array(
87
- 'response' => 403,
88
  'back_link' => 'admin.php?page=' . CNB_SLUG,
89
  ) );
90
  }
91
  }
92
 
93
  /**
94
- * This is called to update the condition
95
- * via `call-now-button.php#cnb_update_condition`
 
 
96
  */
97
- function cnb_admin_page_condition_edit_process() {
98
- $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING );
99
- if( isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $nonce, 'cnb_update_condition') ) {
 
100
 
101
- // sanitize the input
102
- $conditions = filter_input(
103
- INPUT_POST,
104
- 'conditions',
105
- FILTER_SANITIZE_STRING,
106
- FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES);
107
- $result = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  $cnb_cloud_notifications = array();
109
- foreach($conditions as $condition) {
 
110
  // do the processing
111
- $result = CnbAdminCloud::cnb_update_condition( $cnb_cloud_notifications, $condition );
112
  }
 
113
 
114
- // redirect the user to the appropriate page
115
- $transient_id = 'cnb-' . wp_generate_uuid4();
116
- set_transient($transient_id, $cnb_cloud_notifications, HOUR_IN_SECONDS);
117
 
118
- // Create link
119
- $bid = !empty($_GET['bid']) ? sanitize_text_field($_GET['bid']) : null;
120
- $url = admin_url('admin.php');
121
- if (!empty($bid)) {
122
- $redirect_link =
123
- add_query_arg(
124
- array(
125
- 'page' => 'call-now-button',
126
- 'action' => 'edit',
127
- 'id' => $bid,
128
- 'tid' => $transient_id,
129
- 'tab' => 'visibility',
130
- ),
131
- $url);
132
- $redirect_url = esc_url_raw($redirect_link);
133
- wp_safe_redirect($redirect_url);
134
- exit;
135
- } else {
136
- $redirect_link =
137
- add_query_arg(
138
- array(
139
- 'page' => 'call-now-button-conditions',
140
- 'action' => 'edit',
141
- 'id' => $result->id,
142
- 'tid' => $transient_id,
143
- 'bid' => $bid),
144
- $url);
145
- $redirect_url = esc_url_raw($redirect_link);
146
- wp_safe_redirect($redirect_url);
147
- exit;
148
  }
149
- }
150
- else {
151
- wp_die( __( 'Invalid nonce specified', CNB_NAME), __( 'Error', CNB_NAME), array(
152
- 'response' => 403,
153
- 'back_link' => 'admin.php?page=' . CNB_SLUG,
154
- ) );
155
- }
156
  }
157
 
158
  function cnb_create_tab_url_conditions($button, $tab) {
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAdminCloud;
4
+ use cnb\admin\api\CnbAppRemote;
5
+ use cnb\admin\models\CnbCondition;
6
+
7
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
8
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
9
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
28
  }
29
  }
30
 
31
+ function cnb_process_create_and_update_condition($closure) {
32
+ $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING );
33
+ if ( isset( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $nonce, 'cnb_update_condition' ) ) {
 
 
 
 
34
 
35
  // sanitize the input
36
+ $conditions = filter_input(
37
  INPUT_POST,
38
  'conditions',
39
  FILTER_SANITIZE_STRING,
40
+ FILTER_REQUIRE_ARRAY | FILTER_FLAG_NO_ENCODE_QUOTES );
41
 
42
+ $processed_conditions = array();
43
+ if (is_array($conditions)) {
44
+ foreach ( $conditions as $condition ) {
45
+ $processed_conditions[] = CnbCondition::fromObject($condition);
46
+ }
47
  }
48
 
49
+ $closure($processed_conditions);
50
+ } else {
51
+ wp_die( __( 'Invalid nonce specified', CNB_NAME ), __( 'Error', CNB_NAME ), array(
52
+ 'response' => 403,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  'back_link' => 'admin.php?page=' . CNB_SLUG,
54
  ) );
55
  }
56
  }
57
 
58
  /**
59
+ * @param $cnb_cloud_notifications array
60
+ * @param $conditions CnbCondition[]
61
+ *
62
+ * @return void
63
  */
64
+ function cnb_process_create_and_update_condition_post($cnb_cloud_notifications, $conditions) {
65
+ // redirect the user to the appropriate page
66
+ $transient_id = 'cnb-' . wp_generate_uuid4();
67
+ set_transient($transient_id, $cnb_cloud_notifications, HOUR_IN_SECONDS);
68
 
69
+ // Create link
70
+ $bid = !empty($_GET['bid']) ? sanitize_text_field($_GET['bid']) : null;
71
+ $url = admin_url('admin.php');
72
+ if (!empty($bid)) {
73
+ $redirect_link =
74
+ add_query_arg(
75
+ array(
76
+ 'page' => 'call-now-button',
77
+ 'action' => 'edit',
78
+ 'id' => $bid,
79
+ 'tid' => $transient_id,
80
+ 'tab' => 'visibility',
81
+ ),
82
+ $url);
83
+ $redirect_url = esc_url_raw($redirect_link);
84
+ wp_safe_redirect($redirect_url);
85
+ exit;
86
+ } else {
87
+ $redirect_link =
88
+ add_query_arg(
89
+ array(
90
+ 'page' => 'call-now-button-conditions',
91
+ 'action' => 'edit',
92
+ 'id' => $conditions[0]->id,
93
+ 'tid' => $transient_id,
94
+ 'bid' => $bid),
95
+ $url);
96
+ $redirect_url = esc_url_raw($redirect_link);
97
+ wp_safe_redirect($redirect_url);
98
+ exit;
99
+ }
100
+ }
101
+
102
+ /**
103
+ * This is called to create the condition
104
+ * via `call-now-button.php#cnb_admin_create_condition`
105
+ */
106
+ function cnb_admin_page_condition_create_process() {
107
+ /**
108
+ * @param $conditions CnbCondition[]
109
+ *
110
+ * @return void
111
+ */
112
+ $inner = function ($conditions) {
113
  $cnb_cloud_notifications = array();
114
+ $result = array();
115
+ foreach ( $conditions as $condition ) {
116
  // do the processing
117
+ $result[] = CnbAdminCloud::cnb_create_condition( $cnb_cloud_notifications, $condition );
118
  }
119
+ cnb_process_create_and_update_condition_post($cnb_cloud_notifications, $result);
120
 
121
+ };
122
+ cnb_process_create_and_update_condition($inner);
 
123
 
124
+ }
125
+
126
+ /**
127
+ * This is called to update the condition
128
+ * via `call-now-button.php#cnb_update_condition`
129
+ */
130
+ function cnb_admin_page_condition_edit_process() {
131
+ /**
132
+ * @param $conditions CnbCondition[]
133
+ *
134
+ * @return void
135
+ */
136
+ $inner = function ($conditions) {
137
+ $cnb_cloud_notifications = array();
138
+ $result = array();
139
+ foreach($conditions as $condition) {
140
+ // do the processing
141
+ $result[] = CnbAdminCloud::cnb_update_condition( $cnb_cloud_notifications, $condition );
 
 
 
 
 
 
 
 
 
 
 
 
142
  }
143
+ cnb_process_create_and_update_condition_post($cnb_cloud_notifications, $result);
144
+ };
145
+ cnb_process_create_and_update_condition($inner);
 
 
 
 
146
  }
147
 
148
  function cnb_create_tab_url_conditions($button, $tab) {
src/admin/condition-overview.php CHANGED
@@ -1,5 +1,9 @@
1
  <?php
2
 
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
5
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
@@ -290,7 +294,7 @@ class Cnb_Condition_List_Table extends WP_List_Table {
290
  $url ),
291
  'cnb_delete_condition' );
292
  $delete_url = esc_url( $delete_link );
293
- $actions['delete'] = '<a href="'.$delete_url.'">Delete</a>';
294
 
295
  $value = !empty($item['conditionType']) ? $item['conditionType'] : '<em>No value</em>';
296
  return sprintf(
@@ -318,8 +322,9 @@ class Cnb_Condition_List_Table extends WP_List_Table {
318
  switch ($this->current_action()) {
319
  case 'delete':
320
  foreach ($entityIds as $entityId) {
321
- $entity = array('id' => $entityId);
322
- CnbAppRemote::cnb_remote_delete_condition( $entity );
 
323
  }
324
  CnbAdminNotices::get_instance()->renderSuccess(count($entityIds) . ' Condition(s) deleted.');
325
  break;
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAdminCloud;
4
+ use cnb\admin\api\CnbAppRemote;
5
+ use cnb\admin\models\CnbCondition;
6
+
7
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
8
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
9
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
294
  $url ),
295
  'cnb_delete_condition' );
296
  $delete_url = esc_url( $delete_link );
297
+ $actions['delete'] = '<a href="'.$delete_url.'">'.__('Delete').'</a>';
298
 
299
  $value = !empty($item['conditionType']) ? $item['conditionType'] : '<em>No value</em>';
300
  return sprintf(
322
  switch ($this->current_action()) {
323
  case 'delete':
324
  foreach ($entityIds as $entityId) {
325
+ $condition = new CnbCondition();
326
+ $condition->id = $entityId;
327
+ CnbAppRemote::cnb_remote_delete_condition( $condition );
328
  }
329
  CnbAdminNotices::get_instance()->renderSuccess(count($entityIds) . ' Condition(s) deleted.');
330
  break;
src/admin/domain-edit.php CHANGED
@@ -1,5 +1,9 @@
1
  <?php
2
 
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
5
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
@@ -249,8 +253,8 @@ function cnb_admin_page_domain_edit_render_form_plan_details($domain) {
249
 
250
  <input id="cnb-renew" class="cnb_toggle_checkbox" name="domain[renew]" type="checkbox" value="true" <?php checked('1', $domain->renew); ?> />
251
  <label for="cnb-renew" class="cnb_toggle_label">Toggle</label>
252
- <span data-cnb_toggle_state_label="cnb-renew" class="cnb_toggle_state cnb_toggle_false">Inactive</span>
253
- <span data-cnb_toggle_state_label="cnb-renew" class="cnb_toggle_state cnb_toggle_true">Active</span>
254
 
255
  <?php if (!empty($domain->expires)) { ?>
256
  <p class="description" id="domain_expires-description">
@@ -269,17 +273,17 @@ function cnb_admin_page_domain_edit_render_form_tracking($domain) { ?>
269
  <th colspan="2"><h2>Tracking</h2></th>
270
  </tr>
271
  <tr>
272
- <th scope="row"><label for="google_analytics">Google Analytics<label</th>
273
  <td>
274
  <input type="hidden" name="domain[trackGA]" value="0" />
275
  <input id="google_analytics" class="cnb_toggle_checkbox" name="domain[trackGA]" type="checkbox" value="true" <?php checked('1', $domain->trackGA); ?> />
276
  <label for="google_analytics" class="cnb_toggle_label">Enable GA tracking</label>
277
- <span data-cnb_toggle_state_label="google_analytics" class="cnb_toggle_state cnb_toggle_false">Click tracking inactive</span>
278
  <span data-cnb_toggle_state_label="google_analytics" class="cnb_toggle_state cnb_toggle_true">Click tracking active</span>
279
 
280
  <p class="description">
281
  Supports Classic, Universal Analytics and Global site tag (v3 and v4).<br>
282
- 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>
283
  </p>
284
  </td>
285
  </tr>
@@ -289,7 +293,7 @@ function cnb_admin_page_domain_edit_render_form_tracking($domain) { ?>
289
  <input type="hidden" name="domain[trackConversion]" value="0" />
290
  <input id="conversion_tracking" class="cnb_toggle_checkbox" name="domain[trackConversion]" type="checkbox" value="true" <?php checked('1', $domain->trackConversion); ?> />
291
  <label for="conversion_tracking" class="cnb_toggle_label">Enable Google Ads conversion tracking</label>
292
- <span data-cnb_toggle_state_label="conversion_tracking" class="cnb_toggle_state cnb_toggle_false">Conversion tracking inactive</span>
293
  <span data-cnb_toggle_state_label="conversion_tracking" class="cnb_toggle_state cnb_toggle_true">Conversion tracking active</span>
294
 
295
  <p class="description">Select this option if you want to count clicks on the button as Google Ads conversions. This option requires the Event snippet to be present on the page. <a href="https://support.google.com/google-ads/answer/6331304" target="_blank">Learn more...</a></p>
@@ -329,9 +333,29 @@ function cnb_admin_page_domain_edit_render_form_button_display($domain) {
329
  notice) you can move this backwards one step at a time to adapt it to your situation.</p>
330
  </td>
331
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
  <?php
333
  }
334
 
 
 
 
 
 
 
335
  function cnb_admin_page_domain_edit_render_form_advanced($domain, $header=true) {
336
  global $cnb_options;
337
  $show_advanced_view_only = array_key_exists('advanced_view', $cnb_options) && $cnb_options['advanced_view'] === 1;
@@ -385,13 +409,13 @@ function cnb_admin_page_domain_edit_render_form_advanced($domain, $header=true)
385
  <input type="hidden" name="domain[properties][debug]" value="false" />
386
  <input id="domain_properties_debug" class="cnb_toggle_checkbox" name="domain[properties][debug]" type="checkbox" value="true" <?php checked('true', $domain->properties->debug); ?> />
387
  <label for="domain_properties_debug" class="cnb_toggle_label">Enable debugging mode</label>
388
- <span data-cnb_toggle_state_label="domain_properties_debug" class="cnb_toggle_state cnb_toggle_false">Disabled</span>
389
  <span data-cnb_toggle_state_label="domain_properties_debug" class="cnb_toggle_state cnb_toggle_true">Enabled</span>
390
 
391
  <p class="description">
392
  This setting enables debug information in your browser's console, which can help during troubleshooting.
393
  </p>
394
- </fieldset></td>
395
  </tr>
396
  <?php
397
  }
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAdminCloud;
4
+ use cnb\admin\api\CnbAppRemote;
5
+ use cnb\admin\models\CnbDomain;
6
+
7
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
8
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
9
  require_once dirname( __FILE__ ) . '/partials/admin-functions.php';
253
 
254
  <input id="cnb-renew" class="cnb_toggle_checkbox" name="domain[renew]" type="checkbox" value="true" <?php checked('1', $domain->renew); ?> />
255
  <label for="cnb-renew" class="cnb_toggle_label">Toggle</label>
256
+ <span data-cnb_toggle_state_label="cnb-renew" class="cnb_toggle_state cnb_toggle_false">(Off)</span>
257
+ <span data-cnb_toggle_state_label="cnb-renew" class="cnb_toggle_state cnb_toggle_true">On</span>
258
 
259
  <?php if (!empty($domain->expires)) { ?>
260
  <p class="description" id="domain_expires-description">
273
  <th colspan="2"><h2>Tracking</h2></th>
274
  </tr>
275
  <tr>
276
+ <th scope="row"><label for="google_analytics">Google Analytics<label></th>
277
  <td>
278
  <input type="hidden" name="domain[trackGA]" value="0" />
279
  <input id="google_analytics" class="cnb_toggle_checkbox" name="domain[trackGA]" type="checkbox" value="true" <?php checked('1', $domain->trackGA); ?> />
280
  <label for="google_analytics" class="cnb_toggle_label">Enable GA tracking</label>
281
+ <span data-cnb_toggle_state_label="google_analytics" class="cnb_toggle_state cnb_toggle_false">(Click tracking inactive)</span>
282
  <span data-cnb_toggle_state_label="google_analytics" class="cnb_toggle_state cnb_toggle_true">Click tracking active</span>
283
 
284
  <p class="description">
285
  Supports Classic, Universal Analytics and Global site tag (v3 and v4).<br>
286
+ Using Google Tag Manager? Set up click tracking in GTM. <a href="<?php echo CNB_SUPPORT ?>web-app/domains/tracking-button-clicks-gtm/" target="_blank">Here's how...</a>
287
  </p>
288
  </td>
289
  </tr>
293
  <input type="hidden" name="domain[trackConversion]" value="0" />
294
  <input id="conversion_tracking" class="cnb_toggle_checkbox" name="domain[trackConversion]" type="checkbox" value="true" <?php checked('1', $domain->trackConversion); ?> />
295
  <label for="conversion_tracking" class="cnb_toggle_label">Enable Google Ads conversion tracking</label>
296
+ <span data-cnb_toggle_state_label="conversion_tracking" class="cnb_toggle_state cnb_toggle_false">(Conversion tracking inactive)</span>
297
  <span data-cnb_toggle_state_label="conversion_tracking" class="cnb_toggle_state cnb_toggle_true">Conversion tracking active</span>
298
 
299
  <p class="description">Select this option if you want to count clicks on the button as Google Ads conversions. This option requires the Event snippet to be present on the page. <a href="https://support.google.com/google-ads/answer/6331304" target="_blank">Learn more...</a></p>
333
  notice) you can move this backwards one step at a time to adapt it to your situation.</p>
334
  </td>
335
  </tr>
336
+ <tr>
337
+ <th scope="row"><label for="domain_properties_allow_multiple_buttons">Multiple buttons per page</label></th>
338
+ <td>
339
+ <input type="hidden" name="domain[properties][allowMultipleButtons]" value="false" />
340
+ <input id="domain_properties_allow_multiple_buttons" class="cnb_toggle_checkbox" name="domain[properties][allowMultipleButtons]" type="checkbox" value="true" <?php checked('true', $domain->properties->allowMultipleButtons); ?> />
341
+ <label for="domain_properties_allow_multiple_buttons" class="cnb_toggle_label">Allow multiple Buttons on a single page</label>
342
+ <span data-cnb_toggle_state_label="domain_properties_allow_multiple_buttons" class="cnb_toggle_state cnb_toggle_false">(Disabled)</span>
343
+ <span data-cnb_toggle_state_label="domain_properties_allow_multiple_buttons" class="cnb_toggle_state cnb_toggle_true">Enabled</span>
344
+
345
+ <p class="description">
346
+ When enabled, more than one button can be displayed on a single page.
347
+ </p>
348
+ </td>
349
+ </tr>
350
  <?php
351
  }
352
 
353
+ /**
354
+ * @param $domain CnbDomain
355
+ * @param $header boolean
356
+ *
357
+ * @return void
358
+ */
359
  function cnb_admin_page_domain_edit_render_form_advanced($domain, $header=true) {
360
  global $cnb_options;
361
  $show_advanced_view_only = array_key_exists('advanced_view', $cnb_options) && $cnb_options['advanced_view'] === 1;
409
  <input type="hidden" name="domain[properties][debug]" value="false" />
410
  <input id="domain_properties_debug" class="cnb_toggle_checkbox" name="domain[properties][debug]" type="checkbox" value="true" <?php checked('true', $domain->properties->debug); ?> />
411
  <label for="domain_properties_debug" class="cnb_toggle_label">Enable debugging mode</label>
412
+ <span data-cnb_toggle_state_label="domain_properties_debug" class="cnb_toggle_state cnb_toggle_false">(Disabled)</span>
413
  <span data-cnb_toggle_state_label="domain_properties_debug" class="cnb_toggle_state cnb_toggle_true">Enabled</span>
414
 
415
  <p class="description">
416
  This setting enables debug information in your browser's console, which can help during troubleshooting.
417
  </p>
418
+ </td>
419
  </tr>
420
  <?php
421
  }
src/admin/domain-overview.php CHANGED
@@ -1,5 +1,8 @@
1
  <?php
2
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/api/CnbAppRemotePayment.php';
5
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
@@ -236,7 +239,7 @@ class Cnb_Domain_List_Table extends WP_List_Table {
236
  $url ),
237
  'cnb_delete_domain' );
238
  $delete_url = esc_url( $delete_link );
239
- $actions['delete'] = '<a href="'.$delete_url.'">Delete</a>';
240
 
241
  // If the type is not PRO, offer an upgrade
242
  if ($item['type'] !== 'PRO') {
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAdminCloud;
4
+ use cnb\admin\api\CnbAppRemote;
5
+
6
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
7
  require_once dirname( __FILE__ ) . '/api/CnbAppRemotePayment.php';
8
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
239
  $url ),
240
  'cnb_delete_domain' );
241
  $delete_url = esc_url( $delete_link );
242
+ $actions['delete'] = '<a href="'.$delete_url.'">'.__('Delete').'</a>';
243
 
244
  // If the type is not PRO, offer an upgrade
245
  if ($item['type'] !== 'PRO') {
src/admin/domain-upgrade.php CHANGED
@@ -1,5 +1,9 @@
1
  <?php
2
 
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/api/CnbAppRemotePayment.php';
5
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAppRemote;
4
+ use cnb\admin\api\CnbAppRemotePayment;
5
+ use cnb\admin\models\CnbDomain;
6
+
7
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
8
  require_once dirname( __FILE__ ) . '/api/CnbAppRemotePayment.php';
9
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
src/admin/legacy-edit.php CHANGED
@@ -289,15 +289,18 @@ function cnb_admin_page_legacy_edit_render() {
289
  cnb_promobox(
290
  'blue',
291
  'Unlock extra power',
292
- '<p>Need more powerful features such as:</p>
293
- <p>&check; More buttons<br>
294
- &check; Text/SMS, Email, WhatsApp, Maps<br>
 
295
  &check; Scheduling<br>
296
  &check; Multi action buttons<br>
297
- &check; And more!</p>',
 
 
298
  'unlock',
299
  '',
300
- 'Try Premium',
301
  cnb_legacy_upgrade_page()
302
  );
303
  ?>
@@ -305,14 +308,14 @@ function cnb_admin_page_legacy_edit_render() {
305
  cnb_promobox(
306
  'blue',
307
  'Add more actions!',
308
- '<p>Looking for more than just a call button? You can now add the following actions:</p>
309
- <p>&check; SMS/Text<br>
310
  &check; Email<br>
311
- &check; WhatsApp<br>
312
  &check; Directions<br>
313
- &check; Links</p>',
 
314
  'email',
315
- '',
316
  'Learn more',
317
  cnb_legacy_upgrade_page()
318
  );
@@ -320,32 +323,31 @@ function cnb_admin_page_legacy_edit_render() {
320
  </div>
321
  <div class="cnb-on-active-tab <?php echo cnb_is_active_tab('extra_options') ?>">
322
  <?php
323
- cnb_promobox(
324
- 'blue',
325
- 'Phones off at 6pm?',
326
- '<p>Sign up to enable a scheduler that allows you to set the days and hours that you are available.</p>
327
- <p>You can even replace it with an email button during your off-hours so people can still contact you.</p>',
328
- 'clock',
329
- '<strong>Try it, it\'s free!</strong>',
330
- 'Learn more',
331
- cnb_legacy_upgrade_page()
332
- );
333
- ?>
334
- <?php
335
- cnb_promobox(
336
- 'blue',
337
- 'Powerful page targeting',
338
- '<p>Do you need more flexibility in selecting the pages where you want a button to appear?</p>
339
- <p>Sign up to unlock 4 methods for selecting the right pages:</p>
340
- <p>&check; Exact URL<br>
341
- &check; Path begins with ...<br>
342
- &check; URL contains<br>
343
- &check; RegEx</p>',
344
- 'visibility',
345
- '',
346
- 'Learn more',
347
- cnb_legacy_upgrade_page()
348
- );
349
  ?>
350
  </div>
351
  </div>
289
  cnb_promobox(
290
  'blue',
291
  'Unlock extra power',
292
+ '<p>&check; More buttons<br>
293
+ &check; Text/SMS, Email, Links, Maps<br>
294
+ &check; WhatsApp with Chat modal<br>
295
+ &check; More buttons on a page<br>
296
  &check; Scheduling<br>
297
  &check; Multi action buttons<br>
298
+ &check; Button animations<br>
299
+ &check; Live previews</p>
300
+ <p>Get all of this and much more in <strong>Premium</strong></p>',
301
  'unlock',
302
  '',
303
+ 'Get Premium Free',
304
  cnb_legacy_upgrade_page()
305
  );
306
  ?>
308
  cnb_promobox(
309
  'blue',
310
  'Add more actions!',
311
+ '<p>&check; SMS/Text<br>
 
312
  &check; Email<br>
313
+ &check; WhatsApp with Chat modal<br>
314
  &check; Directions<br>
315
+ &check; Links</p>
316
+ <p>And combine them in a multi action button.</p>',
317
  'email',
318
+ '<strong>It\'s all in Premium!</strong>',
319
  'Learn more',
320
  cnb_legacy_upgrade_page()
321
  );
323
  </div>
324
  <div class="cnb-on-active-tab <?php echo cnb_is_active_tab('extra_options') ?>">
325
  <?php
326
+ cnb_promobox(
327
+ 'blue',
328
+ 'Powerful page targeting',
329
+ '<p>Do you need more flexibility in selecting the pages where you want a button to appear?</p>
330
+ <p>Sign up to unlock 4 methods for selecting the right pages:</p>
331
+ <p>&check; Exact URL<br>
332
+ &check; Path begins with ...<br>
333
+ &check; URL contains<br>
334
+ &check; RegEx</p>',
335
+ 'visibility',
336
+ '',
337
+ 'Learn more',
338
+ cnb_legacy_upgrade_page()
339
+ );
340
+ cnb_promobox(
341
+ 'blue',
342
+ 'Go Premium for FREE!',
343
+ 'Premium adds a ton of extra power to the Call Now Button.</p>
344
+ <p>The Premium Free plan shows a little branding with your buttons but gives you access to all features.</p>
345
+ <p>Try it out and enjoy scheduling, multiple buttons, more button types, animations and much more!</p>',
346
+ 'money-alt',
347
+ '',
348
+ 'Try Premium',
349
+ cnb_legacy_upgrade_page()
350
+ );
 
351
  ?>
352
  </div>
353
  </div>
src/admin/legacy-upgrade.php CHANGED
@@ -18,12 +18,15 @@ function cnb_standard_plugin_promobox() { ?>
18
  &check; Circular (single action)<br>
19
  &check; Buttonbar (single action)<br>
20
  &check; Action label<br>
 
21
  </p>
22
  <hr>
23
  <p>
24
  &check; Placement options<br>
25
  &check; For mobile devices<br>
26
  &check; Include or exclude pages<br>
 
 
27
  &nbsp;
28
  </p>
29
  <hr>
@@ -55,16 +58,19 @@ function cnb_premium_plugin_promobox() { ?>
55
  '
56
  <p><strong>&check; Lots of buttons!</strong><br>
57
  &check; Phone, SMS/Text, Email, WhatsApp, Maps, URLs<br>
58
- &check; Circular button (multi action)<br>
59
  &check; Buttonbar (multi action)<br>
60
  &check; Actions labels<br>
 
61
  </p>
62
  <hr>
63
  <p>
64
  &check; Placement options<br>
65
  &check; For mobile and desktop/laptop<br>
66
  &check; Advanced page targeting<br>
67
- &check; Scheduling
 
 
68
  </p>
69
  <hr>
70
  <p>
@@ -77,7 +83,7 @@ function cnb_premium_plugin_promobox() { ?>
77
  &check; Flexible z-index<br>
78
  &check; Live button preview</p>
79
  <hr>
80
- <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>',
81
  'cloud',
82
  cnb_settings_email_activation_input(),
83
  'none'
@@ -90,13 +96,11 @@ function cnb_upgrade_faq() { ?>
90
  <div style="max-width:600px;margin:0 auto">
91
  <h1 class="cnb-center">FAQ</h1>
92
  <h3>Can I really get Premium for Free?</h3>
93
- <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 and there's a monthly pageviews limit of 20k.</p>
94
- <h3>My website has more than 20k monthly pageviews. Can I still use Premium for Free?</h3>
95
- <p>The Free plan can be used by all websites. But once you hit the 20k pageview limit you will need to upgrade to PRO to keep using the plugin. PRO starts at &euro;2.49/$2.99 per month.</p>
96
  <h3>Does the Premium plan require an account?</h3>
97
  <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>
98
  <h3>What is the "powered by" notice on the Free Premium plan?</h3>
99
- <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>
100
  </div>
101
  <?php }
102
 
18
  &check; Circular (single action)<br>
19
  &check; Buttonbar (single action)<br>
20
  &check; Action label<br>
21
+ &nbsp;<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
+ &nbsp;<br>
29
+ &nbsp;<br>
30
  &nbsp;
31
  </p>
32
  <hr>
58
  '
59
  <p><strong>&check; Lots of buttons!</strong><br>
60
  &check; Phone, SMS/Text, Email, WhatsApp, Maps, URLs<br>
61
+ &check; Circular button (single & multi action)<br>
62
  &check; Buttonbar (multi action)<br>
63
  &check; Actions labels<br>
64
+ &check; WhatsApp chat modal<a href="'.CNB_SUPPORT.'wordpress/buttons/whatsapp-modal/'.cnb_utm_params("question-mark", "whatsapp-modal",false).'" target="_blank" class="cnb-nounderscore"><span class="dashicons dashicons-editor-help"></span></a><br>
65
  </p>
66
  <hr>
67
  <p>
68
  &check; Placement options<br>
69
  &check; For mobile and desktop/laptop<br>
70
  &check; Advanced page targeting<br>
71
+ &check; Scheduling<br>
72
+ &check; Button animations (to draw attention)<br>
73
+ &check; Icon selection<br>
74
  </p>
75
  <hr>
76
  <p>
83
  &check; Flexible z-index<br>
84
  &check; Live button preview</p>
85
  <hr>
86
+ <p class="cnb_align_center"><strong style="text-decoration:underline">FREE</strong> with subtle branding. PRO from &euro;2.49/$2.99 per month.</p>',
87
  'cloud',
88
  cnb_settings_email_activation_input(),
89
  'none'
96
  <div style="max-width:600px;margin:0 auto">
97
  <h1 class="cnb-center">FAQ</h1>
98
  <h3>Can I really get Premium for Free?</h3>
99
+ <p>Yes. You can use 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" notice is added to your buttons.</p>
 
 
100
  <h3>Does the Premium plan require an account?</h3>
101
  <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>
102
  <h3>What is the "powered by" notice on the Free Premium plan?</h3>
103
+ <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 content.</p>
104
  </div>
105
  <?php }
106
 
src/admin/models/CnbAction.class.php CHANGED
@@ -1,31 +1,237 @@
1
  <?php
 
 
2
  // don't load directly
3
  defined( 'ABSPATH' ) || die( '-1' );
4
 
5
- class CnbAction {
 
 
 
 
 
 
 
 
6
  public $id;
 
 
 
 
7
  public $actionType;
 
 
 
 
8
  public $actionValue;
9
- public $labelText;
10
- public $schedule;
11
 
12
  /**
13
- * @var boolean
14
  */
15
- public $iconEnabled;
16
 
 
 
 
17
  public $backgroundColor;
18
- public $iconColor;
19
 
20
  /**
21
- * @var CnbActionProperties
22
  */
23
- public $properties;
 
 
 
 
24
 
25
  public $iconText;
 
26
  public $iconType = 'DEFAULT';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  }
28
 
29
- class CnbActionProperties {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
 
 
 
31
  }
1
  <?php
2
+ namespace cnb\admin\models;
3
+
4
  // don't load directly
5
  defined( 'ABSPATH' ) || die( '-1' );
6
 
7
+ use ArrayObject;
8
+ use cnb\utils\CnbUtils;
9
+ use stdClass;
10
+ use WP_Error;
11
+
12
+ class CnbAction implements \JsonSerializable {
13
+ /**
14
+ * @var string
15
+ */
16
  public $id;
17
+
18
+ /**
19
+ * @var string PHONE, TEXT, etc
20
+ */
21
  public $actionType;
22
+
23
+ /**
24
+ * @var string
25
+ */
26
  public $actionValue;
 
 
27
 
28
  /**
29
+ * @var CnbActionProperties
30
  */
31
+ public $properties;
32
 
33
+ /**
34
+ * @var string
35
+ */
36
  public $backgroundColor;
 
37
 
38
  /**
39
+ * @var boolean
40
  */
41
+ public $iconEnabled;
42
+
43
+ public $iconClass;
44
+
45
+ public $iconColor;
46
 
47
  public $iconText;
48
+
49
  public $iconType = 'DEFAULT';
50
+
51
+ public $labelBackgroundColor;
52
+
53
+ public $labelText;
54
+
55
+ /**
56
+ * @var CnbActionSchedule
57
+ */
58
+ public $schedule;
59
+
60
+ /**
61
+ * Should this CnbAction be deleted?
62
+ * @var boolean
63
+ */
64
+ public $delete;
65
+
66
+ /**
67
+ * If a stdClass is passed, it is transformed into a CnbAction.
68
+ * a WP_Error is ignored and return immediatly
69
+ * a null if converted into an (empty) CnbAction
70
+ *
71
+ * @param $object stdClass|array|WP_Error|null
72
+ *
73
+ * @return CnbAction|WP_Error
74
+ */
75
+ public static function fromObject($object) {
76
+ if (is_wp_error($object)) return $object;
77
+
78
+ $action = new CnbAction();
79
+
80
+ $schedule = CnbUtils::getPropertyOrNull($object, 'schedule');
81
+
82
+ $action->schedule = new CnbActionSchedule();
83
+ $action->schedule->showAlways = CnbUtils::getPropertyOrNull($schedule, 'showAlways');
84
+ $action->schedule->start = CnbUtils::getPropertyOrNull($schedule, 'start');
85
+ $action->schedule->stop = CnbUtils::getPropertyOrNull($schedule, 'stop');
86
+ $action->schedule->timezone = CnbUtils::getPropertyOrNull($schedule, 'timezone');
87
+ $action->schedule->outsideHours = CnbUtils::getPropertyOrNull($schedule, 'outsideHours');
88
+ $daysOfWeek = CnbUtils::getPropertyOrNull($schedule, 'daysOfWeek');
89
+ if (isset($daysOfWeek) && is_array($daysOfWeek)) {
90
+ $action->schedule->daysOfWeek = cnb_create_days_of_week_array($daysOfWeek);
91
+ }
92
+
93
+ $action->id = CnbUtils::getPropertyOrNull($object, 'id');
94
+ $action->actionType = CnbUtils::getPropertyOrNull($object, 'actionType');
95
+ $action->actionValue = CnbUtils::getPropertyOrNull($object, 'actionValue');
96
+ $action->backgroundColor = CnbUtils::getPropertyOrNull($object, 'backgroundColor');
97
+ $iconEnabled = CnbUtils::getPropertyOrNull($object, 'iconEnabled');
98
+ if ($iconEnabled === null) {
99
+ $iconEnabled = true;
100
+ }
101
+ // phpcs:ignore
102
+ $action->iconEnabled = boolval($iconEnabled);
103
+ $action->iconClass = CnbUtils::getPropertyOrNull($object, 'iconClass');
104
+ $action->iconColor = CnbUtils::getPropertyOrNull($object, 'iconColor');
105
+ $action->iconText = CnbUtils::getPropertyOrNull($object, 'iconText');
106
+ $action->iconType = CnbUtils::getPropertyOrNull($object, 'iconType');
107
+ $action->labelBackgroundColor = CnbUtils::getPropertyOrNull($object, 'labelBackgroundColor');
108
+ $action->labelText = CnbUtils::getPropertyOrNull($object, 'labelText');
109
+
110
+ $action->properties = CnbUtils::getPropertyOrNull($object, 'properties');
111
+
112
+ // Special cases
113
+ // "Fix" the WHATSAPP values
114
+ $actionValueWhatsappHidden = CnbUtils::getPropertyOrNull($object, 'actionValueWhatsappHidden');
115
+ if ($action->actionType === 'WHATSAPP' && !empty($actionValueWhatsappHidden)) {
116
+ $action->actionValue = $actionValueWhatsappHidden;
117
+ }
118
+
119
+ // Reset the iconText based on type if the iconText is left empty
120
+ if (isset($action->iconText) && empty($action->iconText)) {
121
+ $action->iconText = cnb_actiontype_to_icontext( $action->actionType );
122
+ }
123
+
124
+ return $action;
125
+ }
126
+
127
+ /**
128
+ * @param $objects stdClass[]|WP_Error|null
129
+ *
130
+ * @return CnbAction[]|WP_Error
131
+ */
132
+ public static function fromObjects($objects) {
133
+ if (is_wp_error($objects)) return $objects;
134
+ if ($objects === null) return null;
135
+ return array_map(
136
+ function($object) {
137
+ return CnbAction::fromObject($object);
138
+ },
139
+ $objects
140
+ );
141
+ }
142
+ /**
143
+ * @return array
144
+ */
145
+ public function toArray() {
146
+ return array(
147
+ 'id' => $this->id,
148
+ 'actionType' => $this->actionType,
149
+ 'actionValue' => $this->actionValue,
150
+ 'properties' => $this->properties,
151
+ 'backgroundColor' => $this->backgroundColor,
152
+ 'iconEnabled' => $this->iconEnabled,
153
+ 'iconClass' => $this->iconClass,
154
+ 'iconColor' => $this->iconColor,
155
+ 'iconText' => $this->iconText,
156
+ 'iconType' => $this->iconType,
157
+ 'labelBackgroundColor' => $this->labelBackgroundColor,
158
+ 'labelText' => $this->labelText,
159
+ 'schedule' => $this->schedule,
160
+ );
161
+ }
162
+
163
+ /**
164
+ * @return array
165
+ */
166
+ public function jsonSerialize() {
167
+ return $this->toArray();
168
+ }
169
+ }
170
+
171
+ class CnbActionProperties extends ArrayObject implements \JsonSerializable {
172
+
173
+ /**
174
+ * @return array
175
+ */
176
+ public function toArray() {
177
+ // Since this is an ArrayObject, we can use its "native" functions
178
+ return $this->getArrayCopy();
179
+ }
180
+
181
+ /**
182
+ * @return array
183
+ */
184
+ public function jsonSerialize() {
185
+ return $this->toArray();
186
+ }
187
  }
188
 
189
+ class CnbActionSchedule implements \JsonSerializable {
190
+ /**
191
+ * When `showAlways` is true, the `CnbAction` is always visible and all other
192
+ * elements of the schedule are ignored.
193
+ * @var boolean
194
+ */
195
+ public $showAlways;
196
+
197
+ /**
198
+ * Array of booleans, starting at Monday.
199
+ * @var boolean[]
200
+ */
201
+ public $daysOfWeek;
202
+
203
+ /**
204
+ * @var string hh:mm
205
+ */
206
+ public $start;
207
+
208
+ /**
209
+ * @var string hh:mm
210
+ */
211
+ public $stop;
212
+
213
+ /**
214
+ * @var string
215
+ */
216
+ public $timezone;
217
+
218
+ /**
219
+ * @var boolean
220
+ */
221
+ public $outsideHours;
222
+
223
+ public function toArray() {
224
+ return array(
225
+ 'showAlways' => $this->showAlways,
226
+ 'daysOfWeek' => $this->daysOfWeek,
227
+ 'start' => $this->start,
228
+ 'stop' => $this->stop,
229
+ 'timezone' => $this->timezone,
230
+ 'outsideHours' => $this->outsideHours,
231
+ );
232
+ }
233
 
234
+ public function jsonSerialize() {
235
+ return $this->toArray();
236
+ }
237
  }
src/admin/models/CnbApiKey.class.php CHANGED
@@ -1,9 +1,59 @@
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
  }
1
  <?php
2
+ namespace cnb\admin\models;
3
+
4
  // don't load directly
5
+ use cnb\utils\CnbUtils;
6
+ use stdClass;
7
+ use WP_Error;
8
+
9
  defined( 'ABSPATH' ) || die( '-1' );
10
 
11
+ class CnbApiKey implements \JsonSerializable {
12
+ /**
13
+ * @var string
14
+ */
15
  public $id;
16
+ /**
17
+ * @var string
18
+ */
19
  public $name;
20
+ /**
21
+ * @var string
22
+ */
23
  public $key;
24
+
25
+ /**
26
+ * If a stdClass is passed, it is transformed into a CnbApiKey.
27
+ * a WP_Error is ignored and return immediatly
28
+ * a null if converted into an (empty) CnbApiKey
29
+ *
30
+ * @param $object stdClass|array|WP_Error|null
31
+ *
32
+ * @return CnbApiKey|WP_Error
33
+ */
34
+ public static function fromObject($object) {
35
+ if ( is_wp_error( $object ) ) {
36
+ return $object;
37
+ }
38
+
39
+ $apiKey = new CnbApiKey();
40
+ $apiKey->id = CnbUtils::getPropertyOrNull( $object, 'id' );
41
+ $apiKey->name = CnbUtils::getPropertyOrNull( $object, 'name' );
42
+ $apiKey->key = CnbUtils::getPropertyOrNull( $object, 'key' );
43
+
44
+ return $apiKey;
45
+
46
+ }
47
+
48
+ public function toArray() {
49
+ return array(
50
+ 'id' => $this->id,
51
+ 'name' => $this->name,
52
+ 'key' => $this->key,
53
+ );
54
+ }
55
+
56
+ public function jsonSerialize() {
57
+ return $this->toArray();
58
+ }
59
  }
src/admin/models/CnbButton.class.php CHANGED
@@ -1,8 +1,20 @@
1
  <?php
 
 
2
  // don't load directly
3
  defined( 'ABSPATH' ) || die( '-1' );
4
 
5
- class CnbButton {
 
 
 
 
 
 
 
 
 
 
6
 
7
  /**
8
  * @var string
@@ -24,10 +36,25 @@ class CnbButton {
24
  */
25
  public $type;
26
 
 
 
 
27
  public $domain;
28
 
 
 
 
 
 
 
29
  public $actions;
30
 
 
 
 
 
 
 
31
  public $conditions;
32
 
33
  /**
@@ -35,23 +62,16 @@ class CnbButton {
35
  */
36
  public $options;
37
 
38
- public static function setSaneDefault($button) {
39
- // Set some sane defaults
40
- if (!isset($button->options)) $button->options = new CnbButtonOptions();
41
- $button->options->iconBackgroundColor = !empty($button->options->iconBackgroundColor)
42
- ? $button->options->iconBackgroundColor
43
- : '#009900';
44
- $button->options->iconColor = !empty($button->options->iconColor)
45
- ? $button->options->iconColor
46
- : '#FFFFFF';
47
- $button->options->placement = !empty($button->options->placement)
48
- ? $button->options->placement
49
- : ($button->type === 'FULL' ? 'BOTTOM_CENTER' : 'BOTTOM_RIGHT');
50
- $button->options->scale = !empty($button->options->scale)
51
- ? $button->options->scale
52
- : '1';
53
- }
54
 
 
 
 
 
 
55
  public static function createDummyButton($domain = null) {
56
  $button = new CnbButton();
57
  $button->id = '';
@@ -61,43 +81,113 @@ class CnbButton {
61
  $button->domain = $domain;
62
  $button->actions = array();
63
  $button->conditions = array();
 
 
64
 
65
  return $button;
66
  }
67
 
68
- public function toArray() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  return array(
70
  'id' => $this->id,
71
  'active' => $this->active,
72
  'name' => $this->name,
73
  'type' => $this->type,
74
- 'domain' => $this->domain,
75
- 'actions' => $this->actions,
76
- 'conditions' => $this->conditions,
77
- 'options' => isset($this->options) ? $this->options->toArray() : array()
 
78
  );
79
  }
80
 
 
 
 
 
 
 
 
 
 
81
  public static function fromObject($object) {
 
 
82
  $button = new CnbButton();
83
- $button->id = $object->id;
84
- $button->active = $object->active;
85
- $button->name = $object->name;
86
- $button->type = $object->type;
87
- $button->domain = $object->domain;
88
- $button->actions = $object->actions;
89
- $button->conditions = $object->conditions;
90
- $button->options = CnbButtonOptions::fromObject($object->options);
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
  return $button;
93
  }
94
 
95
  /**
96
- * @param $buttons CnbButton[]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  *
98
  * @return array
99
  */
100
- public static function convert($buttons) {
101
  return array_map(
102
  function($button) {
103
  $button = $button instanceof CnbButton ? $button : self::fromObject($button);
@@ -105,33 +195,112 @@ class CnbButton {
105
  }, $buttons
106
  );
107
  }
 
 
 
 
108
  }
109
 
110
- class CnbButtonOptions {
111
- public $iconBackgroundColor;
112
- public $iconColor;
 
113
  /**
 
 
 
 
 
 
 
 
114
  * @var string
115
  */
116
- public $placement;
117
- public $scale;
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
  public function toArray() {
120
  return array(
 
 
 
121
  'iconBackgroundColor' => $this->iconBackgroundColor,
122
  'iconColor' => $this->iconColor,
123
- 'placement' => $this->placement,
124
- 'scale' => $this->scale
125
  );
126
  }
127
 
128
  public static function fromObject( $object ) {
129
  $options = new CnbButtonOptions();
130
- $options->iconBackgroundColor = $object->iconBackgroundColor;
131
- $options->iconColor = $object->iconColor;
132
- $options->placement = $object->placement;
133
- $options->scale = $object->scale;
 
 
134
 
135
  return $options;
136
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  }
1
  <?php
2
+ namespace cnb\admin\models;
3
+
4
  // don't load directly
5
  defined( 'ABSPATH' ) || die( '-1' );
6
 
7
+ require_once dirname( __FILE__ ) . '/CnbAction.class.php';
8
+ require_once dirname( __FILE__ ) . '/CnbCondition.class.php';
9
+ require_once dirname( __FILE__ ) . '/CnbDomain.class.php';
10
+ require_once dirname( __FILE__ ) . '/../../utils/CnbUtils.php';
11
+ require_once dirname( __FILE__ ) . '/../../utils/utils.php'; // to ensure "boolval" works on older PHP versions
12
+
13
+ use cnb\utils\CnbUtils;
14
+ use stdClass;
15
+ use WP_Error;
16
+
17
+ class CnbButton implements \JsonSerializable {
18
 
19
  /**
20
  * @var string
36
  */
37
  public $type;
38
 
39
+ /**
40
+ * @var CnbDomain
41
+ */
42
  public $domain;
43
 
44
+ /**
45
+ * Depending on the circumstance, this is either an array of CnbAction
46
+ * or (when submitting to the API), reduced to an array of int (CnbAction->id's)
47
+ *
48
+ * @var CnbAction[]|string[]
49
+ */
50
  public $actions;
51
 
52
+ /**
53
+ * Depending on the circumstance, this is either an array of CnbCondition
54
+ * or (when submitting to the API), reduced to an array of int (CnbAction->id's)
55
+ *
56
+ * @var CnbCondition[]|string[]
57
+ */
58
  public $conditions;
59
 
60
  /**
62
  */
63
  public $options;
64
 
65
+ /**
66
+ * @var CnbMultiButtonOptions
67
+ */
68
+ public $multiButtonOptions;
 
 
 
 
 
 
 
 
 
 
 
 
69
 
70
+ /**
71
+ * @param $domain CnbDomain
72
+ *
73
+ * @return CnbButton
74
+ */
75
  public static function createDummyButton($domain = null) {
76
  $button = new CnbButton();
77
  $button->id = '';
81
  $button->domain = $domain;
82
  $button->actions = array();
83
  $button->conditions = array();
84
+ $button->options = new CnbButtonOptions();
85
+ $button->options->placement = 'BOTTOM_RIGHT';
86
 
87
  return $button;
88
  }
89
 
90
+ public function toArray($convertToStringArray = true) {
91
+ // Actions should be string[]
92
+ $actions = array();
93
+ if (is_array($this->actions)) {
94
+ $actions = cnb_array_column( $this->actions, 'id' );
95
+ }
96
+ $actions = array_filter($actions, function($action) { return !empty($action);});
97
+
98
+ // Conditions should be string[]
99
+ $conditions = array();
100
+ if (is_array($this->conditions)) {
101
+ $conditions = cnb_array_column( $this->conditions, 'id' );
102
+ }
103
+ $conditions = array_filter($conditions, function($condition) { return !empty($condition);});
104
+
105
+ // Empty options should not be an array, but a null (so we do not confuse the API server
106
+ $options = isset($this->options) ? $this->options->toArray() : null;
107
+
108
+ // domain should be be string (the CnbDomain ID)
109
+ $domain = $this->domain ? $this->domain->id : $this->domain;
110
+
111
+ // This basically "undo's" the above and returns actual objects instead of strings
112
+ if (!$convertToStringArray) {
113
+ $actions = $this->actions;
114
+ $conditions = $this->conditions;
115
+ $domain = $this->domain;
116
+ }
117
+
118
  return array(
119
  'id' => $this->id,
120
  'active' => $this->active,
121
  'name' => $this->name,
122
  'type' => $this->type,
123
+ 'domain' => $domain,
124
+ 'actions' => $actions,
125
+ 'conditions' => $conditions,
126
+ 'options' => $options,
127
+ 'multiButtonOptions' => $this->multiButtonOptions
128
  );
129
  }
130
 
131
+ /**
132
+ * If a stdClass is passed, it is transformed into a CnbButton.
133
+ * a WP_Error is ignored and return immediatly
134
+ * a null if converted into an (empty) CnbButton
135
+ *
136
+ * @param $object stdClass|array|WP_Error|null
137
+ *
138
+ * @return CnbButton|WP_Error
139
+ */
140
  public static function fromObject($object) {
141
+ if (is_wp_error($object)) return $object;
142
+
143
  $button = new CnbButton();
144
+ $button->id = CnbUtils::getPropertyOrNull($object, 'id');
145
+ // phpcs:ignore
146
+ $button->active = boolval(CnbUtils::getPropertyOrNull($object, 'active'));
147
+ $button->name = CnbUtils::getPropertyOrNull($object, 'name');
148
+ $button->type = CnbUtils::getPropertyOrNull($object, 'type');
149
+ $button->domain = CnbUtils::getPropertyOrNull($object, 'domain');
150
+ $button->actions = CnbUtils::getPropertyOrNull($object, 'actions');
151
+ $button->conditions = CnbUtils::getPropertyOrNull($object, 'conditions');
152
+ $options = CnbUtils::getPropertyOrNull($object, 'options');
153
+ $button->options = CnbButtonOptions::fromObject($options);
154
+ $multiButtonOptions = CnbUtils::getPropertyOrNull($object, 'multiButtonOptions');
155
+ $button->multiButtonOptions = CnbMultiButtonOptions::fromObject($multiButtonOptions);
156
+
157
+ if (gettype($button->domain) === 'string') {
158
+ $domainId = $button->domain;
159
+ $button->domain = new CnbDomain();
160
+ $button->domain->id = $domainId;
161
+ }
162
+
163
+ // Convert "stdClass" actions into Action classes
164
+ $button->actions = CnbAction::fromObjects($button->actions);
165
 
166
  return $button;
167
  }
168
 
169
  /**
170
+ * @param $objects stdClass[]|WP_Error|null
171
+ *
172
+ * @return CnbButton[]|WP_Error
173
+ */
174
+ public static function fromObjects($objects) {
175
+ if (is_wp_error($objects)) return $objects;
176
+ return array_map(
177
+ function($object) {
178
+ return CnbButton::fromObject($object);
179
+ },
180
+ $objects
181
+ );
182
+ }
183
+
184
+ /**
185
+ * Convert an array of CnbButtons into arrays, useful for CLI viewing
186
+ * @param $buttons stdClass[]|CnbButton[]
187
  *
188
  * @return array
189
  */
190
+ public static function convertToArray($buttons) {
191
  return array_map(
192
  function($button) {
193
  $button = $button instanceof CnbButton ? $button : self::fromObject($button);
195
  }, $buttons
196
  );
197
  }
198
+
199
+ public function jsonSerialize() {
200
+ return $this->toArray();
201
+ }
202
  }
203
 
204
+ /**
205
+ * The Options for a CnbButton are varied and can differ
206
+ */
207
+ class CnbButtonOptions implements \JsonSerializable {
208
  /**
209
+ * - BOTTOM_LEFT
210
+ * - BOTTOM_CENTER
211
+ * - BOTTOM_RIGHT
212
+ * - MIDDLE_LEFT
213
+ * - MIDDLE_RIGHT
214
+ * - TOP_LEFT
215
+ * - TOP_CENTER
216
+ * - TOP_RIGHT
217
  * @var string
218
  */
219
+ public $placement; //
220
+ public $position; // DEFAULT, FIXED, ABSOLUTE
221
+ public $animation; // NONE, TADA, SHAKE, SONAR_LIGHT, SONAR_DARK
222
+ public $iconBackgroundColor;
223
+ public $iconColor;
224
+ public $displayMode;
225
+
226
+ public static function getAnimationTypes() {
227
+ return array(
228
+ 'NONE' => 'None',
229
+ 'TADA' => 'Tada',
230
+ 'SHAKE' => 'Shake',
231
+ 'SONAR_LIGHT' => 'Sonar light (for dark backgrounds)',
232
+ 'SONAR_DARK' => 'Sonar dark (for light backgrounds)');
233
+ }
234
 
235
  public function toArray() {
236
  return array(
237
+ 'placement' => $this->placement,
238
+ 'position' => $this->position,
239
+ 'animation' => $this->animation,
240
  'iconBackgroundColor' => $this->iconBackgroundColor,
241
  'iconColor' => $this->iconColor,
242
+ 'displayMode' => $this->displayMode
 
243
  );
244
  }
245
 
246
  public static function fromObject( $object ) {
247
  $options = new CnbButtonOptions();
248
+ $options->placement = CnbUtils::getPropertyOrNull($object, 'placement');
249
+ $options->position = CnbUtils::getPropertyOrNull($object, 'position');
250
+ $options->animation = CnbUtils::getPropertyOrNull($object, 'animation');
251
+ $options->iconBackgroundColor = CnbUtils::getPropertyOrNull($object, 'iconBackgroundColor');
252
+ $options->iconColor = CnbUtils::getPropertyOrNull($object, 'iconColor');
253
+ $options->displayMode = CnbUtils::getPropertyOrNull($object, 'displayMode');
254
 
255
  return $options;
256
  }
257
+
258
+ public function jsonSerialize() {
259
+ return $this->toArray();
260
+ }
261
+ }
262
+
263
+ class CnbMultiButtonOptions implements \JsonSerializable {
264
+ public $id;
265
+ public $iconColor;
266
+ public $iconBackgroundColor;
267
+ public $iconTextOpen;
268
+ public $iconTypeOpen;
269
+ public $iconTextClose;
270
+ public $iconTypeClose;
271
+ public $labelText;
272
+ public $labelBackgroundColor;
273
+
274
+ public function toArray() {
275
+ return array(
276
+ 'id' => !empty($this->id) ? $this->id : null,
277
+ 'iconColor' => $this->iconColor,
278
+ 'iconBackgroundColor' => $this->iconBackgroundColor,
279
+ 'iconTextOpen' => $this->iconTextOpen,
280
+ 'iconTypeOpen' => $this->iconTypeOpen,
281
+ 'iconTextClose' => $this->iconTextClose,
282
+ 'iconTypeClose' => $this->iconTypeClose,
283
+ 'labelText' => $this->labelText, // PRO only
284
+ 'labelBackgroundColor' => $this->labelBackgroundColor, // PRO only
285
+ );
286
+ }
287
+
288
+ public static function fromObject( $object ) {
289
+ $options = new CnbMultiButtonOptions();
290
+ $options->id = CnbUtils::getPropertyOrNull($object, 'id');
291
+ $options->iconColor = CnbUtils::getPropertyOrNull($object, 'iconColor');
292
+ $options->iconBackgroundColor = CnbUtils::getPropertyOrNull($object, 'iconBackgroundColor');
293
+ $options->iconTextOpen = CnbUtils::getPropertyOrNull($object, 'iconTextOpen');
294
+ $options->iconTypeOpen = CnbUtils::getPropertyOrNull($object, 'iconTypeOpen');
295
+ $options->iconTextClose = CnbUtils::getPropertyOrNull($object, 'iconTextClose');
296
+ $options->iconTypeClose = CnbUtils::getPropertyOrNull($object, 'iconTypeClose');
297
+ $options->labelText = CnbUtils::getPropertyOrNull($object, 'labelText');
298
+ $options->labelBackgroundColor = CnbUtils::getPropertyOrNull($object, 'labelBackgroundColor');
299
+
300
+ return $options;
301
+ }
302
+
303
+ public function jsonSerialize() {
304
+ return $this->toArray();
305
+ }
306
  }
src/admin/models/CnbCondition.class.php CHANGED
@@ -1,11 +1,62 @@
1
  <?php
 
 
2
  // don't load directly
 
 
 
 
3
  defined( 'ABSPATH' ) || die( '-1' );
4
 
5
- class CnbCondition {
6
  public $id;
7
  public $conditionType = 'URL';
8
  public $filterType;
9
  public $matchType;
10
  public $matchValue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  }
1
  <?php
2
+ namespace cnb\admin\models;
3
+
4
  // don't load directly
5
+ use cnb\utils\CnbUtils;
6
+ use stdClass;
7
+ use WP_Error;
8
+
9
  defined( 'ABSPATH' ) || die( '-1' );
10
 
11
+ class CnbCondition implements \JsonSerializable {
12
  public $id;
13
  public $conditionType = 'URL';
14
  public $filterType;
15
  public $matchType;
16
  public $matchValue;
17
+
18
+ /**
19
+ * Should this Condition be deleted?
20
+ * @var boolean
21
+ */
22
+ public $delete;
23
+
24
+ /**
25
+ * If a stdClass is passed, it is transformed into a CnbCondition.
26
+ * a WP_Error is ignored and return immediatly
27
+ * a null if converted into an (empty) CnbCondition
28
+ *
29
+ * @param $object stdClass|array|WP_Error|null
30
+ *
31
+ * @return CnbCondition|WP_Error
32
+ */
33
+ public static function fromObject($object) {
34
+ if (is_wp_error($object)) return $object;
35
+
36
+ $condition = new CnbCondition();
37
+
38
+ $condition->id = CnbUtils::getPropertyOrNull($object, 'id');
39
+ $condition->conditionType = CnbUtils::getPropertyOrNull($object, 'conditionType');
40
+ $condition->filterType = CnbUtils::getPropertyOrNull($object, 'filterType');
41
+ $condition->matchType = CnbUtils::getPropertyOrNull($object, 'matchType');
42
+ $condition->matchValue = CnbUtils::getPropertyOrNull($object, 'matchValue');
43
+ $condition->delete = CnbUtils::getPropertyOrNull($object, 'delete');
44
+
45
+ return $condition;
46
+ }
47
+
48
+ public function toArray() {
49
+ // Note, we do not export "delete", since that is only used internally
50
+ return array(
51
+ 'id' => $this->id,
52
+ 'conditionType' => $this->conditionType,
53
+ 'filterType' => $this->filterType,
54
+ 'matchType' => $this->matchType,
55
+ 'matchValue' => $this->matchValue,
56
+ );
57
+ }
58
+
59
+ public function jsonSerialize() {
60
+ return $this->toArray();
61
+ }
62
  }
src/admin/models/CnbDomain.class.php CHANGED
@@ -1,17 +1,25 @@
1
  <?php
 
 
2
  // don't load directly
 
 
 
 
3
  defined( 'ABSPATH' ) || die( '-1' );
4
 
5
- class CnbDomain {
6
 
7
  public $id;
8
  public $name;
9
- public $timezone;
10
  public $type;
 
11
  /**
12
- * @var CnbDomainProperties
13
  */
14
- public $properties;
 
15
  /**
16
  * @var boolean
17
  */
@@ -21,10 +29,38 @@ class CnbDomain {
21
  */
22
  public $trackConversion;
23
  /**
24
- * @var boolean
25
  */
26
- public $renew;
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  /**
29
  *
30
  * This changes the object itself, settings some sane defaults in case those are missing
@@ -76,11 +112,22 @@ class CnbDomain {
76
  }
77
  return $domain;
78
  }
 
 
 
 
 
 
 
 
 
 
 
79
  }
80
 
81
- class CnbDomainProperties {
82
  /**
83
- * @var number
84
  */
85
  public $scale;
86
 
@@ -88,4 +135,49 @@ class CnbDomainProperties {
88
  * @var boolean
89
  */
90
  public $debug;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  }
1
  <?php
2
+ namespace cnb\admin\models;
3
+
4
  // don't load directly
5
+ use cnb\utils\CnbUtils;
6
+ use stdClass;
7
+ use WP_Error;
8
+
9
  defined( 'ABSPATH' ) || die( '-1' );
10
 
11
+ class CnbDomain implements \JsonSerializable {
12
 
13
  public $id;
14
  public $name;
15
+ public $interval;
16
  public $type;
17
+ public $expires;
18
  /**
19
+ * @var boolean
20
  */
21
+ public $renew;
22
+ public $timezone;
23
  /**
24
  * @var boolean
25
  */
29
  */
30
  public $trackConversion;
31
  /**
32
+ * @var CnbDomainProperties
33
  */
34
+ public $properties;
35
 
36
+ /**
37
+ * If a stdClass is passed, it is transformed into a CnbDomain.
38
+ * a WP_Error is ignored and return immediatly
39
+ * a null if converted into an (empty) CnbDomain
40
+ *
41
+ * @param $object stdClass|array|WP_Error|null
42
+ *
43
+ * @return CnbDomain|WP_Error
44
+ */
45
+ public static function fromObject($object) {
46
+ if ( is_wp_error( $object ) ) {
47
+ return $object;
48
+ }
49
+
50
+ $domain = new CnbDomain();
51
+
52
+ $domain->id = CnbUtils::getPropertyOrNull( $object, 'id' );
53
+ $domain->name = CnbUtils::getPropertyOrNull( $object, 'name' );
54
+ $domain->timezone = CnbUtils::getPropertyOrNull( $object, 'timezone' );
55
+ $domain->type = CnbUtils::getPropertyOrNull( $object, 'type' );
56
+ $properties = CnbUtils::getPropertyOrNull( $object, 'properties' );
57
+ $domain->properties = CnbDomainProperties::fromObject($properties);
58
+ $domain->trackGA = CnbUtils::getPropertyOrNull( $object, 'trackGA' );
59
+ $domain->trackConversion = CnbUtils::getPropertyOrNull( $object, 'trackConversion' );
60
+ $domain->renew = CnbUtils::getPropertyOrNull( $object, 'renew' );
61
+
62
+ return $domain;
63
+ }
64
  /**
65
  *
66
  * This changes the object itself, settings some sane defaults in case those are missing
112
  }
113
  return $domain;
114
  }
115
+
116
+ public function toArray() {
117
+ return array(
118
+ 'id' => $this->id,
119
+ // TODO Make this complete??
120
+ );
121
+ }
122
+
123
+ public function jsonSerialize() {
124
+ return $this->toArray();
125
+ }
126
  }
127
 
128
+ class CnbDomainProperties implements \JsonSerializable {
129
  /**
130
+ * @var number 0.7 to 1.3 (normally 1)
131
  */
132
  public $scale;
133
 
135
  * @var boolean
136
  */
137
  public $debug;
138
+
139
+ /**
140
+ * @var number|string ("auto" is also allowed)
141
+ */
142
+ public $zindex;
143
+
144
+ /**
145
+ * @var string "true" or "false"
146
+ */
147
+ public $allowMultipleButtons;
148
+
149
+ /**
150
+ * If a stdClass is passed, it is transformed into a CnbDomainProperties.
151
+ * a WP_Error is ignored and return immediatly
152
+ * a null if converted into an (empty) CnbDomain
153
+ *
154
+ * @param $object stdClass|array|WP_Error|null
155
+ *
156
+ * @return CnbDomainProperties|WP_Error
157
+ */
158
+ public static function fromObject($object) {
159
+ if ( is_wp_error( $object ) ) {
160
+ return $object;
161
+ }
162
+
163
+ $properties = new CnbDomainProperties();
164
+ $properties->scale = CnbUtils::getPropertyOrNull( $object, 'scale' );
165
+ $properties->debug = CnbUtils::getPropertyOrNull( $object, 'debug' );
166
+ $properties->zindex = CnbUtils::getPropertyOrNull( $object, 'zindex' );
167
+ $properties->allowMultipleButtons = CnbUtils::getPropertyOrNull( $object, 'allowMultipleButtons' );
168
+
169
+ return $properties;
170
+ }
171
+
172
+ public function toArray() {
173
+ return array(
174
+ 'scale' => $this->scale,
175
+ 'debug' => $this->debug,
176
+ 'zindex' => $this->zindex,
177
+ 'allowMultipleButtons' => $this->allowMultipleButtons,
178
+ );
179
+ }
180
+ public function jsonSerialize() {
181
+ return $this->toArray();
182
+ }
183
  }
src/admin/models/CnbUser.class.php CHANGED
@@ -1,7 +1,9 @@
1
  <?php
2
-
3
  namespace cnb\admin\models;
4
 
 
 
 
5
  class Cnb_User {
6
  /**
7
  * @var string UUID of the User
1
  <?php
 
2
  namespace cnb\admin\models;
3
 
4
+ // don't load directly
5
+ defined( 'ABSPATH' ) || die( '-1' );
6
+
7
  class Cnb_User {
8
  /**
9
  * @var string UUID of the User
src/admin/partials/admin-footer.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
 
 
 
3
  function cnb_admin_footer() {
4
  cnb_show_feedback_collection();
5
  cnb_show_api_traces();
1
  <?php
2
 
3
+ use cnb\admin\api\RemoteTracer;
4
+
5
  function cnb_admin_footer() {
6
  cnb_show_feedback_collection();
7
  cnb_show_api_traces();
src/admin/partials/admin-functions.php CHANGED
@@ -52,6 +52,16 @@ function has_changelog($cnb_options) {
52
 
53
  function cnb_get_changelog() {
54
  return array(
 
 
 
 
 
 
 
 
 
 
55
  '1.0.6' => array(
56
  '💬 SMS/Text support in Premium',
57
  '⏱️ More intuitive button scheduler in Premium',
@@ -116,8 +126,8 @@ function cnb_get_action_types() {
116
  'ANCHOR' => 'Anchor',
117
  'LINK' => 'Link',
118
  'MAP' => 'Google Maps',
119
- 'WHATSAPP' => 'Whatsapp',
120
- 'SMS' => 'SMS',
121
  );
122
  }
123
 
@@ -145,14 +155,14 @@ function cnb_get_condition_match_types() {
145
  */
146
  function cnb_create_days_of_week_array($original) {
147
  // If original does not exist, leave it as it is
148
- if ($original === null || !is_array($original)) {
149
  return $original;
150
  }
151
 
152
  // Default everything is NOT selected, then we enable only those days that are passed in via $original
153
  $result = array(false, false, false, false, false, false, false);
154
  foreach ($result as $day_of_week_index => $day_of_week) {
155
- $day_of_week_is_enabled = isset($original[$day_of_week_index]) && $original[$day_of_week_index] === "true";
156
  $result[$day_of_week_index] = $day_of_week_is_enabled;
157
  }
158
  return $result;
52
 
53
  function cnb_get_changelog() {
54
  return array(
55
+ '1.0.8' => array(
56
+ 'WhatsApp chat modal (Premium)',
57
+ 'Multiple buttons on a single page (Premium)',
58
+ 'Icon selection (Premium)',
59
+ 'Drag and drop action sorting (Premium)',
60
+ 'Time selector in the preview (Premium)',
61
+ 'Button animations (Premium)',
62
+ 'Set link target (Premium)',
63
+ 'Display setting shown in button overview (Premium)',
64
+ ),
65
  '1.0.6' => array(
66
  '💬 SMS/Text support in Premium',
67
  '⏱️ More intuitive button scheduler in Premium',
126
  'ANCHOR' => 'Anchor',
127
  'LINK' => 'Link',
128
  'MAP' => 'Google Maps',
129
+ 'WHATSAPP' => 'WhatsApp',
130
+ 'SMS' => 'SMS/Text',
131
  );
132
  }
133
 
155
  */
156
  function cnb_create_days_of_week_array($original) {
157
  // If original does not exist, leave it as it is
158
+ if (!is_array($original)) {
159
  return $original;
160
  }
161
 
162
  // Default everything is NOT selected, then we enable only those days that are passed in via $original
163
  $result = array(false, false, false, false, false, false, false);
164
  foreach ($result as $day_of_week_index => $day_of_week) {
165
+ $day_of_week_is_enabled = isset($original[$day_of_week_index]) && ($original[$day_of_week_index] === "true" || $original[$day_of_week_index] === true);
166
  $result[$day_of_week_index] = $day_of_week_is_enabled;
167
  }
168
  return $result;
src/admin/partials/admin-header.php CHANGED
@@ -20,7 +20,7 @@ function cnb_admin_header_no_args() {
20
  }
21
 
22
  function cnb_admin_header_args( $cnb_options, $cnb_settings, $cnb_cloud_notifications = array(), $cnb_changelog = array() ) {
23
- echo '<div class="wrap call-now-button">'; // This is closed in cnb_admin_footer
24
 
25
  echo '<!--## NOTIFICATION BARS ## -->';
26
  $cnb_cloud_notifications = array_merge($cnb_cloud_notifications, cnb_get_cloud_notices());
20
  }
21
 
22
  function cnb_admin_header_args( $cnb_options, $cnb_settings, $cnb_cloud_notifications = array(), $cnb_changelog = array() ) {
23
+ echo '<div class="wrap call-now-button-plugin">'; // This is closed in cnb_admin_footer
24
 
25
  echo '<!--## NOTIFICATION BARS ## -->';
26
  $cnb_cloud_notifications = array_merge($cnb_cloud_notifications, cnb_get_cloud_notices());
src/admin/partials/domain-upgrade/overview.php CHANGED
@@ -1,4 +1,7 @@
1
  <?php
 
 
 
2
  function cnb_get_plan($plans, $name) {
3
  foreach ($plans as $plan) {
4
  if ($plan->nickname === $name) {
@@ -61,7 +64,7 @@ function cnb_domain_upgrade_overview($domain, $user) {
61
  });
62
  <?php } ?>
63
  </script>
64
- <p>Your domain is currently on the Premium <code><?php echo esc_html($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 echo esc_attr($domain->id) ?>">
@@ -75,85 +78,78 @@ function cnb_domain_upgrade_overview($domain, $user) {
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">PRO </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', 'Enter or 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 echo esc_attr($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">PRO </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', 'Enter or 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 echo esc_attr($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">PRO </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', 'Enter or 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 echo esc_attr($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">PRO </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', 'Enter or 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 echo esc_attr($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>
153
- <div><b>&check;</b> Multibutton&trade; (expandable single button with multiple actions)</div>
154
- <div><b>&check;</b> Buttonbar&trade; (full width with multiple actions)</div>
155
- <div><b>&check;</b> Advanced page targeting options</div>
156
- <div><b>&check;</b> Scheduling</div>
157
- <div><b>&check;</b> And more!</div>
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  </div>
 
 
159
  <?php }
1
  <?php
2
+
3
+ use cnb\admin\api\CnbAppRemotePayment;
4
+
5
  function cnb_get_plan($plans, $name) {
6
  foreach ($plans as $plan) {
7
  if ($plan->nickname === $name) {
64
  });
65
  <?php } ?>
66
  </script>
67
+ <?php if($domain->type !== "FREE") { ?><p>Your domain is currently on the Premium <code><?php echo esc_html($domain->type) ?></code> plan.</p><?php } ?>
68
 
69
  <form id="wp_domain_upgrade" method="post">
70
  <input type="hidden" name="cnb_domain_id" id="cnb_domain_id" value="<?php echo esc_attr($domain->id) ?>">
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"><span class="cnb-premium-label">PRO </span>Yearly</h3>
84
+ <div class="benefit">All button 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', 'Upgrade', 'Enter or 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 echo esc_js($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"><span class="cnb-premium-label">PRO </span>Monthly</h3>
96
+ <div class="benefit">All button 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 monthly
100
  </div>
101
  <?php getProfileEditModal('button button-secondary', 'Upgrade', 'Enter or 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 echo esc_js($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"><span class="cnb-premium-label">PRO </span>Yearly</h3>
109
+ <div class="benefit">All button 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 $35.88 annually
113
  </div>
114
  <?php getProfileEditModal('button button-primary', 'Upgrade', 'Enter or 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 echo esc_js($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"><span class="cnb-premium-label">PRO </span>Monthly</h3>
120
+ <div class="benefit">All button 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 monthly
124
  </div>
125
  <?php getProfileEditModal('button button-secondary', 'Upgrade', 'Enter or 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 echo esc_js($plan->id) ?>')">Upgrade</a>
127
  </div>
128
  </div>
 
 
 
 
129
 
130
+ <h3 class="cnb-center">All plans contain the following features:</h3>
131
+ <div class="cnb-flexbox cnb-plan-features">
132
+ <ul class="cnb-checklist">
133
+ <li><strong>Phone</strong></li>
134
+ <li><strong>Email</strong></li>
135
+ <li><strong>SMS/text</strong></li>
136
+ <li><strong>WhatsApp</strong></li>
137
+ <li><strong>Location</strong></li>
138
+ <li><strong>Links</strong></li>
139
+ </ul>
140
+ <ul class="cnb-checklist">
141
+ <li><strong>Multiple buttons</strong><br>Add up to 8 buttons to a single page!</li>
142
+ <li><strong>Circular action button</strong><br>The famous single action button</li>
143
+ <li><strong>Multi action buttons</strong><br>Multibutton&trade; (expandable single button)<br>Buttonbar&trade; (Add up to 5 actions to a full width button)</li>
144
+ <li><strong>WhatsApp modal</strong><br>A chat-like modal to kickstart the conversation</li>
145
+ </ul>
146
+ <ul class="cnb-checklist" >
147
+ <li><strong>Button animations</strong><br>Draw more attention to your buttons with subtle animations</li>
148
+ <li><strong>Advanced page targeting options</strong><br>Ability to select full URLs, entire folders or even url parameters</li>
149
+ <li><strong>Scheduling</strong><br>Select days and times your buttons should be visible</li>
150
+ <li><strong>And so much more!</strong></li>
151
+ </ul>
152
  </div>
153
+ </div>
154
+ </form>
155
  <?php }
src/admin/partials/domain-upgrade/upgraded.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
 
 
 
3
  function cnb_upgrade_create_settings_url() {
4
  $url = admin_url('admin.php');
5
  $tab_link =
@@ -30,6 +32,6 @@ function cnb_domain_upgrade_upgraded($domain, $notice=null) {
30
  <?php echo $domain->renew == 1 ? ' renew automatically ' : ' expire '; ?>
31
  on <?php echo date('F d, Y', strtotime(esc_html($domain->expires))); ?>.
32
  <?php } ?>
33
- You can change this on the <a href="<?php echo esc_html(cnb_upgrade_create_settings_url()) ?>">settings page</a>.</p>
34
- <p>You can access and download your invoice via <a href="<?php echo esc_html($portal_url->url); ?>">the invoice dashboard</a>. For any questions, please head over to our <a href="https://callnowbutton.com/support/">help center</a>.</p>
35
  <?php } ?>
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAppRemote;
4
+
5
  function cnb_upgrade_create_settings_url() {
6
  $url = admin_url('admin.php');
7
  $tab_link =
32
  <?php echo $domain->renew == 1 ? ' renew automatically ' : ' expire '; ?>
33
  on <?php echo date('F d, Y', strtotime(esc_html($domain->expires))); ?>.
34
  <?php } ?>
35
+ You can change this on the <a href="<?php echo esc_attr(cnb_upgrade_create_settings_url()) ?>">settings page</a>.</p>
36
+ <p>You can access and download your invoice via <a href="<?php echo esc_attr($portal_url->url); ?>">the invoice dashboard</a>. For any questions, please head over to our <a href="https://callnowbutton.com/support/">help center</a>.</p>
37
  <?php } ?>
src/admin/settings-profile.php CHANGED
@@ -1,5 +1,6 @@
1
  <?php
2
 
 
3
  use cnb\admin\models\Cnb_User;
4
 
5
  function cnb_add_header_profile_edit() {
@@ -337,14 +338,14 @@ function cnb_admin_page_profile_edit_render_form($modal = false) {
337
  <tr class="cnb_advanced_view">
338
  <th scope="row"><label for="user_id">ID</label></th>
339
  <td>
340
- <code><?php echo esc_html($cnb_user->id) ?></code>
341
  </td>
342
  </tr>
343
  <?php } ?>
344
  <tr>
345
  <th scope="row"><label for="user_email">Email</label></th>
346
  <td>
347
- <input type="text" id="user_email" name="user[email]" value="<?php echo esc_html($cnb_user->email ) ?>"
348
  disabled class="regular-text ltr">
349
  <p class="description">Contact support to change your account email address.</p>
350
  </td>
@@ -353,7 +354,7 @@ function cnb_admin_page_profile_edit_render_form($modal = false) {
353
  <tr>
354
  <th scope="row"><label for="user[name]">Full name<span class="cnb_required">*</span></label></th>
355
  <td>
356
- <input type="text" id="user[name]" name="user[name]" value="<?php echo esc_html($cnb_user->name) ?>" required="required"
357
  class="regular-text ltr">
358
  </td>
359
  </tr>
@@ -361,7 +362,7 @@ function cnb_admin_page_profile_edit_render_form($modal = false) {
361
  <tr>
362
  <th scope="row"><label for="user[companyName]">Company name<span class="cnb_required cnb_vat_companies_show" style="display:none">*</span></label></th>
363
  <td>
364
- <input type="text" id="user[companyName]" name="user[companyName]" value="<?php echo esc_html($cnb_user->companyName) ?>"
365
  class="regular-text ltr cnb_vat_companies_required">
366
  </td>
367
  </tr>
@@ -400,14 +401,14 @@ function cnb_admin_page_profile_edit_render_form($modal = false) {
400
  <tr class="cnb_vat_companies_show" style="display:none">
401
  <th scope="row"><label for="user[address][line1]">Address<span class="cnb_required">*</span></label></th>
402
  <td>
403
- <input type="text" id="user[address][line1]" name="user[address][line1]" value="<?php echo esc_html( isset($cnb_user->address) ? $cnb_user->address->line1: '' ) ?>"
404
  class="regular-text ltr cnb_vat_companies_required cnb_eu_values_only">
405
  </td>
406
  </tr>
407
  <tr class="cnb_vat_companies_show" style="display:none">
408
  <th scope="row"><label for="user[address][line2]">Building, apartment, etc.</label></th>
409
  <td>
410
- <input type="text" id="user[address][line2]" name="user[address][line2]" value="<?php echo esc_html( isset($cnb_user->address) ? $cnb_user->address->line2 : '') ?>"
411
  class="regular-text ltr cnb_eu_values_only">
412
  </td>
413
  </tr>
@@ -416,7 +417,7 @@ function cnb_admin_page_profile_edit_render_form($modal = false) {
416
  <th scope="row"><label for="user[address][postalCode]"><span class="cnb_ie_only" style="display:none">Eircode/</span>Zip/Postal code<span class="cnb_required">*</span></label></th>
417
  <td>
418
  <input type="text" id="user[address][postalCode]" name="user[address][postalCode]"
419
- value="<?php echo esc_html( isset($cnb_user->address) ? $cnb_user->address->postalCode : '' ) ?>"
420
  class="regular-text ltr cnb_us_required cnb_vat_companies_required cnb_useu_values_only">
421
  </td>
422
  </tr>
@@ -424,7 +425,7 @@ function cnb_admin_page_profile_edit_render_form($modal = false) {
424
  <tr>
425
  <th scope="row"><label for="user[address][city]">City<span class="cnb_required">*</span></label></th>
426
  <td>
427
- <input type="text" id="user[address][city]" name="user[address][city]" value="<?php echo esc_html( isset($cnb_user->address) ? $cnb_user->address->city : '' ) ?>"
428
  required="required" class="regular-text ltr">
429
  </td>
430
  </tr>
@@ -432,7 +433,7 @@ function cnb_admin_page_profile_edit_render_form($modal = false) {
432
  <tr class="cnb_us_show" style="display:none">
433
  <th scope="row"><label for="user[address][state]">State<span class="cnb_required">*</span></label></th>
434
  <td>
435
- <input type="text" id="user[address][state]" name="user[address][state]" value="<?php echo esc_html( isset($cnb_user->address) ? $cnb_user->address->state : '' ) ?>"
436
  class="regular-text ltr cnb_us_required cnb_us_values_only">
437
  </td>
438
  </tr>
@@ -444,7 +445,7 @@ function cnb_admin_page_profile_edit_render_form($modal = false) {
444
  </th>
445
  <td>
446
  <input id="cnb_profile_vat" type="text" name="user[taxIds][0][value]"
447
- value="<?php echo esc_html( isset($cnb_user->taxIds[0]) ? $cnb_user->taxIds[0]->value : '' ) ?>"
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">
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAppRemote;
4
  use cnb\admin\models\Cnb_User;
5
 
6
  function cnb_add_header_profile_edit() {
338
  <tr class="cnb_advanced_view">
339
  <th scope="row"><label for="user_id">ID</label></th>
340
  <td>
341
+ <code><?php echo esc_html( $cnb_user->id ) ?></code>
342
  </td>
343
  </tr>
344
  <?php } ?>
345
  <tr>
346
  <th scope="row"><label for="user_email">Email</label></th>
347
  <td>
348
+ <input type="text" id="user_email" name="user[email]" value="<?php echo esc_attr( $cnb_user->email ) ?>"
349
  disabled class="regular-text ltr">
350
  <p class="description">Contact support to change your account email address.</p>
351
  </td>
354
  <tr>
355
  <th scope="row"><label for="user[name]">Full name<span class="cnb_required">*</span></label></th>
356
  <td>
357
+ <input type="text" id="user[name]" name="user[name]" value="<?php echo esc_attr( $cnb_user->name ) ?>" required="required"
358
  class="regular-text ltr">
359
  </td>
360
  </tr>
362
  <tr>
363
  <th scope="row"><label for="user[companyName]">Company name<span class="cnb_required cnb_vat_companies_show" style="display:none">*</span></label></th>
364
  <td>
365
+ <input type="text" id="user[companyName]" name="user[companyName]" value="<?php echo esc_attr( $cnb_user->companyName ) ?>"
366
  class="regular-text ltr cnb_vat_companies_required">
367
  </td>
368
  </tr>
401
  <tr class="cnb_vat_companies_show" style="display:none">
402
  <th scope="row"><label for="user[address][line1]">Address<span class="cnb_required">*</span></label></th>
403
  <td>
404
+ <input type="text" id="user[address][line1]" name="user[address][line1]" value="<?php echo esc_attr( isset($cnb_user->address) ? $cnb_user->address->line1: '' ) ?>"
405
  class="regular-text ltr cnb_vat_companies_required cnb_eu_values_only">
406
  </td>
407
  </tr>
408
  <tr class="cnb_vat_companies_show" style="display:none">
409
  <th scope="row"><label for="user[address][line2]">Building, apartment, etc.</label></th>
410
  <td>
411
+ <input type="text" id="user[address][line2]" name="user[address][line2]" value="<?php echo esc_attr( isset($cnb_user->address) ? $cnb_user->address->line2 : '') ?>"
412
  class="regular-text ltr cnb_eu_values_only">
413
  </td>
414
  </tr>
417
  <th scope="row"><label for="user[address][postalCode]"><span class="cnb_ie_only" style="display:none">Eircode/</span>Zip/Postal code<span class="cnb_required">*</span></label></th>
418
  <td>
419
  <input type="text" id="user[address][postalCode]" name="user[address][postalCode]"
420
+ value="<?php echo esc_attr( isset($cnb_user->address) ? $cnb_user->address->postalCode : '' ) ?>"
421
  class="regular-text ltr cnb_us_required cnb_vat_companies_required cnb_useu_values_only">
422
  </td>
423
  </tr>
425
  <tr>
426
  <th scope="row"><label for="user[address][city]">City<span class="cnb_required">*</span></label></th>
427
  <td>
428
+ <input type="text" id="user[address][city]" name="user[address][city]" value="<?php echo esc_attr( isset($cnb_user->address) ? $cnb_user->address->city : '' ) ?>"
429
  required="required" class="regular-text ltr">
430
  </td>
431
  </tr>
433
  <tr class="cnb_us_show" style="display:none">
434
  <th scope="row"><label for="user[address][state]">State<span class="cnb_required">*</span></label></th>
435
  <td>
436
+ <input type="text" id="user[address][state]" name="user[address][state]" value="<?php echo esc_attr( isset($cnb_user->address) ? $cnb_user->address->state : '' ) ?>"
437
  class="regular-text ltr cnb_us_required cnb_us_values_only">
438
  </td>
439
  </tr>
445
  </th>
446
  <td>
447
  <input id="cnb_profile_vat" type="text" name="user[taxIds][0][value]"
448
+ value="<?php echo esc_attr( isset($cnb_user->taxIds[0]) ? $cnb_user->taxIds[0]->value : '' ) ?>"
449
  class="regular-text ltr cnb_vat_companies_required cnb_eu_values_only">
450
  <input id="cnb_user_taxids_type" type="hidden" name="user[taxIds][0][type]" value="eu_vat"
451
  class="regular-text ltr cnb_vat_companies_required cnb_eu_values_only">
src/admin/settings.php CHANGED
@@ -1,5 +1,10 @@
1
  <?php
2
 
 
 
 
 
 
3
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
4
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
5
  require_once dirname( __FILE__ ) . '/domain-edit.php';
@@ -97,9 +102,9 @@ function cnb_settings_options_validate($input) {
97
  if ((isset($input['api_key']) && $input['api_key'] === 'delete_me') ||
98
  (isset($original_settings['api_key']) && $original_settings['api_key'] === 'delete_me') ) {
99
  $input['api_key'] = '';
100
- $updated_options['api_key'] = '';
101
  $input['cloud_use_id'] = '';
102
- $updated_options['cloud_use_id'] = '';
103
 
104
  $messages[] = new CnbNotice( 'success', '<p>Your API key has been removed - you can now activate Call Now Button with another API key.</p>' );
105
  }
@@ -203,9 +208,9 @@ function cnb_admin_setting_migrate() {
203
  }
204
 
205
  /**
206
- * @param $api_key_ott
207
  *
208
- * @return {string} The API key if found
209
  */
210
  function cnb_try_api_key_ott($api_key_ott, $render_notice=true) {
211
  $api_key_obj = CnbAppRemote::cnb_remote_get_apikey_via_ott($api_key_ott);
@@ -264,6 +269,8 @@ function cnb_admin_settings_page() {
264
  cnb_reset_options();
265
  }
266
 
 
 
267
  /**
268
  * @type CnbDomain
269
  */
@@ -287,11 +294,11 @@ function cnb_admin_settings_page() {
287
  wp_enqueue_script(CNB_SLUG . '-settings');
288
  wp_enqueue_script(CNB_SLUG . '-timezone-picker-fix');
289
 
290
- do_action('cnb_header');
291
  $show_advanced_view_only = array_key_exists('advanced_view', $cnb_options) && $cnb_options['advanced_view'] === 1;
292
  $use_cloud = is_use_cloud($cnb_options);
293
 
294
  $cloud_successful = $cnb_options['status'] === 'cloud' && isset($cnb_cloud_domain) && !($cnb_cloud_domain instanceof WP_Error);
 
295
  if ($cloud_successful) { ?>
296
  <script>
297
  jQuery(() => {
@@ -324,31 +331,28 @@ function cnb_admin_settings_page() {
324
  <tr><th colspan="2"></th></tr>
325
  <tr>
326
  <th scope="row">
327
- Plugin type
328
  <?php if ($cnb_options['cloud_enabled'] == 0) { ?>
329
  <a href="<?php echo cnb_legacy_upgrade_page(); ?>" class="cnb-nounderscore">
330
  <span class="dashicons dashicons-editor-help"></span>
331
  </a>
332
  <?php } ?>
 
333
  </th>
334
  <td>
335
- <div class="cnb-radio-item">
336
- <input type="radio" name="cnb[cloud_enabled]" id="cnb_cloud_disabled" value="0" <?php checked('0', $cnb_options['cloud_enabled']); ?>>
337
- <label for="cnb_cloud_disabled">Normal</label>
338
-
339
- </div>
340
- <div class="cnb-radio-item">
341
- <input type="radio" name="cnb[cloud_enabled]" id="cnb_cloud_enabled" value="1" <?php checked('1', $cnb_options['cloud_enabled']); ?>>
342
- <label for="cnb_cloud_enabled">Premium</label>
343
-
344
- <?php if ($cnb_options['cloud_enabled'] == 0) { ?>
345
- <p class="description">Paid and free options. <a href="<?php echo cnb_legacy_upgrade_page(); ?>">Learn more</a></p>
346
- <?php } ?>
347
-
348
- <?php if ($cnb_options['cloud_enabled'] == 1 && isset($cnb_cloud_domain) && !is_wp_error($cnb_cloud_domain) && $cnb_cloud_domain->type !== 'PRO') { ?>
349
- <p class="description">Paid and free options. <a href="<?php echo get_cnb_domain_upgrade($cnb_cloud_domain); ?>">Learn more</a></p>
350
- <?php } ?>
351
- </div>
352
  </td>
353
  </tr>
354
  <?php if ($cnb_options['status'] !== 'cloud') { ?>
@@ -449,7 +453,7 @@ function cnb_admin_settings_page() {
449
  <input type="hidden" name="cnb[advanced_view]" value="0" />
450
  <input id="cnb-advanced-view" class="cnb_toggle_checkbox" type="checkbox" name="cnb[advanced_view]" value="1" <?php checked('1', $cnb_options['advanced_view']); ?> />
451
  <label for="cnb-advanced-view" class="cnb_toggle_label">Toggle</label>
452
- <span data-cnb_toggle_state_label="cnb-advanced-view" class="cnb_toggle_state cnb_toggle_false">Disabled</span>
453
  <span data-cnb_toggle_state_label="cnb-advanced-view" class="cnb_toggle_state cnb_toggle_true">Enabled</span>
454
  <p class="description">For power users only.</p>
455
  </td>
@@ -461,7 +465,7 @@ function cnb_admin_settings_page() {
461
  <input type="hidden" name="cnb[footer_show_traces]" value="0" />
462
  <input id="cnb-show-traces" class="cnb_toggle_checkbox" type="checkbox" name="cnb[footer_show_traces]" value="1" <?php checked('1', $cnb_options['footer_show_traces']); ?> />
463
  <label for="cnb-show-traces" class="cnb_toggle_label">Toggle</label>
464
- <span data-cnb_toggle_state_label="cnb-show-traces" class="cnb_toggle_state cnb_toggle_false">Disabled</span>
465
  <span data-cnb_toggle_state_label="cnb-show-traces" class="cnb_toggle_state cnb_toggle_true">Enabled</span>
466
  <p class="description">Display API calls and timings in the footer.</p>
467
  </td>
@@ -512,7 +516,7 @@ function cnb_admin_settings_page() {
512
  <input type="hidden" name="cnb[show_all_buttons_for_domain]" value="0" />
513
  <input id="cnb-all-domains" class="cnb_toggle_checkbox" type="checkbox" name="cnb[show_all_buttons_for_domain]" value="1" <?php checked('1', $cnb_options['show_all_buttons_for_domain']); ?> />
514
  <label for="cnb-all-domains" class="cnb_toggle_label">Toggle</label>
515
- <span data-cnb_toggle_state_label="cnb-all-domains" class="cnb_toggle_state cnb_toggle_false">Disabled</span>
516
  <span data-cnb_toggle_state_label="cnb-all-domains" class="cnb_toggle_state cnb_toggle_true">Enabled</span>
517
  <p class="description">When checked, the "All Buttons" overview shows all buttons for this account, not just for the current domain.</p>
518
  </td>
@@ -534,7 +538,7 @@ function cnb_admin_settings_page() {
534
  <input type="hidden" name="cnb[api_caching]" value="0" />
535
  <input id="cnb-api-caching" class="cnb_toggle_checkbox" type="checkbox" name="cnb[api_caching]" value="1" <?php checked('1', $cnb_options['api_caching']); ?> />
536
  <label for="cnb-api-caching" class="cnb_toggle_label">Toggle</label>
537
- <span data-cnb_toggle_state_label="cnb-api-caching" class="cnb_toggle_state cnb_toggle_false">Disabled</span>
538
  <span data-cnb_toggle_state_label="cnb-api-caching" class="cnb_toggle_state cnb_toggle_true">Enabled</span>
539
  <p class="description">Cache API requests (using WordPress transients)</p>
540
  </td>
@@ -548,28 +552,40 @@ function cnb_admin_settings_page() {
548
  </div>
549
  <div class="cnb-postbox-container cnb-side-column">
550
  <?php if(!$use_cloud) {
551
- cnb_promobox(
552
- 'blue',
553
- 'More buttons!',
554
- 'Switch to Premium to enable lots of buttons. Coupled with advanced page selection options you can get really creative.</p>
555
- <p>If you need more phone numbers on a single page, then the Multibutton&trade; and the Buttonbar&trade; give you exactly what you need.</p>',
556
- 'cloud',
557
- '<strong>Give it a try!</strong>',
558
- 'Learn more',
559
- cnb_legacy_upgrade_page()
560
- );
561
- cnb_promobox(
562
- 'grey',
563
- 'Go Premium for free',
564
- 'Premium comes in 2 versions: <em>Free</em> and <em>Paid</em>.</p>
565
- <p>Both plans give you access to <strong>all features</strong>.</p>
566
- <p>The only differences are that the Free version shows <em>Powered by Call Now Button</em> next to your buttons and there\'s a monthly pageviews limit of 20k.</p>',
567
- 'info-outline',
568
- '',
569
- 'Try Premium',
570
- cnb_legacy_upgrade_page()
571
- );
 
 
 
 
 
 
 
 
 
 
 
572
  } ?>
 
573
  <?php if($use_cloud && isset($cnb_cloud_domain) && !is_wp_error($cnb_cloud_domain) && $cnb_cloud_domain->type !== 'PRO') {
574
  cnb_promobox(
575
  'blue',
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAdminCloud;
4
+ use cnb\admin\api\CnbAppRemote;
5
+ use cnb\admin\models\CnbApiKey;
6
+ use cnb\admin\models\CnbDomain;
7
+
8
  require_once dirname( __FILE__ ) . '/api/CnbAppRemote.php';
9
  require_once dirname( __FILE__ ) . '/api/CnbAdminCloud.php';
10
  require_once dirname( __FILE__ ) . '/domain-edit.php';
102
  if ((isset($input['api_key']) && $input['api_key'] === 'delete_me') ||
103
  (isset($original_settings['api_key']) && $original_settings['api_key'] === 'delete_me') ) {
104
  $input['api_key'] = '';
105
+ $original_settings['api_key'] = '';
106
  $input['cloud_use_id'] = '';
107
+ $original_settings['cloud_use_id'] = '';
108
 
109
  $messages[] = new CnbNotice( 'success', '<p>Your API key has been removed - you can now activate Call Now Button with another API key.</p>' );
110
  }
208
  }
209
 
210
  /**
211
+ * @param $api_key_ott string API key OTT (OneTimeToken)
212
  *
213
+ * @return string|null The API key if found
214
  */
215
  function cnb_try_api_key_ott($api_key_ott, $render_notice=true) {
216
  $api_key_obj = CnbAppRemote::cnb_remote_get_apikey_via_ott($api_key_ott);
269
  cnb_reset_options();
270
  }
271
 
272
+ do_action('cnb_header');
273
+
274
  /**
275
  * @type CnbDomain
276
  */
294
  wp_enqueue_script(CNB_SLUG . '-settings');
295
  wp_enqueue_script(CNB_SLUG . '-timezone-picker-fix');
296
 
 
297
  $show_advanced_view_only = array_key_exists('advanced_view', $cnb_options) && $cnb_options['advanced_view'] === 1;
298
  $use_cloud = is_use_cloud($cnb_options);
299
 
300
  $cloud_successful = $cnb_options['status'] === 'cloud' && isset($cnb_cloud_domain) && !($cnb_cloud_domain instanceof WP_Error);
301
+
302
  if ($cloud_successful) { ?>
303
  <script>
304
  jQuery(() => {
331
  <tr><th colspan="2"></th></tr>
332
  <tr>
333
  <th scope="row">
334
+ <label for="cnb_cloud_enabled">Premium
335
  <?php if ($cnb_options['cloud_enabled'] == 0) { ?>
336
  <a href="<?php echo cnb_legacy_upgrade_page(); ?>" class="cnb-nounderscore">
337
  <span class="dashicons dashicons-editor-help"></span>
338
  </a>
339
  <?php } ?>
340
+ <label>
341
  </th>
342
  <td>
343
+
344
+ <input type="hidden" name="cnb[cloud_enabled]" value="0" />
345
+ <input id="cnb_cloud_enabled" class="cnb_toggle_checkbox" name="cnb[cloud_enabled]" type="checkbox" value="1" <?php checked('1', $cnb_options['cloud_enabled']); ?> />
346
+ <label for="cnb_cloud_enabled" class="cnb_toggle_label">Enable Premium</label>
347
+ <span data-cnb_toggle_state_label="cnb_cloud_enabled" class="cnb_toggle_state cnb_toggle_false">(Inactive)</span>
348
+ <span data-cnb_toggle_state_label="cnb_cloud_enabled" class="cnb_toggle_state cnb_toggle_true">Active</span>
349
+ <?php if ($cnb_options['cloud_enabled'] == 0) { ?>
350
+ <p class="description">Free and paid options available. <a href="<?php echo cnb_legacy_upgrade_page(); ?>">Learn more</a></p>
351
+ <?php } ?>
352
+
353
+ <?php if ($cnb_options['cloud_enabled'] == 1 && isset($cnb_cloud_domain) && !is_wp_error($cnb_cloud_domain) && $cnb_cloud_domain->type !== 'PRO') { ?>
354
+ <p class="description">Free and paid options available. <a href="<?php echo get_cnb_domain_upgrade($cnb_cloud_domain); ?>">Learn more</a></p>
355
+ <?php } ?>
 
 
 
 
356
  </td>
357
  </tr>
358
  <?php if ($cnb_options['status'] !== 'cloud') { ?>
453
  <input type="hidden" name="cnb[advanced_view]" value="0" />
454
  <input id="cnb-advanced-view" class="cnb_toggle_checkbox" type="checkbox" name="cnb[advanced_view]" value="1" <?php checked('1', $cnb_options['advanced_view']); ?> />
455
  <label for="cnb-advanced-view" class="cnb_toggle_label">Toggle</label>
456
+ <span data-cnb_toggle_state_label="cnb-advanced-view" class="cnb_toggle_state cnb_toggle_false">(Disabled)</span>
457
  <span data-cnb_toggle_state_label="cnb-advanced-view" class="cnb_toggle_state cnb_toggle_true">Enabled</span>
458
  <p class="description">For power users only.</p>
459
  </td>
465
  <input type="hidden" name="cnb[footer_show_traces]" value="0" />
466
  <input id="cnb-show-traces" class="cnb_toggle_checkbox" type="checkbox" name="cnb[footer_show_traces]" value="1" <?php checked('1', $cnb_options['footer_show_traces']); ?> />
467
  <label for="cnb-show-traces" class="cnb_toggle_label">Toggle</label>
468
+ <span data-cnb_toggle_state_label="cnb-show-traces" class="cnb_toggle_state cnb_toggle_false">(Disabled)</span>
469
  <span data-cnb_toggle_state_label="cnb-show-traces" class="cnb_toggle_state cnb_toggle_true">Enabled</span>
470
  <p class="description">Display API calls and timings in the footer.</p>
471
  </td>
516
  <input type="hidden" name="cnb[show_all_buttons_for_domain]" value="0" />
517
  <input id="cnb-all-domains" class="cnb_toggle_checkbox" type="checkbox" name="cnb[show_all_buttons_for_domain]" value="1" <?php checked('1', $cnb_options['show_all_buttons_for_domain']); ?> />
518
  <label for="cnb-all-domains" class="cnb_toggle_label">Toggle</label>
519
+ <span data-cnb_toggle_state_label="cnb-all-domains" class="cnb_toggle_state cnb_toggle_false">(Disabled)</span>
520
  <span data-cnb_toggle_state_label="cnb-all-domains" class="cnb_toggle_state cnb_toggle_true">Enabled</span>
521
  <p class="description">When checked, the "All Buttons" overview shows all buttons for this account, not just for the current domain.</p>
522
  </td>
538
  <input type="hidden" name="cnb[api_caching]" value="0" />
539
  <input id="cnb-api-caching" class="cnb_toggle_checkbox" type="checkbox" name="cnb[api_caching]" value="1" <?php checked('1', $cnb_options['api_caching']); ?> />
540
  <label for="cnb-api-caching" class="cnb_toggle_label">Toggle</label>
541
+ <span data-cnb_toggle_state_label="cnb-api-caching" class="cnb_toggle_state cnb_toggle_false">(Disabled)</span>
542
  <span data-cnb_toggle_state_label="cnb-api-caching" class="cnb_toggle_state cnb_toggle_true">Enabled</span>
543
  <p class="description">Cache API requests (using WordPress transients)</p>
544
  </td>
552
  </div>
553
  <div class="cnb-postbox-container cnb-side-column">
554
  <?php if(!$use_cloud) {
555
+ cnb_promobox(
556
+ 'blue',
557
+ 'Phones off at 6pm?',
558
+ '<p>Sign up to enable a scheduler that allows you to set the days and hours that you are available.</p>
559
+ <p>You can even replace it with an email button during your off-hours so people can still contact you.</p>',
560
+ 'clock',
561
+ '<strong>Try it, it\'s free!</strong>',
562
+ 'Learn more',
563
+ cnb_legacy_upgrade_page()
564
+ );
565
+ cnb_promobox(
566
+ 'blue',
567
+ 'More buttons!',
568
+ 'Switch to Premium to enable lots of buttons. Coupled with advanced page selection options you can get really creative.</p>
569
+ <p>If you need more phone numbers on a single page, then the Multibutton&trade; and the Buttonbar&trade; give you exactly what you need.</p>',
570
+ 'cloud',
571
+ '<strong>Try it out!</strong>',
572
+ 'Learn more',
573
+ cnb_legacy_upgrade_page()
574
+ );
575
+ cnb_promobox(
576
+ 'blue',
577
+ 'Get Premium for FREE!',
578
+ 'Premium adds a ton of extra power to the Call Now Button.</p>
579
+ <p>The Premium Free plan shows a little branding with your buttons but gives you access to all features.</p>
580
+ <p>Try it out and enjoy scheduling, multiple buttons, more button types, animations and much more!</p>',
581
+ 'money-alt',
582
+ '',
583
+ 'See what\'s incuded',
584
+ cnb_legacy_upgrade_page()
585
+ );
586
+
587
  } ?>
588
+
589
  <?php if($use_cloud && isset($cnb_cloud_domain) && !is_wp_error($cnb_cloud_domain) && $cnb_cloud_domain->type !== 'PRO') {
590
  cnb_promobox(
591
  'blue',
src/call-now-button.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
 
 
 
3
  require_once dirname( __FILE__ ) . '/renderers/render.php';
4
  require_once dirname( __FILE__ ) . '/utils/utils.php';
5
  require_once dirname( __FILE__ ) . '/admin/admin-ajax.php';
@@ -305,6 +307,11 @@ function cnb_options_init() {
305
  plugins_url('../resources/style/intlTelInput.min.css', __FILE__),
306
  false,
307
  '1.13.0');
 
 
 
 
 
308
 
309
  wp_register_script(
310
  CNB_SLUG . '-call-now-button',
@@ -361,12 +368,24 @@ function cnb_options_init() {
361
  array(CNB_SLUG . '-call-now-button'),
362
  CNB_VERSION,
363
  true);
 
 
 
 
 
 
 
 
 
 
 
 
364
 
365
  // Special case: since the preview functionality depends on this,
366
  // and the source is always changing - we include it as external script
367
  wp_register_script(
368
  CNB_SLUG . '-client',
369
- 'https://static.callnowbutton.com/js/client.js',
370
  array(),
371
  CNB_VERSION,
372
  true);
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAppRemote;
4
+
5
  require_once dirname( __FILE__ ) . '/renderers/render.php';
6
  require_once dirname( __FILE__ ) . '/utils/utils.php';
7
  require_once dirname( __FILE__ ) . '/admin/admin-ajax.php';
307
  plugins_url('../resources/style/intlTelInput.min.css', __FILE__),
308
  false,
309
  '1.13.0');
310
+ wp_register_style(
311
+ CNB_SLUG . '-client',
312
+ CnbAppRemote::cnb_get_static_base() . '/css/main.css',
313
+ array(),
314
+ CNB_VERSION);
315
 
316
  wp_register_script(
317
  CNB_SLUG . '-call-now-button',
368
  array(CNB_SLUG . '-call-now-button'),
369
  CNB_VERSION,
370
  true);
371
+ wp_register_script(
372
+ CNB_SLUG . '-action-edit',
373
+ plugins_url( '../resources/js/action-edit.js', __FILE__ ),
374
+ array(CNB_SLUG . '-call-now-button'),
375
+ CNB_VERSION,
376
+ true);
377
+ wp_register_script(
378
+ CNB_SLUG . '-jquery-ui-touch-punch',
379
+ plugins_url( '../resources/js/jquery.ui.touch-punch.js', __FILE__ ),
380
+ array(CNB_SLUG . '-call-now-button', 'jquery-ui-sortable'),
381
+ 'v1.0.8',
382
+ true);
383
 
384
  // Special case: since the preview functionality depends on this,
385
  // and the source is always changing - we include it as external script
386
  wp_register_script(
387
  CNB_SLUG . '-client',
388
+ CnbAppRemote::cnb_get_static_base() . '/js/client.js',
389
  array(),
390
  CNB_VERSION,
391
  true);
src/cli/CNB_CLI_Button.class.php CHANGED
@@ -2,10 +2,10 @@
2
 
3
  namespace cnb\cli;
4
 
5
- use CnbAdminCloud;
6
- use CnbAppRemote;
7
- use CnbButton;
8
- use CnbButtonOptions;
9
  use WP_CLI;
10
  use WP_CLI_Command;
11
 
@@ -72,7 +72,7 @@ class CNB_CLI_Button extends WP_CLI_Command {
72
  $buttons = CnbAppRemote::cnb_remote_get_buttons();
73
  if (!is_wp_error($buttons)) {
74
  // Convert into array
75
- $items = CnbButton::convert($buttons);
76
 
77
  $format = WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'table' );
78
  $fields = WP_CLI\Utils\get_flag_value( $assoc_args, 'fields', array( 'id', 'name', 'active', 'type', 'domain', 'actions', 'conditions', 'options' ) );
@@ -154,13 +154,13 @@ class CNB_CLI_Button extends WP_CLI_Command {
154
  $button->name = $button_name;
155
  $button->type = WP_CLI\Utils\get_flag_value( $assoc_args, 'type', 'SINGLE' );
156
  $button->active = WP_CLI\Utils\get_flag_value( $assoc_args, 'active', 'true' ) == 'true';
157
- $button->domain = $default_domain->id;
158
 
159
  $options = new CnbButtonOptions();
160
  $options->placement = WP_CLI\Utils\get_flag_value( $assoc_args, 'placement', 'BOTTOM_RIGHT' );
161
  $button->options = $options;
162
 
163
- $result = CnbAdminCloud::cnb_create_button( $notifications, $button->toArray() );
164
  if ( is_wp_error( $result ) ) {
165
  WP_CLI::error( $result );
166
  }
2
 
3
  namespace cnb\cli;
4
 
5
+ use cnb\admin\api\CnbAdminCloud;
6
+ use cnb\admin\api\CnbAppRemote;
7
+ use cnb\admin\models\CnbButton;
8
+ use cnb\admin\models\CnbButtonOptions;
9
  use WP_CLI;
10
  use WP_CLI_Command;
11
 
72
  $buttons = CnbAppRemote::cnb_remote_get_buttons();
73
  if (!is_wp_error($buttons)) {
74
  // Convert into array
75
+ $items = CnbButton::convertToArray($buttons);
76
 
77
  $format = WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'table' );
78
  $fields = WP_CLI\Utils\get_flag_value( $assoc_args, 'fields', array( 'id', 'name', 'active', 'type', 'domain', 'actions', 'conditions', 'options' ) );
154
  $button->name = $button_name;
155
  $button->type = WP_CLI\Utils\get_flag_value( $assoc_args, 'type', 'SINGLE' );
156
  $button->active = WP_CLI\Utils\get_flag_value( $assoc_args, 'active', 'true' ) == 'true';
157
+ $button->domain = $default_domain;
158
 
159
  $options = new CnbButtonOptions();
160
  $options->placement = WP_CLI\Utils\get_flag_value( $assoc_args, 'placement', 'BOTTOM_RIGHT' );
161
  $button->options = $options;
162
 
163
+ $result = CnbAdminCloud::cnb_create_button( $notifications, $button );
164
  if ( is_wp_error( $result ) ) {
165
  WP_CLI::error( $result );
166
  }
src/renderers/cloud/wp_head.php CHANGED
@@ -1,4 +1,7 @@
1
  <?php
 
 
 
2
  function cnb_head() {
3
  global $cnb_options;
4
  $id = isset($cnb_options['cloud_use_id']) ? $cnb_options['cloud_use_id'] : 0;
1
  <?php
2
+
3
+ use cnb\admin\api\CnbAppRemote;
4
+
5
  function cnb_head() {
6
  global $cnb_options;
7
  $id = isset($cnb_options['cloud_use_id']) ? $cnb_options['cloud_use_id'] : 0;
src/utils/CnbUtils.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace cnb\utils;
3
+
4
+ // don't load directly
5
+ defined( 'ABSPATH' ) || die( '-1' );
6
+
7
+ use stdClass;
8
+
9
+ class CnbUtils {
10
+ /**
11
+ * @param $object null|array|stdClass
12
+ * @param $property
13
+ *
14
+ * @return mixed|null
15
+ */
16
+ public static function getPropertyOrNull($object, $property) {
17
+ if ($object === null) return null;
18
+
19
+ if(is_array($object) && array_key_exists($property, $object)) {
20
+ return $object[$property];
21
+ }
22
+
23
+ if ($object instanceof stdClass && property_exists($object, $property)) {
24
+ return $object->$property;
25
+ }
26
+
27
+ return null;
28
+ }
29
+
30
+ }
src/utils/notices.php CHANGED
@@ -1,5 +1,7 @@
1
  <?php
2
 
 
 
3
  require_once dirname( __FILE__ ) . '/CnbAdminNotices.class.php';
4
  require_once dirname( __FILE__ ) . '/../admin/api/CnbAdminCloud.php';
5
 
@@ -50,12 +52,13 @@ function cnb_upgrade_notice($cnb_options, $cnb_changelog) {
50
 
51
  function cnb_settings_email_activation_input() {
52
  $message = '<div id="cnb_email_activation_alternate_formd">';
53
- $message .= '<input type="text" class="cnb_activation_input_field" 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
 
58
- $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>. You also acknowledge that the Free plan allows up to 20k pageviews per month.</p>';
59
 
60
  return $message;
61
  }
@@ -84,14 +87,20 @@ function cnb_settings_get_account_missing_notice() {
84
  function cnb_settings_api_key_invalid_notice() {
85
  $message = '<h3 class="title">Ooops, that API key doesn\'t seem right</h3>
86
  <p>The saved API key is invalid. Let\'s give it another try:</p>
 
 
 
 
 
 
87
  <ol>
88
- <li>Head over to the profile panel on <a href="https://app.callnowbutton.com/app/profile" target="_blank">app.callnowbutton.com</a>.</li>
89
- <li>Click <strong>Create new API key</strong>, enter a unique name (can be anything. I always enter my website domain here) and click <strong>Generate new API key</strong>.</li>
90
- <li>Copy the API key, paste it into the field below and click <strong>Save key</strong>.</li>
91
- </ol>
92
- <p>If it\'s still not working, we might be experiencing server issues. Please wait a few minutes and try again. You can check our <a target="_blank" href="https://status.callnowbutton.com">status page</a> to be sure.</p>';
93
  $message .= cnb_settings_api_key_input();
94
 
 
95
  $adminNotices = CnbAdminNotices::get_instance();
96
  $adminNotices->warning($message);
97
  }
@@ -274,18 +283,22 @@ function cnb_get_welcome_banner() {
274
  </div>
275
  </div>
276
  <div class="welcome-banner-column">
277
- <h3>What's Premium?</h3>
278
  <p class="cnb-mobile-inline">+ Create multiple buttons</p>
279
  <p class="cnb-mobile-inline">+ WhatsApp, SMS/text, Email, Maps and Links</p>
 
280
  <p class="cnb-mobile-inline">+ Multi action buttons</p>
281
  <p class="cnb-mobile-inline">+ Button scheduler</p>
 
282
  <p class="cnb-mobile-inline">+ Advanced page targeting</p>
 
283
  </div>
284
  <div class="welcome-banner-column">
285
- <a class="button button-primary button-hero" href="<?php echo $upgrade_url ?>">Try Premium for Free</a>
286
- <p><a href="<?php echo $upgrade_url ?>">More info about Premium</a></p>
 
287
  <h3>Other resources</h3>
288
- <p><a href="<?php echo CNB_SUPPORT; ?>wordpress-free/">The new help center</a></p>
289
  <p><a href="<?php echo CNB_SUPPORT; ?>wordpress-free/#faq">FAQ</a></p>
290
  </div>
291
  </div>
@@ -311,7 +324,6 @@ function cnb_warn_about_timezone($domain) {
311
  array(
312
  'page' => 'call-now-button-settings',
313
  'tab' => 'advanced_options#domain_timezone',
314
-
315
  ),
316
  $url );
317
  $redirect_url = esc_url( $redirect_link );
1
  <?php
2
 
3
+ use cnb\admin\api\CnbAdminCloud;
4
+
5
  require_once dirname( __FILE__ ) . '/CnbAdminNotices.class.php';
6
  require_once dirname( __FILE__ ) . '/../admin/api/CnbAdminCloud.php';
7
 
52
 
53
  function cnb_settings_email_activation_input() {
54
  $message = '<div id="cnb_email_activation_alternate_formd">';
55
+ $message .= '<p style="margin-top: 0;"><strong>Email address</strong> (for sending you an activation link):</p>';
56
+ $message .= '<input type="text" required="required" class="cnb_activation_input_field" name="cnb_email_activation_alternate_address" id="cnb_email_activation_alternate_address" placeholder="Your email address" /> ';
57
  $message .= get_submit_button(__('Activate Premium'), 'primary', 'cnb_email_activation_alternate', false, array('onclick' => 'return cnb_email_activation_alternate()'));
58
  $message .= '</div>';
59
  $message .= '<p id="cnb_email_activation"></p>';
60
 
61
+ $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>';
62
 
63
  return $message;
64
  }
87
  function cnb_settings_api_key_invalid_notice() {
88
  $message = '<h3 class="title">Ooops, that API key doesn\'t seem right</h3>
89
  <p>The saved API key is invalid. Let\'s give it another try:</p>
90
+ <h4>Option 1: Email activation</h4>';
91
+ $message .= cnb_settings_email_activation_input();
92
+
93
+ $message .= '
94
+ <hr>
95
+ <h4>Option 2: Web activation (manual process)</h4>
96
  <ol>
97
+ <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>
98
+ <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>
99
+ <li>Copy the API key that appears, paste it into the field below and click <strong>Store API key</strong>.</li>
100
+ </ol>';
 
101
  $message .= cnb_settings_api_key_input();
102
 
103
+ $message .= '<hr><p>If it\'s still not working, we might be experiencing server issues. Please wait a few minutes and try again. You can check our <a target="_blank" href="https://status.callnowbutton.com">status page</a> to be sure.</p>';
104
  $adminNotices = CnbAdminNotices::get_instance();
105
  $adminNotices->warning($message);
106
  }
283
  </div>
284
  </div>
285
  <div class="welcome-banner-column">
286
+ <h3>What's in Premium?</h3>
287
  <p class="cnb-mobile-inline">+ Create multiple buttons</p>
288
  <p class="cnb-mobile-inline">+ WhatsApp, SMS/text, Email, Maps and Links</p>
289
+ <p class="cnb-mobile-inline">+ WhatsApp chat modal</p>
290
  <p class="cnb-mobile-inline">+ Multi action buttons</p>
291
  <p class="cnb-mobile-inline">+ Button scheduler</p>
292
+ <p class="cnb-mobile-inline">+ Icon selection</p>
293
  <p class="cnb-mobile-inline">+ Advanced page targeting</p>
294
+ <p class="cnb-mobile-inline">+ Live preview</p>
295
  </div>
296
  <div class="welcome-banner-column">
297
+ <a class="button button-primary button-hero" href="<?php echo $upgrade_url ?>">Get Premium Free</a>
298
+
299
+ <p><a href="<?php echo $upgrade_url ?>">More info about Premium</a></p>
300
  <h3>Other resources</h3>
301
+ <p><a href="<?php echo CNB_SUPPORT; ?>wordpress-free/">Help center</a></p>
302
  <p><a href="<?php echo CNB_SUPPORT; ?>wordpress-free/#faq">FAQ</a></p>
303
  </div>
304
  </div>
324
  array(
325
  'page' => 'call-now-button-settings',
326
  'tab' => 'advanced_options#domain_timezone',
 
327
  ),
328
  $url );
329
  $redirect_url = esc_url( $redirect_link );
src/utils/utils.php CHANGED
@@ -1,4 +1,8 @@
1
  <?php
 
 
 
 
2
  require_once dirname( __FILE__ ) . '/notices.php';
3
  require_once dirname( __FILE__ ) . '/../admin/settings.php';
4
 
@@ -293,12 +297,16 @@ function cnb_check_for_caching() {
293
  }
294
  return array($active,$name);
295
  }
296
- function cnb_utm_params($element, $page) {
297
  $output = "?utm_source=wp-plugin";
298
  $output .= "&utm_medium=referral";
299
  $output .= "&utm_campaign=" . $element;
300
  $output .= "&utm_term=" . $page;
301
- echo $output;
 
 
 
 
302
  }
303
 
304
  /**
1
  <?php
2
+
3
+ use cnb\admin\api\CnbAdminCloud;
4
+ use cnb\admin\api\CnbAppRemote;
5
+
6
  require_once dirname( __FILE__ ) . '/notices.php';
7
  require_once dirname( __FILE__ ) . '/../admin/settings.php';
8
 
297
  }
298
  return array($active,$name);
299
  }
300
+ function cnb_utm_params($element, $page, $echo=true) {
301
  $output = "?utm_source=wp-plugin";
302
  $output .= "&utm_medium=referral";
303
  $output .= "&utm_campaign=" . $element;
304
  $output .= "&utm_term=" . $page;
305
+ if(!$echo) {
306
+ return $output;
307
+ } else {
308
+ echo $output;
309
+ }
310
  }
311
 
312
  /**