Event Tickets - Version 5.1.9

Version Description

Download this release

Release Info

Developer bordoni
Plugin Icon 128x128 Event Tickets
Version 5.1.9
Comparing to
See all releases

Code changes from version 5.1.8 to 5.1.9

Files changed (167) hide show
  1. common/lang/tribe-common.pot +25 -25
  2. common/src/Tribe/Main.php +9 -7
  3. common/src/Tribe/Service_Providers/Dialog.php +1 -1
  4. common/src/resources/css/common-full.min.css +1 -1
  5. common/src/resources/css/common-skeleton.min.css +1 -1
  6. common/src/resources/css/customizer-controls.min.css +1 -1
  7. common/src/resources/css/dialog.min.css +1 -1
  8. common/src/resources/css/tribe-common-admin.min.css +1 -1
  9. common/src/resources/css/variables-full.min.css +1 -0
  10. common/src/resources/css/variables-skeleton.min.css +1 -0
  11. common/vendor/autoload.php +1 -1
  12. common/vendor/autoload_52.php +1 -1
  13. common/vendor/composer/autoload_real.php +4 -4
  14. common/vendor/composer/autoload_real_52.php +3 -3
  15. common/vendor/composer/autoload_static.php +5 -5
  16. event-tickets.php +1 -1
  17. lang/event-tickets-cs_CZ.mo +0 -0
  18. lang/event-tickets-es_ES.mo +0 -0
  19. lang/event-tickets-fi.mo +0 -0
  20. lang/event-tickets-fr_CA.mo +0 -0
  21. lang/event-tickets-ja.mo +0 -0
  22. lang/event-tickets-nl_NL.mo +0 -0
  23. lang/event-tickets.pot +581 -485
  24. readme.txt +9 -2
  25. src/Tickets/Commerce.php +30 -0
  26. src/Tickets/Commerce/Assets.php +39 -2
  27. src/Tickets/Commerce/Attendee.php +471 -0
  28. src/Tickets/Commerce/Cart.php +660 -0
  29. src/Tickets/Commerce/Cart/Cart_Interface.php +120 -0
  30. src/Tickets/Commerce/Cart/Unmanaged_Cart.php +176 -0
  31. src/Tickets/Commerce/Checkout.php +162 -0
  32. src/Tickets/Commerce/Communication/Email.php +69 -0
  33. src/Tickets/Commerce/Currency.php +14 -0
  34. src/Tickets/Commerce/Editor/Metabox.php +157 -0
  35. src/Tickets/Commerce/Flag_Actions/Decrease_Stock.php +36 -0
  36. src/Tickets/Commerce/Flag_Actions/Flag_Action_Abstract.php +122 -0
  37. src/Tickets/Commerce/Flag_Actions/Flag_Action_Handler.php +77 -0
  38. src/Tickets/Commerce/Flag_Actions/Flag_Action_Interface.php +104 -0
  39. src/Tickets/Commerce/Flag_Actions/Generate_Attendees.php +36 -0
  40. src/Tickets/Commerce/Flag_Actions/Increase_Stock.php +36 -0
  41. src/Tickets/Commerce/Gateways/Abstract_Gateway.php +9 -6
  42. src/Tickets/Commerce/Gateways/Interface_Gateway.php +11 -2
  43. src/Tickets/Commerce/Gateways/Legacy/Gateway.php +0 -106
  44. src/Tickets/Commerce/Gateways/Legacy/Provider.php +0 -97
  45. src/Tickets/Commerce/Gateways/Legacy/Settings.php +0 -201
  46. src/Tickets/Commerce/Gateways/Manager.php +46 -3
  47. src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php +0 -316
  48. src/Tickets/Commerce/Gateways/PayPal/Ajax_Request_Handler.php +44 -0
  49. src/Tickets/Commerce/Gateways/PayPal/Assets.php +34 -6
  50. src/Tickets/Commerce/Gateways/PayPal/Buttons.php +61 -0
  51. src/Tickets/Commerce/Gateways/PayPal/Client.php +498 -0
  52. src/Tickets/Commerce/Gateways/PayPal/Connect_Client.php +0 -35
  53. src/Tickets/Commerce/Gateways/PayPal/Gateway.php +14 -19
  54. src/Tickets/Commerce/Gateways/PayPal/Hooks.php +105 -29
  55. src/Tickets/Commerce/Gateways/PayPal/Merchant.php +833 -0
  56. src/Tickets/Commerce/Gateways/PayPal/{SDK/Models/PayPalOrder.php → Models/PayPal_Order.php} +19 -21
  57. src/Tickets/Commerce/Gateways/PayPal/{SDK/Models/PayPalPayment.php → Models/PayPal_Payment.php} +14 -13
  58. src/Tickets/Commerce/Gateways/PayPal/Models/Webhook_Config.php +77 -0
  59. src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php +215 -0
  60. src/Tickets/Commerce/Gateways/PayPal/Provider.php +27 -31
  61. src/Tickets/Commerce/Gateways/PayPal/REST.php +8 -40
  62. src/Tickets/Commerce/Gateways/PayPal/REST/On_Boarding_Endpoint.php +433 -0
  63. src/Tickets/Commerce/Gateways/PayPal/REST/Order_Endpoint.php +278 -0
  64. src/{Tribe/REST/V1/Endpoints/Commerce/PayPal_Webhook.php → Tickets/Commerce/Gateways/PayPal/REST/Webhook_Endpoint.php} +34 -7
  65. src/Tickets/Commerce/Gateways/PayPal/Refresh_Token.php +101 -0
  66. src/Tickets/Commerce/Gateways/PayPal/Repositories/Authorization.php +88 -0
  67. src/Tickets/Commerce/Gateways/PayPal/Repositories/Order.php +83 -0
  68. src/Tickets/Commerce/Gateways/PayPal/{SDK/Repositories → Repositories}/Webhooks.php +89 -94
  69. src/Tickets/Commerce/Gateways/PayPal/SDK/Models/MerchantDetail.php +0 -216
  70. src/Tickets/Commerce/Gateways/PayPal/SDK/Models/WebhookConfig.php +0 -70
  71. src/Tickets/Commerce/Gateways/PayPal/SDK/PayPalClient.php +0 -92
  72. src/Tickets/Commerce/Gateways/PayPal/SDK/RefreshToken.php +0 -113
  73. src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/MerchantDetails.php +0 -213
  74. src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php +0 -246
  75. src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalOrder.php +0 -175
  76. src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Traits/HasMode.php +0 -36
  77. src/Tickets/Commerce/Gateways/PayPal/Settings.php +1 -237
  78. src/Tickets/Commerce/Gateways/PayPal/Signup.php +235 -0
  79. src/Tickets/Commerce/Gateways/PayPal/Status.php +128 -0
  80. src/Tickets/Commerce/Gateways/PayPal/Tickets_Form.php +221 -0
  81. src/Tickets/Commerce/Gateways/PayPal/{SDK/DataTransferObjects/PayPalWebhookHeaders.php → Webhooks/Headers.php} +28 -27
  82. src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{EventListener.php → Event_Listener.php} +2 -2
  83. src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{PaymentCaptureCompleted.php → Payment_Capture_Completed.php} +1 -1
  84. src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{PaymentCaptureDenied.php → Payment_Capture_Denied.php} +1 -1
  85. src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{PaymentCaptureRefunded.php → Payment_Capture_Refunded.php} +1 -1
  86. src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{PaymentCaptureReversed.php → Payment_Capture_Reversed.php} +1 -1
  87. src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{PaymentEventListener.php → Payment_Event_Listener.php} +36 -38
  88. src/Tickets/Commerce/Gateways/PayPal/Webhooks/WebhookChecker.php +0 -104
  89. src/Tickets/Commerce/Gateways/PayPal/Webhooks/Webhook_Checker.php +104 -0
  90. src/Tickets/Commerce/Gateways/PayPal/Webhooks/{WebhookRegister.php → Webhook_Register.php} +27 -27
  91. src/Tickets/Commerce/Gateways/PayPal/Webhooks/{WebhooksRoute.php → Webhooks_Route.php} +38 -41
  92. src/Tickets/Commerce/Gateways/PayPal/WhoDat.php +200 -0
  93. src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php +0 -487
  94. src/Tickets/Commerce/Hooks.php +315 -8
  95. src/Tickets/Commerce/Models/Attendee_Model.php +114 -0
  96. src/Tickets/Commerce/Models/Order_Model.php +103 -0
  97. src/Tickets/Commerce/Models/Ticket_Model.php +59 -0
  98. src/Tickets/Commerce/Module.php +615 -0
  99. src/Tickets/Commerce/Order.php +642 -0
  100. src/Tickets/Commerce/Provider.php +40 -4
  101. src/Tickets/Commerce/Reports/Attendance_Totals.php +237 -0
  102. src/Tickets/Commerce/Reports/Event.php +55 -0
  103. src/Tickets/Commerce/Reports/Ticket.php +40 -0
  104. src/Tickets/Commerce/Repositories/Attendees_Repository.php +134 -0
  105. src/Tickets/Commerce/Repositories/Order_Repository.php +486 -0
  106. src/Tickets/Commerce/Repositories/Tickets_Repository.php +124 -0
  107. src/Tickets/Commerce/Settings.php +108 -109
  108. src/Tickets/Commerce/Shortcodes/Checkout_Shortcode.php +84 -0
  109. src/Tickets/Commerce/Shortcodes/Shortcode_Abstract.php +151 -0
  110. src/Tickets/Commerce/Shortcodes/Success_Shortcode.php +75 -0
  111. src/Tickets/Commerce/Status/Action_Required.php +54 -0
  112. src/Tickets/Commerce/Status/Approved.php +54 -0
  113. src/Tickets/Commerce/Status/Completed.php +54 -0
  114. src/Tickets/Commerce/Status/Created.php +50 -0
  115. src/Tickets/Commerce/Status/Denied.php +49 -0
  116. src/Tickets/Commerce/Status/Not_Completed.php +50 -0
  117. src/Tickets/Commerce/Status/Pending.php +155 -0
  118. src/Tickets/Commerce/Status/Refunded.php +47 -0
  119. src/Tickets/Commerce/Status/Reversed.php +47 -0
  120. src/Tickets/Commerce/Status/Status_Abstract.php +184 -0
  121. src/Tickets/Commerce/Status/Status_Handler.php +347 -0
  122. src/Tickets/Commerce/Status/Status_Interface.php +103 -0
  123. src/Tickets/Commerce/Status/Undefined.php +49 -0
  124. src/Tickets/Commerce/Status/Voided.php +50 -0
  125. src/Tickets/Commerce/Success.php +125 -0
  126. src/Tickets/Commerce/Ticket.php +768 -0
  127. src/Tickets/Commerce/Tickets_View.php +157 -0
  128. src/Tickets/Commerce/Traits/Has_Mode.php +75 -0
  129. src/Tickets/Commerce/Utils/Price.php +69 -0
  130. src/Tickets/Event.php +39 -0
  131. src/Tickets/Hooks.php +5 -0
  132. src/Tribe/Admin/Ticket_Settings.php +3 -1
  133. src/Tribe/Assets.php +10 -5
  134. src/Tribe/Attendee_Repository.php +49 -31
  135. src/Tribe/Commerce/PayPal/Main.php +1 -1
  136. src/Tribe/Editor/Configuration.php +3 -0
  137. src/Tribe/Editor/Provider.php +15 -4
  138. src/Tribe/Event_Repository.php +6 -4
  139. src/Tribe/Main.php +12 -4
  140. src/Tribe/REST/V1/Endpoints/Base.php +1 -1
  141. src/Tribe/Repositories/Order.php +1 -1
  142. src/Tribe/Shortcodes/Tribe_Tickets_Checkout.php +19 -6
  143. src/Tribe/Status/Manager.php +5 -4
  144. src/Tribe/Tickets.php +2 -2
  145. src/Tribe/Tickets_View.php +0 -14
  146. src/admin-views/commerce/gateways/paypal/signup-link.php +27 -0
  147. src/admin-views/commerce/metabox/capacity.php +27 -0
  148. src/admin-views/commerce/metabox/sku.php +42 -0
  149. src/admin-views/editor/fieldset/settings-provider.php +3 -3
  150. src/admin-views/payments/tickets-commerce.php +88 -0
  151. src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php +47 -28
  152. src/functions/commerce/attendees.php +128 -0
  153. src/functions/commerce/orders.php +128 -0
  154. src/functions/commerce/orm.php +98 -0
  155. src/functions/commerce/tickets.php +128 -0
  156. src/modules/blocks/rsvp/move-delete/style.pcss +1 -1
  157. src/modules/blocks/ticket/container-content/advanced-options/move-delete/style.pcss +1 -1
  158. src/resources/css/app/rsvp/frontend.css +1 -1
  159. src/resources/css/app/rsvp/frontend.min.css +1 -1
  160. src/resources/css/attendees.css +1 -1
  161. src/resources/css/common-responsive.css +359 -9
  162. src/resources/css/common-responsive.min.css +1 -1
  163. src/resources/css/details.css +2 -2
  164. src/resources/css/details.min.css +1 -1
  165. src/resources/css/freemius.css +4 -4
  166. src/resources/css/rsvp-v1.css +77 -82
  167. src/resources/css/rsvp-v1.min.css +1 -1
common/lang/tribe-common.pot CHANGED
@@ -2,13 +2,13 @@
2
  # This file is distributed under the same license as the Tribe Common package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Tribe Common 4.14.2\n"
6
  "Report-Msgid-Bugs-To: http://m.tri.be/191x\n"
7
- "POT-Creation-Date: 2021-08-24 02:35:57+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
- "PO-Revision-Date: 2021-08-24 02:35\n"
12
  "Last-Translator: \n"
13
  "Language-Team: \n"
14
 
@@ -41,7 +41,7 @@ msgstr ""
41
  msgid "Press \"Cmd + C\" to copy"
42
  msgstr ""
43
 
44
- #. #-#-#-#-# tribe-common.pot (Tribe Common 4.14.2) #-#-#-#-#
45
  #. Author of the plugin/theme
46
  #: src/Tribe/Admin/Help_Page.php:79 src/Tribe/Customizer.php:664
47
  #: src/Tribe/Plugins_API.php:25 src/admin-views/help-calendar.php:97
@@ -2198,87 +2198,87 @@ msgstr ""
2198
  msgid "Full debug (all events)"
2199
  msgstr ""
2200
 
2201
- #: src/Tribe/Main.php:320
2202
  msgid ": activate to sort column ascending"
2203
  msgstr ""
2204
 
2205
- #: src/Tribe/Main.php:321
2206
  msgid ": activate to sort column descending"
2207
  msgstr ""
2208
 
2209
- #: src/Tribe/Main.php:323
2210
  msgid "Show _MENU_ entries"
2211
  msgstr ""
2212
 
2213
- #: src/Tribe/Main.php:324
2214
  msgid "No data available in table"
2215
  msgstr ""
2216
 
2217
- #: src/Tribe/Main.php:325
2218
  msgid "Showing _START_ to _END_ of _TOTAL_ entries"
2219
  msgstr ""
2220
 
2221
- #: src/Tribe/Main.php:326
2222
  msgid "Showing 0 to 0 of 0 entries"
2223
  msgstr ""
2224
 
2225
- #: src/Tribe/Main.php:327
2226
  msgid "(filtered from _MAX_ total entries)"
2227
  msgstr ""
2228
 
2229
- #: src/Tribe/Main.php:328
2230
  msgid "No matching records found"
2231
  msgstr ""
2232
 
2233
- #: src/Tribe/Main.php:329
2234
  msgid "Search:"
2235
  msgstr ""
2236
 
2237
- #: src/Tribe/Main.php:330
2238
  msgid "All items on this page were selected. "
2239
  msgstr ""
2240
 
2241
- #: src/Tribe/Main.php:331
2242
  msgid "Select all pages"
2243
  msgstr ""
2244
 
2245
- #: src/Tribe/Main.php:332
2246
  msgid "Clear Selection."
2247
  msgstr ""
2248
 
2249
- #: src/Tribe/Main.php:334
2250
  msgid "All"
2251
  msgstr ""
2252
 
2253
- #: src/Tribe/Main.php:335 src/Tribe/Main.php:352
2254
  msgid "Next"
2255
  msgstr ""
2256
 
2257
- #: src/Tribe/Main.php:336
2258
  msgid "Previous"
2259
  msgstr ""
2260
 
2261
- #: src/Tribe/Main.php:341
2262
  msgid ": Selected %d rows"
2263
  msgstr ""
2264
 
2265
- #: src/Tribe/Main.php:342
2266
  msgid ": Selected 1 row"
2267
  msgstr ""
2268
 
2269
- #: src/Tribe/Main.php:353
2270
  msgid "Prev"
2271
  msgstr ""
2272
 
2273
- #: src/Tribe/Main.php:354 src/Tribe/Main.php:356
2274
  msgid "Today"
2275
  msgstr ""
2276
 
2277
- #: src/Tribe/Main.php:355
2278
  msgid "Done"
2279
  msgstr ""
2280
 
2281
- #: src/Tribe/Main.php:357
2282
  msgid "Clear"
2283
  msgstr ""
2284
 
2
  # This file is distributed under the same license as the Tribe Common package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Tribe Common 4.14.4\n"
6
  "Report-Msgid-Bugs-To: http://m.tri.be/191x\n"
7
+ "POT-Creation-Date: 2021-08-31 16:17:54+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2021-08-31 16:17\n"
12
  "Last-Translator: \n"
13
  "Language-Team: \n"
14
 
41
  msgid "Press \"Cmd + C\" to copy"
42
  msgstr ""
43
 
44
+ #. #-#-#-#-# tribe-common.pot (Tribe Common 4.14.4) #-#-#-#-#
45
  #. Author of the plugin/theme
46
  #: src/Tribe/Admin/Help_Page.php:79 src/Tribe/Customizer.php:664
47
  #: src/Tribe/Plugins_API.php:25 src/admin-views/help-calendar.php:97
2198
  msgid "Full debug (all events)"
2199
  msgstr ""
2200
 
2201
+ #: src/Tribe/Main.php:322
2202
  msgid ": activate to sort column ascending"
2203
  msgstr ""
2204
 
2205
+ #: src/Tribe/Main.php:323
2206
  msgid ": activate to sort column descending"
2207
  msgstr ""
2208
 
2209
+ #: src/Tribe/Main.php:325
2210
  msgid "Show _MENU_ entries"
2211
  msgstr ""
2212
 
2213
+ #: src/Tribe/Main.php:326
2214
  msgid "No data available in table"
2215
  msgstr ""
2216
 
2217
+ #: src/Tribe/Main.php:327
2218
  msgid "Showing _START_ to _END_ of _TOTAL_ entries"
2219
  msgstr ""
2220
 
2221
+ #: src/Tribe/Main.php:328
2222
  msgid "Showing 0 to 0 of 0 entries"
2223
  msgstr ""
2224
 
2225
+ #: src/Tribe/Main.php:329
2226
  msgid "(filtered from _MAX_ total entries)"
2227
  msgstr ""
2228
 
2229
+ #: src/Tribe/Main.php:330
2230
  msgid "No matching records found"
2231
  msgstr ""
2232
 
2233
+ #: src/Tribe/Main.php:331
2234
  msgid "Search:"
2235
  msgstr ""
2236
 
2237
+ #: src/Tribe/Main.php:332
2238
  msgid "All items on this page were selected. "
2239
  msgstr ""
2240
 
2241
+ #: src/Tribe/Main.php:333
2242
  msgid "Select all pages"
2243
  msgstr ""
2244
 
2245
+ #: src/Tribe/Main.php:334
2246
  msgid "Clear Selection."
2247
  msgstr ""
2248
 
2249
+ #: src/Tribe/Main.php:336
2250
  msgid "All"
2251
  msgstr ""
2252
 
2253
+ #: src/Tribe/Main.php:337 src/Tribe/Main.php:354
2254
  msgid "Next"
2255
  msgstr ""
2256
 
2257
+ #: src/Tribe/Main.php:338
2258
  msgid "Previous"
2259
  msgstr ""
2260
 
2261
+ #: src/Tribe/Main.php:343
2262
  msgid ": Selected %d rows"
2263
  msgstr ""
2264
 
2265
+ #: src/Tribe/Main.php:344
2266
  msgid ": Selected 1 row"
2267
  msgstr ""
2268
 
2269
+ #: src/Tribe/Main.php:355
2270
  msgid "Prev"
2271
  msgstr ""
2272
 
2273
+ #: src/Tribe/Main.php:356 src/Tribe/Main.php:358
2274
  msgid "Today"
2275
  msgstr ""
2276
 
2277
+ #: src/Tribe/Main.php:357
2278
  msgid "Done"
2279
  msgstr ""
2280
 
2281
+ #: src/Tribe/Main.php:359
2282
  msgid "Clear"
2283
  msgstr ""
2284
 
common/src/Tribe/Main.php CHANGED
@@ -20,7 +20,7 @@ class Tribe__Main {
20
  const OPTIONNAME = 'tribe_events_calendar_options';
21
  const OPTIONNAMENETWORK = 'tribe_events_calendar_network_options';
22
 
23
- const VERSION = '4.14.3';
24
 
25
  const FEED_URL = 'https://theeventscalendar.com/feed/';
26
 
@@ -212,8 +212,10 @@ class Tribe__Main {
212
  tribe_assets(
213
  $this,
214
  [
215
- [ 'tribe-common-skeleton-style', 'common-skeleton.css' ],
216
- [ 'tribe-common-full-style', 'common-full.css', [ 'tribe-common-skeleton-style' ] ],
 
 
217
  ],
218
  null
219
  );
@@ -222,11 +224,11 @@ class Tribe__Main {
222
  tribe_assets(
223
  $this,
224
  [
225
- [ 'tribe-ui', 'tribe-ui.css' ],
226
  [ 'tribe-buttonset', 'buttonset.js', [ 'jquery', 'underscore' ] ],
227
- [ 'tribe-common-admin', 'tribe-common-admin.css', [ 'tribe-dependency-style', 'tribe-bumpdown-css', 'tribe-buttonset-style', 'tribe-select2-css' ] ],
228
  [ 'tribe-validation', 'validation.js', [ 'jquery', 'underscore', 'tribe-common', 'tribe-utils-camelcase', 'tribe-tooltipster' ] ],
229
- [ 'tribe-validation-style', 'validation.css', [ 'tribe-tooltipster-css' ] ],
230
  [ 'tribe-dependency', 'dependency.js', [ 'jquery', 'underscore', 'tribe-common' ] ],
231
  [ 'tribe-dependency-style', 'dependency.css', [ 'tribe-select2-css' ] ],
232
  [ 'tribe-pue-notices', 'pue-notices.js', [ 'jquery' ] ],
@@ -267,7 +269,7 @@ class Tribe__Main {
267
  $this,
268
  'tribe-customizer-controls',
269
  'customizer-controls.css',
270
- [],
271
  'customize_controls_print_styles'
272
  );
273
 
20
  const OPTIONNAME = 'tribe_events_calendar_options';
21
  const OPTIONNAMENETWORK = 'tribe_events_calendar_network_options';
22
 
23
+ const VERSION = '4.14.4';
24
 
25
  const FEED_URL = 'https://theeventscalendar.com/feed/';
26
 
212
  tribe_assets(
213
  $this,
214
  [
215
+ [ 'tec-variables-skeleton', 'variables-skeleton.css', ],
216
+ [ 'tribe-common-skeleton-style', 'common-skeleton.css', [ 'tec-variables-skeleton' ] ],
217
+ [ 'tec-variables-full', 'variables-full.css', ],
218
+ [ 'tribe-common-full-style', 'common-full.css', [ 'tec-variables-full', 'tribe-common-skeleton-style' ] ],
219
  ],
220
  null
221
  );
224
  tribe_assets(
225
  $this,
226
  [
227
+ [ 'tribe-ui', 'tribe-ui.css', [ 'tec-variables-full' ] ],
228
  [ 'tribe-buttonset', 'buttonset.js', [ 'jquery', 'underscore' ] ],
229
+ [ 'tribe-common-admin', 'tribe-common-admin.css', [ 'tec-variables-full', 'tribe-dependency-style', 'tribe-bumpdown-css', 'tribe-buttonset-style', 'tribe-select2-css' ] ],
230
  [ 'tribe-validation', 'validation.js', [ 'jquery', 'underscore', 'tribe-common', 'tribe-utils-camelcase', 'tribe-tooltipster' ] ],
231
+ [ 'tribe-validation-style', 'validation.css', [ 'tec-variables-full', 'tribe-tooltipster-css' ] ],
232
  [ 'tribe-dependency', 'dependency.js', [ 'jquery', 'underscore', 'tribe-common' ] ],
233
  [ 'tribe-dependency-style', 'dependency.css', [ 'tribe-select2-css' ] ],
234
  [ 'tribe-pue-notices', 'pue-notices.js', [ 'jquery' ] ],
269
  $this,
270
  'tribe-customizer-controls',
271
  'customizer-controls.css',
272
+ [ 'tec-variables-full' ],
273
  'customize_controls_print_styles'
274
  );
275
 
common/src/Tribe/Service_Providers/Dialog.php CHANGED
@@ -75,7 +75,7 @@ class Dialog extends \tad_DI52_ServiceProvider {
75
  $main,
76
  'tribe-dialog',
77
  'dialog.css',
78
- [],
79
  [],
80
  [ 'groups' => 'tribe-dialog' ]
81
  );
75
  $main,
76
  'tribe-dialog',
77
  'dialog.css',
78
+ [ 'tec-variables-full' ],
79
  [],
80
  [ 'groups' => 'tribe-dialog' ]
81
  );
common/src/resources/css/common-full.min.css CHANGED
@@ -1 +1 @@
1
- .tribe-common figure{line-height:0}.tribe-common figcaption{line-height:normal}.tribe-common a{background-color:transparent;-webkit-text-decoration-skip:objects}.tribe-common abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.tribe-common code,.tribe-common kbd,.tribe-common pre,.tribe-common samp{font-family:monospace;font-size:1em}.tribe-common b,.tribe-common strong{font-weight:inherit;font-weight:bolder}.tribe-common dfn{font-style:italic}.tribe-common mark{background-color:#ff0;color:#000}.tribe-common small{font-size:80%}.tribe-common sub,.tribe-common sup{font-size:75%;line-height:0}.tribe-common hr{border:0;height:0}.tribe-common button,.tribe-common input[type=button],.tribe-common input[type=email],.tribe-common input[type=password],.tribe-common input[type=reset],.tribe-common input[type=search],.tribe-common input[type=submit],.tribe-common input[type=text],.tribe-common input[type=url],.tribe-common textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none}.tribe-common button,.tribe-common input,.tribe-common optgroup,.tribe-common select,.tribe-common textarea{color:inherit;font:inherit;-webkit-font-smoothing:antialiased;line-height:normal}.tribe-common button,.tribe-common input,.tribe-common select,.tribe-common textarea{border-radius:0;outline:0}.tribe-common select:-moz-focusring{color:transparent;text-shadow:0 0 0 #000}.tribe-common optgroup{font-weight:700}.tribe-common h1,.tribe-common h2,.tribe-common h3,.tribe-common h4,.tribe-common h5,.tribe-common h6,.tribe-common p{font-weight:400;text-rendering:optimizeLegibility}#top .main_color .tribe-common button[disabled],#top.tribe-theme-enfold .tribe-common button[disabled]{opacity:1}.tribe-theme-twentynineteen .tribe-common h1:before,.tribe-theme-twentynineteen .tribe-common h2:before{content:none}.tribe-theme-twentynineteen .tribe-common button,.tribe-theme-twentynineteen .tribe-common input[type=button],.tribe-theme-twentynineteen .tribe-common input[type=reset],.tribe-theme-twentynineteen .tribe-common input[type=submit]{outline:none}.tribe-theme-twentynineteen .tribe-common td,.tribe-theme-twentynineteen .tribe-common th{word-break:normal}.tribe-theme-twentyseventeen .tribe-common h5{letter-spacing:normal;text-transform:none}.tribe-theme-twentyseventeen .tribe-common input[type=text]{border-radius:0}.tribe-theme-twentytwenty .tribe-common{background-color:var(--tec-color-background-events);letter-spacing:normal}.tribe-theme-twentytwenty .tribe-common input,.tribe-theme-twentytwenty .tribe-common textarea{letter-spacing:normal}.tribe-theme-twentytwenty .tribe-common *{word-break:normal}.tribe-theme-twentytwentyone.tribe-common .tribe-common .button:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common .wp-block-button .wp-block-button__link:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common .wp-block-file a.wp-block-file__button:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common .wp-block-search .wp-block-search__button:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common button:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common input[type=reset]:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common input[type=submit]:not(:hover):not(:active):not(.has-background){background-color:transparent;background-color:initial}:root{--tec-border-radius-default:4px;--tec-border-width-week-event:2px;--border-radius-default:var(--tec-border-radius-default);--border-width-week-event:var(--tec-border-width-week-event);--tec-box-shadow-default:0 2px 5px 0 var(--tec-color-box-shadow);--tec-box-shadow-tooltip:0 2px 12px 0 var(--tec-color-box-shadow);--tec-box-shadow-card:0 1px 6px 2px var(--tec-color-box-shadow);--tec-box-shadow-multiday:16px 6px 6px -2px var(--tec-color-box-shadow-secondary);--box-shadow-default:var(--tec-box-shadow-default);--box-shadow-tooltip:var(--tec-box-shadow-tooltip);--box-shadow-card:var(--tec-box-shadow-card);--box-shadow-multiday:var(--tec-box-shadow-multiday);--tec-form-color-background:var(--tec-color-background);--tec-form-color-border-default:var(--tec-color-text-primary);--tec-form-color-border-active:var(--tec-color-accent-secondary);--tec-form-color-border-secondary:var(--tec-color-border-tertiary);--tec-form-color-accent-primary:var(--tec-color-accent-primary);--tec-form-box-shadow-default:var(--tec-box-shadow-default);--form-color-background:var(--tec-form-color-background);--form-color-border-default:var(--tec-form-color-border-default);--form-color-border-active:var(--tec-form-color-border-active);--form-color-border-secondary:var(--tec-form-color-border-secondary);--form-color-accent-primary:var(--tec-form-color-accent-primary);--form-box-shadow-default:var(--tec-form-box-shadow-default);--tec-opacity-background:0.07;--tec-opacity-select-highlighted:0.3;--tec-opacity-icon-hover:0.8;--tec-opacity-icon-active:0.9;--tec-opacity-default:1;--opacity-background:var(--tec-opacity-background);--opacity-select-highlighted:var(--tec-opacity-select-highlighted);--opacity-icon-hover:var(--tec-opacity-icon-hover);--opacity-icon-active:var(--tec-opacity-icon-active);--opacity-default:var(--tec-opacity-default);--tec-transition:all 0.2s ease;--tec-transition-background-color:background-color 0.2s ease;--tec-transition-color-border-color:color 0.2s ease,border-color 0.2s ease;--tec-transition-transform:transform 0.2s ease;--tec-transition-border-color:border-color 0.2s ease;--tec-transition-color:color 0.2s ease;--tec-transition-opacity:opacity 0.2s ease;--transition:var(--tec-transition);--transition-background-color:var(--tec-transition-background-color);--transition-color-border-color:var(--tec-transition-color-border-color);--transition-transform:var(--tec-transition-transform);--transition-border-color:var(--tec-transition-border-color);--transition-color:var(--tec-transition-color);--transition-opacity:var(--tec-transition-opacity);--tec-font-family-sans-serif:"Helvetica Neue",Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;--tec-font-weight-regular:400;--tec-font-weight-bold:700;--tec-font-size-0:11px;--tec-font-size-1:12px;--tec-font-size-2:14px;--tec-font-size-3:16px;--tec-font-size-4:18px;--tec-font-size-5:20px;--tec-font-size-6:22px;--tec-font-size-7:24px;--tec-font-size-8:28px;--tec-font-size-9:32px;--tec-font-size-10:42px;--tec-line-height-0:1.38;--tec-line-height-1:1.42;--tec-line-height-2:1.5;--tec-line-height-3:1.62;--font-family-sans-serif:var(--tec-font-family-sans-serif);--font-family-base:var(--tec-font-family-sans-serif);--font-weight-regular:var(--tec-font-weight-regular);--font-weight-bold:var(--tec-font-weight-bold);--font-size-0:var(--tec-font-size-0);--font-size-1:var(--tec-font-size-1);--font-size-2:var(--tec-font-size-2);--font-size-3:var(--tec-font-size-3);--font-size-4:var(--tec-font-size-4);--font-size-5:var(--tec-font-size-5);--font-size-6:var(--tec-font-size-6);--font-size-7:var(--tec-font-size-7);--font-size-8:var(--tec-font-size-8);--font-size-9:var(--tec-font-size-9);--font-size-10:var(--tec-font-size-10);--line-height-0:var(--tec-line-height-0);--line-height-1:var(--tec-line-height-1);--line-height-2:var(--tec-line-height-2);--line-height-3:var(--tec-line-height-3)}.tribe-common .tribe-common-form-control-checkbox,.tribe-common .tribe-common-form-control-radio{line-height:0}.tribe-common .tribe-common-form-control-checkbox__label,.tribe-common .tribe-common-form-control-radio__label{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-size:14px;font-size:var(--tec-font-size-2);line-height:1.62;line-height:var(--tec-line-height-3);font-weight:400;font-weight:var(--tec-font-weight-regular)}.tribe-common .tribe-common-form-control-checkbox__label:hover,.tribe-common .tribe-common-form-control-radio__label:hover{opacity:.8;opacity:var(--tec-opacity-icon-hover)}.tribe-common .tribe-common-form-control-checkbox__input,.tribe-common .tribe-common-form-control-radio__input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--tec-color-background);background-color:var(--tec-form-color-background);border:1px solid var(--tec-color-text-primary);border:1px solid var(--tec-form-color-border-default);height:20px;position:relative;width:20px}.tribe-common .tribe-common-form-control-checkbox__input:active,.tribe-common .tribe-common-form-control-checkbox__input:focus,.tribe-common .tribe-common-form-control-checkbox__input:hover,.tribe-common .tribe-common-form-control-radio__input:active,.tribe-common .tribe-common-form-control-radio__input:focus,.tribe-common .tribe-common-form-control-radio__input:hover{border-color:var(--tec-color-accent-secondary);border-color:var(--tec-form-color-border-active);opacity:.8;opacity:var(--tec-opacity-icon-hover)}.tribe-common .tribe-common-form-control-checkbox__input:checked,.tribe-common .tribe-common-form-control-radio__input:checked{background-color:var(--tec-color-accent-secondary);background-color:var(--tec-form-color-border-active)}.tribe-common .tribe-common-form-control-checkbox__input{border-radius:4px}.tribe-common .tribe-common-form-control-checkbox__input:checked:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='9' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10.6.1L3.9 6.8 1.4 4.3c-.1-.1-.3-.1-.4 0l-.8.8c-.1.1-.1.3 0 .4l3.4 3.4c.2.1.4.1.5 0l7.7-7.7c.1-.1.1-.3 0-.4L11 .1c-.1-.1-.3-.1-.4 0z' fill='var(--tec-color-background)'/%3E%3C/svg%3E");background-repeat:no-repeat;background-size:contain;content:"";display:block;height:9px;left:50%;margin:0;position:absolute;top:50%;transform:translate(-50%,-50%);width:12px}.tribe-common .tribe-common-form-control-checkbox__input:focus+.tribe-common-form-control-checkbox__label,.tribe-common .tribe-common-form-control-checkbox__input:hover+.tribe-common-form-control-checkbox__label{opacity:.8;opacity:var(--tec-opacity-icon-hover)}.tribe-common .tribe-common-form-control-radio__input{border-radius:50%}.tribe-common .tribe-common-form-control-radio__input:checked:before{background-color:var(--tec-color-background);background-color:var(--tec-form-color-background);border-radius:50%;content:"";display:block;height:8px;left:50%;margin:0;position:absolute;top:50%;transform:translate(-50%,-50%);width:8px}.tribe-common .tribe-common-form-control-radio__input:focus+.tribe-common-form-control-radio__label,.tribe-common .tribe-common-form-control-radio__input:hover+.tribe-common-form-control-radio__label{opacity:.8;opacity:var(--tec-opacity-icon-hover)}#top .main_color .tribe-common .tribe-common-form-control-checkbox__label,#top .main_color .tribe-common .tribe-common-form-control-radio__label,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-checkbox__label,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-radio__label{font-size:14px;font-size:var(--tec-font-size-2);font-weight:400;font-weight:var(--tec-font-weight-regular)}.tribe-theme-twentytwenty .tribe-common .tribe-common-form-control-checkbox__input:checked:before{margin:0}.tribe-common .tribe-common-form-control-slider{line-height:0}.tribe-common .tribe-common-form-control-slider__input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:0}.tribe-common .tribe-common-form-control-slider__input::-webkit-slider-runnable-track{border:none;border-radius:5px;height:10px;margin:5px 0;padding:0;position:relative;transition:background-color .2s ease;transition:var(--tec-transition-background-color);background-color:var(--tec-color-accent-primary);background-color:var(--tec-form-color-accent-primary)}.tribe-common .tribe-common-form-control-slider__input::-moz-range-track{border:none;border-radius:5px;height:10px;margin:5px 0;padding:0;position:relative;transition:background-color .2s ease;transition:var(--tec-transition-background-color);background-color:var(--tec-color-accent-primary);background-color:var(--tec-form-color-accent-primary)}.tribe-common .tribe-common-form-control-slider__input::-ms-track{background-color:transparent;border-color:transparent;border-width:5px 0;color:transparent;height:10px}.tribe-common .tribe-common-form-control-slider__input::-ms-fill-lower,.tribe-common .tribe-common-form-control-slider__input::-ms-fill-upper{background-color:var(--tec-color-accent-primary);background-color:var(--tec-form-color-accent-primary);border-radius:10px}.tribe-common .tribe-common-form-control-slider__input::-webkit-slider-thumb{background-color:var(--tec-color-background);background-color:var(--tec-form-color-background);border:1px solid var(--tec-color-border-tertiary);border:1px solid var(--tec-form-color-border-secondary);border-radius:50%;box-shadow:0 2px 5px 0 var(--tec-color-box-shadow);box-shadow:var(--tec-form-box-shadow-default);height:20px;width:20px;margin-top:-5px;-webkit-appearance:none;appearance:none}.tribe-common .tribe-common-form-control-slider__input::-moz-range-thumb{background-color:var(--tec-color-background);background-color:var(--tec-form-color-background);border:1px solid var(--tec-color-border-tertiary);border:1px solid var(--tec-form-color-border-secondary);border-radius:50%;box-shadow:0 2px 5px 0 var(--tec-color-box-shadow);box-shadow:var(--tec-form-box-shadow-default);height:20px;width:20px;margin-top:-5px}.tribe-common .tribe-common-form-control-slider__input::-ms-thumb{background-color:var(--tec-color-background);background-color:var(--tec-form-color-background);border:1px solid var(--tec-color-border-tertiary);border:1px solid var(--tec-form-color-border-secondary);border-radius:50%;box-shadow:0 2px 5px 0 var(--tec-color-box-shadow);box-shadow:var(--tec-form-box-shadow-default);height:20px;width:20px;margin-top:-5px;box-shadow:none;margin-top:-1px}.tribe-common .tribe-common-form-control-slider__label{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);line-height:1.38;line-height:var(--tec-line-height-0);color:var(--tec-color-text-secondary)}#top .main_color .tribe-common .tribe-common-form-control-slider__label,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-slider__label,.tribe-common .tribe-common-form-control-slider__label{font-size:12px;font-size:var(--tec-font-size-1);font-weight:400;font-weight:var(--tec-font-weight-regular)}.tribe-common .tribe-common-form-control-text__input{font-size:16px;font-size:var(--tec-font-size-3);border:0;border-bottom:1px solid var(--tec-color-border-default)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-form-control-text__input,.tribe-common .tribe-common-form-control-text__input{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);line-height:1.62;line-height:var(--tec-line-height-3);font-weight:400;font-weight:var(--tec-font-weight-regular)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-form-control-text__input{font-size:14px;font-size:var(--tec-font-size-2);border:0}.tribe-common .tribe-common-form-control-text__input:-ms-input-placeholder{color:var(--tec-color-text-secondary);font-style:normal;opacity:1;opacity:var(--tec-opacity-default)}.tribe-common .tribe-common-form-control-text__input::placeholder{color:var(--tec-color-text-secondary);font-style:normal;opacity:1;opacity:var(--tec-opacity-default)}.tribe-common .tribe-common-form-control-text__input:focus{border-bottom-color:var(--tec-color-border-active);outline:0}.tribe-theme-twentyseventeen .tribe-common .tribe-common-form-control-text__input{color:var(--tec-color-text-primary)}.tribe-theme-twentytwenty .tribe-common .tribe-common-form-control-text__input{line-height:inherit}#top .main_color .tribe-common .tribe-common-form-control-text__input,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-text__input{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-size:16px;font-size:var(--tec-font-size-3);line-height:1.62;line-height:var(--tec-line-height-3);font-weight:400;font-weight:var(--tec-font-weight-regular);background:var(--tec-color-background);border:0;border-bottom:1px solid var(--tec-color-border-default)}#top .main_color .tribe-common .tribe-common-form-control-text__input:focus,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-text__input:focus{border-bottom-color:var(--tec-color-border-active);box-shadow:none}#top .main_color .tribe-common.tribe-common--breakpoint-medium .tribe-common-form-control-text__input,#top.tribe-theme-enfold .tribe-common.tribe-common--breakpoint-medium .tribe-common-form-control-text__input{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-size:14px;font-size:var(--tec-font-size-2);line-height:1.62;line-height:var(--tec-line-height-3);font-weight:400;font-weight:var(--tec-font-weight-regular);border:0}.tribe-common .tribe-common-form-control-toggle{line-height:0;position:relative}.tribe-common .tribe-common-form-control-toggle__input{border:none;border-radius:5px;height:10px;margin:5px 0;padding:0;position:relative;transition:background-color .2s ease;transition:var(--tec-transition-background-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--tec-color-border-tertiary);background-color:var(--tec-form-color-border-secondary);width:40px}.tribe-common .tribe-common-form-control-toggle__input::-ms-check{display:none}.tribe-common .tribe-common-form-control-toggle__input+label:before{background-color:var(--tec-color-background);background-color:var(--tec-form-color-background);border:1px solid var(--tec-color-border-tertiary);border:1px solid var(--tec-form-color-border-secondary);border-radius:50%;box-shadow:0 2px 5px 0 var(--tec-color-box-shadow);box-shadow:var(--tec-form-box-shadow-default);height:20px;width:20px;content:"";left:0;position:absolute;top:0;transition:transform .2s ease;transition:var(--tec-transition-transform)}.tribe-common .tribe-common-form-control-toggle__input:checked{background-color:var(--tec-color-accent-primary);background-color:var(--tec-form-color-accent-primary)}.tribe-common .tribe-common-form-control-toggle__input:checked+label:before{transform:translateX(20px)}.tribe-common .tribe-common-form-control-toggle__label{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);line-height:1.38;line-height:var(--tec-line-height-0);color:var(--tec-color-text-secondary)}#top .main_color .tribe-common .tribe-common-form-control-toggle__label,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-toggle__label,.tribe-common .tribe-common-form-control-toggle__label{font-size:12px;font-size:var(--tec-font-size-1);font-weight:400;font-weight:var(--tec-font-weight-regular)}.tribe-theme-twentytwenty .tribe-common .tribe-common-form-control-toggle__input{top:0}.tribe-theme-twentytwenty .tribe-common .tribe-common-form-control-toggle__input:checked:before{content:none}.tribe-theme-twentytwentyone .tribe-common .tribe-common-form-control-toggle__input:after{display:none}.tribe-common a,.tribe-common a:active,.tribe-common a:focus,.tribe-common a:hover,.tribe-common a:visited{color:var(--tec-color-text-primary);outline:0;text-decoration:none}.site-footer .widget-area .tribe-common a,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common a,.tribe-theme-twentyseventeen .tribe-common a{box-shadow:none}.site-footer .widget-area .tribe-common a:focus,.site-footer .widget-area .tribe-common a:hover,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common a:focus,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common a:hover,.tribe-theme-twentyseventeen .tribe-common a:focus,.tribe-theme-twentyseventeen .tribe-common a:hover{box-shadow:none;color:var(--tec-color-text-primary)}.tribe-theme-twentynineteen .entry .tribe-common a,.tribe-theme-twentynineteen .tribe-common a,.tribe-theme-twentytwentyone .entry .tribe-common a,.tribe-theme-twentytwentyone .tribe-common a{text-decoration:none}.main_color .sidebar .tribe-common a,.main_color .sidebar .tribe-common a:active,.main_color .sidebar .tribe-common a:focus,.main_color .sidebar .tribe-common a:hover,.main_color .sidebar .tribe-common a:visited,.tribe-theme-enfold .tribe-common a,.tribe-theme-enfold .tribe-common a:active,.tribe-theme-enfold .tribe-common a:focus,.tribe-theme-enfold .tribe-common a:hover,.tribe-theme-enfold .tribe-common a:visited{color:var(--tec-color-text-primary)}.tribe-common .tribe-common-anchor{border-bottom:2px solid transparent;transition:border-color .2s ease;transition:var(--tec-transition-border-color)}.tribe-common .tribe-common-anchor:active,.tribe-common .tribe-common-anchor:focus,.tribe-common .tribe-common-anchor:hover{border-bottom:2px solid currentColor}.tribe-common .tribe-common-anchor-alt{border-bottom:2px solid var(--tec-color-link-accent);color:var(--tec-color-link-primary);transition:color .2s ease;transition:var(--tec-transition-color)}.tribe-common .tribe-common-anchor-alt:active,.tribe-common .tribe-common-anchor-alt:focus,.tribe-common .tribe-common-anchor-alt:hover{border-bottom:2px solid currentColor;color:var(--tec-color-link-accent)}.tribe-common .tribe-common-anchor-thin{border-bottom:1px solid transparent;transition:border-color .2s ease;transition:var(--tec-transition-border-color)}.tribe-common .tribe-common-anchor-thin:active,.tribe-common .tribe-common-anchor-thin:focus,.tribe-common .tribe-common-anchor-thin:hover{border-bottom:1px solid var(--tec-color-link-primary)}.tribe-common .tribe-common-anchor-thin-alt{border-bottom:1px solid var(--tec-color-link-accent);color:var(--tec-color-link-primary);transition:color .2s ease;transition:var(--tec-transition-color)}.tribe-common .tribe-common-anchor-thin-alt:active,.tribe-common .tribe-common-anchor-thin-alt:focus,.tribe-common .tribe-common-anchor-thin-alt:hover{border-bottom:1px solid currentColor;color:var(--tec-color-link-accent)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-anchor-alt:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-anchor-alt:hover,.tribe-theme-twentyseventeen .tribe-common .tribe-common-anchor-thin-alt:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-anchor-thin-alt:hover{color:var(--tec-color-accent-primary)}.site-footer .widget-area .tribe-common .tribe-common-anchor,.site-footer .widget-area .tribe-common .tribe-common-anchor-thin,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common .tribe-common-anchor,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common .tribe-common-anchor-thin{transition:border-color .2s ease;transition:var(--tec-transition-border-color)}.site-footer .widget-area .tribe-common .tribe-common-anchor-alt,.site-footer .widget-area .tribe-common .tribe-common-anchor-thin-alt,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common .tribe-common-anchor-alt,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common .tribe-common-anchor-thin-alt{transition:color .2s ease;transition:var(--tec-transition-color)}.tribe-common .tribe-common-b1{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-size:14px;font-size:var(--tec-font-size-2);font-weight:400;font-weight:var(--tec-font-weight-regular);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b1{font-size:16px;font-size:var(--tec-font-size-3);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-common .tribe-common-b1--bold{font-weight:700;font-weight:var(--tec-font-weight-bold)}.tribe-common .tribe-common-b2{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-size:12px;font-size:var(--tec-font-size-1);font-weight:400;font-weight:var(--tec-font-weight-regular);line-height:1.38;line-height:var(--tec-line-height-0)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b2{font-size:14px;font-size:var(--tec-font-size-2);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-common .tribe-common-b2--bold{font-weight:700;font-weight:var(--tec-font-weight-bold)}.tribe-common .tribe-common-b3{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-size:11px;font-size:var(--tec-font-size-0);font-weight:400;font-weight:var(--tec-font-weight-regular);line-height:1.5;line-height:var(--tec-line-height-2)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b3{font-size:12px;font-size:var(--tec-font-size-1);line-height:1.38;line-height:var(--tec-line-height-0)}.tribe-common .tribe-common-b3--bold{font-weight:700;font-weight:var(--tec-font-weight-bold)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b1--min-medium{font-size:16px;font-size:var(--tec-font-size-3);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b2--min-medium{font-size:14px;font-size:var(--tec-font-size-2);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b3--min-medium,.tribe-common .tribe-common-cta{font-size:12px;font-size:var(--tec-font-size-1);line-height:1.38;line-height:var(--tec-line-height-0)}.tribe-common .tribe-common-cta{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:400;font-weight:var(--tec-font-weight-regular);font-weight:700;font-weight:var(--tec-font-weight-bold);border-bottom:2px solid transparent;transition:border-color .2s ease;transition:var(--tec-transition-border-color)}.tribe-common .tribe-common-cta:active,.tribe-common .tribe-common-cta:focus,.tribe-common .tribe-common-cta:hover{border-bottom:2px solid currentColor}.tribe-common .tribe-common-cta--alt{border-bottom:2px solid var(--tec-color-link-accent);color:var(--tec-color-link-primary);transition:color .2s ease;transition:var(--tec-transition-color)}.tribe-common .tribe-common-cta--alt:active,.tribe-common .tribe-common-cta--alt:focus,.tribe-common .tribe-common-cta--alt:hover{border-bottom:2px solid currentColor;color:var(--tec-color-link-accent)}.tribe-common .tribe-common-cta--thin{border-bottom:1px solid transparent;transition:border-color .2s ease;transition:var(--tec-transition-border-color)}.tribe-common .tribe-common-cta--thin:active,.tribe-common .tribe-common-cta--thin:focus,.tribe-common .tribe-common-cta--thin:hover{border-bottom:1px solid var(--tec-color-link-primary)}.tribe-common .tribe-common-cta--thin-alt{border-bottom:1px solid var(--tec-color-link-accent);color:var(--tec-color-link-primary);transition:color .2s ease;transition:var(--tec-transition-color)}.tribe-common .tribe-common-cta--thin-alt:active,.tribe-common .tribe-common-cta--thin-alt:focus,.tribe-common .tribe-common-cta--thin-alt:hover{border-bottom:1px solid currentColor;color:var(--tec-color-link-accent)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-cta--alt:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-cta--alt:hover,.tribe-theme-twentyseventeen .tribe-common .tribe-common-cta--thin-alt:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-cta--thin-alt:hover{color:var(--tec-color-accent-primary)}.tribe-common .tribe-common-h1{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold);font-size:28px;font-size:var(--tec-font-size-8);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h1{font-size:42px;font-size:var(--tec-font-size-10);line-height:1.38;line-height:var(--tec-line-height-0)}.tribe-common .tribe-common-h2{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold);font-size:24px;font-size:var(--tec-font-size-7);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h2{font-size:32px;font-size:var(--tec-font-size-9);line-height:1.38;line-height:var(--tec-line-height-0)}.tribe-common .tribe-common-h3{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold);font-size:22px;font-size:var(--tec-font-size-6);line-height:1.5;line-height:var(--tec-line-height-2)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h3{font-size:28px;font-size:var(--tec-font-size-8);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-common .tribe-common-h4{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold);font-size:20px;font-size:var(--tec-font-size-5);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h4{font-size:24px;font-size:var(--tec-font-size-7);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-common .tribe-common-h5{font-size:18px;font-size:var(--tec-font-size-4)}.tribe-common .tribe-common-h5,.tribe-common .tribe-common-h6{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold);line-height:1.5;line-height:var(--tec-line-height-2)}.tribe-common .tribe-common-h6{font-size:16px;font-size:var(--tec-font-size-3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h6{font-size:16px;font-size:var(--tec-font-size-3);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-common .tribe-common-h7{font-size:14px;font-size:var(--tec-font-size-2);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-common .tribe-common-h7,.tribe-common .tribe-common-h8{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold)}.tribe-common .tribe-common-h8{font-size:12px;font-size:var(--tec-font-size-1);line-height:1.38;line-height:var(--tec-line-height-0)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h3--min-medium{font-size:28px;font-size:var(--tec-font-size-8);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h4--min-medium{font-size:24px;font-size:var(--tec-font-size-7);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h5--min-medium{font-size:18px;font-size:var(--tec-font-size-4);line-height:1.5;line-height:var(--tec-line-height-2)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h6--min-medium{font-size:16px;font-size:var(--tec-font-size-3);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h7--min-medium{font-size:14px;font-size:var(--tec-font-size-2);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-common .tribe-common-h--alt{font-weight:400;font-weight:var(--tec-font-weight-regular)}.tribe-theme-avada #main .tribe-common .tribe-common-h1{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold);font-size:28px;font-size:var(--tec-font-size-8);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h1{font-size:42px;font-size:var(--tec-font-size-10);line-height:1.38;line-height:var(--tec-line-height-0)}.tribe-theme-avada #main .tribe-common .tribe-common-h2{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold);font-size:24px;font-size:var(--tec-font-size-7);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h2{font-size:32px;font-size:var(--tec-font-size-9);line-height:1.38;line-height:var(--tec-line-height-0)}.tribe-theme-avada #main .tribe-common .tribe-common-h3{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold);font-size:22px;font-size:var(--tec-font-size-6);line-height:1.5;line-height:var(--tec-line-height-2)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h3{font-size:28px;font-size:var(--tec-font-size-8);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common .tribe-common-h4{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold);font-size:20px;font-size:var(--tec-font-size-5);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h4{font-size:24px;font-size:var(--tec-font-size-7);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common .tribe-common-h5{font-size:18px;font-size:var(--tec-font-size-4)}.tribe-theme-avada #main .tribe-common .tribe-common-h5,.tribe-theme-avada #main .tribe-common .tribe-common-h6{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold);line-height:1.5;line-height:var(--tec-line-height-2)}.tribe-theme-avada #main .tribe-common .tribe-common-h6{font-size:16px;font-size:var(--tec-font-size-3)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h6{font-size:16px;font-size:var(--tec-font-size-3);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-theme-avada #main .tribe-common .tribe-common-h7{font-size:14px;font-size:var(--tec-font-size-2);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-theme-avada #main .tribe-common .tribe-common-h7,.tribe-theme-avada #main .tribe-common .tribe-common-h8{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-weight:700;font-weight:var(--tec-font-weight-bold)}.tribe-theme-avada #main .tribe-common .tribe-common-h8{font-size:12px;font-size:var(--tec-font-size-1);line-height:1.38;line-height:var(--tec-line-height-0)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h3--min-medium{font-size:28px;font-size:var(--tec-font-size-8);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h4--min-medium{font-size:24px;font-size:var(--tec-font-size-7);line-height:1.42;line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h5--min-medium{font-size:18px;font-size:var(--tec-font-size-4);line-height:1.5;line-height:var(--tec-line-height-2)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h6--min-medium{font-size:16px;font-size:var(--tec-font-size-3);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h7--min-medium{font-size:14px;font-size:var(--tec-font-size-2);line-height:1.62;line-height:var(--tec-line-height-3)}.tribe-theme-avada #main .tribe-common .tribe-common-h--alt{font-weight:400;font-weight:var(--tec-font-weight-regular)}.tribe-common button{border:none}.tribe-common button,.tribe-common button:focus,.tribe-common button:hover,.tribe-theme-twentyseventeen .tribe-common button:focus,.tribe-theme-twentyseventeen .tribe-common button:hover{background-color:transparent}.tribe-theme-twentytwenty .tribe-common button{background-color:transparent;text-transform:inherit}.tribe-theme-twentytwenty .tribe-common button:focus,.tribe-theme-twentytwenty .tribe-common button:hover{text-decoration:none}.tribe-theme-twentytwentyone .tribe-common button:not(:hover):not(:active){background-color:inherit;color:inherit}.tribe-theme-enfold .tribe-common th{letter-spacing:0;text-transform:none}.tribe-common .tribe-common-c-btn-border,.tribe-common a.tribe-common-c-btn-border{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-size:14px;font-size:var(--tec-font-size-2);line-height:1.62;line-height:var(--tec-line-height-3);font-weight:400;font-weight:var(--tec-font-weight-regular);font-weight:700;font-weight:var(--tec-font-weight-bold);border:0;cursor:pointer;display:inline-block;height:auto;padding:0;text-decoration:none;width:auto;background-color:var(--tec-color-background);border:1px solid var(--tec-color-accent-primary);border-radius:4px;border-radius:var(--tec-border-radius-default);text-align:center;transition:all .2s ease;transition:var(--tec-transition);color:var(--tec-color-button-primary);padding:11px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn-border,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn-border{width:auto}.tribe-common .tribe-common-c-btn-border:focus,.tribe-common .tribe-common-c-btn-border:hover,.tribe-common a.tribe-common-c-btn-border:focus,.tribe-common a.tribe-common-c-btn-border:hover{background-color:var(--tec-color-accent-primary);color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn-border:active,.tribe-common a.tribe-common-c-btn-border:active{opacity:.9}.tribe-common .tribe-common-c-btn-border--secondary,.tribe-common a.tribe-common-c-btn-border--secondary{border-color:var(--tec-color-button-secondary);color:var(--tec-color-button-secondary)}.tribe-common .tribe-common-c-btn-border--secondary:focus,.tribe-common .tribe-common-c-btn-border--secondary:hover,.tribe-common a.tribe-common-c-btn-border--secondary:focus,.tribe-common a.tribe-common-c-btn-border--secondary:hover{background-color:var(--tec-color-button-secondary)}.tribe-common .tribe-common-c-btn-border--secondary:active,.tribe-common a.tribe-common-c-btn-border--secondary:active{opacity:.9}.tribe-common .tribe-common-c-btn-border--alt,.tribe-common a.tribe-common-c-btn-border--alt{border-color:var(--tec-color-border-secondary);color:var(--tec-color-text-primary);font-weight:400;font-weight:var(--tec-font-weight-regular)}.tribe-common .tribe-common-c-btn-border--alt:focus,.tribe-common .tribe-common-c-btn-border--alt:hover,.tribe-common a.tribe-common-c-btn-border--alt:focus,.tribe-common a.tribe-common-c-btn-border--alt:hover{background-color:var(--tec-color-background);border-color:var(--tec-color-border-active);color:var(--tec-color-text-primary)}.tribe-common .tribe-common-c-btn-border--alt:active,.tribe-common a.tribe-common-c-btn-border--alt:active{opacity:.9}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border:hover{background-color:var(--tec-color-button-primary)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border--secondary:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border--secondary:hover{background-color:var(--tec-color-button-secondary)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border--alt:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border--alt:hover{background-color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn-border-small,.tribe-common a.tribe-common-c-btn-border-small{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-size:12px;font-size:var(--tec-font-size-1);line-height:1.38;line-height:var(--tec-line-height-0);font-weight:400;font-weight:var(--tec-font-weight-regular);border:0;cursor:pointer;display:inline-block;height:auto;padding:0;text-decoration:none;width:auto;background-color:var(--tec-color-background);border:1px solid var(--tec-color-border-default);border-radius:4px;border-radius:var(--tec-border-radius-default);text-align:center;transition:color .2s ease,border-color .2s ease;transition:var(--tec-transition-color-border-color)}.tribe-common .tribe-common-c-btn-border-small:focus,.tribe-common .tribe-common-c-btn-border-small:hover,.tribe-common a.tribe-common-c-btn-border-small:focus,.tribe-common a.tribe-common-c-btn-border-small:hover{background-color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn-border-small:active,.tribe-common a.tribe-common-c-btn-border-small:active{border-color:var(--tec-color-border-active)}.tribe-common .tribe-common-c-btn-border-small,.tribe-common a.tribe-common-c-btn-border-small{color:var(--tec-color-text-secondary);padding:14px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn-border-small,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn-border-small{padding:6px 15px;width:auto}.tribe-common .tribe-common-c-btn-border-small:active,.tribe-common .tribe-common-c-btn-border-small:focus,.tribe-common .tribe-common-c-btn-border-small:hover,.tribe-common a.tribe-common-c-btn-border-small:active,.tribe-common a.tribe-common-c-btn-border-small:focus,.tribe-common a.tribe-common-c-btn-border-small:hover{color:var(--tec-color-text-primary)}.tribe-common .tribe-common-c-btn-border-small:disabled,.tribe-common a.tribe-common-c-btn-border-small:disabled{color:var(--tec-color-text-disabled)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border-small:hover{background-color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn-icon{border:0;cursor:pointer;display:inline-block;height:auto;padding:0;text-decoration:none;width:auto}.tribe-common .tribe-common-c-btn-icon--caret-left:active .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-left:focus .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-left:hover .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right:active .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right:focus .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right:hover .tribe-common-c-btn-icon__icon-svg path{fill:var(--tec-color-icon-primary)}.tribe-common .tribe-common-c-btn-icon--caret-left:disabled .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right:disabled .tribe-common-c-btn-icon__icon-svg path{fill:var(--tec-color-icon-disabled)}.tribe-common .tribe-common-c-btn-icon--caret-left .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right .tribe-common-c-btn-icon__icon-svg path{fill:var(--tec-color-icon-secondary)}.tribe-common .tribe-common-c-btn-icon--border{align-items:center;background-color:var(--tec-color-background);border:1px solid var(--tec-color-border-default);display:inline-flex;height:56px;justify-content:center;transition:none;width:56px}.tribe-common .tribe-common-c-btn-icon--border:focus,.tribe-common .tribe-common-c-btn-icon--border:hover{background-color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn-icon--border:active{border-color:var(--tec-color-border-active)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-icon--border:hover{background-color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn,.tribe-common a.tribe-common-c-btn{color:var(--tec-color-text-primary);font-family:Helvetica Neue,Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;font-family:var(--tec-font-family-sans-serif);font-size:14px;font-size:var(--tec-font-size-2);line-height:1.62;line-height:var(--tec-line-height-3);font-weight:400;font-weight:var(--tec-font-weight-regular);font-weight:700;font-weight:var(--tec-font-weight-bold);border:0;cursor:pointer;display:inline-block;height:auto;padding:0;text-decoration:none;width:auto;border-radius:4px;border-radius:var(--tec-border-radius-default);color:var(--tec-color-background);text-align:center;transition:background-color .2s ease;transition:var(--tec-transition-background-color);background-color:var(--tec-color-button-primary);padding:11px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn{width:auto}.tribe-common .tribe-common-c-btn:focus,.tribe-common .tribe-common-c-btn:hover,.tribe-common a.tribe-common-c-btn:focus,.tribe-common a.tribe-common-c-btn:hover{background-color:var(--tec-color-button-primary-hover)}.tribe-common .tribe-common-c-btn:active,.tribe-common a.tribe-common-c-btn:active{background-color:var(--tec-color-button-primary-active)}.tribe-common .tribe-common-c-btn:disabled,.tribe-common a.tribe-common-c-btn:disabled{background-color:var(--tec-color-button-primary-background)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn:hover{background-color:var(--tec-color-button-primary-hover);color:var(--tec-color-background)}.tribe-theme-twentytwenty .tribe-common .tribe-common-c-btn{background-color:var(--tec-color-button-primary)}.tribe-theme-twentytwenty .tribe-common .tribe-common-c-btn:focus,.tribe-theme-twentytwenty .tribe-common .tribe-common-c-btn:hover{background-color:var(--tec-color-button-primary-hover);color:var(--tec-color-background)}.tribe-theme-twentytwentyone .tribe-common .tribe-common-c-btn{outline:none}.tribe-theme-twentytwentyone .tribe-common .tribe-common-c-btn:not(:hover):not(:active){background-color:var(--tec-color-button-primary);color:var(--tec-color-background)}.tribe-common .tribe-common-c-loader__dot circle{animation-direction:normal;animation-duration:2.24s;animation-iteration-count:infinite;animation-name:a;fill:currentColor;opacity:.07;opacity:var(--tec-opacity-background)}.tribe-common .tribe-common-c-loader__dot--first circle{animation-delay:.45s}.tribe-common .tribe-common-c-loader__dot--second circle{animation-delay:1.05s}.tribe-common .tribe-common-c-loader__dot--third circle{animation-delay:1.35s}@keyframes a{50%{opacity:1;opacity:var(--tec-opacity-default)}}.tribe-common .tribe-common-c-svgicon{color:var(--tec-color-accent-primary)}.tribe-common .tribe-common-c-svgicon--featured path{fill:currentColor}.tribe-common .tribe-common-c-svgicon--recurring path{fill:var(--tec-color-icon-active);stroke:var(--tec-color-icon-active)}.tribe-common .tribe-common-c-svgicon--close-alt path,.tribe-common .tribe-common-c-svgicon--close path{stroke:var(--tec-color-icon-secondary)}.tribe-common .tribe-common-c-svgicon--messages-not-found path{stroke:var(--tec-color-icon-active)}.tribe-common .tribe-common-c-svgicon--messages-not-found .tribe-common-c-svgicon__svg-stroke{stroke:currentColor}.tribe-common .tribe-common-c-svgicon__svg-fill{fill:var(--tec-color-icon-active)}.tribe-common .tribe-common-c-svgicon__svg-stroke{stroke:var(--tec-color-icon-active)}
1
+ .tribe-common figure{line-height:0}.tribe-common figcaption{line-height:normal}.tribe-common a{background-color:transparent;-webkit-text-decoration-skip:objects}.tribe-common abbr[title]{border-bottom:none;text-decoration:underline;-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.tribe-common code,.tribe-common kbd,.tribe-common pre,.tribe-common samp{font-family:monospace;font-size:1em}.tribe-common b,.tribe-common strong{font-weight:inherit;font-weight:bolder}.tribe-common dfn{font-style:italic}.tribe-common mark{background-color:#ff0;color:#000}.tribe-common small{font-size:80%}.tribe-common sub,.tribe-common sup{font-size:75%;line-height:0}.tribe-common hr{border:0;height:0}.tribe-common button,.tribe-common input[type=button],.tribe-common input[type=email],.tribe-common input[type=password],.tribe-common input[type=reset],.tribe-common input[type=search],.tribe-common input[type=submit],.tribe-common input[type=text],.tribe-common input[type=url],.tribe-common textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none}.tribe-common button,.tribe-common input,.tribe-common optgroup,.tribe-common select,.tribe-common textarea{color:inherit;font:inherit;-webkit-font-smoothing:antialiased;line-height:normal}.tribe-common button,.tribe-common input,.tribe-common select,.tribe-common textarea{border-radius:0;outline:0}.tribe-common select:-moz-focusring{color:transparent;text-shadow:0 0 0 #000}.tribe-common optgroup{font-weight:700}.tribe-common h1,.tribe-common h2,.tribe-common h3,.tribe-common h4,.tribe-common h5,.tribe-common h6,.tribe-common p{font-weight:400;text-rendering:optimizeLegibility}#top .main_color .tribe-common button[disabled],#top.tribe-theme-enfold .tribe-common button[disabled]{opacity:1}.tribe-theme-twentynineteen .tribe-common h1:before,.tribe-theme-twentynineteen .tribe-common h2:before{content:none}.tribe-theme-twentynineteen .tribe-common button,.tribe-theme-twentynineteen .tribe-common input[type=button],.tribe-theme-twentynineteen .tribe-common input[type=reset],.tribe-theme-twentynineteen .tribe-common input[type=submit]{outline:none}.tribe-theme-twentynineteen .tribe-common td,.tribe-theme-twentynineteen .tribe-common th{word-break:normal}.tribe-theme-twentyseventeen .tribe-common h5{letter-spacing:normal;text-transform:none}.tribe-theme-twentyseventeen .tribe-common input[type=text]{border-radius:0}.tribe-theme-twentytwenty .tribe-common{background-color:var(--tec-color-background-events);letter-spacing:normal}.tribe-theme-twentytwenty .tribe-common input,.tribe-theme-twentytwenty .tribe-common textarea{letter-spacing:normal}.tribe-theme-twentytwenty .tribe-common *{word-break:normal}.tribe-theme-twentytwentyone.tribe-common .tribe-common .button:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common .wp-block-button .wp-block-button__link:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common .wp-block-file a.wp-block-file__button:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common .wp-block-search .wp-block-search__button:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common button:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common input[type=reset]:not(:hover):not(:active):not(.has-background),.tribe-theme-twentytwentyone.tribe-common .tribe-common input[type=submit]:not(:hover):not(:active):not(.has-background){background-color:transparent;background-color:initial}.tribe-common .tribe-common-form-control-checkbox,.tribe-common .tribe-common-form-control-radio{line-height:0}.tribe-common .tribe-common-form-control-checkbox__label,.tribe-common .tribe-common-form-control-radio__label{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3);font-weight:var(--tec-font-weight-regular)}.tribe-common .tribe-common-form-control-checkbox__label:hover,.tribe-common .tribe-common-form-control-radio__label:hover{opacity:var(--tec-opacity-icon-hover)}.tribe-common .tribe-common-form-control-checkbox__input,.tribe-common .tribe-common-form-control-radio__input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--tec-form-color-background);border:1px solid var(--tec-form-color-border-default);height:20px;position:relative;width:20px}.tribe-common .tribe-common-form-control-checkbox__input:active,.tribe-common .tribe-common-form-control-checkbox__input:focus,.tribe-common .tribe-common-form-control-checkbox__input:hover,.tribe-common .tribe-common-form-control-radio__input:active,.tribe-common .tribe-common-form-control-radio__input:focus,.tribe-common .tribe-common-form-control-radio__input:hover{border-color:var(--tec-form-color-border-active);opacity:var(--tec-opacity-icon-hover)}.tribe-common .tribe-common-form-control-checkbox__input:checked,.tribe-common .tribe-common-form-control-radio__input:checked{background-color:var(--tec-form-color-border-active)}.tribe-common .tribe-common-form-control-checkbox__input{border-radius:4px}.tribe-common .tribe-common-form-control-checkbox__input:checked:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg width='12' height='9' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10.6.1L3.9 6.8 1.4 4.3c-.1-.1-.3-.1-.4 0l-.8.8c-.1.1-.1.3 0 .4l3.4 3.4c.2.1.4.1.5 0l7.7-7.7c.1-.1.1-.3 0-.4L11 .1c-.1-.1-.3-.1-.4 0z' fill='%23fff'/%3E%3C/svg%3E");background-repeat:no-repeat;background-size:contain;content:"";display:block;height:9px;left:50%;margin:0;position:absolute;top:50%;transform:translate(-50%,-50%);width:12px}.tribe-common .tribe-common-form-control-checkbox__input:focus+.tribe-common-form-control-checkbox__label,.tribe-common .tribe-common-form-control-checkbox__input:hover+.tribe-common-form-control-checkbox__label{opacity:var(--tec-opacity-icon-hover)}.tribe-common .tribe-common-form-control-radio__input{border-radius:50%}.tribe-common .tribe-common-form-control-radio__input:checked:before{background-color:var(--tec-form-color-background);border-radius:50%;content:"";display:block;height:8px;left:50%;margin:0;position:absolute;top:50%;transform:translate(-50%,-50%);width:8px}.tribe-common .tribe-common-form-control-radio__input:focus+.tribe-common-form-control-radio__label,.tribe-common .tribe-common-form-control-radio__input:hover+.tribe-common-form-control-radio__label{opacity:var(--tec-opacity-icon-hover)}#top .main_color .tribe-common .tribe-common-form-control-checkbox__label,#top .main_color .tribe-common .tribe-common-form-control-radio__label,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-checkbox__label,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-radio__label{font-size:var(--tec-font-size-2);font-weight:var(--tec-font-weight-regular)}.tribe-theme-twentytwenty .tribe-common .tribe-common-form-control-checkbox__input:checked:before{margin:0}.tribe-common .tribe-common-form-control-slider{line-height:0}.tribe-common .tribe-common-form-control-slider__input{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:0}.tribe-common .tribe-common-form-control-slider__input::-webkit-slider-runnable-track{border:none;border-radius:5px;height:10px;margin:5px 0;padding:0;position:relative;transition:var(--tec-transition-background-color);background-color:var(--tec-form-color-accent-primary)}.tribe-common .tribe-common-form-control-slider__input::-moz-range-track{border:none;border-radius:5px;height:10px;margin:5px 0;padding:0;position:relative;transition:var(--tec-transition-background-color);background-color:var(--tec-form-color-accent-primary)}.tribe-common .tribe-common-form-control-slider__input::-ms-track{background-color:transparent;border-color:transparent;border-width:5px 0;color:transparent;height:10px}.tribe-common .tribe-common-form-control-slider__input::-ms-fill-lower,.tribe-common .tribe-common-form-control-slider__input::-ms-fill-upper{background-color:var(--tec-form-color-accent-primary);border-radius:10px}.tribe-common .tribe-common-form-control-slider__input::-webkit-slider-thumb{background-color:var(--tec-form-color-background);border:1px solid var(--tec-form-color-border-secondary);border-radius:50%;box-shadow:var(--tec-form-box-shadow-default);height:20px;width:20px;margin-top:-5px;-webkit-appearance:none;appearance:none}.tribe-common .tribe-common-form-control-slider__input::-moz-range-thumb{background-color:var(--tec-form-color-background);border:1px solid var(--tec-form-color-border-secondary);border-radius:50%;box-shadow:var(--tec-form-box-shadow-default);height:20px;width:20px;margin-top:-5px}.tribe-common .tribe-common-form-control-slider__input::-ms-thumb{background-color:var(--tec-form-color-background);border:1px solid var(--tec-form-color-border-secondary);border-radius:50%;box-shadow:var(--tec-form-box-shadow-default);height:20px;width:20px;margin-top:-5px;box-shadow:none;margin-top:-1px}.tribe-common .tribe-common-form-control-slider__label{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);line-height:var(--tec-line-height-0);color:var(--tec-color-text-secondary)}#top .main_color .tribe-common .tribe-common-form-control-slider__label,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-slider__label,.tribe-common .tribe-common-form-control-slider__label{font-size:var(--tec-font-size-1);font-weight:var(--tec-font-weight-regular)}.tribe-common .tribe-common-form-control-text__input{font-size:var(--tec-font-size-3);border:0;border-bottom:1px solid var(--tec-color-border-default)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-form-control-text__input,.tribe-common .tribe-common-form-control-text__input{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);line-height:var(--tec-line-height-3);font-weight:var(--tec-font-weight-regular)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-form-control-text__input{font-size:var(--tec-font-size-2);border:0}.tribe-common .tribe-common-form-control-text__input:-ms-input-placeholder{color:var(--tec-color-text-secondary);font-style:normal;opacity:var(--tec-opacity-default)}.tribe-common .tribe-common-form-control-text__input::placeholder{color:var(--tec-color-text-secondary);font-style:normal;opacity:var(--tec-opacity-default)}.tribe-common .tribe-common-form-control-text__input:focus{border-bottom-color:var(--tec-color-border-active);outline:0}.tribe-theme-twentyseventeen .tribe-common .tribe-common-form-control-text__input{color:var(--tec-color-text-primary)}.tribe-theme-twentytwenty .tribe-common .tribe-common-form-control-text__input{line-height:inherit}#top .main_color .tribe-common .tribe-common-form-control-text__input,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-text__input{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3);font-weight:var(--tec-font-weight-regular);background:var(--tec-color-background);border:0;border-bottom:1px solid var(--tec-color-border-default)}#top .main_color .tribe-common .tribe-common-form-control-text__input:focus,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-text__input:focus{border-bottom-color:var(--tec-color-border-active);box-shadow:none}#top .main_color .tribe-common.tribe-common--breakpoint-medium .tribe-common-form-control-text__input,#top.tribe-theme-enfold .tribe-common.tribe-common--breakpoint-medium .tribe-common-form-control-text__input{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3);font-weight:var(--tec-font-weight-regular);border:0}.tribe-common .tribe-common-form-control-toggle{line-height:0;position:relative}.tribe-common .tribe-common-form-control-toggle__input{border:none;border-radius:5px;height:10px;margin:5px 0;padding:0;position:relative;transition:var(--tec-transition-background-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--tec-form-color-border-secondary);width:40px}.tribe-common .tribe-common-form-control-toggle__input::-ms-check{display:none}.tribe-common .tribe-common-form-control-toggle__input+label:before{background-color:var(--tec-form-color-background);border:1px solid var(--tec-form-color-border-secondary);border-radius:50%;box-shadow:var(--tec-form-box-shadow-default);height:20px;width:20px;content:"";left:0;position:absolute;top:0;transition:var(--tec-transition-transform)}.tribe-common .tribe-common-form-control-toggle__input:checked{background-color:var(--tec-form-color-accent-primary)}.tribe-common .tribe-common-form-control-toggle__input:checked+label:before{transform:translateX(20px)}.tribe-common .tribe-common-form-control-toggle__label{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);line-height:var(--tec-line-height-0);color:var(--tec-color-text-secondary)}#top .main_color .tribe-common .tribe-common-form-control-toggle__label,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-toggle__label,.tribe-common .tribe-common-form-control-toggle__label{font-size:var(--tec-font-size-1);font-weight:var(--tec-font-weight-regular)}.tribe-theme-twentytwenty .tribe-common .tribe-common-form-control-toggle__input{top:0}.tribe-theme-twentytwenty .tribe-common .tribe-common-form-control-toggle__input:checked:before{content:none}.tribe-theme-twentytwentyone .tribe-common .tribe-common-form-control-toggle__input:after{display:none}.tribe-common a,.tribe-common a:active,.tribe-common a:focus,.tribe-common a:hover,.tribe-common a:visited{color:var(--tec-color-text-primary);outline:0;text-decoration:none}.site-footer .widget-area .tribe-common a,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common a,.tribe-theme-twentyseventeen .tribe-common a{box-shadow:none}.site-footer .widget-area .tribe-common a:focus,.site-footer .widget-area .tribe-common a:hover,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common a:focus,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common a:hover,.tribe-theme-twentyseventeen .tribe-common a:focus,.tribe-theme-twentyseventeen .tribe-common a:hover{box-shadow:none;color:var(--tec-color-text-primary)}.tribe-theme-twentynineteen .entry .tribe-common a,.tribe-theme-twentynineteen .tribe-common a,.tribe-theme-twentytwentyone .entry .tribe-common a,.tribe-theme-twentytwentyone .tribe-common a{text-decoration:none}.main_color .sidebar .tribe-common a,.main_color .sidebar .tribe-common a:active,.main_color .sidebar .tribe-common a:focus,.main_color .sidebar .tribe-common a:hover,.main_color .sidebar .tribe-common a:visited,.tribe-theme-enfold .tribe-common a,.tribe-theme-enfold .tribe-common a:active,.tribe-theme-enfold .tribe-common a:focus,.tribe-theme-enfold .tribe-common a:hover,.tribe-theme-enfold .tribe-common a:visited{color:var(--tec-color-text-primary)}.tribe-common .tribe-common-anchor{border-bottom:2px solid transparent;transition:var(--tec-transition-border-color)}.tribe-common .tribe-common-anchor:active,.tribe-common .tribe-common-anchor:focus,.tribe-common .tribe-common-anchor:hover{border-bottom:2px solid currentColor}.tribe-common .tribe-common-anchor-alt{border-bottom:2px solid var(--tec-color-link-accent);color:var(--tec-color-link-primary);transition:var(--tec-transition-color)}.tribe-common .tribe-common-anchor-alt:active,.tribe-common .tribe-common-anchor-alt:focus,.tribe-common .tribe-common-anchor-alt:hover{border-bottom:2px solid currentColor;color:var(--tec-color-link-accent)}.tribe-common .tribe-common-anchor-thin{border-bottom:1px solid transparent;transition:var(--tec-transition-border-color)}.tribe-common .tribe-common-anchor-thin:active,.tribe-common .tribe-common-anchor-thin:focus,.tribe-common .tribe-common-anchor-thin:hover{border-bottom:1px solid var(--tec-color-link-primary)}.tribe-common .tribe-common-anchor-thin-alt{border-bottom:1px solid var(--tec-color-link-accent);color:var(--tec-color-link-primary);transition:var(--tec-transition-color)}.tribe-common .tribe-common-anchor-thin-alt:active,.tribe-common .tribe-common-anchor-thin-alt:focus,.tribe-common .tribe-common-anchor-thin-alt:hover{border-bottom:1px solid currentColor;color:var(--tec-color-link-accent)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-anchor-alt:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-anchor-alt:hover,.tribe-theme-twentyseventeen .tribe-common .tribe-common-anchor-thin-alt:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-anchor-thin-alt:hover{color:var(--tec-color-accent-primary)}.site-footer .widget-area .tribe-common .tribe-common-anchor,.site-footer .widget-area .tribe-common .tribe-common-anchor-thin,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common .tribe-common-anchor,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common .tribe-common-anchor-thin{transition:var(--tec-transition-border-color)}.site-footer .widget-area .tribe-common .tribe-common-anchor-alt,.site-footer .widget-area .tribe-common .tribe-common-anchor-thin-alt,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common .tribe-common-anchor-alt,.tribe-theme-twentyseventeen .site-footer .widget-area .tribe-common .tribe-common-anchor-thin-alt{transition:var(--tec-transition-color)}.tribe-common .tribe-common-b1{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-2);font-weight:var(--tec-font-weight-regular);line-height:var(--tec-line-height-3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b1{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.tribe-common .tribe-common-b1--bold{font-weight:var(--tec-font-weight-bold)}.tribe-common .tribe-common-b2{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-1);font-weight:var(--tec-font-weight-regular);line-height:var(--tec-line-height-0)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b2{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.tribe-common .tribe-common-b2--bold{font-weight:var(--tec-font-weight-bold)}.tribe-common .tribe-common-b3{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-0);font-weight:var(--tec-font-weight-regular);line-height:var(--tec-line-height-2)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b3{font-size:var(--tec-font-size-1);line-height:var(--tec-line-height-0)}.tribe-common .tribe-common-b3--bold{font-weight:var(--tec-font-weight-bold)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b1--min-medium{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b2--min-medium{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-b3--min-medium,.tribe-common .tribe-common-cta{font-size:var(--tec-font-size-1);line-height:var(--tec-line-height-0)}.tribe-common .tribe-common-cta{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-regular);font-weight:var(--tec-font-weight-bold);border-bottom:2px solid transparent;transition:var(--tec-transition-border-color)}.tribe-common .tribe-common-cta:active,.tribe-common .tribe-common-cta:focus,.tribe-common .tribe-common-cta:hover{border-bottom:2px solid currentColor}.tribe-common .tribe-common-cta--alt{border-bottom:2px solid var(--tec-color-link-accent);color:var(--tec-color-link-primary);transition:var(--tec-transition-color)}.tribe-common .tribe-common-cta--alt:active,.tribe-common .tribe-common-cta--alt:focus,.tribe-common .tribe-common-cta--alt:hover{border-bottom:2px solid currentColor;color:var(--tec-color-link-accent)}.tribe-common .tribe-common-cta--thin{border-bottom:1px solid transparent;transition:var(--tec-transition-border-color)}.tribe-common .tribe-common-cta--thin:active,.tribe-common .tribe-common-cta--thin:focus,.tribe-common .tribe-common-cta--thin:hover{border-bottom:1px solid var(--tec-color-link-primary)}.tribe-common .tribe-common-cta--thin-alt{border-bottom:1px solid var(--tec-color-link-accent);color:var(--tec-color-link-primary);transition:var(--tec-transition-color)}.tribe-common .tribe-common-cta--thin-alt:active,.tribe-common .tribe-common-cta--thin-alt:focus,.tribe-common .tribe-common-cta--thin-alt:hover{border-bottom:1px solid currentColor;color:var(--tec-color-link-accent)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-cta--alt:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-cta--alt:hover,.tribe-theme-twentyseventeen .tribe-common .tribe-common-cta--thin-alt:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-cta--thin-alt:hover{color:var(--tec-color-accent-primary)}.tribe-common .tribe-common-h1{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold);font-size:var(--tec-font-size-8);line-height:var(--tec-line-height-1)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h1{font-size:var(--tec-font-size-10);line-height:var(--tec-line-height-0)}.tribe-common .tribe-common-h2{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold);font-size:var(--tec-font-size-7);line-height:var(--tec-line-height-1)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h2{font-size:var(--tec-font-size-9);line-height:var(--tec-line-height-0)}.tribe-common .tribe-common-h3{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold);font-size:var(--tec-font-size-6);line-height:var(--tec-line-height-2)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h3{font-size:var(--tec-font-size-8);line-height:var(--tec-line-height-1)}.tribe-common .tribe-common-h4{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold);font-size:var(--tec-font-size-5);line-height:var(--tec-line-height-1)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h4{font-size:var(--tec-font-size-7);line-height:var(--tec-line-height-1)}.tribe-common .tribe-common-h5{font-size:var(--tec-font-size-4)}.tribe-common .tribe-common-h5,.tribe-common .tribe-common-h6{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold);line-height:var(--tec-line-height-2)}.tribe-common .tribe-common-h6{font-size:var(--tec-font-size-3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h6{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.tribe-common .tribe-common-h7{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.tribe-common .tribe-common-h7,.tribe-common .tribe-common-h8{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold)}.tribe-common .tribe-common-h8{font-size:var(--tec-font-size-1);line-height:var(--tec-line-height-0)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h3--min-medium{font-size:var(--tec-font-size-8);line-height:var(--tec-line-height-1)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h4--min-medium{font-size:var(--tec-font-size-7);line-height:var(--tec-line-height-1)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h5--min-medium{font-size:var(--tec-font-size-4);line-height:var(--tec-line-height-2)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h6--min-medium{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-h7--min-medium{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.tribe-common .tribe-common-h--alt{font-weight:var(--tec-font-weight-regular)}.tribe-theme-avada #main .tribe-common .tribe-common-h1{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold);font-size:var(--tec-font-size-8);line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h1{font-size:var(--tec-font-size-10);line-height:var(--tec-line-height-0)}.tribe-theme-avada #main .tribe-common .tribe-common-h2{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold);font-size:var(--tec-font-size-7);line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h2{font-size:var(--tec-font-size-9);line-height:var(--tec-line-height-0)}.tribe-theme-avada #main .tribe-common .tribe-common-h3{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold);font-size:var(--tec-font-size-6);line-height:var(--tec-line-height-2)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h3{font-size:var(--tec-font-size-8);line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common .tribe-common-h4{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold);font-size:var(--tec-font-size-5);line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h4{font-size:var(--tec-font-size-7);line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common .tribe-common-h5{font-size:var(--tec-font-size-4)}.tribe-theme-avada #main .tribe-common .tribe-common-h5,.tribe-theme-avada #main .tribe-common .tribe-common-h6{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold);line-height:var(--tec-line-height-2)}.tribe-theme-avada #main .tribe-common .tribe-common-h6{font-size:var(--tec-font-size-3)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h6{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.tribe-theme-avada #main .tribe-common .tribe-common-h7{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.tribe-theme-avada #main .tribe-common .tribe-common-h7,.tribe-theme-avada #main .tribe-common .tribe-common-h8{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-weight:var(--tec-font-weight-bold)}.tribe-theme-avada #main .tribe-common .tribe-common-h8{font-size:var(--tec-font-size-1);line-height:var(--tec-line-height-0)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h3--min-medium{font-size:var(--tec-font-size-8);line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h4--min-medium{font-size:var(--tec-font-size-7);line-height:var(--tec-line-height-1)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h5--min-medium{font-size:var(--tec-font-size-4);line-height:var(--tec-line-height-2)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h6--min-medium{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.tribe-theme-avada #main .tribe-common.tribe-common--breakpoint-medium .tribe-common-h7--min-medium{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.tribe-theme-avada #main .tribe-common .tribe-common-h--alt{font-weight:var(--tec-font-weight-regular)}.tribe-common button{border:none}.tribe-common button,.tribe-common button:focus,.tribe-common button:hover,.tribe-theme-twentyseventeen .tribe-common button:focus,.tribe-theme-twentyseventeen .tribe-common button:hover{background-color:transparent}.tribe-theme-twentytwenty .tribe-common button{background-color:transparent;text-transform:inherit}.tribe-theme-twentytwenty .tribe-common button:focus,.tribe-theme-twentytwenty .tribe-common button:hover{text-decoration:none}.tribe-theme-twentytwentyone .tribe-common button:not(:hover):not(:active){background-color:inherit;color:inherit}.tribe-theme-enfold .tribe-common th{letter-spacing:0;text-transform:none}.tribe-common .tribe-common-c-btn-border,.tribe-common a.tribe-common-c-btn-border{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3);font-weight:var(--tec-font-weight-regular);font-weight:var(--tec-font-weight-bold);border:0;cursor:pointer;display:inline-block;height:auto;padding:0;text-decoration:none;width:auto;background-color:var(--tec-color-background);border:1px solid var(--tec-color-accent-primary);border-radius:var(--tec-border-radius-default);text-align:center;transition:var(--tec-transition);color:var(--tec-color-button-primary);padding:11px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn-border,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn-border{width:auto}.tribe-common .tribe-common-c-btn-border:focus,.tribe-common .tribe-common-c-btn-border:hover,.tribe-common a.tribe-common-c-btn-border:focus,.tribe-common a.tribe-common-c-btn-border:hover{background-color:var(--tec-color-accent-primary);color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn-border:active,.tribe-common a.tribe-common-c-btn-border:active{opacity:.9}.tribe-common .tribe-common-c-btn-border--secondary,.tribe-common a.tribe-common-c-btn-border--secondary{border-color:var(--tec-color-button-secondary);color:var(--tec-color-button-secondary)}.tribe-common .tribe-common-c-btn-border--secondary:focus,.tribe-common .tribe-common-c-btn-border--secondary:hover,.tribe-common a.tribe-common-c-btn-border--secondary:focus,.tribe-common a.tribe-common-c-btn-border--secondary:hover{background-color:var(--tec-color-button-secondary)}.tribe-common .tribe-common-c-btn-border--secondary:active,.tribe-common a.tribe-common-c-btn-border--secondary:active{opacity:.9}.tribe-common .tribe-common-c-btn-border--alt,.tribe-common a.tribe-common-c-btn-border--alt{border-color:var(--tec-color-border-secondary);color:var(--tec-color-text-primary);font-weight:var(--tec-font-weight-regular)}.tribe-common .tribe-common-c-btn-border--alt:focus,.tribe-common .tribe-common-c-btn-border--alt:hover,.tribe-common a.tribe-common-c-btn-border--alt:focus,.tribe-common a.tribe-common-c-btn-border--alt:hover{background-color:var(--tec-color-background);border-color:var(--tec-color-border-active);color:var(--tec-color-text-primary)}.tribe-common .tribe-common-c-btn-border--alt:active,.tribe-common a.tribe-common-c-btn-border--alt:active{opacity:.9}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border:hover{background-color:var(--tec-color-button-primary)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border--secondary:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border--secondary:hover{background-color:var(--tec-color-button-secondary)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border--alt:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border--alt:hover{background-color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn-border-small,.tribe-common a.tribe-common-c-btn-border-small{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-1);line-height:var(--tec-line-height-0);font-weight:var(--tec-font-weight-regular);border:0;cursor:pointer;display:inline-block;height:auto;padding:0;text-decoration:none;width:auto;background-color:var(--tec-color-background);border:1px solid var(--tec-color-border-default);border-radius:var(--tec-border-radius-default);text-align:center;transition:var(--tec-transition-color-border-color)}.tribe-common .tribe-common-c-btn-border-small:focus,.tribe-common .tribe-common-c-btn-border-small:hover,.tribe-common a.tribe-common-c-btn-border-small:focus,.tribe-common a.tribe-common-c-btn-border-small:hover{background-color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn-border-small:active,.tribe-common a.tribe-common-c-btn-border-small:active{border-color:var(--tec-color-border-active)}.tribe-common .tribe-common-c-btn-border-small,.tribe-common a.tribe-common-c-btn-border-small{color:var(--tec-color-text-secondary);padding:14px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn-border-small,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn-border-small{padding:6px 15px;width:auto}.tribe-common .tribe-common-c-btn-border-small:active,.tribe-common .tribe-common-c-btn-border-small:focus,.tribe-common .tribe-common-c-btn-border-small:hover,.tribe-common a.tribe-common-c-btn-border-small:active,.tribe-common a.tribe-common-c-btn-border-small:focus,.tribe-common a.tribe-common-c-btn-border-small:hover{color:var(--tec-color-text-primary)}.tribe-common .tribe-common-c-btn-border-small:disabled,.tribe-common a.tribe-common-c-btn-border-small:disabled{color:var(--tec-color-text-disabled)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-border-small:hover{background-color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn-icon{border:0;cursor:pointer;display:inline-block;height:auto;padding:0;text-decoration:none;width:auto}.tribe-common .tribe-common-c-btn-icon--caret-left:active .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-left:focus .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-left:hover .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right:active .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right:focus .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right:hover .tribe-common-c-btn-icon__icon-svg path{fill:var(--tec-color-icon-primary)}.tribe-common .tribe-common-c-btn-icon--caret-left:disabled .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right:disabled .tribe-common-c-btn-icon__icon-svg path{fill:var(--tec-color-icon-disabled)}.tribe-common .tribe-common-c-btn-icon--caret-left .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right .tribe-common-c-btn-icon__icon-svg path{fill:var(--tec-color-icon-secondary)}.tribe-common .tribe-common-c-btn-icon--border{align-items:center;background-color:var(--tec-color-background);border:1px solid var(--tec-color-border-default);display:inline-flex;height:56px;justify-content:center;transition:none;width:56px}.tribe-common .tribe-common-c-btn-icon--border:focus,.tribe-common .tribe-common-c-btn-icon--border:hover{background-color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn-icon--border:active{border-color:var(--tec-color-border-active)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn-icon--border:hover{background-color:var(--tec-color-background)}.tribe-common .tribe-common-c-btn,.tribe-common a.tribe-common-c-btn{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3);font-weight:var(--tec-font-weight-regular);font-weight:var(--tec-font-weight-bold);border:0;cursor:pointer;display:inline-block;height:auto;padding:0;text-decoration:none;width:auto;border-radius:var(--tec-border-radius-default);color:var(--tec-color-background);text-align:center;transition:var(--tec-transition-background-color);background-color:var(--tec-color-button-primary);padding:11px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn{width:auto}.tribe-common .tribe-common-c-btn:focus,.tribe-common .tribe-common-c-btn:hover,.tribe-common a.tribe-common-c-btn:focus,.tribe-common a.tribe-common-c-btn:hover{background-color:var(--tec-color-button-primary-hover)}.tribe-common .tribe-common-c-btn:active,.tribe-common a.tribe-common-c-btn:active{background-color:var(--tec-color-button-primary-active)}.tribe-common .tribe-common-c-btn:disabled,.tribe-common a.tribe-common-c-btn:disabled{background-color:var(--tec-color-button-primary-background)}.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn:focus,.tribe-theme-twentyseventeen .tribe-common .tribe-common-c-btn:hover{background-color:var(--tec-color-button-primary-hover);color:var(--tec-color-background)}.tribe-theme-twentytwenty .tribe-common .tribe-common-c-btn{background-color:var(--tec-color-button-primary)}.tribe-theme-twentytwenty .tribe-common .tribe-common-c-btn:focus,.tribe-theme-twentytwenty .tribe-common .tribe-common-c-btn:hover{background-color:var(--tec-color-button-primary-hover);color:var(--tec-color-background)}.tribe-theme-twentytwentyone .tribe-common .tribe-common-c-btn{outline:none}.tribe-theme-twentytwentyone .tribe-common .tribe-common-c-btn:not(:hover):not(:active){background-color:var(--tec-color-button-primary);color:var(--tec-color-background)}.tribe-common .tribe-common-c-loader__dot circle{animation-direction:normal;animation-duration:2.24s;animation-iteration-count:infinite;animation-name:a;fill:currentColor;opacity:var(--tec-opacity-background)}.tribe-common .tribe-common-c-loader__dot--first circle{animation-delay:.45s}.tribe-common .tribe-common-c-loader__dot--second circle{animation-delay:1.05s}.tribe-common .tribe-common-c-loader__dot--third circle{animation-delay:1.35s}@keyframes a{50%{opacity:var(--tec-opacity-default)}}.tribe-common .tribe-common-c-svgicon{color:var(--tec-color-accent-primary)}.tribe-common .tribe-common-c-svgicon--featured path{fill:currentColor}.tribe-common .tribe-common-c-svgicon--recurring path{fill:var(--tec-color-icon-active);stroke:var(--tec-color-icon-active)}.tribe-common .tribe-common-c-svgicon--close-alt path,.tribe-common .tribe-common-c-svgicon--close path{stroke:var(--tec-color-icon-secondary)}.tribe-common .tribe-common-c-svgicon--messages-not-found path{stroke:var(--tec-color-icon-active)}.tribe-common .tribe-common-c-svgicon--messages-not-found .tribe-common-c-svgicon__svg-stroke{stroke:currentColor}.tribe-common .tribe-common-c-svgicon__svg-fill{fill:var(--tec-color-icon-active)}.tribe-common .tribe-common-c-svgicon__svg-stroke{stroke:var(--tec-color-icon-active)}
common/src/resources/css/common-skeleton.min.css CHANGED
@@ -1 +1 @@
1
- .tribe-common{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased}.tribe-common *{box-sizing:border-box}.tribe-common article,.tribe-common aside,.tribe-common details,.tribe-common figcaption,.tribe-common figure,.tribe-common footer,.tribe-common header,.tribe-common main,.tribe-common menu,.tribe-common nav,.tribe-common section,.tribe-common summary{display:block}.tribe-common svg:not(:root){overflow:hidden}.tribe-common audio,.tribe-common canvas,.tribe-common progress,.tribe-common video{display:inline-block}.tribe-common audio:not([controls]){display:none;height:0}.tribe-common progress{vertical-align:baseline}.tribe-common [hidden],.tribe-common template{display:none}.tribe-common pre{overflow:auto}.tribe-common sub,.tribe-common sup{position:relative;vertical-align:baseline}.tribe-common sup{top:-.5em}.tribe-common sub{bottom:-.25em}.tribe-common button,.tribe-common input,.tribe-common select,.tribe-common textarea{box-sizing:border-box;margin:0}.tribe-common input[type=number]::-webkit-inner-spin-button,.tribe-common input[type=number]::-webkit-outer-spin-button{height:auto}.tribe-common legend{color:inherit;display:table;max-width:100%;white-space:normal}.tribe-common textarea{overflow:auto;resize:none}.tribe-common button,.tribe-common input[type=button],.tribe-common input[type=reset],.tribe-common input[type=submit]{cursor:pointer;overflow:visible}.tribe-common button[disabled],.tribe-common input[disabled]{cursor:default}.tribe-common button::-moz-focus-inner,.tribe-common input::-moz-focus-inner{border:0;padding:0}.tribe-common a,.tribe-common abbr,.tribe-common acronym,.tribe-common address,.tribe-common applet,.tribe-common article,.tribe-common aside,.tribe-common audio,.tribe-common b,.tribe-common big,.tribe-common blockquote,.tribe-common canvas,.tribe-common caption,.tribe-common center,.tribe-common cite,.tribe-common code,.tribe-common dd,.tribe-common del,.tribe-common details,.tribe-common dfn,.tribe-common div,.tribe-common dl,.tribe-common dt,.tribe-common em,.tribe-common embed,.tribe-common fieldset,.tribe-common figcaption,.tribe-common figure,.tribe-common footer,.tribe-common form,.tribe-common h1,.tribe-common h2,.tribe-common h3,.tribe-common h4,.tribe-common h5,.tribe-common h6,.tribe-common header,.tribe-common i,.tribe-common iframe,.tribe-common img,.tribe-common ins,.tribe-common kbd,.tribe-common label,.tribe-common legend,.tribe-common li,.tribe-common main,.tribe-common mark,.tribe-common menu,.tribe-common nav,.tribe-common object,.tribe-common ol,.tribe-common output,.tribe-common p,.tribe-common pre,.tribe-common q,.tribe-common ruby,.tribe-common s,.tribe-common samp,.tribe-common section,.tribe-common small,.tribe-common span,.tribe-common strike,.tribe-common strong,.tribe-common sub,.tribe-common summary,.tribe-common sup,.tribe-common table,.tribe-common tbody,.tribe-common td,.tribe-common tfoot,.tribe-common th,.tribe-common thead,.tribe-common time,.tribe-common tr,.tribe-common tt,.tribe-common u,.tribe-common ul,.tribe-common var,.tribe-common video{border:0;margin:0;padding:0}.tribe-common ol,.tribe-common ul{list-style:none}.tribe-common img{border-style:none;height:auto;-ms-interpolation-mode:bicubic;max-width:100%}.tribe-common embed,.tribe-common iframe,.tribe-common video{max-height:100%;max-width:100%}.tribe-theme-avada input[type=text]{margin:0}.tribe-theme-divi .entry-content .tribe-common table,.tribe-theme-divibody.et-pb-preview #main-content .container .tribe-common table{border:0;margin:0}.tribe-theme-divi .entry-content .tribe-common td,.tribe-theme-divibody.et-pb-preview #main-content .container .tribe-common td{border:0}.tribe-theme-divi #content-area .tribe-common td,.tribe-theme-divi #content-area .tribe-common th,.tribe-theme-divi #content-area .tribe-common tr,.tribe-theme-divi #left-area .tribe-common ul{padding:0}#top .main_color .tribe-common button[disabled],#top.tribe-theme-enfold .tribe-common button[disabled]{cursor:default}#top .main_color .tribe-common form,#top .main_color .tribe-common input,#top.tribe-theme-enfold .tribe-common form,#top.tribe-theme-enfold .tribe-common input{margin:0}.entry-content-wrapper .tribe-common li,.entry-content .tribe-common ol,.entry-content .tribe-common ul,.tribe-theme-genesis .tribe-common ol,.tribe-theme-genesis .tribe-common ul{margin:0;padding:0}.tribe-theme-twentynineteen .tribe-common svg{fill:none}.tribe-theme-twentyseventeen .tribe-common div.tribe-dialog{z-index:5!important}:root{--tec-grid-gutter:48px;--tec-grid-gutter-negative:calc(var(--tec-grid-gutter)*-1);--tec-grid-gutter-half:calc(var(--tec-grid-gutter)/2);--tec-grid-gutter-half-negative:calc(var(--tec-grid-gutter-half)*-1);--tec-grid-gutter-small:42px;--tec-grid-gutter-small-negative:calc(var(--tec-grid-gutter-small)*-1);--tec-grid-gutter-small-half:calc(var(--tec-grid-gutter-small)/2);--tec-grid-gutter-small-half-negative:calc(var(--tec-grid-gutter-small-half)*-1);--tec-grid-gutter-page:42px;--tec-grid-gutter-page-small:19.5px;--tec-grid-width-default:1176px;--tec-grid-width-min:320px;--tec-grid-width:calc(var(--tec-grid-width-default) + var(--tec-grid-gutter-page)*2);--tec-grid-width-1-of-2:50%;--tec-grid-width-1-of-3:33.333%;--tec-grid-width-1-of-4:25%;--tec-grid-width-1-of-5:20%;--tec-grid-width-1-of-7:14.285%;--tec-grid-width-1-of-8:12.5%;--tec-grid-width-1-of-9:11.111%;--grid-gutter:var(--tec-grid-gutter);--grid-gutter-negative:var(--tec-grid-gutter-negative);--grid-gutter-half:var(--tec-grid-gutter-half);--grid-gutter-half-negative:var(--tec-grid-gutter-half-negative);--grid-gutter-small:var(--tec-grid-gutter-small);--grid-gutter-small-negative:var(--tec-grid-gutter-small-negative);--grid-gutter-small-half:var(--tec-grid-gutter-small-half);--grid-gutter-small-half-negative:var(--tec-grid-gutter-small-half-negative);--grid-gutter-page:var(--tec-grid-gutter-page);--grid-gutter-page-small:var(--tec-grid-gutter-page-small);--grid-width-default:var(--tec-grid-width-default);--grid-width-min:var(--tec-grid-width-min);--grid-width:var(--tec-grid-width);--grid-width-1-of-2:var(--tec-grid-width-1-of-2);--grid-width-1-of-3:var(--tec-grid-width-1-of-3);--grid-width-1-of-4:var(--tec-grid-width-1-of-4);--grid-width-1-of-5:var(--tec-grid-width-1-of-5);--grid-width-1-of-7:var(--tec-grid-width-1-of-7);--grid-width-1-of-8:var(--tec-grid-width-1-of-8);--grid-width-1-of-9:var(--tec-grid-width-1-of-9);--tec-spacer-0:4px;--tec-spacer-1:8px;--tec-spacer-2:12px;--tec-spacer-3:16px;--tec-spacer-4:20px;--tec-spacer-5:24px;--tec-spacer-6:28px;--tec-spacer-7:32px;--tec-spacer-8:40px;--tec-spacer-9:48px;--tec-spacer-10:56px;--tec-spacer-11:64px;--tec-spacer-12:80px;--tec-spacer-13:96px;--tec-spacer-14:160px;--spacer-0:var(--tec-spacer-0);--spacer-1:var(--tec-spacer-1);--spacer-2:var(--tec-spacer-2);--spacer-3:var(--tec-spacer-3);--spacer-4:var(--tec-spacer-4);--spacer-5:var(--tec-spacer-5);--spacer-6:var(--tec-spacer-6);--spacer-7:var(--tec-spacer-7);--spacer-8:var(--tec-spacer-8);--spacer-9:var(--tec-spacer-9);--spacer-10:var(--tec-spacer-10);--spacer-11:var(--tec-spacer-11);--spacer-12:var(--tec-spacer-12);--spacer-13:var(--tec-spacer-13);--spacer-14:var(--tec-spacer-14);--tec-z-index-spinner-container:100;--tec-z-index-views-selector:30;--tec-z-index-dropdown:30;--tec-z-index-events-bar-button:20;--tec-z-index-search:10;--tec-z-index-filters:9;--tec-z-index-scroller:7;--tec-z-index-week-event-hover:5;--tec-z-index-map-event-hover:5;--tec-z-index-map-event-hover-actions:6;--tec-z-index-multiday-event:5;--tec-z-index-multiday-event-bar:2;--z-index-spinner-container:var(--tec-z-index-spinner-container);--z-index-views-selector:var(--tec-z-index-views-selector);--z-index-dropdown:var(--tec-z-index-dropdown);--z-index-events-bar-button:var(--tec-z-index-events-bar-button);--z-index-search:var(--tec-z-index-search);--z-index-filters:var(--tec-z-index-filters);--z-index-scroller:var(--tec-z-index-scroller);--z-index-week-event-hover:var(--tec-z-index-week-event-hover);--z-index-map-event-hover:var(--tec-z-index-map-event-hover);--z-index-map-event-hover-actions:var(--tec-z-index-map-event-hover-actions);--z-index-multiday-event:var(--tec-z-index-multiday-event);--z-index-multiday-event-bar:var(--tec-z-index-multiday-event-bar);--tec-color-text-primary:#141827;--tec-color-text-primary-light:rgba(20,24,39,.62);--tec-color-text-secondary:#5d5d5d;--tec-color-text-disabled:#d5d5d5;--tec-color-text-events-title:var(--tec-color-text-primary);--tec-color-text-event-title:var(--tec-color-text-events-title);--tec-color-text-event-date:var(--tec-color-text-primary);--tec-color-text-secondary-event-date:var(--tec-color-text-secondary);--tec-color-icon-primary:#5d5d5d;--tec-color-icon-primary-alt:#757575;--tec-color-icon-secondary:#bababa;--tec-color-icon-active:#141827;--tec-color-icon-disabled:#d5d5d5;--tec-color-icon-focus:#334aff;--tec-color-icon-error:#da394d;--tec-color-event-icon:#141827;--tec-color-event-icon-hover:#334aff;--tec-color-accent-primary:#334aff;--tec-color-accent-primary-hover:rgba(51,74,255,.8);--tec-color-accent-primary-active:rgba(51,74,255,.9);--tec-color-accent-primary-background:rgba(51,74,255,.07);--tec-color-accent-secondary:#141827;--tec-color-accent-secondary-hover:rgba(20,24,39,.8);--tec-color-accent-secondary-active:rgba(20,24,39,.9);--tec-color-accent-secondary-background:rgba(20,24,39,.07);--tec-color-button-primary:var(--tec-color-accent-primary);--tec-color-button-primary-hover:var(--tec-color-accent-primary-hover);--tec-color-button-primary-active:var(--tec-color-accent-primary-active);--tec-color-button-primary-background:var(--tec-color-accent-primary-background);--tec-color-button-secondary:var(--tec-color-accent-secondary);--tec-color-button-secondary-hover:var(--tec-color-accent-secondary-hover);--tec-color-button-secondary-active:var(--tec-color-accent-secondary-active);--tec-color-button-secondary-background:var(--tec-color-accent-secondary-background);--tec-color-link-primary:var(--tec-color-text-primary);--tec-color-link-accent-hover:rgba(51,74,255,.8);--tec-color-border-default:#d5d5d5;--tec-color-border-secondary:#e4e4e4;--tec-color-border-tertiary:#7d7d7d;--tec-color-border-hover:#5d5d5d;--tec-color-border-active:#141827;--tec-color-background:#fff;--tec-color-background-events:transparent;--tec-color-background-transparent:hsla(0,0%,100%,.6);--tec-color-background-secondary:#f7f6f6;--tec-color-background-messages:rgba(20,24,39,.07);--tec-color-background-secondary-hover:#f0eeee;--tec-color-background-error:rgba(218,57,77,.08);--tec-color-box-shadow:rgba(0,0,0,.14);--tec-color-box-shadow-secondary:rgba(0,0,0,.1);--tec-color-scroll-track:rgba(0,0,0,.25);--tec-color-scroll-bar:rgba(0,0,0,.5);--tec-color-background-primary-multiday:rgba(51,74,255,.24);--tec-color-background-primary-multiday-hover:rgba(51,74,255,.34);--tec-color-background-secondary-multiday:rgba(20,24,39,.24);--tec-color-background-secondary-multiday-hover:rgba(20,24,39,.34);--tec-color-accent-primary-week-event:rgba(51,74,255,.1);--tec-color-accent-primary-week-event-hover:rgba(51,74,255,.2);--tec-color-accent-primary-week-event-featured:rgba(51,74,255,.04);--tec-color-accent-primary-week-event-featured-hover:rgba(51,74,255,.14);--tec-color-background-secondary-datepicker:var(--tec-color-background-secondary);--tec-color-accent-primary-background-datepicker:var(--tec-color-accent-primary-background);--color-text-primary:var(--tec-color-text-primary);--color-text-primary-light:var(--tec-color-text-primary-light);--color-text-secondary:var(--tec-color-text-secondary);--color-text-disabled:var(--tec-color-text-disabled);--color-icon-primary:var(--tec-color-icon-primary);--color-icon-primary-alt:var(--tec-color-icon-primary);--color-icon-secondary:var(--tec-color-icon-secondary);--color-icon-active:var(--tec-color-icon-active);--color-icon-disabled:var(--tec-color-icon-disabled);--color-icon-focus:var(--tec-color-icon-focus);--color-icon-error:var(--tec-color-icon-error);--color-accent-primary:var(--tec-color-accent-primary);--color-accent-primary-hover:var(--tec-color-accent-primary-hover);--color-accent-primary-active:var(--tec-color-accent-primary-active);--color-accent-primary-background:var(--tec-color-accent-primary-background);--color-accent-primary-multiday:var(--tec-color-accent-primary-multiday);--color-accent-primary-multiday-hover:var(--tec-color-accent-primary-multiday-hover);--color-accent-primary-week-event:var(--tec-color-accent-primary-week-event);--color-accent-primary-week-event-hover:var(--tec-color-accent-primary-week-event-hover);--color-accent-primary-week-event-featured:var(--tec-color-accent-primary-week-event-featured);--color-accent-primary-week-event-featured-hover:var(--tec-color-accent-primary-week-event-featured-hover);--color-accent-secondary:var(--tec-color-accent-secondary);--color-accent-secondary-hover:var(--tec-color-accent-secondary-hover);--color-accent-secondary-active:var(--tec-color-accent-secondary-active);--color-accent-secondary-background:var(--tec-color-accent-secondary-background);--color-border-default:var(--tec-color-border-default);--color-border-secondary:var(--tec-color-border-secondary);--color-border-tertiary:var(--tec-color-border-tertiary);--color-border-hover:var(--tec-color-border-hover);--color-border-active:var(--tec-color-border-active);--color-background:var(--tec-color-background);--color-background-transparent:var(--tec-color-background-transparent);--color-background-secondary:var(--tec-color-background-secondary);--color-background-messages:var(--tec-color-background-messages);--color-background-secondary-hover:var(--tec-color-background-secondary-hover);--color-background-error:var(--tec-color-icon-error);--color-box-shadow:var(--tec-color-box-shadow);--color-box-shadow-secondary:var(--tec-color-box-shadow-secondary);--color-scroll-track:var(--tec-color-scroll-track);--color-scroll-bar:var(--tec-color-scroll-bar)}.tribe-common .tribe-common-form-control-checkbox,.tribe-common .tribe-common-form-control-radio{align-items:flex-start;display:flex}.tribe-common .tribe-common-form-control-checkbox__label,.tribe-common .tribe-common-form-control-radio__label{cursor:pointer;margin-left:15px}.tribe-common .tribe-common-form-control-checkbox__input,.tribe-common .tribe-common-form-control-radio__input{cursor:pointer;flex:none;margin:1px 0 0}#top .main_color .tribe-common .tribe-common-form-control-checkbox__input,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-checkbox__input{margin:1px 0 0}.tribe-theme-twentytwenty .tribe-common .tribe-common-form-control-checkbox__input{top:0}.tribe-theme-twentytwentyone .tribe-common .tribe-common-form-control-checkbox__input:checked:after{border:none}.tribe-theme-twentytwentyone .tribe-common .tribe-common-form-control-radio__input:checked:after{background-color:transparent}.tribe-common .tribe-common-form-control-checkbox-radio-group>*{margin-bottom:15px}.tribe-common .tribe-common-form-control-checkbox-radio-group>:last-child{margin-bottom:0}.tribe-common .tribe-common-form-control-slider__input{cursor:pointer;display:inline-block;margin:0;padding:0;vertical-align:middle;width:120px}.tribe-common .tribe-common-form-control-slider__label{cursor:pointer;display:inline-block;margin-left:11px;vertical-align:middle}.tribe-common .tribe-common-form-control-slider--vertical .tribe-common-form-control-slider__label{display:block;margin:0 0 6px}.tribe-common .tribe-common-form-control-text__label{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.tribe-common .tribe-common-form-control-text__input{height:auto;padding:12px 28px 12px 0;padding:var(--tec-spacer-2) var(--tec-spacer-6) var(--tec-spacer-2) 0;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-form-control-text__input{padding:20px 20px 20px 40px;padding:var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-8)}#top .main_color .tribe-common .tribe-common-form-control-text__input,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-text__input{padding:12px 28px 12px 0;padding:var(--tec-spacer-2) var(--tec-spacer-6) var(--tec-spacer-2) 0;width:100%}#top .main_color .tribe-common.tribe-common--breakpoint-medium .tribe-common-form-control-text__input,#top.tribe-theme-enfold .tribe-common.tribe-common--breakpoint-medium .tribe-common-form-control-text__input{padding:20px 20px 20px 40px;padding:var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-8)}.tribe-common .tribe-common-form-control-toggle__input,.tribe-common .tribe-common-form-control-toggle__label{cursor:pointer;display:inline-block;vertical-align:middle}.tribe-common .tribe-common-form-control-toggle__label{margin-left:11px}.tribe-common .tribe-common-form-control-toggle--vertical .tribe-common-form-control-toggle__label{display:block;margin:0 0 6px}#top .main_color .tribe-common .tribe-common-form-control-toggle__input,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-toggle__input{display:inline-block;margin:5px 0}.tribe-common .tribe-common-g-col{min-width:0;width:100%}.tribe-common .tribe-common-g-row{display:flex;flex-wrap:wrap}.tribe-common .tribe-common-g-row--gutters{margin-left:-21px;margin-left:var(--tec-grid-gutter-small-half-negative);margin-right:-21px;margin-right:var(--tec-grid-gutter-small-half-negative)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-g-row--gutters{margin-left:-24px;margin-left:var(--tec-grid-gutter-half-negative);margin-right:-24px;margin-right:var(--tec-grid-gutter-half-negative)}.tribe-common .tribe-common-g-row--gutters>.tribe-common-g-col{padding-left:21px;padding-left:var(--tec-grid-gutter-small-half);padding-right:21px;padding-right:var(--tec-grid-gutter-small-half)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-g-row--gutters>.tribe-common-g-col{padding-left:24px;padding-left:var(--tec-grid-gutter-half);padding-right:24px;padding-right:var(--tec-grid-gutter-half)}.tribe-theme-twentynineteen .tribe-common .entry.tribe-common-g-row--gutters{margin-left:-21px;margin-left:var(--tec-grid-gutter-small-half-negative);margin-right:-21px;margin-right:var(--tec-grid-gutter-small-half-negative);padding:0}.tribe-theme-twentynineteen .tribe-common.tribe-common--breakpoint-medium .entry.tribe-common-g-row--gutters{margin-left:-24px;margin-left:var(--tec-grid-gutter-half-negative);margin-right:-24px;margin-right:var(--tec-grid-gutter-half-negative)}.tribe-theme-twentynineteen .tribe-common .tribe-common-g-row--gutters>.entry.tribe-common-g-col{margin:0;padding-left:21px;padding-left:var(--tec-grid-gutter-small-half);padding-right:21px;padding-right:var(--tec-grid-gutter-small-half)}.tribe-theme-twentynineteen .tribe-common.tribe-common--breakpoint-medium .tribe-common-g-row--gutters>.entry.tribe-common-g-col{padding-left:24px;padding-left:var(--tec-grid-gutter-half);padding-right:24px;padding-right:var(--tec-grid-gutter-half)}.tribe-common a{cursor:pointer}.tribe-theme-divi #left-area .tribe-common ul,.tribe-theme-divi .entry-content .tribe-common ul,body.et-pb-preview.tribe-theme-divi #main-content .container .tribe-common ul{list-style-type:none;padding:0}.entry-content .tribe-common ol>li,.entry-content .tribe-common ul>li{list-style-type:none}.tribe-common button{padding:0}.tribe-common .tribe-common-l-container{margin-left:auto;margin-right:auto;max-width:1260px;max-width:var(--tec-grid-width);padding-left:19.5px;padding-left:var(--tec-grid-gutter-page-small);padding-right:19.5px;padding-right:var(--tec-grid-gutter-page-small);width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-l-container{padding-left:42px;padding-left:var(--tec-grid-gutter-page);padding-right:42px;padding-right:var(--tec-grid-gutter-page)}.tribe-common .tribe-common-a11y-hidden{display:none!important;visibility:hidden}.tribe-common .tribe-common-a11y-visual-hide{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.tribe-common .tribe-common-a11y-visual-show{clip:auto;height:auto;margin:0;position:static;width:auto}.tribe-common .tribe-common-c-btn-border,.tribe-common a.tribe-common-c-btn-border{padding:11px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn-border,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn-border{width:auto}.tribe-common .tribe-common-c-btn-border-small,.tribe-common a.tribe-common-c-btn-border-small{padding:14px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn-border-small,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn-border-small{padding:6px 15px;width:auto}.tribe-common .tribe-common-c-btn-icon:before{background-repeat:no-repeat;background-size:contain;content:"";display:block}.tribe-common .tribe-common-c-btn-icon--caret-left .tribe-common-c-btn-icon__icon-svg,.tribe-common .tribe-common-c-btn-icon--caret-right .tribe-common-c-btn-icon__icon-svg{width:11px}.tribe-common .tribe-common-c-btn-icon--caret-left .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right .tribe-common-c-btn-icon__icon-svg path{fill:currentColor}.tribe-common .tribe-common-c-btn,.tribe-common a.tribe-common-c-btn{padding:11px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn{width:auto}.tribe-common .tribe-common-c-image{display:block;height:auto;margin-left:auto;margin-right:auto;width:100%}.tribe-common .tribe-common-c-image--bg{position:relative}.tribe-common .tribe-common-c-image__bg{background:50% no-repeat;background-size:cover;bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.tribe-common .tribe-common-c-loader{display:flex;padding-top:192px;padding-top:calc(var(--tec-spacer-11)*3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-loader{padding-top:288px;padding-top:calc(var(--tec-spacer-13)*3)}.tribe-common .tribe-common-c-loader__dot{width:15px}.tribe-common .tribe-common-c-loader__dot:not(:first-of-type){margin-left:8px}.tribe-common .tribe-common-c-loader__dot circle{fill:currentColor}.tribe-common .tribe-common-c-svgicon--featured{width:8px}.tribe-common .tribe-common-c-svgicon--recurring{width:12px}.tribe-common .tribe-common-c-svgicon--search{width:16px}.tribe-common .tribe-common-c-svgicon--location{width:10px}.tribe-common .tribe-common-c-svgicon--day,.tribe-common .tribe-common-c-svgicon--map,.tribe-common .tribe-common-c-svgicon--month,.tribe-common .tribe-common-c-svgicon--photo,.tribe-common .tribe-common-c-svgicon--week{height:100%;width:100%}.tribe-common .tribe-common-c-svgicon--close-alt path,.tribe-common .tribe-common-c-svgicon--close path{stroke:currentColor}.tribe-common .tribe-common-c-svgicon--hybrid circle,.tribe-common .tribe-common-c-svgicon--mail,.tribe-common .tribe-common-c-svgicon--map-pin,.tribe-common .tribe-common-c-svgicon--messages-not-found g,.tribe-common .tribe-common-c-svgicon--no-map,.tribe-common .tribe-common-c-svgicon--phone,.tribe-common .tribe-common-c-svgicon--virtual g,.tribe-common .tribe-common-c-svgicon--website{fill:none}.tribe-common .tribe-common-c-svgicon--messages-not-found{width:22px}.tribe-common .tribe-common-c-svgicon--messages-not-found path{stroke:currentColor}.tribe-common .tribe-common-c-svgicon--error{width:18px}.tribe-common .tribe-common-c-svgicon--error g,.tribe-common .tribe-common-c-svgicon--reset path{fill:none}.tribe-common .tribe-common-c-svgicon__svg-fill{fill:currentColor}.tribe-common .tribe-common-c-svgicon__svg-stroke{stroke:currentColor}
1
+ .tribe-common{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased}.tribe-common *{box-sizing:border-box}.tribe-common article,.tribe-common aside,.tribe-common details,.tribe-common figcaption,.tribe-common figure,.tribe-common footer,.tribe-common header,.tribe-common main,.tribe-common menu,.tribe-common nav,.tribe-common section,.tribe-common summary{display:block}.tribe-common svg:not(:root){overflow:hidden}.tribe-common audio,.tribe-common canvas,.tribe-common progress,.tribe-common video{display:inline-block}.tribe-common audio:not([controls]){display:none;height:0}.tribe-common progress{vertical-align:baseline}.tribe-common [hidden],.tribe-common template{display:none}.tribe-common pre{overflow:auto}.tribe-common sub,.tribe-common sup{position:relative;vertical-align:baseline}.tribe-common sup{top:-.5em}.tribe-common sub{bottom:-.25em}.tribe-common button,.tribe-common input,.tribe-common select,.tribe-common textarea{box-sizing:border-box;margin:0}.tribe-common input[type=number]::-webkit-inner-spin-button,.tribe-common input[type=number]::-webkit-outer-spin-button{height:auto}.tribe-common legend{color:inherit;display:table;max-width:100%;white-space:normal}.tribe-common textarea{overflow:auto;resize:none}.tribe-common button,.tribe-common input[type=button],.tribe-common input[type=reset],.tribe-common input[type=submit]{cursor:pointer;overflow:visible}.tribe-common button[disabled],.tribe-common input[disabled]{cursor:default}.tribe-common button::-moz-focus-inner,.tribe-common input::-moz-focus-inner{border:0;padding:0}.tribe-common a,.tribe-common abbr,.tribe-common acronym,.tribe-common address,.tribe-common applet,.tribe-common article,.tribe-common aside,.tribe-common audio,.tribe-common b,.tribe-common big,.tribe-common blockquote,.tribe-common canvas,.tribe-common caption,.tribe-common center,.tribe-common cite,.tribe-common code,.tribe-common dd,.tribe-common del,.tribe-common details,.tribe-common dfn,.tribe-common div,.tribe-common dl,.tribe-common dt,.tribe-common em,.tribe-common embed,.tribe-common fieldset,.tribe-common figcaption,.tribe-common figure,.tribe-common footer,.tribe-common form,.tribe-common h1,.tribe-common h2,.tribe-common h3,.tribe-common h4,.tribe-common h5,.tribe-common h6,.tribe-common header,.tribe-common i,.tribe-common iframe,.tribe-common img,.tribe-common ins,.tribe-common kbd,.tribe-common label,.tribe-common legend,.tribe-common li,.tribe-common main,.tribe-common mark,.tribe-common menu,.tribe-common nav,.tribe-common object,.tribe-common ol,.tribe-common output,.tribe-common p,.tribe-common pre,.tribe-common q,.tribe-common ruby,.tribe-common s,.tribe-common samp,.tribe-common section,.tribe-common small,.tribe-common span,.tribe-common strike,.tribe-common strong,.tribe-common sub,.tribe-common summary,.tribe-common sup,.tribe-common table,.tribe-common tbody,.tribe-common td,.tribe-common tfoot,.tribe-common th,.tribe-common thead,.tribe-common time,.tribe-common tr,.tribe-common tt,.tribe-common u,.tribe-common ul,.tribe-common var,.tribe-common video{border:0;margin:0;padding:0}.tribe-common ol,.tribe-common ul{list-style:none}.tribe-common img{border-style:none;height:auto;-ms-interpolation-mode:bicubic;max-width:100%}.tribe-common embed,.tribe-common iframe,.tribe-common video{max-height:100%;max-width:100%}.tribe-theme-avada input[type=text]{margin:0}.tribe-theme-divi .entry-content .tribe-common table,.tribe-theme-divibody.et-pb-preview #main-content .container .tribe-common table{border:0;margin:0}.tribe-theme-divi .entry-content .tribe-common td,.tribe-theme-divibody.et-pb-preview #main-content .container .tribe-common td{border:0}.tribe-theme-divi #content-area .tribe-common td,.tribe-theme-divi #content-area .tribe-common th,.tribe-theme-divi #content-area .tribe-common tr,.tribe-theme-divi #left-area .tribe-common ul{padding:0}#top .main_color .tribe-common button[disabled],#top.tribe-theme-enfold .tribe-common button[disabled]{cursor:default}#top .main_color .tribe-common form,#top .main_color .tribe-common input,#top.tribe-theme-enfold .tribe-common form,#top.tribe-theme-enfold .tribe-common input{margin:0}.entry-content-wrapper .tribe-common li,.entry-content .tribe-common ol,.entry-content .tribe-common ul,.tribe-theme-genesis .tribe-common ol,.tribe-theme-genesis .tribe-common ul{margin:0;padding:0}.tribe-theme-twentynineteen .tribe-common svg{fill:none}.tribe-theme-twentyseventeen .tribe-common div.tribe-dialog{z-index:5!important}.tribe-common .tribe-common-form-control-checkbox,.tribe-common .tribe-common-form-control-radio{align-items:flex-start;display:flex}.tribe-common .tribe-common-form-control-checkbox__label,.tribe-common .tribe-common-form-control-radio__label{cursor:pointer;margin-left:15px}.tribe-common .tribe-common-form-control-checkbox__input,.tribe-common .tribe-common-form-control-radio__input{cursor:pointer;flex:none;margin:1px 0 0}#top .main_color .tribe-common .tribe-common-form-control-checkbox__input,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-checkbox__input{margin:1px 0 0}.tribe-theme-twentytwenty .tribe-common .tribe-common-form-control-checkbox__input{top:0}.tribe-theme-twentytwentyone .tribe-common .tribe-common-form-control-checkbox__input:checked:after{border:none}.tribe-theme-twentytwentyone .tribe-common .tribe-common-form-control-radio__input:checked:after{background-color:transparent}.tribe-common .tribe-common-form-control-checkbox-radio-group>*{margin-bottom:15px}.tribe-common .tribe-common-form-control-checkbox-radio-group>:last-child{margin-bottom:0}.tribe-common .tribe-common-form-control-slider__input{cursor:pointer;display:inline-block;margin:0;padding:0;vertical-align:middle;width:120px}.tribe-common .tribe-common-form-control-slider__label{cursor:pointer;display:inline-block;margin-left:11px;vertical-align:middle}.tribe-common .tribe-common-form-control-slider--vertical .tribe-common-form-control-slider__label{display:block;margin:0 0 6px}.tribe-common .tribe-common-form-control-text__label{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.tribe-common .tribe-common-form-control-text__input{height:auto;padding:var(--tec-spacer-2) var(--tec-spacer-6) var(--tec-spacer-2) 0;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-form-control-text__input{padding:var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-8)}#top .main_color .tribe-common .tribe-common-form-control-text__input,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-text__input{padding:var(--tec-spacer-2) var(--tec-spacer-6) var(--tec-spacer-2) 0;width:100%}#top .main_color .tribe-common.tribe-common--breakpoint-medium .tribe-common-form-control-text__input,#top.tribe-theme-enfold .tribe-common.tribe-common--breakpoint-medium .tribe-common-form-control-text__input{padding:var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-8)}.tribe-common .tribe-common-form-control-toggle__input,.tribe-common .tribe-common-form-control-toggle__label{cursor:pointer;display:inline-block;vertical-align:middle}.tribe-common .tribe-common-form-control-toggle__label{margin-left:11px}.tribe-common .tribe-common-form-control-toggle--vertical .tribe-common-form-control-toggle__label{display:block;margin:0 0 6px}#top .main_color .tribe-common .tribe-common-form-control-toggle__input,#top.tribe-theme-enfold .tribe-common .tribe-common-form-control-toggle__input{display:inline-block;margin:5px 0}.tribe-common .tribe-common-g-col{min-width:0;width:100%}.tribe-common .tribe-common-g-row{display:flex;flex-wrap:wrap}.tribe-common .tribe-common-g-row--gutters{margin-left:var(--tec-grid-gutter-small-half-negative);margin-right:var(--tec-grid-gutter-small-half-negative)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-g-row--gutters{margin-left:var(--tec-grid-gutter-half-negative);margin-right:var(--tec-grid-gutter-half-negative)}.tribe-common .tribe-common-g-row--gutters>.tribe-common-g-col{padding-left:var(--tec-grid-gutter-small-half);padding-right:var(--tec-grid-gutter-small-half)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-g-row--gutters>.tribe-common-g-col{padding-left:var(--tec-grid-gutter-half);padding-right:var(--tec-grid-gutter-half)}.tribe-theme-twentynineteen .tribe-common .entry.tribe-common-g-row--gutters{margin-left:var(--tec-grid-gutter-small-half-negative);margin-right:var(--tec-grid-gutter-small-half-negative);padding:0}.tribe-theme-twentynineteen .tribe-common.tribe-common--breakpoint-medium .entry.tribe-common-g-row--gutters{margin-left:var(--tec-grid-gutter-half-negative);margin-right:var(--tec-grid-gutter-half-negative)}.tribe-theme-twentynineteen .tribe-common .tribe-common-g-row--gutters>.entry.tribe-common-g-col{margin:0;padding-left:var(--tec-grid-gutter-small-half);padding-right:var(--tec-grid-gutter-small-half)}.tribe-theme-twentynineteen .tribe-common.tribe-common--breakpoint-medium .tribe-common-g-row--gutters>.entry.tribe-common-g-col{padding-left:var(--tec-grid-gutter-half);padding-right:var(--tec-grid-gutter-half)}.tribe-common a{cursor:pointer}.tribe-theme-divi #left-area .tribe-common ul,.tribe-theme-divi .entry-content .tribe-common ul,body.et-pb-preview.tribe-theme-divi #main-content .container .tribe-common ul{list-style-type:none;padding:0}.entry-content .tribe-common ol>li,.entry-content .tribe-common ul>li{list-style-type:none}.tribe-common button{padding:0}.tribe-common .tribe-common-l-container{margin-left:auto;margin-right:auto;max-width:var(--tec-grid-width);padding-left:var(--tec-grid-gutter-page-small);padding-right:var(--tec-grid-gutter-page-small);width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-l-container{padding-left:var(--tec-grid-gutter-page);padding-right:var(--tec-grid-gutter-page)}.tribe-common .tribe-common-a11y-hidden{display:none!important;visibility:hidden}.tribe-common .tribe-common-a11y-visual-hide{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.tribe-common .tribe-common-a11y-visual-show{clip:auto;height:auto;margin:0;position:static;width:auto}.tribe-common .tribe-common-c-btn-border,.tribe-common a.tribe-common-c-btn-border{padding:11px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn-border,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn-border{width:auto}.tribe-common .tribe-common-c-btn-border-small,.tribe-common a.tribe-common-c-btn-border-small{padding:14px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn-border-small,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn-border-small{padding:6px 15px;width:auto}.tribe-common .tribe-common-c-btn-icon:before{background-repeat:no-repeat;background-size:contain;content:"";display:block}.tribe-common .tribe-common-c-btn-icon--caret-left .tribe-common-c-btn-icon__icon-svg,.tribe-common .tribe-common-c-btn-icon--caret-right .tribe-common-c-btn-icon__icon-svg{width:11px}.tribe-common .tribe-common-c-btn-icon--caret-left .tribe-common-c-btn-icon__icon-svg path,.tribe-common .tribe-common-c-btn-icon--caret-right .tribe-common-c-btn-icon__icon-svg path{fill:currentColor}.tribe-common .tribe-common-c-btn,.tribe-common a.tribe-common-c-btn{padding:11px 20px;width:100%}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-btn,.tribe-common--breakpoint-medium.tribe-common a.tribe-common-c-btn{width:auto}.tribe-common .tribe-common-c-image{display:block;height:auto;margin-left:auto;margin-right:auto;width:100%}.tribe-common .tribe-common-c-image--bg{position:relative}.tribe-common .tribe-common-c-image__bg{background:50% no-repeat;background-size:cover;bottom:0;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.tribe-common .tribe-common-c-loader{display:flex;padding-top:calc(var(--tec-spacer-11)*3)}.tribe-common--breakpoint-medium.tribe-common .tribe-common-c-loader{padding-top:calc(var(--tec-spacer-13)*3)}.tribe-common .tribe-common-c-loader__dot{width:15px}.tribe-common .tribe-common-c-loader__dot:not(:first-of-type){margin-left:8px}.tribe-common .tribe-common-c-loader__dot circle{fill:currentColor}.tribe-common .tribe-common-c-svgicon--featured{width:8px}.tribe-common .tribe-common-c-svgicon--recurring{width:12px}.tribe-common .tribe-common-c-svgicon--search{width:16px}.tribe-common .tribe-common-c-svgicon--location{width:10px}.tribe-common .tribe-common-c-svgicon--day,.tribe-common .tribe-common-c-svgicon--map,.tribe-common .tribe-common-c-svgicon--month,.tribe-common .tribe-common-c-svgicon--photo,.tribe-common .tribe-common-c-svgicon--week{height:100%;width:100%}.tribe-common .tribe-common-c-svgicon--close-alt path,.tribe-common .tribe-common-c-svgicon--close path{stroke:currentColor}.tribe-common .tribe-common-c-svgicon--hybrid circle,.tribe-common .tribe-common-c-svgicon--mail,.tribe-common .tribe-common-c-svgicon--map-pin,.tribe-common .tribe-common-c-svgicon--messages-not-found g,.tribe-common .tribe-common-c-svgicon--no-map,.tribe-common .tribe-common-c-svgicon--phone,.tribe-common .tribe-common-c-svgicon--virtual g,.tribe-common .tribe-common-c-svgicon--website{fill:none}.tribe-common .tribe-common-c-svgicon--messages-not-found{width:22px}.tribe-common .tribe-common-c-svgicon--messages-not-found path{stroke:currentColor}.tribe-common .tribe-common-c-svgicon--error{width:18px}.tribe-common .tribe-common-c-svgicon--error g,.tribe-common .tribe-common-c-svgicon--reset path{fill:none}.tribe-common .tribe-common-c-svgicon__svg-fill{fill:currentColor}.tribe-common .tribe-common-c-svgicon__svg-stroke{stroke:currentColor}
common/src/resources/css/customizer-controls.min.css CHANGED
@@ -1 +1 @@
1
- :root{--tec-grid-gutter:48px;--tec-grid-gutter-negative:calc(var(--tec-grid-gutter)*-1);--tec-grid-gutter-half:calc(var(--tec-grid-gutter)/2);--tec-grid-gutter-half-negative:calc(var(--tec-grid-gutter-half)*-1);--tec-grid-gutter-small:42px;--tec-grid-gutter-small-negative:calc(var(--tec-grid-gutter-small)*-1);--tec-grid-gutter-small-half:calc(var(--tec-grid-gutter-small)/2);--tec-grid-gutter-small-half-negative:calc(var(--tec-grid-gutter-small-half)*-1);--tec-grid-gutter-page:42px;--tec-grid-gutter-page-small:19.5px;--tec-grid-width-default:1176px;--tec-grid-width-min:320px;--tec-grid-width:calc(var(--tec-grid-width-default) + var(--tec-grid-gutter-page)*2);--tec-grid-width-1-of-2:50%;--tec-grid-width-1-of-3:33.333%;--tec-grid-width-1-of-4:25%;--tec-grid-width-1-of-5:20%;--tec-grid-width-1-of-7:14.285%;--tec-grid-width-1-of-8:12.5%;--tec-grid-width-1-of-9:11.111%;--grid-gutter:var(--tec-grid-gutter);--grid-gutter-negative:var(--tec-grid-gutter-negative);--grid-gutter-half:var(--tec-grid-gutter-half);--grid-gutter-half-negative:var(--tec-grid-gutter-half-negative);--grid-gutter-small:var(--tec-grid-gutter-small);--grid-gutter-small-negative:var(--tec-grid-gutter-small-negative);--grid-gutter-small-half:var(--tec-grid-gutter-small-half);--grid-gutter-small-half-negative:var(--tec-grid-gutter-small-half-negative);--grid-gutter-page:var(--tec-grid-gutter-page);--grid-gutter-page-small:var(--tec-grid-gutter-page-small);--grid-width-default:var(--tec-grid-width-default);--grid-width-min:var(--tec-grid-width-min);--grid-width:var(--tec-grid-width);--grid-width-1-of-2:var(--tec-grid-width-1-of-2);--grid-width-1-of-3:var(--tec-grid-width-1-of-3);--grid-width-1-of-4:var(--tec-grid-width-1-of-4);--grid-width-1-of-5:var(--tec-grid-width-1-of-5);--grid-width-1-of-7:var(--tec-grid-width-1-of-7);--grid-width-1-of-8:var(--tec-grid-width-1-of-8);--grid-width-1-of-9:var(--tec-grid-width-1-of-9);--tec-spacer-0:4px;--tec-spacer-1:8px;--tec-spacer-2:12px;--tec-spacer-3:16px;--tec-spacer-4:20px;--tec-spacer-5:24px;--tec-spacer-6:28px;--tec-spacer-7:32px;--tec-spacer-8:40px;--tec-spacer-9:48px;--tec-spacer-10:56px;--tec-spacer-11:64px;--tec-spacer-12:80px;--tec-spacer-13:96px;--tec-spacer-14:160px;--spacer-0:var(--tec-spacer-0);--spacer-1:var(--tec-spacer-1);--spacer-2:var(--tec-spacer-2);--spacer-3:var(--tec-spacer-3);--spacer-4:var(--tec-spacer-4);--spacer-5:var(--tec-spacer-5);--spacer-6:var(--tec-spacer-6);--spacer-7:var(--tec-spacer-7);--spacer-8:var(--tec-spacer-8);--spacer-9:var(--tec-spacer-9);--spacer-10:var(--tec-spacer-10);--spacer-11:var(--tec-spacer-11);--spacer-12:var(--tec-spacer-12);--spacer-13:var(--tec-spacer-13);--spacer-14:var(--tec-spacer-14);--tec-z-index-spinner-container:100;--tec-z-index-views-selector:30;--tec-z-index-dropdown:30;--tec-z-index-events-bar-button:20;--tec-z-index-search:10;--tec-z-index-filters:9;--tec-z-index-scroller:7;--tec-z-index-week-event-hover:5;--tec-z-index-map-event-hover:5;--tec-z-index-map-event-hover-actions:6;--tec-z-index-multiday-event:5;--tec-z-index-multiday-event-bar:2;--z-index-spinner-container:var(--tec-z-index-spinner-container);--z-index-views-selector:var(--tec-z-index-views-selector);--z-index-dropdown:var(--tec-z-index-dropdown);--z-index-events-bar-button:var(--tec-z-index-events-bar-button);--z-index-search:var(--tec-z-index-search);--z-index-filters:var(--tec-z-index-filters);--z-index-scroller:var(--tec-z-index-scroller);--z-index-week-event-hover:var(--tec-z-index-week-event-hover);--z-index-map-event-hover:var(--tec-z-index-map-event-hover);--z-index-map-event-hover-actions:var(--tec-z-index-map-event-hover-actions);--z-index-multiday-event:var(--tec-z-index-multiday-event);--z-index-multiday-event-bar:var(--tec-z-index-multiday-event-bar);--tec-color-text-primary:#141827;--tec-color-text-primary-light:rgba(20,24,39,.62);--tec-color-text-secondary:#5d5d5d;--tec-color-text-disabled:#d5d5d5;--tec-color-text-events-title:var(--tec-color-text-primary);--tec-color-text-event-title:var(--tec-color-text-events-title);--tec-color-text-event-date:var(--tec-color-text-primary);--tec-color-text-secondary-event-date:var(--tec-color-text-secondary);--tec-color-icon-primary:#5d5d5d;--tec-color-icon-primary-alt:#757575;--tec-color-icon-secondary:#bababa;--tec-color-icon-active:#141827;--tec-color-icon-disabled:#d5d5d5;--tec-color-icon-focus:#334aff;--tec-color-icon-error:#da394d;--tec-color-event-icon:#141827;--tec-color-event-icon-hover:#334aff;--tec-color-accent-primary:#334aff;--tec-color-accent-primary-hover:rgba(51,74,255,.8);--tec-color-accent-primary-active:rgba(51,74,255,.9);--tec-color-accent-primary-background:rgba(51,74,255,.07);--tec-color-accent-secondary:#141827;--tec-color-accent-secondary-hover:rgba(20,24,39,.8);--tec-color-accent-secondary-active:rgba(20,24,39,.9);--tec-color-accent-secondary-background:rgba(20,24,39,.07);--tec-color-button-primary:var(--tec-color-accent-primary);--tec-color-button-primary-hover:var(--tec-color-accent-primary-hover);--tec-color-button-primary-active:var(--tec-color-accent-primary-active);--tec-color-button-primary-background:var(--tec-color-accent-primary-background);--tec-color-button-secondary:var(--tec-color-accent-secondary);--tec-color-button-secondary-hover:var(--tec-color-accent-secondary-hover);--tec-color-button-secondary-active:var(--tec-color-accent-secondary-active);--tec-color-button-secondary-background:var(--tec-color-accent-secondary-background);--tec-color-link-primary:var(--tec-color-text-primary);--tec-color-link-accent-hover:rgba(51,74,255,.8);--tec-color-border-default:#d5d5d5;--tec-color-border-secondary:#e4e4e4;--tec-color-border-tertiary:#7d7d7d;--tec-color-border-hover:#5d5d5d;--tec-color-border-active:#141827;--tec-color-background:#fff;--tec-color-background-events:transparent;--tec-color-background-transparent:hsla(0,0%,100%,.6);--tec-color-background-secondary:#f7f6f6;--tec-color-background-messages:rgba(20,24,39,.07);--tec-color-background-secondary-hover:#f0eeee;--tec-color-background-error:rgba(218,57,77,.08);--tec-color-box-shadow:rgba(0,0,0,.14);--tec-color-box-shadow-secondary:rgba(0,0,0,.1);--tec-color-scroll-track:rgba(0,0,0,.25);--tec-color-scroll-bar:rgba(0,0,0,.5);--tec-color-background-primary-multiday:rgba(51,74,255,.24);--tec-color-background-primary-multiday-hover:rgba(51,74,255,.34);--tec-color-background-secondary-multiday:rgba(20,24,39,.24);--tec-color-background-secondary-multiday-hover:rgba(20,24,39,.34);--tec-color-accent-primary-week-event:rgba(51,74,255,.1);--tec-color-accent-primary-week-event-hover:rgba(51,74,255,.2);--tec-color-accent-primary-week-event-featured:rgba(51,74,255,.04);--tec-color-accent-primary-week-event-featured-hover:rgba(51,74,255,.14);--tec-color-background-secondary-datepicker:var(--tec-color-background-secondary);--tec-color-accent-primary-background-datepicker:var(--tec-color-accent-primary-background);--color-text-primary:var(--tec-color-text-primary);--color-text-primary-light:var(--tec-color-text-primary-light);--color-text-secondary:var(--tec-color-text-secondary);--color-text-disabled:var(--tec-color-text-disabled);--color-icon-primary:var(--tec-color-icon-primary);--color-icon-primary-alt:var(--tec-color-icon-primary);--color-icon-secondary:var(--tec-color-icon-secondary);--color-icon-active:var(--tec-color-icon-active);--color-icon-disabled:var(--tec-color-icon-disabled);--color-icon-focus:var(--tec-color-icon-focus);--color-icon-error:var(--tec-color-icon-error);--color-accent-primary:var(--tec-color-accent-primary);--color-accent-primary-hover:var(--tec-color-accent-primary-hover);--color-accent-primary-active:var(--tec-color-accent-primary-active);--color-accent-primary-background:var(--tec-color-accent-primary-background);--color-accent-primary-multiday:var(--tec-color-accent-primary-multiday);--color-accent-primary-multiday-hover:var(--tec-color-accent-primary-multiday-hover);--color-accent-primary-week-event:var(--tec-color-accent-primary-week-event);--color-accent-primary-week-event-hover:var(--tec-color-accent-primary-week-event-hover);--color-accent-primary-week-event-featured:var(--tec-color-accent-primary-week-event-featured);--color-accent-primary-week-event-featured-hover:var(--tec-color-accent-primary-week-event-featured-hover);--color-accent-secondary:var(--tec-color-accent-secondary);--color-accent-secondary-hover:var(--tec-color-accent-secondary-hover);--color-accent-secondary-active:var(--tec-color-accent-secondary-active);--color-accent-secondary-background:var(--tec-color-accent-secondary-background);--color-border-default:var(--tec-color-border-default);--color-border-secondary:var(--tec-color-border-secondary);--color-border-tertiary:var(--tec-color-border-tertiary);--color-border-hover:var(--tec-color-border-hover);--color-border-active:var(--tec-color-border-active);--color-background:var(--tec-color-background);--color-background-transparent:var(--tec-color-background-transparent);--color-background-secondary:var(--tec-color-background-secondary);--color-background-messages:var(--tec-color-background-messages);--color-background-secondary-hover:var(--tec-color-background-secondary-hover);--color-background-error:var(--tec-color-icon-error);--color-box-shadow:var(--tec-color-box-shadow);--color-box-shadow-secondary:var(--tec-color-box-shadow-secondary);--color-scroll-track:var(--tec-color-scroll-track);--color-scroll-bar:var(--tec-color-scroll-bar);--tec-border-radius-default:4px;--tec-border-width-week-event:2px;--border-radius-default:var(--tec-border-radius-default);--border-width-week-event:var(--tec-border-width-week-event);--tec-box-shadow-default:0 2px 5px 0 var(--tec-color-box-shadow);--tec-box-shadow-tooltip:0 2px 12px 0 var(--tec-color-box-shadow);--tec-box-shadow-card:0 1px 6px 2px var(--tec-color-box-shadow);--tec-box-shadow-multiday:16px 6px 6px -2px var(--tec-color-box-shadow-secondary);--box-shadow-default:var(--tec-box-shadow-default);--box-shadow-tooltip:var(--tec-box-shadow-tooltip);--box-shadow-card:var(--tec-box-shadow-card);--box-shadow-multiday:var(--tec-box-shadow-multiday);--tec-form-color-background:var(--tec-color-background);--tec-form-color-border-default:var(--tec-color-text-primary);--tec-form-color-border-active:var(--tec-color-accent-secondary);--tec-form-color-border-secondary:var(--tec-color-border-tertiary);--tec-form-color-accent-primary:var(--tec-color-accent-primary);--tec-form-box-shadow-default:var(--tec-box-shadow-default);--form-color-background:var(--tec-form-color-background);--form-color-border-default:var(--tec-form-color-border-default);--form-color-border-active:var(--tec-form-color-border-active);--form-color-border-secondary:var(--tec-form-color-border-secondary);--form-color-accent-primary:var(--tec-form-color-accent-primary);--form-box-shadow-default:var(--tec-form-box-shadow-default);--tec-opacity-background:0.07;--tec-opacity-select-highlighted:0.3;--tec-opacity-icon-hover:0.8;--tec-opacity-icon-active:0.9;--tec-opacity-default:1;--opacity-background:var(--tec-opacity-background);--opacity-select-highlighted:var(--tec-opacity-select-highlighted);--opacity-icon-hover:var(--tec-opacity-icon-hover);--opacity-icon-active:var(--tec-opacity-icon-active);--opacity-default:var(--tec-opacity-default);--tec-transition:all 0.2s ease;--tec-transition-background-color:background-color 0.2s ease;--tec-transition-color-border-color:color 0.2s ease,border-color 0.2s ease;--tec-transition-transform:transform 0.2s ease;--tec-transition-border-color:border-color 0.2s ease;--tec-transition-color:color 0.2s ease;--tec-transition-opacity:opacity 0.2s ease;--transition:var(--tec-transition);--transition-background-color:var(--tec-transition-background-color);--transition-color-border-color:var(--tec-transition-color-border-color);--transition-transform:var(--tec-transition-transform);--transition-border-color:var(--tec-transition-border-color);--transition-color:var(--tec-transition-color);--transition-opacity:var(--tec-transition-opacity);--tec-font-family-sans-serif:"Helvetica Neue",Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;--tec-font-weight-regular:400;--tec-font-weight-bold:700;--tec-font-size-0:11px;--tec-font-size-1:12px;--tec-font-size-2:14px;--tec-font-size-3:16px;--tec-font-size-4:18px;--tec-font-size-5:20px;--tec-font-size-6:22px;--tec-font-size-7:24px;--tec-font-size-8:28px;--tec-font-size-9:32px;--tec-font-size-10:42px;--tec-line-height-0:1.38;--tec-line-height-1:1.42;--tec-line-height-2:1.5;--tec-line-height-3:1.62;--font-family-sans-serif:var(--tec-font-family-sans-serif);--font-family-base:var(--tec-font-family-sans-serif);--font-weight-regular:var(--tec-font-weight-regular);--font-weight-bold:var(--tec-font-weight-bold);--font-size-0:var(--tec-font-size-0);--font-size-1:var(--tec-font-size-1);--font-size-2:var(--tec-font-size-2);--font-size-3:var(--tec-font-size-3);--font-size-4:var(--tec-font-size-4);--font-size-5:var(--tec-font-size-5);--font-size-6:var(--tec-font-size-6);--font-size-7:var(--tec-font-size-7);--font-size-8:var(--tec-font-size-8);--font-size-9:var(--tec-font-size-9);--font-size-10:var(--tec-font-size-10);--line-height-0:var(--tec-line-height-0);--line-height-1:var(--tec-line-height-1);--line-height-2:var(--tec-line-height-2);--line-height-3:var(--tec-line-height-3)}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control-heading{font-size:20px;font-size:var(--tec-font-size-5);font-weight:400;line-height:1.62;line-height:var(--tec-line-height-3);margin-bottom:0;margin-top:0}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control-heading-description{margin-bottom:0}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control-description{font-style:normal;margin-bottom:12px;margin-bottom:var(--tec-spacer-2)}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control-title{margin-bottom:0}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control-title~.customize-control-content{margin-top:8px;margin-top:var(--tec-spacer-1)}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control-title~.customize-control-description{margin-bottom:3px;margin-top:4px;margin-top:var(--tec-spacer-0)}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control .customize-inside-control-row{padding:3px 0}.wp-customizer [id^=customize-control-tribe_customizer] .button.wp-color-result{border-color:#141827;border-color:var(--tec-color-text-primary)}.wp-customizer [id^=customize-control-tribe_customizer] .button.wp-color-result:active,.wp-customizer [id^=customize-control-tribe_customizer] .button.wp-color-result:focus,.wp-customizer [id^=customize-control-tribe_customizer] .button.wp-color-result:hover{border-color:#141827;border-color:var(--tec-color-text-primary);box-shadow:0 0 0 .75px rgba(20,24,39,.5)}.wp-customizer [id^=customize-control-tribe_customizer][id$=_choice].customize-control-radio+[id^=customize-control-tribe_customizer][id$=_color]{margin-top:-18px}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:1px solid #d5d5d5;border:1px solid var(--tec-color-border-default);border-radius:9px;width:calc(100% - 24px)}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider.focus-visible,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider:active,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider:focus,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider:focus-visible{box-shadow:0 0 0 2px #334aff;box-shadow:0 0 0 2px var(--tec-color-accent-primary);outline:none}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-moz-range-track{background-color:#fff;background-color:var(--tec-color-background);border:0;border-radius:3px;cursor:pointer;height:3px;width:100%}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-webkit-slider-runnable-track{background-color:#fff;border:0;border-radius:3px;cursor:pointer;height:3px;width:100%}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-ms-track{background-color:#fff;background-color:var(--tec-color-background);border:0;border-radius:3px;cursor:pointer;height:3px;width:100%}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-moz-range-progress{background-color:#334aff;background-color:var(--tec-color-accent-primary);border-radius:3px;height:3px}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-webkit-progress-value{background-color:#334aff;background-color:var(--tec-color-accent-primary)}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-ms-fill-lower{background-color:#334aff;background-color:var(--tec-color-accent-primary)}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-moz-range-thumb{background-color:#fff;background-color:var(--tec-color-background);border:5px solid #334aff;border:5px solid var(--tec-color-accent-primary);border-radius:50%;cursor:pointer;height:5px;width:5px}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-moz-range-thumb:active,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-moz-range-thumb:focus{border-color:rgba(51,74,255,.8);border-color:var(--tec-color-link-accent-hover)}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;background-color:#fff;background-color:var(--tec-color-background);border:5px solid #334aff;border:5px solid var(--tec-color-accent-primary);border-radius:50%;cursor:pointer;height:16px;margin-top:-7px;width:16px}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-webkit-slider-thumb:active,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-webkit-slider-thumb:focus{border-color:rgba(51,74,255,.8);border-color:var(--tec-color-link-accent-hover)}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-ms-thumb{background-color:#fff;background-color:var(--tec-color-background);border:5px solid #334aff;border:5px solid var(--tec-color-accent-primary);border-radius:50%;cursor:pointer;height:5px;width:5px}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-ms-thumb:active,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-ms-thumb:focus{border-color:rgba(51,74,255,.8);border-color:var(--tec-color-link-accent-hover)}.wp-customizer [id^=customize-control-tribe_customizer] .tec-range-slider-datalist{display:flex;justify-content:space-between;width:calc(100% - 24px)}.wp-customizer [id^=customize-control-tribe_customizer] .tec-range-slider-option{text-align:center}.wp-customizer [id^=customize-control-tribe_customizer] .tec-range-slider-option:first-child{text-align:left}.wp-customizer [id^=customize-control-tribe_customizer] .tec-range-slider-option:last-child{text-align:right}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .customize-inside-control-row{display:flex;justify-content:space-between;margin-left:0;padding-left:0}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label{align-items:center;display:inline-flex;margin:5px 0}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label.focus-visible,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:active,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:focus,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:focus-visible{outline:none}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label.focus-visible .tec-switch-toggle,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:active .tec-switch-toggle,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:focus-visible .tec-switch-toggle,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:focus .tec-switch-toggle{box-shadow:0 0 0 2px #334aff;box-shadow:0 0 0 2px var(--tec-color-accent-primary)}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-toggle{border-radius:12px;cursor:pointer;font-size:16px;padding:2px;position:relative}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-toggle:after,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-toggle:before{content:"";display:block;margin:0;transition:all .1s cubic-bezier(.4,0,.2,1)}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-toggle:before{background-color:#f7f6f6;background-color:var(--tec-color-background-secondary);border:1px solid #bababa;border:1px solid var(--tec-color-icon-secondary);border-radius:.55em;height:1.125em;opacity:.6;width:2.75em}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-toggle:after{background-color:#d5d5d5;background-color:var(--tec-color-icon-disabled);border-radius:50%;height:16px;left:3px;position:absolute;top:50%;transform:translateY(-50%);width:16px}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-input:checked+.tec-switch-toggle:before{background-color:#334aff;background-color:var(--tec-color-accent-primary);border-color:rgba(51,74,255,.6);opacity:1}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-input:checked+.tec-switch-toggle:after{background-color:#fff;background-color:var(--tec-color-background);transform:translate(calc(41px - 100%),-50%)}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-input:disabled+.tec-switch-toggle{cursor:not-allowed;filter:grayscale(100%);opacity:.6}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-input:focus+.tec-switch-toggle:before{border-color:#334aff;border-color:var(--tec-color-accent-primary)}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .toggle-label-off{margin-right:4px}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .toggle-label-on{margin-left:4px}.wp-customizer [id^=customize-control-tribe_customizer][id$=_choice].customize-control-toggle+[id^=customize-control-tribe_customizer][id$=_color]{margin-top:-8px}
1
+ .wp-customizer [id^=customize-control-tribe_customizer] .customize-control-heading{font-size:var(--tec-font-size-5);font-weight:400;line-height:var(--tec-line-height-3);margin-bottom:0;margin-top:0}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control-heading-description{margin-bottom:0}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control-description{font-style:normal;margin-bottom:var(--tec-spacer-2)}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control-title{margin-bottom:0}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control-title~.customize-control-content{margin-top:var(--tec-spacer-1)}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control-title~.customize-control-description{margin-bottom:3px;margin-top:var(--tec-spacer-0)}.wp-customizer [id^=customize-control-tribe_customizer] .customize-control .customize-inside-control-row{padding:3px 0}.wp-customizer [id^=customize-control-tribe_customizer] .button.wp-color-result{border-color:var(--tec-color-text-primary)}.wp-customizer [id^=customize-control-tribe_customizer] .button.wp-color-result:active,.wp-customizer [id^=customize-control-tribe_customizer] .button.wp-color-result:focus,.wp-customizer [id^=customize-control-tribe_customizer] .button.wp-color-result:hover{border-color:var(--tec-color-text-primary);box-shadow:0 0 0 .75px rgba(20,24,39,.5)}.wp-customizer [id^=customize-control-tribe_customizer][id$=_choice].customize-control-radio+[id^=customize-control-tribe_customizer][id$=_color]{margin-top:-18px}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;border:1px solid var(--tec-color-border-default);border-radius:9px;width:calc(100% - 24px)}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider.focus-visible,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider:active,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider:focus,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider:focus-visible{box-shadow:0 0 0 2px var(--tec-color-accent-primary);outline:none}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-moz-range-track{background-color:var(--tec-color-background);border:0;border-radius:3px;cursor:pointer;height:3px;width:100%}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-webkit-slider-runnable-track{background-color:#fff;border:0;border-radius:3px;cursor:pointer;height:3px;width:100%}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-ms-track{background-color:var(--tec-color-background);border:0;border-radius:3px;cursor:pointer;height:3px;width:100%}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-moz-range-progress{background-color:var(--tec-color-accent-primary);border-radius:3px;height:3px}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-webkit-progress-value{background-color:var(--tec-color-accent-primary)}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-ms-fill-lower{background-color:var(--tec-color-accent-primary)}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-moz-range-thumb{background-color:var(--tec-color-background);border:5px solid var(--tec-color-accent-primary);border-radius:50%;cursor:pointer;height:5px;width:5px}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-moz-range-thumb:active,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-moz-range-thumb:focus{border-color:var(--tec-color-link-accent-hover)}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;background-color:var(--tec-color-background);border:5px solid var(--tec-color-accent-primary);border-radius:50%;cursor:pointer;height:16px;margin-top:-7px;width:16px}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-webkit-slider-thumb:active,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-webkit-slider-thumb:focus{border-color:var(--tec-color-link-accent-hover)}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-ms-thumb{background-color:var(--tec-color-background);border:5px solid var(--tec-color-accent-primary);border-radius:50%;cursor:pointer;height:5px;width:5px}.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-ms-thumb:active,.wp-customizer [id^=customize-control-tribe_customizer] input[type=range].tec-range-slider::-ms-thumb:focus{border-color:var(--tec-color-link-accent-hover)}.wp-customizer [id^=customize-control-tribe_customizer] .tec-range-slider-datalist{display:flex;justify-content:space-between;width:calc(100% - 24px)}.wp-customizer [id^=customize-control-tribe_customizer] .tec-range-slider-option{text-align:center}.wp-customizer [id^=customize-control-tribe_customizer] .tec-range-slider-option:first-child{text-align:left}.wp-customizer [id^=customize-control-tribe_customizer] .tec-range-slider-option:last-child{text-align:right}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .customize-inside-control-row{display:flex;justify-content:space-between;margin-left:0;padding-left:0}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label{align-items:center;display:inline-flex;margin:5px 0}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label.focus-visible,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:active,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:focus,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:focus-visible{outline:none}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label.focus-visible .tec-switch-toggle,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:active .tec-switch-toggle,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:focus-visible .tec-switch-toggle,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-label:focus .tec-switch-toggle{box-shadow:0 0 0 2px var(--tec-color-accent-primary)}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-toggle{border-radius:12px;cursor:pointer;font-size:16px;padding:2px;position:relative}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-toggle:after,.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-toggle:before{content:"";display:block;margin:0;transition:all .1s cubic-bezier(.4,0,.2,1)}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-toggle:before{background-color:var(--tec-color-background-secondary);border:1px solid var(--tec-color-icon-secondary);border-radius:.55em;height:1.125em;opacity:.6;width:2.75em}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-toggle:after{background-color:var(--tec-color-icon-disabled);border-radius:50%;height:16px;left:3px;position:absolute;top:50%;transform:translateY(-50%);width:16px}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-input:checked+.tec-switch-toggle:before{background-color:var(--tec-color-accent-primary);border-color:rgba(51,74,255,.6);opacity:1}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-input:checked+.tec-switch-toggle:after{background-color:var(--tec-color-background);transform:translate(calc(41px - 100%),-50%)}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-input:disabled+.tec-switch-toggle{cursor:not-allowed;filter:grayscale(100%);opacity:.6}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .tec-switch-input:focus+.tec-switch-toggle:before{border-color:var(--tec-color-accent-primary)}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .toggle-label-off{margin-right:4px}.wp-customizer [id^=customize-control-tribe_customizer].customize-control-toggle .toggle-label-on{margin-left:4px}.wp-customizer [id^=customize-control-tribe_customizer][id$=_choice].customize-control-toggle+[id^=customize-control-tribe_customizer][id$=_color]{margin-top:-8px}
common/src/resources/css/dialog.min.css CHANGED
@@ -1 +1 @@
1
- :root{--tec-grid-gutter:48px;--tec-grid-gutter-negative:calc(var(--tec-grid-gutter)*-1);--tec-grid-gutter-half:calc(var(--tec-grid-gutter)/2);--tec-grid-gutter-half-negative:calc(var(--tec-grid-gutter-half)*-1);--tec-grid-gutter-small:42px;--tec-grid-gutter-small-negative:calc(var(--tec-grid-gutter-small)*-1);--tec-grid-gutter-small-half:calc(var(--tec-grid-gutter-small)/2);--tec-grid-gutter-small-half-negative:calc(var(--tec-grid-gutter-small-half)*-1);--tec-grid-gutter-page:42px;--tec-grid-gutter-page-small:19.5px;--tec-grid-width-default:1176px;--tec-grid-width-min:320px;--tec-grid-width:calc(var(--tec-grid-width-default) + var(--tec-grid-gutter-page)*2);--tec-grid-width-1-of-2:50%;--tec-grid-width-1-of-3:33.333%;--tec-grid-width-1-of-4:25%;--tec-grid-width-1-of-5:20%;--tec-grid-width-1-of-7:14.285%;--tec-grid-width-1-of-8:12.5%;--tec-grid-width-1-of-9:11.111%;--grid-gutter:var(--tec-grid-gutter);--grid-gutter-negative:var(--tec-grid-gutter-negative);--grid-gutter-half:var(--tec-grid-gutter-half);--grid-gutter-half-negative:var(--tec-grid-gutter-half-negative);--grid-gutter-small:var(--tec-grid-gutter-small);--grid-gutter-small-negative:var(--tec-grid-gutter-small-negative);--grid-gutter-small-half:var(--tec-grid-gutter-small-half);--grid-gutter-small-half-negative:var(--tec-grid-gutter-small-half-negative);--grid-gutter-page:var(--tec-grid-gutter-page);--grid-gutter-page-small:var(--tec-grid-gutter-page-small);--grid-width-default:var(--tec-grid-width-default);--grid-width-min:var(--tec-grid-width-min);--grid-width:var(--tec-grid-width);--grid-width-1-of-2:var(--tec-grid-width-1-of-2);--grid-width-1-of-3:var(--tec-grid-width-1-of-3);--grid-width-1-of-4:var(--tec-grid-width-1-of-4);--grid-width-1-of-5:var(--tec-grid-width-1-of-5);--grid-width-1-of-7:var(--tec-grid-width-1-of-7);--grid-width-1-of-8:var(--tec-grid-width-1-of-8);--grid-width-1-of-9:var(--tec-grid-width-1-of-9);--tec-spacer-0:4px;--tec-spacer-1:8px;--tec-spacer-2:12px;--tec-spacer-3:16px;--tec-spacer-4:20px;--tec-spacer-5:24px;--tec-spacer-6:28px;--tec-spacer-7:32px;--tec-spacer-8:40px;--tec-spacer-9:48px;--tec-spacer-10:56px;--tec-spacer-11:64px;--tec-spacer-12:80px;--tec-spacer-13:96px;--tec-spacer-14:160px;--spacer-0:var(--tec-spacer-0);--spacer-1:var(--tec-spacer-1);--spacer-2:var(--tec-spacer-2);--spacer-3:var(--tec-spacer-3);--spacer-4:var(--tec-spacer-4);--spacer-5:var(--tec-spacer-5);--spacer-6:var(--tec-spacer-6);--spacer-7:var(--tec-spacer-7);--spacer-8:var(--tec-spacer-8);--spacer-9:var(--tec-spacer-9);--spacer-10:var(--tec-spacer-10);--spacer-11:var(--tec-spacer-11);--spacer-12:var(--tec-spacer-12);--spacer-13:var(--tec-spacer-13);--spacer-14:var(--tec-spacer-14);--tec-z-index-spinner-container:100;--tec-z-index-views-selector:30;--tec-z-index-dropdown:30;--tec-z-index-events-bar-button:20;--tec-z-index-search:10;--tec-z-index-filters:9;--tec-z-index-scroller:7;--tec-z-index-week-event-hover:5;--tec-z-index-map-event-hover:5;--tec-z-index-map-event-hover-actions:6;--tec-z-index-multiday-event:5;--tec-z-index-multiday-event-bar:2;--z-index-spinner-container:var(--tec-z-index-spinner-container);--z-index-views-selector:var(--tec-z-index-views-selector);--z-index-dropdown:var(--tec-z-index-dropdown);--z-index-events-bar-button:var(--tec-z-index-events-bar-button);--z-index-search:var(--tec-z-index-search);--z-index-filters:var(--tec-z-index-filters);--z-index-scroller:var(--tec-z-index-scroller);--z-index-week-event-hover:var(--tec-z-index-week-event-hover);--z-index-map-event-hover:var(--tec-z-index-map-event-hover);--z-index-map-event-hover-actions:var(--tec-z-index-map-event-hover-actions);--z-index-multiday-event:var(--tec-z-index-multiday-event);--z-index-multiday-event-bar:var(--tec-z-index-multiday-event-bar);--tec-color-text-primary:#141827;--tec-color-text-primary-light:rgba(20,24,39,.62);--tec-color-text-secondary:#5d5d5d;--tec-color-text-disabled:#d5d5d5;--tec-color-text-events-title:var(--tec-color-text-primary);--tec-color-text-event-title:var(--tec-color-text-events-title);--tec-color-text-event-date:var(--tec-color-text-primary);--tec-color-text-secondary-event-date:var(--tec-color-text-secondary);--tec-color-icon-primary:#5d5d5d;--tec-color-icon-primary-alt:#757575;--tec-color-icon-secondary:#bababa;--tec-color-icon-active:#141827;--tec-color-icon-disabled:#d5d5d5;--tec-color-icon-focus:#334aff;--tec-color-icon-error:#da394d;--tec-color-event-icon:#141827;--tec-color-event-icon-hover:#334aff;--tec-color-accent-primary:#334aff;--tec-color-accent-primary-hover:rgba(51,74,255,.8);--tec-color-accent-primary-active:rgba(51,74,255,.9);--tec-color-accent-primary-background:rgba(51,74,255,.07);--tec-color-accent-secondary:#141827;--tec-color-accent-secondary-hover:rgba(20,24,39,.8);--tec-color-accent-secondary-active:rgba(20,24,39,.9);--tec-color-accent-secondary-background:rgba(20,24,39,.07);--tec-color-button-primary:var(--tec-color-accent-primary);--tec-color-button-primary-hover:var(--tec-color-accent-primary-hover);--tec-color-button-primary-active:var(--tec-color-accent-primary-active);--tec-color-button-primary-background:var(--tec-color-accent-primary-background);--tec-color-button-secondary:var(--tec-color-accent-secondary);--tec-color-button-secondary-hover:var(--tec-color-accent-secondary-hover);--tec-color-button-secondary-active:var(--tec-color-accent-secondary-active);--tec-color-button-secondary-background:var(--tec-color-accent-secondary-background);--tec-color-link-primary:var(--tec-color-text-primary);--tec-color-link-accent-hover:rgba(51,74,255,.8);--tec-color-border-default:#d5d5d5;--tec-color-border-secondary:#e4e4e4;--tec-color-border-tertiary:#7d7d7d;--tec-color-border-hover:#5d5d5d;--tec-color-border-active:#141827;--tec-color-background:#fff;--tec-color-background-events:transparent;--tec-color-background-transparent:hsla(0,0%,100%,.6);--tec-color-background-secondary:#f7f6f6;--tec-color-background-messages:rgba(20,24,39,.07);--tec-color-background-secondary-hover:#f0eeee;--tec-color-background-error:rgba(218,57,77,.08);--tec-color-box-shadow:rgba(0,0,0,.14);--tec-color-box-shadow-secondary:rgba(0,0,0,.1);--tec-color-scroll-track:rgba(0,0,0,.25);--tec-color-scroll-bar:rgba(0,0,0,.5);--tec-color-background-primary-multiday:rgba(51,74,255,.24);--tec-color-background-primary-multiday-hover:rgba(51,74,255,.34);--tec-color-background-secondary-multiday:rgba(20,24,39,.24);--tec-color-background-secondary-multiday-hover:rgba(20,24,39,.34);--tec-color-accent-primary-week-event:rgba(51,74,255,.1);--tec-color-accent-primary-week-event-hover:rgba(51,74,255,.2);--tec-color-accent-primary-week-event-featured:rgba(51,74,255,.04);--tec-color-accent-primary-week-event-featured-hover:rgba(51,74,255,.14);--tec-color-background-secondary-datepicker:var(--tec-color-background-secondary);--tec-color-accent-primary-background-datepicker:var(--tec-color-accent-primary-background);--color-text-primary:var(--tec-color-text-primary);--color-text-primary-light:var(--tec-color-text-primary-light);--color-text-secondary:var(--tec-color-text-secondary);--color-text-disabled:var(--tec-color-text-disabled);--color-icon-primary:var(--tec-color-icon-primary);--color-icon-primary-alt:var(--tec-color-icon-primary);--color-icon-secondary:var(--tec-color-icon-secondary);--color-icon-active:var(--tec-color-icon-active);--color-icon-disabled:var(--tec-color-icon-disabled);--color-icon-focus:var(--tec-color-icon-focus);--color-icon-error:var(--tec-color-icon-error);--color-accent-primary:var(--tec-color-accent-primary);--color-accent-primary-hover:var(--tec-color-accent-primary-hover);--color-accent-primary-active:var(--tec-color-accent-primary-active);--color-accent-primary-background:var(--tec-color-accent-primary-background);--color-accent-primary-multiday:var(--tec-color-accent-primary-multiday);--color-accent-primary-multiday-hover:var(--tec-color-accent-primary-multiday-hover);--color-accent-primary-week-event:var(--tec-color-accent-primary-week-event);--color-accent-primary-week-event-hover:var(--tec-color-accent-primary-week-event-hover);--color-accent-primary-week-event-featured:var(--tec-color-accent-primary-week-event-featured);--color-accent-primary-week-event-featured-hover:var(--tec-color-accent-primary-week-event-featured-hover);--color-accent-secondary:var(--tec-color-accent-secondary);--color-accent-secondary-hover:var(--tec-color-accent-secondary-hover);--color-accent-secondary-active:var(--tec-color-accent-secondary-active);--color-accent-secondary-background:var(--tec-color-accent-secondary-background);--color-border-default:var(--tec-color-border-default);--color-border-secondary:var(--tec-color-border-secondary);--color-border-tertiary:var(--tec-color-border-tertiary);--color-border-hover:var(--tec-color-border-hover);--color-border-active:var(--tec-color-border-active);--color-background:var(--tec-color-background);--color-background-transparent:var(--tec-color-background-transparent);--color-background-secondary:var(--tec-color-background-secondary);--color-background-messages:var(--tec-color-background-messages);--color-background-secondary-hover:var(--tec-color-background-secondary-hover);--color-background-error:var(--tec-color-icon-error);--color-box-shadow:var(--tec-color-box-shadow);--color-box-shadow-secondary:var(--tec-color-box-shadow-secondary);--color-scroll-track:var(--tec-color-scroll-track);--color-scroll-bar:var(--tec-color-scroll-bar);--tec-border-radius-default:4px;--tec-border-width-week-event:2px;--border-radius-default:var(--tec-border-radius-default);--border-width-week-event:var(--tec-border-width-week-event);--tec-box-shadow-default:0 2px 5px 0 var(--tec-color-box-shadow);--tec-box-shadow-tooltip:0 2px 12px 0 var(--tec-color-box-shadow);--tec-box-shadow-card:0 1px 6px 2px var(--tec-color-box-shadow);--tec-box-shadow-multiday:16px 6px 6px -2px var(--tec-color-box-shadow-secondary);--box-shadow-default:var(--tec-box-shadow-default);--box-shadow-tooltip:var(--tec-box-shadow-tooltip);--box-shadow-card:var(--tec-box-shadow-card);--box-shadow-multiday:var(--tec-box-shadow-multiday);--tec-form-color-background:var(--tec-color-background);--tec-form-color-border-default:var(--tec-color-text-primary);--tec-form-color-border-active:var(--tec-color-accent-secondary);--tec-form-color-border-secondary:var(--tec-color-border-tertiary);--tec-form-color-accent-primary:var(--tec-color-accent-primary);--tec-form-box-shadow-default:var(--tec-box-shadow-default);--form-color-background:var(--tec-form-color-background);--form-color-border-default:var(--tec-form-color-border-default);--form-color-border-active:var(--tec-form-color-border-active);--form-color-border-secondary:var(--tec-form-color-border-secondary);--form-color-accent-primary:var(--tec-form-color-accent-primary);--form-box-shadow-default:var(--tec-form-box-shadow-default);--tec-opacity-background:0.07;--tec-opacity-select-highlighted:0.3;--tec-opacity-icon-hover:0.8;--tec-opacity-icon-active:0.9;--tec-opacity-default:1;--opacity-background:var(--tec-opacity-background);--opacity-select-highlighted:var(--tec-opacity-select-highlighted);--opacity-icon-hover:var(--tec-opacity-icon-hover);--opacity-icon-active:var(--tec-opacity-icon-active);--opacity-default:var(--tec-opacity-default);--tec-transition:all 0.2s ease;--tec-transition-background-color:background-color 0.2s ease;--tec-transition-color-border-color:color 0.2s ease,border-color 0.2s ease;--tec-transition-transform:transform 0.2s ease;--tec-transition-border-color:border-color 0.2s ease;--tec-transition-color:color 0.2s ease;--tec-transition-opacity:opacity 0.2s ease;--transition:var(--tec-transition);--transition-background-color:var(--tec-transition-background-color);--transition-color-border-color:var(--tec-transition-color-border-color);--transition-transform:var(--tec-transition-transform);--transition-border-color:var(--tec-transition-border-color);--transition-color:var(--tec-transition-color);--transition-opacity:var(--tec-transition-opacity);--tec-font-family-sans-serif:"Helvetica Neue",Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;--tec-font-weight-regular:400;--tec-font-weight-bold:700;--tec-font-size-0:11px;--tec-font-size-1:12px;--tec-font-size-2:14px;--tec-font-size-3:16px;--tec-font-size-4:18px;--tec-font-size-5:20px;--tec-font-size-6:22px;--tec-font-size-7:24px;--tec-font-size-8:28px;--tec-font-size-9:32px;--tec-font-size-10:42px;--tec-line-height-0:1.38;--tec-line-height-1:1.42;--tec-line-height-2:1.5;--tec-line-height-3:1.62;--font-family-sans-serif:var(--tec-font-family-sans-serif);--font-family-base:var(--tec-font-family-sans-serif);--font-weight-regular:var(--tec-font-weight-regular);--font-weight-bold:var(--tec-font-weight-bold);--font-size-0:var(--tec-font-size-0);--font-size-1:var(--tec-font-size-1);--font-size-2:var(--tec-font-size-2);--font-size-3:var(--tec-font-size-3);--font-size-4:var(--tec-font-size-4);--font-size-5:var(--tec-font-size-5);--font-size-6:var(--tec-font-size-6);--font-size-7:var(--tec-font-size-7);--font-size-8:var(--tec-font-size-8);--font-size-9:var(--tec-font-size-9);--font-size-10:var(--tec-font-size-10);--line-height-0:var(--tec-line-height-0);--line-height-1:var(--tec-line-height-1);--line-height-2:var(--tec-line-height-2);--line-height-3:var(--tec-line-height-3)}.tribe-common .tribe-dialog{--tribe-dialog-background-color:#fff;--tribe-dialog-close-background:#fff;--tribe-dialog-close-border-color:#bababa;--tribe-dialog-close-border-width:1px;--tribe-dialog-close-color:#bababa;--tribe-dialog-close-height:12px;--tribe-dialog-close-height-desktop:16px;--tribe-dialog-overlay-color:transparent;--tribe-modal-overlay-color:rgba(20,24,39,.9);--tribe-dialog-border-radius:4px;--tribe-dialog-padding:16px;--tribe-dialog-padding-top:24px;--tribe-dialog-padding-side:28px}.tribe-common div.tribe-dialog{align-items:center;display:flex;height:100vh;justify-content:center;left:0;position:fixed;top:0;width:100vw;z-index:100}.tribe-common div.tribe-dialog[aria-hidden=true]{display:none}.tribe-common .tribe-dialog__overlay{background-color:var(--tribe-dialog-overlay-color);height:100vh;left:0;opacity:.9;position:fixed;top:0;width:100vw;z-index:100}.tribe-common .tribe-dialog__wrapper{background-color:var(--tribe-dialog-background-color);border-radius:var(--tribe-dialog-border-radius);box-shadow:0 2px 54px 0 var(--tribe-modal-overlay-color);max-height:100vh;max-width:100vw;overflow-y:auto;padding:var(--tribe-dialog-padding);-webkit-perspective:1000;-webkit-transform:translateZ(0);width:800px;z-index:200}.tribe-common .tribe-dialog__wrapper div[role=document]{align-items:flex-end;display:flex;flex-flow:column;justify-content:space-between;position:relative}.tribe-common .tribe-dialog__close-button{background:var(--tribe-dialog-close-background);background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18'%3E%3Cpath d='M16 2L2 16m14 0L2 2' stroke='var(--tec-color-icon-secondary)' fill='none' fill-rule='evenodd' stroke-linecap='square' stroke-width='2'/%3E%3C/svg%3E");background-repeat:no-repeat;background-size:contain;cursor:pointer;display:inline-block;font-size:14px;height:var(--tribe-dialog-close-height);line-height:var(--tribe-dialog-close-height);padding:0;position:absolute;width:var(--tribe-dialog-close-height);z-index:1}.tribe-common .tribe-dialog__close-button:focus,.tribe-common .tribe-dialog__close-button:hover{background:var(--tribe-dialog-close-background);background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18'%3E%3Cpath d='M16 2L2 16m14 0L2 2' stroke='var(--tec-color-icon-primary)' fill='none' fill-rule='evenodd' stroke-linecap='square' stroke-width='2'/%3E%3C/svg%3E");background-size:contain;outline:none}.tribe-common .tribe-dialog__close-button--hidden{display:none}.tribe-common .tribe-dialog__close-button--round{border-radius:50%}.tribe-common .tribe-dialog__close-button--border{border:var(--tribe-dialog-close-border-width) solid var(--tribe-dialog-close-border-color)}.tribe-common h2.tribe-dialog__title{align-self:flex-start;margin:0 0 22px;padding-right:calc(var(--tribe-dialog-close-height) + .5em);padding-top:0}.tribe-common .tribe-dialog__content{color:#141827;font-size:14px;line-height:1.64em;padding-right:calc(var(--tribe-dialog-close-height) + .5em);padding-top:calc(var(--tribe-dialog-close-height) + .5em);width:100%}.tribe-common .tribe-dialog__title+.tribe-dialog__content{padding:0}.tribe-common .tribe-dialog__content p{font-size:14px;font-size:var(--font-size-2)}.tribe-common .tribe-modal__overlay{background-color:var(--tribe-modal-overlay-color)}.tribe-common .tribe-confirm__content{padding-right:0}.tribe-common .tribe-dialog__button_wrap{display:flex;flex-flow:row wrap;justify-content:flex-end;margin-top:1rem}.tribe-common .tribe-dialog__button-cancel,.tribe-common .tribe-dialog__button-continue{margin-left:8px;margin-left:var(--spacer-1);width:auto}#top .main_color .tribe-common div.tribe-dialog,#top.tribe-theme-enfold .tribe-common div.tribe-dialog,.tribe-theme-avada .tribe-common div.tribe-dialog,.tribe-theme-divi .tribe-common div.tribe-dialog{z-index:99999}@media screen and (min-width:768px){.tribe-common .tribe-dialog__wrapper{max-height:calc(100vh - 160px);padding:var(--tribe-dialog-padding-top) var(--tribe-dialog-padding-side)}.tribe-common .tribe-dialog__close-button{height:var(--tribe-dialog-close-height-desktop);line-height:var(--tribe-dialog-close-height-desktop);width:var(--tribe-dialog-close-height-desktop)}}@media screen and (max-width:768px){.tribe-common .tribe-dialog__content:last-of-type{padding-bottom:36px}}
1
+ .tribe-common .tribe-dialog{--tribe-dialog-background-color:#fff;--tribe-dialog-close-background:#fff;--tribe-dialog-close-border-color:#bababa;--tribe-dialog-close-border-width:1px;--tribe-dialog-close-color:#bababa;--tribe-dialog-close-height:12px;--tribe-dialog-close-height-desktop:16px;--tribe-dialog-overlay-color:transparent;--tribe-modal-overlay-color:rgba(20,24,39,.9);--tribe-dialog-border-radius:4px;--tribe-dialog-padding:16px;--tribe-dialog-padding-top:24px;--tribe-dialog-padding-side:28px}.tribe-common div.tribe-dialog{align-items:center;display:flex;height:100vh;justify-content:center;left:0;position:fixed;top:0;width:100vw;z-index:100}.tribe-common div.tribe-dialog[aria-hidden=true]{display:none}.tribe-common .tribe-dialog__overlay{background-color:var(--tribe-dialog-overlay-color);height:100vh;left:0;opacity:.9;position:fixed;top:0;width:100vw;z-index:100}.tribe-common .tribe-dialog__wrapper{background-color:var(--tribe-dialog-background-color);border-radius:var(--tribe-dialog-border-radius);box-shadow:0 2px 54px 0 var(--tribe-modal-overlay-color);max-height:100vh;max-width:100vw;overflow-y:auto;padding:var(--tribe-dialog-padding);-webkit-perspective:1000;-webkit-transform:translateZ(0);width:800px;z-index:200}.tribe-common .tribe-dialog__wrapper div[role=document]{align-items:flex-end;display:flex;flex-flow:column;justify-content:space-between;position:relative}.tribe-common .tribe-dialog__close-button{background:var(--tribe-dialog-close-background);background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18'%3E%3Cpath d='M16 2L2 16m14 0L2 2' stroke='%23bababa' fill='none' fill-rule='evenodd' stroke-linecap='square' stroke-width='2'/%3E%3C/svg%3E");background-repeat:no-repeat;background-size:contain;cursor:pointer;display:inline-block;font-size:14px;height:var(--tribe-dialog-close-height);line-height:var(--tribe-dialog-close-height);padding:0;position:absolute;width:var(--tribe-dialog-close-height);z-index:1}.tribe-common .tribe-dialog__close-button:focus,.tribe-common .tribe-dialog__close-button:hover{background:var(--tribe-dialog-close-background);background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18'%3E%3Cpath d='M16 2L2 16m14 0L2 2' stroke='%235d5d5d' fill='none' fill-rule='evenodd' stroke-linecap='square' stroke-width='2'/%3E%3C/svg%3E");background-size:contain;outline:none}.tribe-common .tribe-dialog__close-button--hidden{display:none}.tribe-common .tribe-dialog__close-button--round{border-radius:50%}.tribe-common .tribe-dialog__close-button--border{border:var(--tribe-dialog-close-border-width) solid var(--tribe-dialog-close-border-color)}.tribe-common h2.tribe-dialog__title{align-self:flex-start;margin:0 0 22px;padding-right:calc(var(--tribe-dialog-close-height) + .5em);padding-top:0}.tribe-common .tribe-dialog__content{color:#141827;font-size:14px;line-height:1.64em;padding-right:calc(var(--tribe-dialog-close-height) + .5em);padding-top:calc(var(--tribe-dialog-close-height) + .5em);width:100%}.tribe-common .tribe-dialog__title+.tribe-dialog__content{padding:0}.tribe-common .tribe-dialog__content p{font-size:var(--font-size-2)}.tribe-common .tribe-modal__overlay{background-color:var(--tribe-modal-overlay-color)}.tribe-common .tribe-confirm__content{padding-right:0}.tribe-common .tribe-dialog__button_wrap{display:flex;flex-flow:row wrap;justify-content:flex-end;margin-top:1rem}.tribe-common .tribe-dialog__button-cancel,.tribe-common .tribe-dialog__button-continue{margin-left:var(--spacer-1);width:auto}#top .main_color .tribe-common div.tribe-dialog,#top.tribe-theme-enfold .tribe-common div.tribe-dialog,.tribe-theme-avada .tribe-common div.tribe-dialog,.tribe-theme-divi .tribe-common div.tribe-dialog{z-index:99999}@media screen and (min-width:768px){.tribe-common .tribe-dialog__wrapper{max-height:calc(100vh - 160px);padding:var(--tribe-dialog-padding-top) var(--tribe-dialog-padding-side)}.tribe-common .tribe-dialog__close-button{height:var(--tribe-dialog-close-height-desktop);line-height:var(--tribe-dialog-close-height-desktop);width:var(--tribe-dialog-close-height-desktop)}}@media screen and (max-width:768px){.tribe-common .tribe-dialog__content:last-of-type{padding-bottom:36px}}
common/src/resources/css/tribe-common-admin.min.css CHANGED
@@ -1 +1 @@
1
- .invalid input,input:out-of-range{border:2px solid red!important}.valid input{border:1px solid green}.clearfix{zoom:1}.placeholder{color:#999;cursor:text;padding:4px}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::placeholder,textarea::placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.bubble{background-color:#f9f9f9;border:1px solid #dfdfdf;border-radius:3px;border-spacing:0;padding:10px}.tribe-sticky-tooltip{color:#bbb}td.tribe_message{padding-bottom:10px!important}#tribe_thanks{float:left;margin:5px 0 0;width:200px}.tribe_brand{font-family:Georgia,serif!important;font-size:17px!important;font-weight:400;margin:8px 0}.tribe-rating{color:#3d54ff}.tribe-rating:hover{color:#1c39bb}#tribe-upgrade{background:#f6f6f6;border:1px solid #ccc;border-radius:5px;margin:20px 0 30px;padding:0 20px 20px}#tribe-upgrade .message{background-color:#ffffe0;border:1px solid #e6db55;border-radius:3px;padding:6px 12px}table.plugins .tribe-plugin-update-message{background:#d54e21;color:#fff;display:inline-table;margin:6px 0;padding:10px 12px}table.plugins .tribe-plugin-update-message h4{display:inline;font-weight:700;margin-right:8px}table.plugins .tribe-plugin-update-message h4:after{content:" \00BB "}table.plugins .tribe-plugin-update-message a{color:#fff;text-decoration:underline}.tribe-settings-form{max-width:1000px}.tribe-settings-form fieldset{clear:both;display:inline-block;padding:10px 0}.tribe-settings-form fieldset.tribe-field-license_key legend{width:auto}.tribe-settings-form legend{float:left;font-weight:700;margin-right:20px;width:220px}.tribe-settings-form .tribe-field-wrap{float:left;max-width:500px}.tribe-settings-form .tribe-field-wrap :first-child{margin-top:0}.tribe-settings-form .tribe-field-checkbox_list label,.tribe-settings-form .tribe-field-radio label{display:block;margin:5px 0 5px 20px;text-indent:-20px}.tribe-settings-form .tribe-field-checkbox_list label>p,.tribe-settings-form .tribe-field-radio label>p{margin-left:1px;text-indent:0}.tribe-settings-form .tribe-field-checkbox_list label input,.tribe-settings-form .tribe-field-radio label input{margin-right:5px}.tribe-settings-form .tribe-settings-form-wrap .description,.tribe-settings-form .tribe-settings-form-wrap fieldset,.tribe-settings-form fieldset[id^=tribe-field-geoloc_]{padding-left:12px}.tribe-settings-form .tribe-settings-form-wrap fieldset .description{margin-left:0;max-width:450px;padding-left:0}.tribe-settings-form .tribe-settings-form-wrap fieldset .tribe-style-selection{margin-bottom:18px}.tribe-settings-form .tribe-settings-form-wrap #tribe-field-stylesheetOption .description{color:#999;margin-left:1px}.tribe-settings-form .tribe-settings-form-wrap h3{background-color:#f9f9f9;margin-bottom:10px;padding:6px 0 6px 12px}.tribe-settings-form .tribe-settings-form-wrap .contained,.tribe-settings-form .tribe-settings-form-wrap .system-info,.tribe-settings-form .tribe-settings-form-wrap .tribe-sysinfo-optin-msg,.tribe-settings-form .tribe-settings-form-wrap h3+p{margin:0 0 10px;padding-left:12px}.tribe_settings .tribe-field-indent{margin-left:245px}.tribe_settings #pu_dashboard_message{display:none}.tribe_settings .tribe-errors-list{margin-left:15px}.tribe_settings .expiring-license{color:red}.tribe_settings .tribe-error{border:1px solid red}.tribe_settings .tribe-field-description{margin-bottom:0;position:relative;top:-12px}.tribe_settings #ical-link{top:-14px}#modern-tribe-info{background-color:#f9f9f9;border:1px solid #ccc;border-radius:4px;margin:20px 0;padding:8px 20px 12px}#modern-tribe-info img{margin:10px 0}#modern-tribe-info ul{list-style:disc;margin-left:20px}#modern-tribe-info ul ul{list-style:circle}.tribe-field-inline-dropdown{margin-left:0;margin-right:0}.tribe-field-inline-text{line-height:28px;margin:0 2px}.tribe-field-textarea.tribe-size-small textarea{height:60px;width:180px}.tribe-field-textarea.tribe-size-medium textarea{height:80px;width:300px}.tribe-field-textarea.tribe-size-large textarea{height:120px;width:450px}.tribe-field-email.tribe-size-small input,.tribe-field-license_key.tribe-size-small input,.tribe-field-text.tribe-size-small input{width:50px}.tribe-field-email.tribe-size-medium input,.tribe-field-license_key.tribe-size-medium input,.tribe-field-text.tribe-size-medium input{width:225px}.tribe-field-email.tribe-size-large input,.tribe-field-license_key.tribe-size-large input,.tribe-field-text.tribe-size-large input{width:450px}.tribe-field-dropdown.tribe-size-small select{width:100px}.tribe-field-dropdown.tribe-size-medium select{width:300px}.tribe-field-dropdown.tribe-size-large select{width:450px}.tribe-field-wrapped_html.tribe-size-large .tribe-field-wrap{max-width:600px}.tribe-field-wrapped_html.tribe-size-large .tribe-field-wrap .description{max-width:100%}.tribe-field-dropdown_chosen.tribe-size-small select{width:100px}.tribe-field-dropdown_chosen.tribe-size-medium select{width:200px}.tribe-field-dropdown_chosen.tribe-size-large select{width:300px}.tribe-field-wrap .tooltip:first-child{font-style:normal}.tribe-field.indent{margin-left:252px;width:75%}.tribe-field.indent legend{font-weight:400;width:auto}.tribe-field.indent .tribe-field-wrap{padding-right:12px}.tribe-field.indent.tribe-field-radio .tribe-field-wrap{clear:left;margin-top:12px}.tribe-field.light-bordered{background-color:#fff;border:1px solid #d3d3d3}.ajax-loading-license,.invalid-key,.valid-key{display:none;margin:0 5px}.ajax-loading-license{position:relative;top:5px}.key-validity{display:inline-block}.invalid-key,.optin-fail{color:red}.optin-success,.valid-key{color:green}.valid-key.service-msg{color:#b72}#additional-field-table{margin-bottom:20px}.tribe-admin-box-left{float:left;width:20%}.tribe-admin-box-left,.tribe-admin-box-right{background-color:#f9f9f9;border:1px solid #ccc;border-radius:4px;margin:20px 0;padding:0 20px 15px}.tribe-admin-box-right{float:right;width:68%}.ajax-loader{float:right;margin:10px}.tribe-arrangeable-item{border:1px solid #d3d3d3;border-radius:3px}.tribe-arrangeable-item .ui-state-default{border:none}.tribe-arrangeable-item-top{padding:6px}.tribe-arrangeable-item-top:hover{cursor:move}.tribe-arrangeable-action{float:right}.tribe-arrangeable-child{background-color:#f9f9f9;border-top:1px solid #d3d3d3;display:none;padding:25px}.tribe-arrangeable-child label{display:block;margin:0 0 7px}.tribe_events_active_filter_type_options{margin:10px 0}.tribe_events_active_filter_type_options label{margin:7px 0}#event_organizer td small,.OrganizerInfo td small{display:block;margin:0;max-width:250px}#event_organizer .organizer-email,.OrganizerInfo .organizer-email{vertical-align:top}.tribe-table-field-label{max-width:100%;width:200px}#tribe-help-general,#tribe-help-sidebar{float:left;margin-top:20px}#tribe-help-general p{margin-left:15px}#tribe-help-general ul{list-style-type:square}#tribe-help-general ol,#tribe-help-general ul{margin-bottom:20px;margin-left:35px}#tribe-help-general h3{background-color:#f9f9f9;margin-bottom:10px;padding:6px 0 6px 12px}#tribe-help-general h3~h3{margin-top:2.25em}#tribe-help-general h3+p{margin:0 0 20px;padding-left:12px}#tribe-help-general{width:65%}.tribe-help-section{padding-bottom:10px}.tribe-section-type-box{background-color:#f9f9f9;border:1px solid #ccc;border-radius:4px;padding:8px 20px 12px}.tribe-section-type-box img{height:auto;margin:10px 0;max-width:300px}.tribe-section-type-box ul{list-style:disc;margin-left:20px}.tribe-section-type-box ul ul{list-style:circle}#tribe-log-controls{padding-bottom:1rem;padding-left:12px}#tribe-log-controls>div{display:inline-block;padding-right:1rem}#tribe-log-controls .working{opacity:1;transition:opacity .2s}#tribe-log-controls .working.hidden{opacity:0;transition:opacity .2s}#tribe-log-viewer,#tribe-system-info dl.support-stats,.template-updates-wrapper{background:#000;border-radius:2px;color:#888;max-height:400px;overflow:scroll;padding:10px}#tribe-system-info dl.support-stats dt,.template-updates-wrapper dt{clear:both;float:left;font-weight:700;text-transform:uppercase;width:25%}#tribe-system-info dl.support-stats dd,.template-updates-wrapper dd{margin-left:25%;padding-left:10px}.system-info-copy .system-info-copy-btn{padding:6px}.system-info-copy .system-info-copy-btn .dashicons{padding-right:10px}.template-updates-wrapper p{margin-top:0}#tribe-help-sidebar{margin:20px 0 0 3%;max-width:225px;width:32%}.tribe-help-plugin-info{border:1px solid #ccc;padding:0 12px 12px}.tribe-help-plugin-info dd,.tribe-help-plugin-info dt{display:inline;margin:0}.tribe-help-plugin-info dt{font-weight:700}.tribe-help-plugin-info dd:after{content:"";display:block;height:.4em}.tribe-help-plugin-info dd:last-child:after{height:0}.tribe-help-plugin-info+.tribe-help-plugin-info{margin-top:20px}.tribe-help-plugin-info>div{line-height:2em}.tribe-help-plugin-info .star-rating{display:inline-block;margin-left:3px;position:relative;top:-2px}.tribe-help-plugin-info .tribe-list-addons{color:#21a6cb;font-size:24px;list-style:circle inside;margin-bottom:10px;margin-top:10px;padding-left:4px}.tribe-help-plugin-info .tribe-list-addons a{font-size:13px;left:-5px;position:relative;top:-5px}.tribe-help-plugin-info .tribe-list-addons .tribe-active-addon{list-style:disc inside}.ui-widget-overlay{background:#666;filter:alpha(opacity=50);opacity:.5}.ui-widget-shadow{background:#000;border-radius:5px;filter:alpha(opacity=20);margin:-5px 0 0 -5px;opacity:.2;padding:5px}.ui-resizable{position:relative}.ui-resizable-handle{display:block;font-size:.1px;position:absolute;z-index:99999}.ui-resizable-autohide .ui-resizable-handle,.ui-resizable-disabled .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;left:0;top:-5px;width:100%}.ui-resizable-s{bottom:-5px;cursor:s-resize;height:7px;left:0;width:100%}.ui-resizable-e{cursor:e-resize;height:100%;right:-5px;top:0;width:7px}.ui-resizable-w{cursor:w-resize;height:100%;left:-5px;top:0;width:7px}.ui-resizable-se{bottom:1px;cursor:se-resize;height:12px;right:1px;width:12px}.ui-resizable-sw{bottom:-5px;cursor:sw-resize;height:9px;left:-5px;width:9px}.ui-resizable-nw{cursor:nw-resize;height:9px;left:-5px;top:-5px;width:9px}.ui-resizable-ne{cursor:ne-resize;height:9px;right:-5px;top:-5px;width:9px}.ui-dialog{padding:.2em;position:relative;width:375px}.ui-dialog .ui-dialog-titlebar{padding:.5em .3em .3em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0 .2em}.ui-dialog .ui-dialog-titlebar-close{height:18px;margin:-10px 0 0;padding:1px;position:absolute;right:.3em;top:50%;width:19px}.ui-dialog .ui-dialog-titlebar-close span{display:block;margin-left:-8px;margin-top:-8px}.ui-dialog .ui-dialog-titlebar-close:focus,.ui-dialog .ui-dialog-titlebar-close:hover{padding:0}.ui-dialog .ui-dialog-content{background:none;border:0;overflow:auto;padding:.5em 1em;zoom:1}.ui-dialog .ui-dialog-buttonpane{background-image:none;border-width:1px 0 0;margin:.5em 0 0;padding:.3em 1em .5em!important;text-align:right}.ui-dialog .ui-dialog-buttonpane button{cursor:pointer;line-height:1.4em;margin:.5em .4em!important;overflow:visible;padding:.2em .6em .3em;text-shadow:none;width:auto}.ui-dialog .ui-resizable-se{bottom:3px;height:14px;right:3px;width:14px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:none!important;text-align:center}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button .ui-button-text{display:block;line-height:1.4}#ui-datepicker-div{display:none}#tribe-loading{background:#fff;background:hsla(0,0%,100%,.8);display:none;height:100%;left:0;position:absolute;top:0;transition:all 1s linear;width:100%;z-index:4}#tribe-loading span{background:url(../images/tribe-loading.gif) 0 0 no-repeat;background-size:32px 32px;height:32px;left:50%;margin:-16px 0 0 -16px;position:absolute;top:50%;width:32px}<<<<<<< HEAD =======>>>>>>>b509f7a664980817599b22fafa19c531746d5b03 @media only screen and(min--moz-device-pixel-ratio: 2) <<<<<<< HEAD =======>>>>>>>b509f7a664980817599b22fafa19c531746d5b03 #tribe-loading span,only screen and(-o-min-device-pixel-ratio: 2/1) <<<<<<< HEAD =======>>>>>>>b509f7a664980817599b22fafa19c531746d5b03 #tribe-loading span,only screen and(-webkit-min-device-pixel-ratio: 2) <<<<<<< HEAD =======>>>>>>>b509f7a664980817599b22fafa19c531746d5b03 #tribe-loading span,only screen and(min-device-pixel-ratio: 2) <<<<<<< HEAD =======>>>>>>>b509f7a664980817599b22fafa19c531746d5b03 #tribe-loading span{background-image:url(../images/tribe-loading@2x.gif)}.tribe_update_page{max-width:850px}.tribe-half-column{float:left;margin-bottom:30px;margin-right:5%;width:45%}.tribe-row:after,.tribe-row:before{content:"";display:table}.tribe-row,.tribe-row:after{clear:both}.tribe-row .tribe-half-column:last-child{margin-right:0;width:50%}.tribe_update_page h2{font-size:30px;line-height:1.2;margin-bottom:20px}.tribe_update_page h3{font-size:24px;font-weight:400;line-height:24px;margin-top:0}.tribe_update_page h4{font-size:18px;font-weight:600;line-height:18px;margin:0}.tribe_update_page p{font-size:15px}p.tribe-update-message{font-size:18px;font-weight:400}.tribe_update_page h4:before{content:"\f145";font-family:dashicons;font-size:34px;line-height:1;margin-right:5px;position:relative;top:5px}a.tribe-rating-link{text-decoration:none}.tribe-update-links{margin-top:30px}.tribe_update_page li:before{content:"\2022";padding-right:3px}.tribe_update_page .rss-widget{margin:1em 0}.tribe_update_page a.rsswidget{font-size:14px;font-weight:400;line-height:1}.tribe_update_page .rss-widget li:before{display:none}.tribe-events-widget-admin-form__input-section p{margin:0}.tribe-events-widget-admin-form__input-section h4{margin:.5em 0}.tribe-update-bar{display:inline-block}.tribe-update-bar .progress{border:1px solid #ccc;float:left;margin-right:1rem;padding:1px;width:18rem}.tribe-update-bar .progress .bar{background:#7ad03a;height:1rem;width:1%}#tribe-dialog-wrapper>div{padding:1rem}#tribe-dialog-wrapper>div .stage{display:none}#tribe-dialog-wrapper #heading{background:#fff}#tribe-dialog-wrapper label{display:block}#tribe-dialog-wrapper .select-single-container{border:1px solid #888;height:300px;overflow-y:scroll}#tribe-dialog-wrapper .select-single-container label{opacity:1;padding:3px 5px;transition:opacity .2s}#tribe-dialog-wrapper .select-single-container label:nth-child(odd){background:#fff}#tribe-dialog-wrapper .select-single-container label.selected{background:#0073aa;color:#fff;font-weight:700}#tribe-dialog-wrapper .select-single-container label input{display:none}#tribe-dialog-wrapper .select-single-container.updating label{opacity:.35;transition:opacity .2s}.ui-front{z-index:1000000}.wp-list-table.plugins .column-description .update-message{color:#d54e21}.api-check{min-height:100px;padding:1em}.api-check+.notice-dismiss:hover:before{color:#fff}.api-check:after,.api-check:before{content:"";display:table}.api-check:after{clear:both}.api-check .tribe-mascot{bottom:0;display:none;padding:0 1rem 0 0;position:absolute;right:0;top:0}.api-check .tribe-mascot img{display:inline-block;height:100%;max-height:150px;max-width:150px;vertical-align:middle;width:auto}.api-check p{line-height:1.7;margin-bottom:1em}.api-check a{text-decoration:none}.api-check a:hover{text-decoration:underline}.api-check .plugin-list{display:inline;font-weight:600;margin:0;padding:0}.api-check .plugin-list span.plugin-invalid:after{content:", "}.api-check .plugin-list span.plugin-invalid:last-of-type:after{content:""}.tribe-marketing-notice{padding:1em}.tribe-marketing-notice+.notice-dismiss:hover:before{color:#fff}.tribe-marketing-notice:after,.tribe-marketing-notice:before{content:"";display:table}.tribe-marketing-notice:after{clear:both}.tribe-marketing-notice .tribe-marketing-notice__icon{display:none;flex-shrink:0;padding:0;position:static}.tribe-marketing-notice .tribe-marketing-notice__icon img{display:inline-block;max-height:100%;max-width:none;vertical-align:middle;width:100%}.tribe-marketing-notice h3{margin-bottom:.5em;margin-top:.5em}.tribe-marketing-notice p{line-height:1.7;margin-bottom:.5em}.tribe-marketing-notice a{text-decoration:none}.tribe-marketing-notice a:hover{text-decoration:underline}#wpcontent .notice-tribe-banner{align-items:center;background:#161b7d;border:0;box-shadow:none;display:flex;justify-content:flex-start;margin:0 0 16px;padding-right:0}.notice-tribe-banner .tribe-marketing-notice__icon{width:47px}.notice-tribe-banner .tribe-marketing-notice__content{margin-left:0;padding:1em 0}.notice-tribe-banner h3{color:#fff;display:block;font-size:.875rem;line-height:1.25;margin:0 0 .25rem}.notice-tribe-banner a{border-bottom:1px solid #fff;line-height:1.25;margin:0;text-decoration:none}.notice-tribe-banner a:hover{text-decoration:none}.notice-tribe-banner a,.notice-tribe-banner p{color:#fff;display:inline-block;font-size:.875rem;line-height:1.25}.notice-tribe-banner p{display:inline-block;margin:0;padding:0}.notice-tribe-banner .tribe-marketing-notice{align-items:center;display:flex;justify-content:flex-start;margin:0 auto;min-height:65px;padding:0 .75rem;width:100%}.events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice,.tribe-welcome .notice-tribe-banner .tribe-marketing-notice,.tribe_events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice{max-width:100%}.notice-tribe-banner .notice-dismiss{position:static}.notice-tribe-banner .notice-dismiss:before{color:#eaf1ff}.tribe-dropdown,.tribe-ea-dropdown{max-width:100%;width:auto}.tribe-dropdown.select2-container .selection,.tribe-ea-dropdown.select2-container .selection{margin-top:inherit}.tribe-dropdown .select2-selection--single,.tribe-ea-dropdown .select2-selection--single{height:32px}.tribe-dropdown .select2-selection--single .select2-selection__clear,.tribe-ea-dropdown .select2-selection--single .select2-selection__clear{line-height:28px}.tribe-dropdown .select2-selection--single .select2-selection__rendered,.tribe-ea-dropdown .select2-selection--single .select2-selection__rendered{line-height:32px;padding-right:28px}.tribe-dropdown.select2-container--focus .select2-selection--single,.tribe-ea-dropdown.select2-container--focus .select2-selection--single{border-color:#5897fb;box-shadow:0 0 5px rgba(0,0,0,.1)}.tribe-dropdown.select2-container--open .select2-search__field,.tribe-ea-dropdown.select2-container--open .select2-search__field{padding:0}.tribe-dropdown.select2-container--open .select2-dropdown--below,.tribe-ea-dropdown.select2-container--open .select2-dropdown--below{border-top:1px solid #aaa;margin-top:-1px}.tribe-dropdown.select2-container--open .select2-dropdown--above,.tribe-ea-dropdown.select2-container--open .select2-dropdown--above{border-bottom:1px solid #aaa;margin-bottom:-16px}.tribe-dropdown.select2-container--open .select2-selection--single,.tribe-ea-dropdown.select2-container--open .select2-selection--single{border-bottom-left-radius:0;border-bottom-right-radius:0;border-color:#aaa}.tribe-dropdown.select2-container--open .select2-selection__arrow b,.tribe-ea-dropdown.select2-container--open .select2-selection__arrow b{transform:rotate(180deg)}.tribe-dropdown.select2-selection--single,.tribe-ea-dropdown.select2-selection--single{background-image:none;border:1px solid #ccc;border-radius:3px;overflow:hidden}.tribe-dropdown.select2-selection--single>.select2-selection__rendered,.tribe-ea-dropdown.select2-selection--single>.select2-selection__rendered{white-space:normal}.tribe-dropdown.select2-selection--single .select2-selection__arrow,.tribe-ea-dropdown.select2-selection--single .select2-selection__arrow{background:transparent;background-image:none;border-left:0;top:2px;width:26px}.tribe-dropdown.select2-selection--single .select2-selection__arrow b,.tribe-ea-dropdown.select2-selection--single .select2-selection__arrow b{background:#fff url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E") no-repeat right 5px top 55%;background-size:auto;background-size:16px 16px;border:0;bottom:0;display:block;height:auto;left:0;margin:0;padding:0;right:0;top:0;width:auto}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered{background-image:none;border:1px solid #ccc;border-radius:3px;min-height:25px}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered .select2-search--inline,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered .select2-search--inline{line-height:25px}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered .select2-search--inline input,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered .select2-search--inline input{padding-bottom:0;padding-top:0}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice{line-height:19px;margin-top:2px;padding-bottom:0;padding-top:0}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice div,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice div{line-height:inherit}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice__remove,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice__remove{left:4px;top:3px;transition-property:border,color}.select2-results .select2-results__option{color:#939393;font-weight:400;margin-bottom:0}.select2-results .select2-results__option[aria-disabled=true]{background-color:#e0e0e0}.select2-results.select2-results__option--highlighted{background-color:#efefef;color:#a1a1a1;cursor:default;display:block}.wp-core-ui .button-red{background-color:#a00;border-color:#9b2124;box-shadow:inset 0 1px 0 rgba(120,200,230,.5);color:#fff;text-decoration:none;text-shadow:0 1px 0 rgba(0,0,0,.1)}.wp-core-ui .button-red.focus,.wp-core-ui .button-red.hover,.wp-core-ui .button-red:focus,.wp-core-ui .button-red:hover{background-color:#a00;border-color:#7f1c1f;box-shadow:inset 0 1px 0 rgba(120,200,230,.6);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.3)}.wp-core-ui .button-red.focus,.wp-core-ui .button-red:focus{border-color:#500f0e;box-shadow:inset 0 1px 0 rgba(120,200,230,.6),1px 1px 2px rgba(0,0,0,.4)}.wp-core-ui .button-red.active,.wp-core-ui .button-red.active:focus,.wp-core-ui .button-red.active:hover,.wp-core-ui .button-red:active{background:#7f1c1f;border-color:#601312 #ae2426 #ae2426;box-shadow:inset 0 1px 0 rgba(0,0,0,.1);color:hsla(0,0%,100%,.95);text-shadow:0 1px 0 rgba(0,0,0,.1)}.wp-core-ui .button-red-disabled,.wp-core-ui .button-red:disabled,.wp-core-ui .button-red[disabled]{background:#ba292b!important;border-color:#7f1c1f!important;box-shadow:none!important;color:#e79496!important;cursor:default;text-shadow:0 -1px 0 rgba(0,0,0,.1)!important}.ticket_form .select2-container .select2-selection--single .select2-selection__arrow{display:none}.clear{zoom:1}.clear:after,.clear:before{content:" ";display:table}.clear:after{clear:both}.checkmark:after{border:solid #0ab152;border-width:0 3px 3px 0;content:"";display:block;height:15px;transform:rotate(45deg);width:8px}.checkmark.checkmark-right:after{float:right;margin-right:2em}.checkmark.checkmark-left:after{float:left;margin-left:2em}.checkmark.no-checkmark:after{display:none}.complete,.ok,.on,.yes,[data-status=complete],[data-status=ok],[data-status=on],[data-status=yes]{color:#0ab152}.incomplete,.ko,.no,.off,[data-status=incomplete],[data-status=ko],[data-status=no],[data-status=off]{color:#ff2500}.plugin-card-event-tickets-plus .column-downloaded,.plugin-card-event-tickets-plus .column-rating,.plugin-card-event-tickets-plus .column-updated,.plugin-card-event-tickets .column-downloaded,.plugin-card-event-tickets .column-rating,.plugin-card-event-tickets .column-updated,.plugin-card-events-calendar-pro .column-downloaded,.plugin-card-events-calendar-pro .column-rating,.plugin-card-events-calendar-pro .column-updated,.plugin-card-events-community-tickets .column-downloaded,.plugin-card-events-community-tickets .column-rating,.plugin-card-events-community-tickets .column-updated,.plugin-card-events-community .column-downloaded,.plugin-card-events-community .column-rating,.plugin-card-events-community .column-updated,.plugin-card-image-widget-plus .column-downloaded,.plugin-card-image-widget-plus .column-rating,.plugin-card-image-widget-plus .column-updated,.plugin-card-image-widget .column-downloaded,.plugin-card-image-widget .column-rating,.plugin-card-image-widget .column-updated,.plugin-card-the-events-calendar .column-downloaded,.plugin-card-the-events-calendar .column-rating,.plugin-card-the-events-calendar .column-updated,.plugin-card-tribe-eventbrite .column-downloaded,.plugin-card-tribe-eventbrite .column-rating,.plugin-card-tribe-eventbrite .column-updated,.plugin-card-tribe-filterbar .column-downloaded,.plugin-card-tribe-filterbar .column-rating,.plugin-card-tribe-filterbar .column-updated{display:none}.tribe-events-admin-content-wrapper{font-style:normal;margin:0 auto;padding:20px;width:calc(100% - 40px)}.tribe-events-admin-card{background:#fff;border:1px solid #e1e1e4;border-radius:16px;box-sizing:border-box;display:block;margin:0 auto 36px;padding:27px;text-align:center}.tribe-events-admin-card--2up .tribe-events-admin-card__title{max-width:260px}.tribe-events-admin-card--3up .tribe-events-admin-card__description{height:71px}.tribe-events-admin-card--3up .tribe-events-admin-card__image{margin-bottom:28px}.tribe-events-admin-card__button{background-color:#fff;border:none;color:#3d54ff;font-size:14px;font-weight:700;letter-spacing:1px;line-height:16px;position:absolute;right:20px;text-transform:uppercase;top:17px}.tribe-events-admin-card__button:hover{color:#161b7d}.tribe-events-admin-card__description{color:#000;font-size:14px;font-style:normal;font-weight:400;line-height:22px;margin-top:16px}.tribe-events-admin-card__image{display:block;height:100px;margin:0 auto}.tribe-events-admin-card__link{color:#3d54ff;display:inline-block;font-size:16px;font-style:normal;font-weight:700;line-height:18px;margin-top:24px;position:relative;text-decoration:none}.tribe-events-admin-card__link:hover{color:#161b7d}.tribe-events-admin-card__link:after{border-style:solid;border-width:0 0 1px;bottom:-4px;content:"";left:0;position:absolute;width:100%}.tribe-events-admin-card__title{color:#0f1031;font-size:20px;font-weight:700;line-height:23px;margin:auto}.tribe-events-admin-card-grid{max-width:1048px}.tribe-events-admin-section-header{color:#000;font-size:24px;font-weight:700;line-height:28px;margin:21px 0 24px}input[type=checkbox].tribe-common-switch__input{display:none}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label{background:#fff;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;cursor:pointer;display:block;height:18px;outline:0;padding:3px;position:relative;transition:all .2s ease;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:27px}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label:after,input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label:before{content:"";display:block;height:10px;position:relative;width:10px}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label:after{background:#878787;border-radius:2px;content:"";left:0;transition:all .2s ease}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label:before{display:none}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label::-moz-selection{background:none}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label::selection{background:none}input[type=checkbox].tribe-common-switch__input:checked+.tribe-common-switch__label:after{background:#2e709d;left:50%}body.tribe-welcome,body.tribe_events_page_tribe-help{background-color:#fff;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}body.tribe-welcome .update-nag,body.tribe_events_page_tribe-help .update-nag{display:none}body.tribe-welcome #wpcontent,body.tribe_events_page_tribe-help #wpcontent{padding:0}body.tribe-welcome .tribe_settings,body.tribe_events_page_tribe-help .tribe_settings{margin:0}body.tribe-welcome #wpfooter,body.tribe-welcome .tribe_settings>h1,body.tribe_events_page_tribe-help #wpfooter,body.tribe_events_page_tribe-help .tribe_settings>h1{display:none}body.tribe-welcome #wpbody-content,body.tribe_events_page_tribe-help #wpbody-content{padding-bottom:25px}body.tribe-welcome .tribe-dependency-error,body.tribe_events_page_tribe-help .tribe-dependency-error{display:none}.tribe-events-admin-header__logo-word-mark{display:inline-block;height:auto;margin:0 0 26px;vertical-align:middle;width:312px}.tribe-events-admin-content-wrapper{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;padding:0 0 30px}.tribe-events-admin-header{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;padding:45px 0 0}.tribe-events-admin-header__right-image{height:280px;position:absolute;right:0;top:0;width:auto;z-index:-1}.tribe-events-admin-header__title{font-size:48px;line-height:48px;margin:0 0 18px}.tribe-events-admin-header__description{font-size:18px;line-height:28px;margin-bottom:44px;max-width:60%}.tribe-events-admin-tab-nav{display:flex;margin:0}.tribe-events-admin-tab-nav li{cursor:pointer;font-size:16px;font-weight:500;margin-bottom:0;margin-right:30px}.tribe-events-admin-tab-nav li:hover{color:#334aff}.tribe-events-admin-tab-nav .selected{border-bottom:3px solid #334aff;color:#334aff;padding-bottom:17px}.tribe-events-admin-tab-nav li:after{background:#334aff;border-radius:100px;bottom:0;content:"";display:block;height:3px;left:0;position:absolute;right:0}.tribe-events-admin__line{border-top:1px solid #e1e1e4}.tribe-events-admin-products-description{color:#0f1031;font-size:14px;line-height:2}.tribe-events-admin-products-card{align-items:center;border:1px solid #e1e1e4;border-radius:20px;display:flex;padding:10px 15px}.tribe-events-admin-products-card__icon{height:40px;-o-object-fit:contain;object-fit:contain;width:40px}.tribe-events-admin-products-card__group{margin:0 20px;max-width:55%}.tribe-events-admin-products-card__group-title{color:#0f1031;font-size:16px;font-weight:700;line-height:1;margin:0}.tribe-events-admin-products-card__group-description{font-size:12px;margin-top:5px}.tribe-events-admin-products-card__button{background-color:#fff;border:1px solid #e1e1e4;border-radius:20px;color:#0f1031;font-size:12px;font-weight:700;letter-spacing:1px;line-height:16px;margin-left:auto;padding:10px 15px;text-decoration:none;text-transform:uppercase}.tribe-events-admin-products-card__button:hover{background-color:#334aff;color:#fff}.tribe-events-admin-products-card__button:active,.tribe-events-admin-products-card__button:focus{box-shadow:none;outline:none}.tribe-events-admin-products-card__button--active,.tribe-events-admin-products-card__button--active:active,.tribe-events-admin-products-card__button--active:focus,.tribe-events-admin-products-card__button--active:hover{background:rgba(61,84,255,.16);color:#334aff;cursor:not-allowed;text-transform:uppercase}.tribe-events-admin-card--1up{width:100%}.tribe-events-admin-card--no-pad{padding:0}.tribe-events-admin-card--no-pad .tribe-events-admin-card__image{display:block;height:152px;margin:0;padding:0}.tribe-events-admin-card--no-pad .tribe-events-admin-card__title{font-size:28px;line-height:34px;text-align:left}.tribe-events-admin-card--no-pad .tribe-events-admin-card__description{margin:0;padding:0;text-align:left}.tribe-events-admin-card--no-pad .tribe-events-admin-card__link{margin:0;padding:0}.tribe-events-admin-card--faq{display:inline-block;font-size:0;height:147px;margin:0 0 0 30px;padding:24px 16px 22px 20px;width:230px}.tribe-events-admin-card--faq:first-child{margin-left:0}.tribe-events-admin-card--faq img{float:left;height:22px;width:16px}.tribe-events-admin-card--faq .tribe-events-admin-faq__question{color:#334aff;font-size:16px;line-height:19px;margin:0 0 12px 26px;text-align:left}.tribe-events-admin-card--faq .tribe-events-admin-faq__answer{font-size:13px;line-height:16px;margin-left:26px;text-align:left}.tribe-events-admin-video{border-radius:16px;height:200px;margin-bottom:72px;-webkit-mask-image:-webkit-radial-gradient(circle,#fff 100%,#000 0);overflow:hidden;-webkit-transform:rotate(.000001deg)}.tribe-events-admin-video iframe{width:100%}.tribe-events-admin-card--promo-blue{background-color:#3d54ff;background-image:url(../images/welcome/promo.jpg)}.tribe-events-admin-card--promo-blue .tribe-events-admin-card__description{color:#fff;font-size:16px;margin-bottom:16px;text-align:left}.tribe-events-admin-card--promo-blue .tribe-events-admin-card__title{color:#fff;text-align:left}.tribe-events-admin-graphic{position:absolute;right:0;top:106px;z-index:-1}.tribe-events-admin-graphic--desktop-only{display:none}.tribe-events-admin-graphic--mobile-only{display:block}.tribe-events-admin-card__form{position:relative}input[type=email].tribe-events-admin-card__input{background:#fff;border:1px solid #e1e1e4;border-radius:16px;box-sizing:border-box;font-size:14px;height:54px}input[type=email].tribe-events-admin-card__input:-ms-input-placeholder{color:rgba(15,16,49,.72);letter-spacing:.5px;padding-left:10px}input[type=email].tribe-events-admin-card__input::placeholder{color:rgba(15,16,49,.72);letter-spacing:.5px;padding-left:10px}.tribe-events-admin-container,.tribe-events-admin-content-wrapper.tribe-events-admin-container{margin:0 auto;max-width:1024px;width:90%}.tribe-events-admin-2col-grid{display:grid;grid-gap:15px 30px;gap:15px 30px;grid-template-areas:". .";grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:1fr}.tribe-events-admin-3col-grid{display:grid;grid-gap:30px;gap:30px;grid-template-areas:". . .";grid-template-columns:repeat(3,minmax(0,1fr));grid-template-rows:1fr}.tribe-events-admin-4col-grid{display:grid;grid-gap:30px;gap:30px;grid-template-areas:". . . .";grid-template-columns:repeat(4,minmax(0,1fr));grid-template-rows:1fr}.tribe-events-admin-products{margin:10px 0 0}.tribe-events-admin-quick-nav{background:#fff;border:1px solid #e1e1e4;border-radius:16px;box-sizing:border-box;display:block;margin:40px 0 78px;padding:18px 23px 2px}.tribe-events-admin-quick-nav__link{color:#3d54ff;font-size:16px;font-weight:700;line-height:18px;text-align:center;text-decoration:none}.tribe-events-admin-quick-nav__link:hover{color:#161b7d}.tribe-events-admin-quick-nav__link-item{display:block;padding-bottom:19px}.tribe-events-admin-quick-nav__links{display:inline}.tribe-events-admin-quick-nav__title{color:rgba(15,16,49,.72);display:inline-block;font-size:14px;font-weight:400;line-height:16px;padding-bottom:14px;text-transform:uppercase}.tribe-events-admin-title{padding-top:14px}.tribe-events-admin-title__description{color:#0f1031;font-size:16px;font-weight:400;line-height:24px;max-width:584px;padding-top:15px}.tribe-events-admin-title__heading{color:#0f1031;display:inline-block;font-size:24px;font-weight:700;line-height:28px;margin:5px 0 0}.tribe-events-admin-title__logo{margin-right:8px;vertical-align:top;width:34px}.tribe-events-admin-notice{background-color:#3d54ff;height:65px}.tribe-events-admin-notice .tribe-events-admin-content-wrapper{padding-bottom:0;padding-top:8px}.tribe-events-admin-notice p{color:#fff;display:inline-block;font-family:Helvetica;font-size:16px;line-height:18px;margin-top:0;padding-bottom:12px;padding-left:16px;vertical-align:middle;width:calc(100% - 60px)}.tribe-events-admin-notice__logo{display:inline-block}.tribe-events-admin-tickets .tribe-events-admin-section-header{font-size:28px;line-height:32px}.tribe-events-admin-tickets .tribe-events-admin-graphic--desktop-only{width:365px}.tribe-events-admin-tickets .tribe-events-admin-graphic--mobile-only{top:230px;width:300px}.tribe-events-admin-tickets .tribe-events-admin-title__heading{margin-top:0}.tribe-events-admin-tickets .tribe-events-admin-title__logo{margin-right:4px;width:32px}.tribe-events-admin-kb{margin:10px 0 0}.tribe-events-admin-kb-card{border:1px solid #e1e1e4;border-radius:20px}.tribe-events-admin-kb-card__image{height:auto;width:100%}.tribe-events-admin-kb-card__title{color:#0f1031;flex-grow:0;font-size:20px;font-weight:700;line-height:1.2;margin:0;padding:20px 28px 10px}.tribe-events-admin-kb-card__links{margin:0;padding:0 28px 25px}.tribe-events-admin-kb-card__links li{margin:0 0 10px}.tribe-events-admin-kb-card__links li a{color:#334aff;font-size:14px;line-height:1.2;text-decoration:none}.tribe-events-admin-kb-card__links li a:focus{box-shadow:none;outline:none}.tribe-events-admin-kb-card__links li a:hover{color:#1c39bb}.tribe-events-admin-section-header{align-items:center;display:flex;justify-content:space-between;margin:50px 0 0}.tribe-events-admin-section-header h3{color:#0f1031;font-size:28px;font-weight:700;line-height:1}.tribe-events-admin-section-header a{border-bottom:2px solid #334aff;color:#334aff;font-size:14px;padding-bottom:2px;text-decoration:none}.tribe-events-admin-section-header a:focus{box-shadow:none;outline:none}.tribe-events-admin-section-header a:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin-faq{margin:10px 0 0}.tribe-events-admin-faq-card{border:1px solid #e1e1e4;border-radius:20px;display:flex;justify-content:space-between;padding:24px 15px 19px 19px}.tribe-events-admin-faq-card a{color:#0f1031}.tribe-events-admin-faq-card a:focus{box-shadow:none;outline:none}.tribe-events-admin-faq-card a:hover{color:#1c39bb}.tribe-events-admin-faq-card__icon img{height:22px;width:16px}.tribe-events-admin-faq-card__content{margin-left:10px}.tribe-events-admin-faq__question,.tribe-events-admin-faq__question a{color:#334aff;font-size:16px;text-decoration:none}.tribe-events-admin-faq__question a:focus{box-shadow:none;outline:none}.tribe-events-admin-faq__question a:hover{color:#1c39bb}.tribe-events-admin-faq__answer{color:#0f1031;font-size:13px;margin-top:18px}.tribe-events-admin-extensions-title{color:#0f1031;font-size:16px;line-height:1.5;margin:0 0 30px;max-width:70%}.tribe-events-admin-extensions{margin:10px 0 0}.tribe-events-admin-extensions-card{border:1px solid #e1e1e4;border-radius:20px;border-top:8px solid #334aff;padding:48px 35px 24px 25px}.tribe-events-admin-extensions-card__title{font-size:20px;margin:0}.tribe-events-admin-extensions-card__title a{color:#0f1031;font-family:Helvetica;font-size:20px;font-weight:700;line-height:1.2;text-decoration:none}.tribe-events-admin-extensions-card__title a:active,.tribe-events-admin-extensions-card__title a:focus,.tribe-events-admin-extensions-card__title a:hover{box-shadow:none;color:#334aff}.tribe-events-admin-extensions-card__description{color:#0f1031;font-family:Helvetica;font-size:14px;line-height:1.43;margin:20px 0}.tribe-events-admin-cta{align-items:center;border:1px solid #e1e1e4;border-radius:20px;display:flex;justify-content:space-between;margin:60px 0}.tribe-events-admin-cta__image{height:152px;-o-object-fit:contain;object-fit:contain;width:auto}.tribe-events-admin-cta__content,.tribe-events-admin__troubleshooting-cta{align-items:center;display:flex;flex-direction:column;justify-content:center;padding:20px 0;width:100%}.tribe-events-admin-cta__content-title{color:#0f1031;font-size:28px;font-weight:700;line-height:normal;margin:0 0 10px;text-align:center}.tribe-events-admin-cta__content-subtitle{color:#0f1031;font-size:16px;line-height:1.5;margin-bottom:10px;text-align:center}.tribe-events-admin-cta__content-description a{border-bottom:2px solid #334aff;color:#334aff;font-size:16px;font-weight:700;padding-bottom:2px;text-decoration:none}.tribe-events-admin-cta__content-description a:focus{box-shadow:none;outline:none}.tribe-events-admin-cta__content-description a:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin-footer-logo{display:inline-block;vertical-align:middle;width:228px}.tribe-events-admin-step{margin:10px 0 0}.tribe-events-admin-step-card{border:1px solid #e1e1e4;border-radius:20px;display:flex;justify-content:space-between;padding:24px 15px 19px 19px}.tribe-events-admin-step-card a{border-bottom:2px solid #334aff;color:#334aff;padding-bottom:2px;text-decoration:none}.tribe-events-admin-step-card a:focus{box-shadow:none;outline:none}.tribe-events-admin-step-card a:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin-step-card__icon img{height:43px;margin-right:5px;width:42px}.tribe-events-admin-step-card__content{margin-left:10px}.tribe-events-admin-step__title{color:#0f1031;font-size:20px;font-weight:700;line-height:1.2;margin-bottom:10px}.tribe-events-admin-step__answer{color:#0f1031;font-size:13px;margin-top:18px}.tribe-events-admin__system-information{display:grid;grid-gap:15px 30px;gap:15px 30px;grid-template-areas:". .";grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:1fr;margin:100px 0;position:relative}.tribe-events-admin__troubleshooting-title{color:#0f1031;font-size:28px;font-weight:700;line-height:1;margin:0}.tribe-events-admin__troubleshooting-description{color:#0f1031;font-size:18px;line-height:1.2;line-height:1.44;margin:20px 0}.tribe-events-admin__system-information-select{display:flex;margin:30px 0 20px}.tribe-events-admin__system-information-select input[type=checkbox]{margin:0 10px 0 0}.tribe-events-admin__system-information-select label{color:#0f1031;font-size:16px;line-height:1.2}.tribe-events-admin__system-information-content small{color:#0f1031;font-size:12px;line-height:1.2}.tribe-events-admin__recent-template-changes .template-updates-wrapper,.tribe-events-admin__system-information-widget{background:#0f1031;border-radius:16px;color:#fff;font-size:14px;line-height:1.14;max-height:280px;overflow:scroll;-ms-overflow-style:none;padding:12px 0 0 27px;scrollbar-width:none}.tribe-events-admin__system-information-widget a{color:#334aff}.tribe-events-admin__system-information-widget a:hover{opacity:.8}.tribe-events-admin__recent-template-changes .template-updates-wrapper{padding:30px 0 30px 27px}.tribe-events-admin__recent-template-changes .template-updates-wrapper::-webkit-scrollbar,.tribe-events-admin__system-information-widget::-webkit-scrollbar{display:none}.tribe-events-admin__system-information-widget-copy{bottom:10px;position:absolute}.tribe-events-admin__system-information-widget-copy button{background-color:#334aff;border:none;border-radius:100px;color:#fff;cursor:pointer;font-size:16px;font-weight:700;outline:none;padding:18px 25px;text-align:center}.tribe-events-admin__system-information-widget-copy button:hover{background-color:#1c39bb}.tribe-events-admin__system-information-widget-copy button .dashicons,.tribe-events-admin__system-information-widget-copy button .dashicons-before:before{display:none}.tribe-events-admin__system-information-widget-copy button .optin-success{color:#fff;font-size:16px;font-weight:700;text-align:center}.tribe-events-admin__recent-template-changes p{color:#0f1031;font-size:18px;line-height:1.2;line-height:1.44;margin:20px 0}.tribe-events-admin__recent-log{margin-top:50px}.tribe-events-admin__troubleshooting-event-log-wrapper label{color:#0f1031;display:block;font-size:16px;line-height:1.63;margin-bottom:10px}.tribe-events-admin__troubleshooting-event-log-wrapper #tribe-log-controls{margin:20px 0 10px}.tribe-events-admin__troubleshooting-event-log-wrapper #tribe-log-viewer{background:#0f1031;border-radius:16px;color:#fff;font-size:14px;line-height:1.14;max-height:280px;min-height:60px;overflow:scroll;-ms-overflow-style:none;padding:12px 0 0 27px;scrollbar-width:none}.tribe-events-admin__troubleshooting-event-log-wrapper #tribe-log-viewer::-webkit-scrollbar{display:none}.tribe-events-admin__troubleshooting-event-log-wrapper .download_log{border-bottom:2px solid #334aff;color:#334aff;font-size:16px;padding-bottom:2px;text-decoration:none}.tribe-events-admin__troubleshooting-event-log-wrapper .download_log:focus{box-shadow:none;outline:none}.tribe-events-admin__troubleshooting-event-log-wrapper .download_log:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin__troubleshooting-event-log-wrapper .tribe-events-admin__recent-log-filters-select-wrapper:after{display:none}.tribe-events-admin__recent-log-filters{display:flex;padding:20px 0 40px}.tribe-events-admin__recent-log-filters-field{margin-right:40px}.tribe-events-admin__recent-log-filters-select-wrapper:after{content:url(../images/help/polygon.svg);height:13px;pointer-events:none;position:absolute;right:22px;top:20px;width:14px}.tribe-events-admin__recent-log-filters-select-wrapper .select2-container--default .select2-selection--single{border:1px solid #e1e1e4!important;border-radius:16px;color:#0f1031;font-size:14px;line-height:1.14;padding:0 25px 0 15px!important}.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls{margin-bottom:20px;padding:0}.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:first-child,.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:nth-child(2),.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:nth-child(3){padding-right:75px}.tribe-events-admin__recent-log-filters-select-wrapper .select2-selection__clear{display:none}.tribe-events-admin__recent-log-filters-select-wrapper .select2-container--default .select2-selection--single .select2-selection__arrow{right:5px}.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple,.tribe-events-admin__recent-log-filters-select-wrapper .select2-container--default.select2-container--open.select2-container--below .select2-selection--single{border-bottom-left-radius:16px;border-bottom-right-radius:16px}.tribe-events-admin__recent-log-filters-select-wrapper .select2-container .select2-selection--single .select2-selection__rendered{width:100%}.tribe-events-admin__recent-log-filters-select-wrapper select.focus-visible,.tribe-events-admin__recent-log-filters-select-wrapper select:focus-visible{outline:none}.tribe-events-admin__recent-log-filters-select-wrapper select option{color:#0f1031;font-size:14px;line-height:1.14}.tribe-events-admin__ea-status{margin-top:50px}.tribe-events-admin__issues-found-card{background-color:#f3eee8;border-radius:8px;margin-bottom:20px}.tribe-events-admin__issues-found-card:last-of-type{margin-bottom:100px}.tribe-events-admin__issues-found-card-title{align-items:center;cursor:pointer;display:flex;padding:10px 20px 10px 17px;position:relative}.tribe-events-admin__issues-found-card-title img{height:21px;margin-right:14px;-o-object-fit:contain;object-fit:contain;width:21px}.tribe-events-admin__issues-found-card-title h3{margin:0}.tribe-events-admin__issues-found-card-title span{color:#0f1031;display:block}.tribe-events-admin__issues-found-card-title i{background-image:url(../images/help/arrow-down.svg);background-position:50%;background-repeat:no-repeat;background-size:contain;height:15px;margin:12px 20px;position:absolute;right:0;top:0;transition:all .3s ease;width:15px}.tribe-events-admin__issues-found-card-title.active i{background-image:url(../images/help/arrow-up.svg);background-repeat:no-repeat;top:5px}.tribe-events-admin__issues-found-card-description{display:none;padding:0 20px 20px 55px}.tribe-events-admin__issues-found-card-description p{color:#0f1031;font-size:16px;margin:0}.tribe-events-admin__issues-found-card-description-actions{display:flex;padding:20px 0 10px}.tribe-events-admin__issues-found-card-description-actions a{border-bottom:2px solid #334aff;color:#334aff;font-size:16px;margin-right:20px;padding-bottom:5px;text-decoration:none}.tribe-events-admin__issues-found-card-description-actions a:focus{box-shadow:none;outline:none}.tribe-events-admin__issues-found-card-description-actions a:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin__ea-status-table-wrapper{overflow-x:auto}.tribe-events-admin__ea-status-table{border:1px solid #e1e1e4;border-radius:16px;margin:30px 0 40px;overflow:hidden}.tribe-events-admin__ea-status-table a{border-bottom:2px solid #334aff;color:#334aff;padding-bottom:2px;text-decoration:none}.tribe-events-admin__ea-status-table a:focus{box-shadow:none;outline:none}.tribe-events-admin__ea-status-table a:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin__ea-status-table tr{display:flex;align-items:center}.tribe-events-admin__ea-status-table th{color:#0f1031;font-weight:700;line-height:1.17;margin-top:10px;padding:5px 25px}.tribe-events-admin__ea-status-table td{align-items:center;color:#0f1031;display:flex;font-size:16px;line-height:1.63;padding:10px 25px;width:25%}.tribe-events-admin__ea-status-table td:nth-child(2){width:45%}.tribe-events-admin__ea-status-table td:nth-child(3){display:flex;justify-content:flex-end;width:30%}.tribe-events-admin__ea-status-table-dark{background-color:#f9f7f4}.tribe-events-admin__ea-status-table td img{height:21px;margin-right:14px;-o-object-fit:contain;object-fit:contain;width:21px}.tribe_events_page_tec-troubleshooting{background-color:#fff}#tribe-community,#tribe-ticketing{display:none}.tribe-events-admin__troubleshooting-notice{background-color:#161b7d;color:#fff;font-size:16px;line-height:1;margin-left:-1.55vw;padding:24px 0}.tribe-events-admin__troubleshooting-notice_title{margin:0 auto;max-width:1024px;padding-left:25px;width:90%}.tribe-events-admin__troubleshooting-notice_title a{border-bottom:2px solid #fff;color:#fff;font-size:16px;line-height:1;padding-bottom:2px;text-decoration:none}.tribe-events-admin__troubleshooting-notice_title a:focus{box-shadow:none;outline:none}.tribe-events-admin__troubleshooting-notice_title a:hover{border-bottom:2px solid #f3eee8;color:#f3eee8}.tribe_events_page_tribe-help #tec-help-community,.tribe_events_page_tribe-help #tec-help-ticketing{display:none}.tribe_events_page_tribe-help .tribe-events-admin-title{padding-top:25px}.tribe_events_page_tribe-help .tribe-events-admin-title img{height:67px}body.tribe-welcome #fs_connect{border:1px solid #e1e1e4;border-radius:16px;box-shadow:none;box-sizing:border-box;margin-left:22px}body.tribe-welcome #fs_connect .fs-actions{background-color:transparent}body.tribe-welcome #fs_connect .fs-permissions{border-top:1px solid #e1e1e4;margin:0 16px}body.tribe-welcome #fs_connect button{background-color:#3d54ff;border-color:#3d54ff}body.tribe-welcome #fs_connect .button-secondary{background:#fff;border-color:#3d54ff;color:#3d54ff}body.tribe-welcome #fs_connect a{color:#3d54ff}body.tribe-welcome #fs_connect a:focus{box-shadow:none;outline:none}body.tribe-welcome #fs_connect a:hover{color:#161b7d}@media screen and (max-width:782px){.tribe-half-column,.tribe-row .tribe-half-column:last-child{margin:0 0 20px;width:100%}input[type=email]{width:100%}<<<<<<< HEAD =======>>>>>>>b509f7a664980817599b22fafa19c531746d5b03 .events-cal .subsubsub{float:none}.events-cal .search-box{width:98%}.events-cal #search-submit{width:100%}.events-cal .tablenav.top{display:none}}@media screen and (min-width:500px){.api-check .tribe-mascot{display:block}.api-check .notice-content{margin-right:180px}}@media screen and (min-width:320px){.tribe-marketing-notice .tribe-marketing-notice__icon{display:block}.notice-tribe-banner .tribe-marketing-notice__content{margin-left:22px}}@media screen and (min-width:600px) and (max-width:782px){.tribe-marketing-notice .tribe-marketing-notice__content{margin-left:145px}.notice-tribe-banner .tribe-marketing-notice__content{margin-left:22px;padding:0}}@media screen and (min-width:782px){.tribe-marketing-notice .tribe-marketing-notice__content{margin-left:130px}.notice-tribe-banner .tribe-marketing-notice__content{margin-left:22px;padding:0}.events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice,.tribe-welcome .notice-tribe-banner .tribe-marketing-notice,.tribe_events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice{max-width:642px}}@media screen and (min-width:400px){.notice-tribe-banner .tribe-marketing-notice__icon{width:67px}}@media screen and (min-width:800px){.notice-tribe-banner h3{display:inline-block;font-size:1rem;margin:0 .5rem 0 0}.notice-tribe-banner a{line-height:1.5}.notice-tribe-banner a,.notice-tribe-banner p{font-size:1rem}.notice-tribe-banner p{margin:0 .5rem 0 0}.notice-tribe-banner .tribe-marketing-notice__cta{display:inline-block;margin-left:.5rem}}@media screen and (min-width:1215px){.events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice,.tribe_events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice{max-width:992px}.tribe-welcome .notice-tribe-banner .tribe-marketing-notice{max-width:1036px}}@media screen and (min-width:710px){.tribe-events-admin-content-wrapper{width:670px}.tribe-events-admin-card--2up{display:inline-block;width:calc(50% - 20px)}.tribe-events-admin-card--2up.tribe-events-admin-card--first{margin-right:36px}.tribe-events-admin-card--2up.tribe-events-admin-card--last{margin-right:0}.tribe-events-admin-card--2up .tribe-events-admin-card__image{height:100px;margin-bottom:12px}.tribe-events-admin-card--2up .tribe-events-admin-card__title{margin-bottom:27px;max-width:340px}.tribe-events-admin-card--3up{display:inline-block;margin-bottom:32px;width:calc(50% - 18px)}.tribe-events-admin-card--3up.tribe-events-admin-card--first{margin-right:32px}.tribe-events-admin-card--3up.tribe-events-admin-card--middle{margin-right:0}.tribe-events-admin-card__title{font-size:20px;line-height:23px}.tribe-events-admin-section-header{font-size:28px;line-height:32px;margin-bottom:21px}.tribe-events-admin-card--1up{display:inline-block;margin-left:32px;width:calc(50% - 18px)}.tribe-events-admin-card--1up .tribe-events-admin-card__description{height:71px}.tribe-events-admin-card--1up .tribe-events-admin-card__image{margin-bottom:28px}.tribe-events-admin-card--no-pad{height:154px;padding:0}.tribe-events-admin-card--no-pad .tribe-events-admin-card__title{margin-left:50%;padding:42px 0 10px}.tribe-events-admin-card--no-pad .tribe-events-admin-card__description{margin-left:50%}.tribe-events-admin-card--promo-blue{display:block;margin-left:0;min-height:170px;width:100%}.tribe-events-admin-card--promo-blue .tribe-events-admin-card__description{float:left;max-width:300px}.tribe-events-admin-graphic{max-width:250px;top:0}.tribe-events-admin-graphic--desktop-only{display:block}.tribe-events-admin-graphic--mobile-only{display:none}.tribe-events-admin-card__form{float:right;width:300px}input[type=email].tribe-events-admin-card__input{width:300px}.tribe-events-admin-title{padding-top:50px}.tribe-events-admin-title__description{padding-top:15px}.tribe-events-admin-title__heading{font-size:48px;line-height:55px;margin:0}.tribe-events-admin-title__logo{margin-right:14px;padding-top:5px;width:40px}.tribe-events-admin-tickets .tribe-events-admin-card__title{font-size:18px}.tribe-events-admin-tickets .tribe-events-admin-card--2up .tribe-events-admin-card__title{font-size:18px;height:66px}.tribe-events-admin-tickets .tribe-events-admin-title__logo{margin-right:8px;padding-top:4px;width:60px}}@media screen and (min-width:1217px){.tribe-events-admin-content-wrapper{max-width:1060px;width:100%}.tribe-events-admin-card--2up{margin-right:36px;width:486px}.tribe-events-admin-card--3up{width:310px}.tribe-events-admin-card--3up.tribe-events-admin-card--first,.tribe-events-admin-card--3up.tribe-events-admin-card--middle{margin-right:36px}.tribe-events-admin-card--3up.tribe-events-admin-card--last{margin-right:0}.tribe-events-admin-quick-nav{padding:0 36px}.tribe-events-admin-card--1up{margin:0 0 36px;padding:33px 44px 30px;text-align:left;width:1012px}.tribe-events-admin-card--1up .tribe-events-admin-card__description{height:auto}.tribe-events-admin-card--1up .tribe-events-admin-card__image{float:left;margin:0 48px 10px 0}.tribe-events-admin-card--no-pad{padding:0}.tribe-events-admin-card--no-pad .tribe-events-admin-card__image{margin:0;padding:0}.tribe-events-admin-card--no-pad .tribe-events-admin-card__title{margin-left:50%;padding:42px 0 10px}.tribe-events-admin-card--no-pad .tribe-events-admin-card__description{margin-left:50%}.tribe-events-admin-card--promo-blue{min-height:150px}.tribe-events-admin-card--promo-blue .tribe-events-admin-card__description{max-width:450px}.tribe-events-admin-graphic{max-width:none}.tribe-events-admin-card__form,input[type=email].tribe-events-admin-card__input{width:365px}.tribe-events-admin-quick-nav{border-radius:100px;display:inline-block;height:54px;margin:24px 0 94px;max-width:1010px;padding:0 36px 0 0}.tribe-events-admin-quick-nav__link-item{display:inline-block;padding:18px 10px 0}.tribe-events-admin-quick-nav__title{padding:19px 6px 17px 32px}.tribe-events-admin-tickets .tribe-events-admin-card--2up .tribe-events-admin-card__title{height:auto}}@media screen and (max-width:768px){.tribe-events-admin-header__logo-word-mark{width:285px}.tribe-events-admin-header__right-image{height:160px}.tribe-events-admin-header__description{max-width:100%}.tribe-events-admin-tab-nav li{margin-right:20px}.tribe-events-admin-tab-nav .selected{border-bottom:2px solid #334aff;padding-bottom:10px}.tribe-events-admin-2col-grid{grid-template-areas:".";grid-template-columns:repeat(1,minmax(0,1fr))}.tribe-events-admin-3col-grid{grid-template-areas:". .";grid-template-columns:repeat(2,minmax(0,1fr))}.tribe-events-admin-extensions-title{max-width:100%}.tribe-events-admin-cta{align-items:flex-start;flex-direction:column;overflow:hidden}.tribe-events-admin-footer-logo{width:225px}.tribe-events-admin__system-information{grid-template-areas:".";grid-template-columns:repeat(1,minmax(0,1fr));margin:50px 0}}@media screen and (max-width:480px){.tribe-events-admin-header__logo-word-mark{width:260px}.tribe-events-admin-header__right-image{height:120px}.tribe-events-admin-header__title{font-size:35px}.tribe-events-admin-header__description{max-width:100%}.tribe-events-admin-tab-nav{border:1px solid #e1e1e4;border-radius:20px;flex-direction:column;padding:18px 22px}.tribe-events-admin-tab-nav li{margin-bottom:18px;margin-right:0}.tribe-events-admin-tab-nav .selected{border-bottom:2px solid #334aff;padding-bottom:10px;width:-moz-fit-content;width:fit-content}.tribe-events-admin__line{border:none}.tribe-events-admin-products-card,.tribe-events-admin-products-description{display:none}.tribe-events-admin-container,.tribe-events-admin-content-wrapper.tribe-events-admin-container{max-width:90%}.tribe-events-admin-2col-grid,.tribe-events-admin-3col-grid,.tribe-events-admin-4col-grid{grid-template-areas:".";grid-template-columns:repeat(1,minmax(0,1fr))}.tribe-events-admin-section-header{margin:0}.tribe-events-admin-extensions-title{max-width:100%}.tribe-events-admin-cta__image{height:auto;width:90%}.tribe-events-admin-cta__content,.tribe-events-admin__troubleshooting-cta{align-items:flex-start;padding:32px 23px 45px;width:auto}.tribe-events-admin-cta__content-title{font-size:22px;text-align:left}.tribe-events-admin-cta__content-subtitle{text-align:left}.tribe-events-admin-footer-logo{width:210px}.tribe-events-admin__system-information{grid-template-areas:".";grid-template-columns:repeat(1,minmax(0,1fr));margin:50px 0}.tribe-events-admin__troubleshooting-notice{margin-left:-20px}.tribe-events-admin__troubleshooting-notice_title{max-width:90%}}@media screen and (min-width:1200px){.tribe-events-admin-products-card__group{max-width:47%}}@media screen and (min-width:500px) and (max-width:1080px){.tribe-events-admin-4col-grid{grid-template-areas:". .";grid-template-columns:repeat(2,minmax(0,1fr))}}@media screen and (max-width:1080px){.tribe-events-admin-cta__content-title{font-size:24px}}@media only screen and (max-width:1920px){.tribe-events-admin__system-information-widget-copy{right:20.5vw}}@media only screen and (max-width:1280px){.tribe-events-admin__system-information-widget-copy{right:22vw}}@media only screen and (max-width:768px){.tribe-events-admin__system-information-widget-copy{left:10px;right:auto}.tribe-events-admin__recent-log-filters{flex-direction:column}.tribe-events-admin__recent-log-filters-field{margin-bottom:30px;margin-right:0}.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:first-child,.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:nth-child(2),.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:nth-child(3){padding-right:30px}.tribe-events-admin__issues-found-card-title h3{max-width:90%}}@media only screen and (max-width:480px){.tribe-events-admin__system-information-widget-copy{left:10px;right:auto}.tribe-events-admin__recent-log-filters{flex-direction:column}.tribe-events-admin__recent-log-filters-field{margin-bottom:30px;margin-right:0}.tribe-events-admin__recent-log-filters-select-wrapper:after{right:25px}.tribe-events-admin__issues-found-card-title h3{max-width:80%}.tribe-events-admin__ea-status-table{overflow:scroll}.tribe-events-admin__ea-status-table td{min-width:150px}.tribe-events-admin__ea-status-table td:nth-child(2),.tribe-events-admin__ea-status-table td:nth-child(3){width:100%}}
1
+ .invalid input,input:out-of-range{border:2px solid red!important}.valid input{border:1px solid green}.clearfix{zoom:1}.placeholder{color:#999;cursor:text;padding:4px}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::placeholder,textarea::placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.bubble{background-color:#f9f9f9;border:1px solid #dfdfdf;border-radius:3px;border-spacing:0;padding:10px}.tribe-sticky-tooltip{color:#bbb}td.tribe_message{padding-bottom:10px!important}#tribe_thanks{float:left;margin:5px 0 0;width:200px}.tribe_brand{font-family:Georgia,serif!important;font-size:17px!important;font-weight:400;margin:8px 0}.tribe-rating{color:#3d54ff}.tribe-rating:hover{color:#1c39bb}#tribe-upgrade{background:#f6f6f6;border:1px solid #ccc;border-radius:5px;margin:20px 0 30px;padding:0 20px 20px}#tribe-upgrade .message{background-color:#ffffe0;border:1px solid #e6db55;border-radius:3px;padding:6px 12px}table.plugins .tribe-plugin-update-message{background:#d54e21;color:#fff;display:inline-table;margin:6px 0;padding:10px 12px}table.plugins .tribe-plugin-update-message h4{display:inline;font-weight:700;margin-right:8px}table.plugins .tribe-plugin-update-message h4:after{content:" \00BB "}table.plugins .tribe-plugin-update-message a{color:#fff;text-decoration:underline}.tribe-settings-form{max-width:1000px}.tribe-settings-form fieldset{clear:both;display:inline-block;padding:10px 0}.tribe-settings-form fieldset.tribe-field-license_key legend{width:auto}.tribe-settings-form legend{float:left;font-weight:700;margin-right:20px;width:220px}.tribe-settings-form .tribe-field-wrap{float:left;max-width:500px}.tribe-settings-form .tribe-field-wrap :first-child{margin-top:0}.tribe-settings-form .tribe-field-checkbox_list label,.tribe-settings-form .tribe-field-radio label{display:block;margin:5px 0 5px 20px;text-indent:-20px}.tribe-settings-form .tribe-field-checkbox_list label>p,.tribe-settings-form .tribe-field-radio label>p{margin-left:1px;text-indent:0}.tribe-settings-form .tribe-field-checkbox_list label input,.tribe-settings-form .tribe-field-radio label input{margin-right:5px}.tribe-settings-form .tribe-settings-form-wrap .description,.tribe-settings-form .tribe-settings-form-wrap fieldset,.tribe-settings-form fieldset[id^=tribe-field-geoloc_]{padding-left:12px}.tribe-settings-form .tribe-settings-form-wrap fieldset .description{margin-left:0;max-width:450px;padding-left:0}.tribe-settings-form .tribe-settings-form-wrap fieldset .tribe-style-selection{margin-bottom:18px}.tribe-settings-form .tribe-settings-form-wrap #tribe-field-stylesheetOption .description{color:#999;margin-left:1px}.tribe-settings-form .tribe-settings-form-wrap h3{background-color:#f9f9f9;margin-bottom:10px;padding:6px 0 6px 12px}.tribe-settings-form .tribe-settings-form-wrap .contained,.tribe-settings-form .tribe-settings-form-wrap .system-info,.tribe-settings-form .tribe-settings-form-wrap .tribe-sysinfo-optin-msg,.tribe-settings-form .tribe-settings-form-wrap h3+p{margin:0 0 10px;padding-left:12px}.tribe_settings .tribe-field-indent{margin-left:245px}.tribe_settings #pu_dashboard_message{display:none}.tribe_settings .tribe-errors-list{margin-left:15px}.tribe_settings .expiring-license{color:red}.tribe_settings .tribe-error{border:1px solid red}.tribe_settings .tribe-field-description{margin-bottom:0;position:relative;top:-12px}.tribe_settings #ical-link{top:-14px}#modern-tribe-info{background-color:#f9f9f9;border:1px solid #ccc;border-radius:4px;margin:20px 0;padding:8px 20px 12px}#modern-tribe-info img{margin:10px 0}#modern-tribe-info ul{list-style:disc;margin-left:20px}#modern-tribe-info ul ul{list-style:circle}.tribe-field-inline-dropdown{margin-left:0;margin-right:0}.tribe-field-inline-text{line-height:28px;margin:0 2px}.tribe-field-textarea.tribe-size-small textarea{height:60px;width:180px}.tribe-field-textarea.tribe-size-medium textarea{height:80px;width:300px}.tribe-field-textarea.tribe-size-large textarea{height:120px;width:450px}.tribe-field-email.tribe-size-small input,.tribe-field-license_key.tribe-size-small input,.tribe-field-text.tribe-size-small input{width:50px}.tribe-field-email.tribe-size-medium input,.tribe-field-license_key.tribe-size-medium input,.tribe-field-text.tribe-size-medium input{width:225px}.tribe-field-email.tribe-size-large input,.tribe-field-license_key.tribe-size-large input,.tribe-field-text.tribe-size-large input{width:450px}.tribe-field-dropdown.tribe-size-small select{width:100px}.tribe-field-dropdown.tribe-size-medium select{width:300px}.tribe-field-dropdown.tribe-size-large select{width:450px}.tribe-field-wrapped_html.tribe-size-large .tribe-field-wrap{max-width:600px}.tribe-field-wrapped_html.tribe-size-large .tribe-field-wrap .description{max-width:100%}.tribe-field-dropdown_chosen.tribe-size-small select{width:100px}.tribe-field-dropdown_chosen.tribe-size-medium select{width:200px}.tribe-field-dropdown_chosen.tribe-size-large select{width:300px}.tribe-field-wrap .tooltip:first-child{font-style:normal}.tribe-field.indent{margin-left:252px;width:75%}.tribe-field.indent legend{font-weight:400;width:auto}.tribe-field.indent .tribe-field-wrap{padding-right:12px}.tribe-field.indent.tribe-field-radio .tribe-field-wrap{clear:left;margin-top:12px}.tribe-field.light-bordered{background-color:#fff;border:1px solid #d3d3d3}.ajax-loading-license,.invalid-key,.valid-key{display:none;margin:0 5px}.ajax-loading-license{position:relative;top:5px}.key-validity{display:inline-block}.invalid-key,.optin-fail{color:red}.optin-success,.valid-key{color:green}.valid-key.service-msg{color:#b72}#additional-field-table{margin-bottom:20px}.tribe-admin-box-left{float:left;width:20%}.tribe-admin-box-left,.tribe-admin-box-right{background-color:#f9f9f9;border:1px solid #ccc;border-radius:4px;margin:20px 0;padding:0 20px 15px}.tribe-admin-box-right{float:right;width:68%}.ajax-loader{float:right;margin:10px}.tribe-arrangeable-item{border:1px solid #d3d3d3;border-radius:3px}.tribe-arrangeable-item .ui-state-default{border:none}.tribe-arrangeable-item-top{padding:6px}.tribe-arrangeable-item-top:hover{cursor:move}.tribe-arrangeable-action{float:right}.tribe-arrangeable-child{background-color:#f9f9f9;border-top:1px solid #d3d3d3;display:none;padding:25px}.tribe-arrangeable-child label{display:block;margin:0 0 7px}.tribe_events_active_filter_type_options{margin:10px 0}.tribe_events_active_filter_type_options label{margin:7px 0}#event_organizer td small,.OrganizerInfo td small{display:block;margin:0;max-width:250px}#event_organizer .organizer-email,.OrganizerInfo .organizer-email{vertical-align:top}.tribe-table-field-label{max-width:100%;width:200px}#tribe-help-general,#tribe-help-sidebar{float:left;margin-top:20px}#tribe-help-general p{margin-left:15px}#tribe-help-general ul{list-style-type:square}#tribe-help-general ol,#tribe-help-general ul{margin-bottom:20px;margin-left:35px}#tribe-help-general h3{background-color:#f9f9f9;margin-bottom:10px;padding:6px 0 6px 12px}#tribe-help-general h3~h3{margin-top:2.25em}#tribe-help-general h3+p{margin:0 0 20px;padding-left:12px}#tribe-help-general{width:65%}.tribe-help-section{padding-bottom:10px}.tribe-section-type-box{background-color:#f9f9f9;border:1px solid #ccc;border-radius:4px;padding:8px 20px 12px}.tribe-section-type-box img{height:auto;margin:10px 0;max-width:300px}.tribe-section-type-box ul{list-style:disc;margin-left:20px}.tribe-section-type-box ul ul{list-style:circle}#tribe-log-controls{padding-bottom:1rem;padding-left:12px}#tribe-log-controls>div{display:inline-block;padding-right:1rem}#tribe-log-controls .working{opacity:1;transition:opacity .2s}#tribe-log-controls .working.hidden{opacity:0;transition:opacity .2s}#tribe-log-viewer,#tribe-system-info dl.support-stats,.template-updates-wrapper{background:#000;border-radius:2px;color:#888;max-height:400px;overflow:scroll;padding:10px}#tribe-system-info dl.support-stats dt,.template-updates-wrapper dt{clear:both;float:left;font-weight:700;text-transform:uppercase;width:25%}#tribe-system-info dl.support-stats dd,.template-updates-wrapper dd{margin-left:25%;padding-left:10px}.system-info-copy .system-info-copy-btn{padding:6px}.system-info-copy .system-info-copy-btn .dashicons{padding-right:10px}.template-updates-wrapper p{margin-top:0}#tribe-help-sidebar{margin:20px 0 0 3%;max-width:225px;width:32%}.tribe-help-plugin-info{border:1px solid #ccc;padding:0 12px 12px}.tribe-help-plugin-info dd,.tribe-help-plugin-info dt{display:inline;margin:0}.tribe-help-plugin-info dt{font-weight:700}.tribe-help-plugin-info dd:after{content:"";display:block;height:.4em}.tribe-help-plugin-info dd:last-child:after{height:0}.tribe-help-plugin-info+.tribe-help-plugin-info{margin-top:20px}.tribe-help-plugin-info>div{line-height:2em}.tribe-help-plugin-info .star-rating{display:inline-block;margin-left:3px;position:relative;top:-2px}.tribe-help-plugin-info .tribe-list-addons{color:#21a6cb;font-size:24px;list-style:circle inside;margin-bottom:10px;margin-top:10px;padding-left:4px}.tribe-help-plugin-info .tribe-list-addons a{font-size:13px;left:-5px;position:relative;top:-5px}.tribe-help-plugin-info .tribe-list-addons .tribe-active-addon{list-style:disc inside}.ui-widget-overlay{background:#666;filter:alpha(opacity=50);opacity:.5}.ui-widget-shadow{background:#000;border-radius:5px;filter:alpha(opacity=20);margin:-5px 0 0 -5px;opacity:.2;padding:5px}.ui-resizable{position:relative}.ui-resizable-handle{display:block;font-size:.1px;position:absolute;z-index:99999}.ui-resizable-autohide .ui-resizable-handle,.ui-resizable-disabled .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;left:0;top:-5px;width:100%}.ui-resizable-s{bottom:-5px;cursor:s-resize;height:7px;left:0;width:100%}.ui-resizable-e{cursor:e-resize;height:100%;right:-5px;top:0;width:7px}.ui-resizable-w{cursor:w-resize;height:100%;left:-5px;top:0;width:7px}.ui-resizable-se{bottom:1px;cursor:se-resize;height:12px;right:1px;width:12px}.ui-resizable-sw{bottom:-5px;cursor:sw-resize;height:9px;left:-5px;width:9px}.ui-resizable-nw{cursor:nw-resize;height:9px;left:-5px;top:-5px;width:9px}.ui-resizable-ne{cursor:ne-resize;height:9px;right:-5px;top:-5px;width:9px}.ui-dialog{padding:.2em;position:relative;width:375px}.ui-dialog .ui-dialog-titlebar{padding:.5em .3em .3em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0 .2em}.ui-dialog .ui-dialog-titlebar-close{height:18px;margin:-10px 0 0;padding:1px;position:absolute;right:.3em;top:50%;width:19px}.ui-dialog .ui-dialog-titlebar-close span{display:block;margin-left:-8px;margin-top:-8px}.ui-dialog .ui-dialog-titlebar-close:focus,.ui-dialog .ui-dialog-titlebar-close:hover{padding:0}.ui-dialog .ui-dialog-content{background:none;border:0;overflow:auto;padding:.5em 1em;zoom:1}.ui-dialog .ui-dialog-buttonpane{background-image:none;border-width:1px 0 0;margin:.5em 0 0;padding:.3em 1em .5em!important;text-align:right}.ui-dialog .ui-dialog-buttonpane button{cursor:pointer;line-height:1.4em;margin:.5em .4em!important;overflow:visible;padding:.2em .6em .3em;text-shadow:none;width:auto}.ui-dialog .ui-resizable-se{bottom:3px;height:14px;right:3px;width:14px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:none!important;text-align:center}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button .ui-button-text{display:block;line-height:1.4}#ui-datepicker-div{display:none}#tribe-loading{background:#fff;background:hsla(0,0%,100%,.8);display:none;height:100%;left:0;position:absolute;top:0;transition:all 1s linear;width:100%;z-index:4}#tribe-loading span{background:url(../images/tribe-loading.gif) 0 0 no-repeat;background-size:32px 32px;height:32px;left:50%;margin:-16px 0 0 -16px;position:absolute;top:50%;width:32px}.tribe_update_page{max-width:850px}.tribe-half-column{float:left;margin-bottom:30px;margin-right:5%;width:45%}.tribe-row:after,.tribe-row:before{content:"";display:table}.tribe-row,.tribe-row:after{clear:both}.tribe-row .tribe-half-column:last-child{margin-right:0;width:50%}.tribe_update_page h2{font-size:30px;line-height:1.2;margin-bottom:20px}.tribe_update_page h3{font-size:24px;font-weight:400;line-height:24px;margin-top:0}.tribe_update_page h4{font-size:18px;font-weight:600;line-height:18px;margin:0}.tribe_update_page p{font-size:15px}p.tribe-update-message{font-size:18px;font-weight:400}.tribe_update_page h4:before{content:"\f145";font-family:dashicons;font-size:34px;line-height:1;margin-right:5px;position:relative;top:5px}a.tribe-rating-link{text-decoration:none}.tribe-update-links{margin-top:30px}.tribe_update_page li:before{content:"\2022";padding-right:3px}.tribe_update_page .rss-widget{margin:1em 0}.tribe_update_page a.rsswidget{font-size:14px;font-weight:400;line-height:1}.tribe_update_page .rss-widget li:before{display:none}.tribe-events-widget-admin-form__input-section p{margin:0}.tribe-events-widget-admin-form__input-section h4{margin:.5em 0}.tribe-update-bar{display:inline-block}.tribe-update-bar .progress{border:1px solid #ccc;float:left;margin-right:1rem;padding:1px;width:18rem}.tribe-update-bar .progress .bar{background:#7ad03a;height:1rem;width:1%}#tribe-dialog-wrapper>div{padding:1rem}#tribe-dialog-wrapper>div .stage{display:none}#tribe-dialog-wrapper #heading{background:#fff}#tribe-dialog-wrapper label{display:block}#tribe-dialog-wrapper .select-single-container{border:1px solid #888;height:300px;overflow-y:scroll}#tribe-dialog-wrapper .select-single-container label{opacity:1;padding:3px 5px;transition:opacity .2s}#tribe-dialog-wrapper .select-single-container label:nth-child(odd){background:#fff}#tribe-dialog-wrapper .select-single-container label.selected{background:#0073aa;color:#fff;font-weight:700}#tribe-dialog-wrapper .select-single-container label input{display:none}#tribe-dialog-wrapper .select-single-container.updating label{opacity:.35;transition:opacity .2s}.ui-front{z-index:1000000}.wp-list-table.plugins .column-description .update-message{color:#d54e21}.api-check{min-height:100px;padding:1em}.api-check+.notice-dismiss:hover:before{color:#fff}.api-check:after,.api-check:before{content:"";display:table}.api-check:after{clear:both}.api-check .tribe-mascot{bottom:0;display:none;padding:0 1rem 0 0;position:absolute;right:0;top:0}.api-check .tribe-mascot img{display:inline-block;height:100%;max-height:150px;max-width:150px;vertical-align:middle;width:auto}.api-check p{line-height:1.7;margin-bottom:1em}.api-check a{text-decoration:none}.api-check a:hover{text-decoration:underline}.api-check .plugin-list{display:inline;font-weight:600;margin:0;padding:0}.api-check .plugin-list span.plugin-invalid:after{content:", "}.api-check .plugin-list span.plugin-invalid:last-of-type:after{content:""}.tribe-marketing-notice{padding:1em}.tribe-marketing-notice+.notice-dismiss:hover:before{color:#fff}.tribe-marketing-notice:after,.tribe-marketing-notice:before{content:"";display:table}.tribe-marketing-notice:after{clear:both}.tribe-marketing-notice .tribe-marketing-notice__icon{display:none;flex-shrink:0;padding:0;position:static}.tribe-marketing-notice .tribe-marketing-notice__icon img{display:inline-block;max-height:100%;max-width:none;vertical-align:middle;width:100%}.tribe-marketing-notice h3{margin-bottom:.5em;margin-top:.5em}.tribe-marketing-notice p{line-height:1.7;margin-bottom:.5em}.tribe-marketing-notice a{text-decoration:none}.tribe-marketing-notice a:hover{text-decoration:underline}#wpcontent .notice-tribe-banner{align-items:center;background:#161b7d;border:0;box-shadow:none;display:flex;justify-content:flex-start;margin:0 0 16px;padding-right:0}.notice-tribe-banner .tribe-marketing-notice__icon{width:47px}.notice-tribe-banner .tribe-marketing-notice__content{margin-left:0;padding:1em 0}.notice-tribe-banner h3{color:#fff;display:block;font-size:.875rem;line-height:1.25;margin:0 0 .25rem}.notice-tribe-banner a{border-bottom:1px solid #fff;line-height:1.25;margin:0;text-decoration:none}.notice-tribe-banner a:hover{text-decoration:none}.notice-tribe-banner a,.notice-tribe-banner p{color:#fff;display:inline-block;font-size:.875rem;line-height:1.25}.notice-tribe-banner p{display:inline-block;margin:0;padding:0}.notice-tribe-banner .tribe-marketing-notice{align-items:center;display:flex;justify-content:flex-start;margin:0 auto;min-height:65px;padding:0 .75rem;width:100%}.events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice,.tribe-welcome .notice-tribe-banner .tribe-marketing-notice,.tribe_events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice{max-width:100%}.notice-tribe-banner .notice-dismiss{position:static}.notice-tribe-banner .notice-dismiss:before{color:#eaf1ff}.tribe-dropdown,.tribe-ea-dropdown{max-width:100%;width:auto}.tribe-dropdown.select2-container .selection,.tribe-ea-dropdown.select2-container .selection{margin-top:inherit}.tribe-dropdown .select2-selection--single,.tribe-ea-dropdown .select2-selection--single{height:32px}.tribe-dropdown .select2-selection--single .select2-selection__clear,.tribe-ea-dropdown .select2-selection--single .select2-selection__clear{line-height:28px}.tribe-dropdown .select2-selection--single .select2-selection__rendered,.tribe-ea-dropdown .select2-selection--single .select2-selection__rendered{line-height:32px;padding-right:28px}.tribe-dropdown.select2-container--focus .select2-selection--single,.tribe-ea-dropdown.select2-container--focus .select2-selection--single{border-color:#5897fb;box-shadow:0 0 5px rgba(0,0,0,.1)}.tribe-dropdown.select2-container--open .select2-search__field,.tribe-ea-dropdown.select2-container--open .select2-search__field{padding:0}.tribe-dropdown.select2-container--open .select2-dropdown--below,.tribe-ea-dropdown.select2-container--open .select2-dropdown--below{border-top:1px solid #aaa;margin-top:-1px}.tribe-dropdown.select2-container--open .select2-dropdown--above,.tribe-ea-dropdown.select2-container--open .select2-dropdown--above{border-bottom:1px solid #aaa;margin-bottom:-16px}.tribe-dropdown.select2-container--open .select2-selection--single,.tribe-ea-dropdown.select2-container--open .select2-selection--single{border-bottom-left-radius:0;border-bottom-right-radius:0;border-color:#aaa}.tribe-dropdown.select2-container--open .select2-selection__arrow b,.tribe-ea-dropdown.select2-container--open .select2-selection__arrow b{transform:rotate(180deg)}.tribe-dropdown.select2-selection--single,.tribe-ea-dropdown.select2-selection--single{background-image:none;border:1px solid #ccc;border-radius:3px;overflow:hidden}.tribe-dropdown.select2-selection--single>.select2-selection__rendered,.tribe-ea-dropdown.select2-selection--single>.select2-selection__rendered{white-space:normal}.tribe-dropdown.select2-selection--single .select2-selection__arrow,.tribe-ea-dropdown.select2-selection--single .select2-selection__arrow{background:transparent;background-image:none;border-left:0;top:2px;width:26px}.tribe-dropdown.select2-selection--single .select2-selection__arrow b,.tribe-ea-dropdown.select2-selection--single .select2-selection__arrow b{background:#fff url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%206l5%205%205-5%202%201-7%207-7-7%202-1z%22%20fill%3D%22%23555%22%2F%3E%3C%2Fsvg%3E") no-repeat right 5px top 55%;background-size:auto;background-size:16px 16px;border:0;bottom:0;display:block;height:auto;left:0;margin:0;padding:0;right:0;top:0;width:auto}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered{background-image:none;border:1px solid #ccc;border-radius:3px;min-height:25px}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered .select2-search--inline,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered .select2-search--inline{line-height:25px}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered .select2-search--inline input,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered .select2-search--inline input{padding-bottom:0;padding-top:0}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice{line-height:19px;margin-top:2px;padding-bottom:0;padding-top:0}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice div,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice div{line-height:inherit}.tribe-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice__remove,.tribe-ea-dropdown .select2-selection--multiple .select2-selection__rendered .select2-selection__choice__remove{left:4px;top:3px;transition-property:border,color}.select2-results .select2-results__option{color:#939393;font-weight:400;margin-bottom:0}.select2-results .select2-results__option[aria-disabled=true]{background-color:#e0e0e0}.select2-results.select2-results__option--highlighted{background-color:#efefef;color:#a1a1a1;cursor:default;display:block}.wp-core-ui .button-red{background-color:#a00;border-color:#9b2124;box-shadow:inset 0 1px 0 rgba(120,200,230,.5);color:#fff;text-decoration:none;text-shadow:0 1px 0 rgba(0,0,0,.1)}.wp-core-ui .button-red.focus,.wp-core-ui .button-red.hover,.wp-core-ui .button-red:focus,.wp-core-ui .button-red:hover{background-color:#a00;border-color:#7f1c1f;box-shadow:inset 0 1px 0 rgba(120,200,230,.6);color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.3)}.wp-core-ui .button-red.focus,.wp-core-ui .button-red:focus{border-color:#500f0e;box-shadow:inset 0 1px 0 rgba(120,200,230,.6),1px 1px 2px rgba(0,0,0,.4)}.wp-core-ui .button-red.active,.wp-core-ui .button-red.active:focus,.wp-core-ui .button-red.active:hover,.wp-core-ui .button-red:active{background:#7f1c1f;border-color:#601312 #ae2426 #ae2426;box-shadow:inset 0 1px 0 rgba(0,0,0,.1);color:hsla(0,0%,100%,.95);text-shadow:0 1px 0 rgba(0,0,0,.1)}.wp-core-ui .button-red-disabled,.wp-core-ui .button-red:disabled,.wp-core-ui .button-red[disabled]{background:#ba292b!important;border-color:#7f1c1f!important;box-shadow:none!important;color:#e79496!important;cursor:default;text-shadow:0 -1px 0 rgba(0,0,0,.1)!important}.ticket_form .select2-container .select2-selection--single .select2-selection__arrow{display:none}.clear{zoom:1}.clear:after,.clear:before{content:" ";display:table}.clear:after{clear:both}.checkmark:after{border:solid #0ab152;border-width:0 3px 3px 0;content:"";display:block;height:15px;transform:rotate(45deg);width:8px}.checkmark.checkmark-right:after{float:right;margin-right:2em}.checkmark.checkmark-left:after{float:left;margin-left:2em}.checkmark.no-checkmark:after{display:none}.complete,.ok,.on,.yes,[data-status=complete],[data-status=ok],[data-status=on],[data-status=yes]{color:#0ab152}.incomplete,.ko,.no,.off,[data-status=incomplete],[data-status=ko],[data-status=no],[data-status=off]{color:#ff2500}.plugin-card-event-tickets-plus .column-downloaded,.plugin-card-event-tickets-plus .column-rating,.plugin-card-event-tickets-plus .column-updated,.plugin-card-event-tickets .column-downloaded,.plugin-card-event-tickets .column-rating,.plugin-card-event-tickets .column-updated,.plugin-card-events-calendar-pro .column-downloaded,.plugin-card-events-calendar-pro .column-rating,.plugin-card-events-calendar-pro .column-updated,.plugin-card-events-community-tickets .column-downloaded,.plugin-card-events-community-tickets .column-rating,.plugin-card-events-community-tickets .column-updated,.plugin-card-events-community .column-downloaded,.plugin-card-events-community .column-rating,.plugin-card-events-community .column-updated,.plugin-card-image-widget-plus .column-downloaded,.plugin-card-image-widget-plus .column-rating,.plugin-card-image-widget-plus .column-updated,.plugin-card-image-widget .column-downloaded,.plugin-card-image-widget .column-rating,.plugin-card-image-widget .column-updated,.plugin-card-the-events-calendar .column-downloaded,.plugin-card-the-events-calendar .column-rating,.plugin-card-the-events-calendar .column-updated,.plugin-card-tribe-eventbrite .column-downloaded,.plugin-card-tribe-eventbrite .column-rating,.plugin-card-tribe-eventbrite .column-updated,.plugin-card-tribe-filterbar .column-downloaded,.plugin-card-tribe-filterbar .column-rating,.plugin-card-tribe-filterbar .column-updated{display:none}.tribe-events-admin-content-wrapper{font-style:normal;margin:0 auto;padding:20px;width:calc(100% - 40px)}.tribe-events-admin-card{background:#fff;border:1px solid #e1e1e4;border-radius:16px;box-sizing:border-box;display:block;margin:0 auto 36px;padding:27px;text-align:center}.tribe-events-admin-card--2up .tribe-events-admin-card__title{max-width:260px}.tribe-events-admin-card--3up .tribe-events-admin-card__description{height:71px}.tribe-events-admin-card--3up .tribe-events-admin-card__image{margin-bottom:28px}.tribe-events-admin-card__button{background-color:#fff;border:none;color:#3d54ff;font-size:14px;font-weight:700;letter-spacing:1px;line-height:16px;position:absolute;right:20px;text-transform:uppercase;top:17px}.tribe-events-admin-card__button:hover{color:#161b7d}.tribe-events-admin-card__description{color:#000;font-size:14px;font-style:normal;font-weight:400;line-height:22px;margin-top:16px}.tribe-events-admin-card__image{display:block;height:100px;margin:0 auto}.tribe-events-admin-card__link{color:#3d54ff;display:inline-block;font-size:16px;font-style:normal;font-weight:700;line-height:18px;margin-top:24px;position:relative;text-decoration:none}.tribe-events-admin-card__link:hover{color:#161b7d}.tribe-events-admin-card__link:after{border-style:solid;border-width:0 0 1px;bottom:-4px;content:"";left:0;position:absolute;width:100%}.tribe-events-admin-card__title{color:#0f1031;font-size:20px;font-weight:700;line-height:23px;margin:auto}.tribe-events-admin-card-grid{max-width:1048px}.tribe-events-admin-section-header{color:#000;font-size:24px;font-weight:700;line-height:28px;margin:21px 0 24px}input[type=checkbox].tribe-common-switch__input{display:none}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label{background:#fff;border:1px solid #aaa;border-radius:4px;box-sizing:border-box;cursor:pointer;display:block;height:18px;outline:0;padding:3px;position:relative;transition:all .2s ease;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:27px}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label:after,input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label:before{content:"";display:block;height:10px;position:relative;width:10px}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label:after{background:#878787;border-radius:2px;content:"";left:0;transition:all .2s ease}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label:before{display:none}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label::-moz-selection{background:none}input[type=checkbox].tribe-common-switch__input+.tribe-common-switch__label::selection{background:none}input[type=checkbox].tribe-common-switch__input:checked+.tribe-common-switch__label:after{background:#2e709d;left:50%}body.tribe-welcome,body.tribe_events_page_tribe-help{background-color:#fff;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}body.tribe-welcome .update-nag,body.tribe_events_page_tribe-help .update-nag{display:none}body.tribe-welcome #wpcontent,body.tribe_events_page_tribe-help #wpcontent{padding:0}body.tribe-welcome .tribe_settings,body.tribe_events_page_tribe-help .tribe_settings{margin:0}body.tribe-welcome #wpfooter,body.tribe-welcome .tribe_settings>h1,body.tribe_events_page_tribe-help #wpfooter,body.tribe_events_page_tribe-help .tribe_settings>h1{display:none}body.tribe-welcome #wpbody-content,body.tribe_events_page_tribe-help #wpbody-content{padding-bottom:25px}body.tribe-welcome .tribe-dependency-error,body.tribe_events_page_tribe-help .tribe-dependency-error{display:none}.tribe-events-admin-header__logo-word-mark{display:inline-block;height:auto;margin:0 0 26px;vertical-align:middle;width:312px}.tribe-events-admin-content-wrapper{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;padding:0 0 30px}.tribe-events-admin-header{font-family:Helvetica Neue,Helvetica,Arial,sans-serif;padding:45px 0 0}.tribe-events-admin-header__right-image{height:280px;position:absolute;right:0;top:0;width:auto;z-index:-1}.tribe-events-admin-header__title{font-size:48px;line-height:48px;margin:0 0 18px}.tribe-events-admin-header__description{font-size:18px;line-height:28px;margin-bottom:44px;max-width:60%}.tribe-events-admin-tab-nav{display:flex;margin:0}.tribe-events-admin-tab-nav li{cursor:pointer;font-size:16px;font-weight:500;margin-bottom:0;margin-right:30px}.tribe-events-admin-tab-nav li:hover{color:#334aff}.tribe-events-admin-tab-nav .selected{border-bottom:3px solid #334aff;color:#334aff;padding-bottom:17px}.tribe-events-admin-tab-nav li:after{background:#334aff;border-radius:100px;bottom:0;content:"";display:block;height:3px;left:0;position:absolute;right:0}.tribe-events-admin__line{border-top:1px solid #e1e1e4}.tribe-events-admin-products-description{color:#0f1031;font-size:14px;line-height:2}.tribe-events-admin-products-card{align-items:center;border:1px solid #e1e1e4;border-radius:20px;display:flex;padding:10px 15px}.tribe-events-admin-products-card__icon{height:40px;-o-object-fit:contain;object-fit:contain;width:40px}.tribe-events-admin-products-card__group{margin:0 20px;max-width:55%}.tribe-events-admin-products-card__group-title{color:#0f1031;font-size:16px;font-weight:700;line-height:1;margin:0}.tribe-events-admin-products-card__group-description{font-size:12px;margin-top:5px}.tribe-events-admin-products-card__button{background-color:#fff;border:1px solid #e1e1e4;border-radius:20px;color:#0f1031;font-size:12px;font-weight:700;letter-spacing:1px;line-height:16px;margin-left:auto;padding:10px 15px;text-decoration:none;text-transform:uppercase}.tribe-events-admin-products-card__button:hover{background-color:#334aff;color:#fff}.tribe-events-admin-products-card__button:active,.tribe-events-admin-products-card__button:focus{box-shadow:none;outline:none}.tribe-events-admin-products-card__button--active,.tribe-events-admin-products-card__button--active:active,.tribe-events-admin-products-card__button--active:focus,.tribe-events-admin-products-card__button--active:hover{background:rgba(61,84,255,.16);color:#334aff;cursor:not-allowed;text-transform:uppercase}.tribe-events-admin-card--1up{width:100%}.tribe-events-admin-card--no-pad{padding:0}.tribe-events-admin-card--no-pad .tribe-events-admin-card__image{display:block;height:152px;margin:0;padding:0}.tribe-events-admin-card--no-pad .tribe-events-admin-card__title{font-size:28px;line-height:34px;text-align:left}.tribe-events-admin-card--no-pad .tribe-events-admin-card__description{margin:0;padding:0;text-align:left}.tribe-events-admin-card--no-pad .tribe-events-admin-card__link{margin:0;padding:0}.tribe-events-admin-card--faq{display:inline-block;font-size:0;height:147px;margin:0 0 0 30px;padding:24px 16px 22px 20px;width:230px}.tribe-events-admin-card--faq:first-child{margin-left:0}.tribe-events-admin-card--faq img{float:left;height:22px;width:16px}.tribe-events-admin-card--faq .tribe-events-admin-faq__question{color:#334aff;font-size:16px;line-height:19px;margin:0 0 12px 26px;text-align:left}.tribe-events-admin-card--faq .tribe-events-admin-faq__answer{font-size:13px;line-height:16px;margin-left:26px;text-align:left}.tribe-events-admin-video{border-radius:16px;height:200px;margin-bottom:72px;-webkit-mask-image:-webkit-radial-gradient(circle,#fff 100%,#000 0);overflow:hidden;-webkit-transform:rotate(.000001deg)}.tribe-events-admin-video iframe{width:100%}.tribe-events-admin-card--promo-blue{background-color:#3d54ff;background-image:url(../images/welcome/promo.jpg)}.tribe-events-admin-card--promo-blue .tribe-events-admin-card__description{color:#fff;font-size:16px;margin-bottom:16px;text-align:left}.tribe-events-admin-card--promo-blue .tribe-events-admin-card__title{color:#fff;text-align:left}.tribe-events-admin-graphic{position:absolute;right:0;top:106px;z-index:-1}.tribe-events-admin-graphic--desktop-only{display:none}.tribe-events-admin-graphic--mobile-only{display:block}.tribe-events-admin-card__form{position:relative}input[type=email].tribe-events-admin-card__input{background:#fff;border:1px solid #e1e1e4;border-radius:16px;box-sizing:border-box;font-size:14px;height:54px}input[type=email].tribe-events-admin-card__input:-ms-input-placeholder{color:rgba(15,16,49,.72);letter-spacing:.5px;padding-left:10px}input[type=email].tribe-events-admin-card__input::placeholder{color:rgba(15,16,49,.72);letter-spacing:.5px;padding-left:10px}.tribe-events-admin-container,.tribe-events-admin-content-wrapper.tribe-events-admin-container{margin:0 auto;max-width:1024px;width:90%}.tribe-events-admin-2col-grid{display:grid;grid-gap:15px 30px;gap:15px 30px;grid-template-areas:". .";grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:1fr}.tribe-events-admin-3col-grid{display:grid;grid-gap:30px;gap:30px;grid-template-areas:". . .";grid-template-columns:repeat(3,minmax(0,1fr));grid-template-rows:1fr}.tribe-events-admin-4col-grid{display:grid;grid-gap:30px;gap:30px;grid-template-areas:". . . .";grid-template-columns:repeat(4,minmax(0,1fr));grid-template-rows:1fr}.tribe-events-admin-products{margin:10px 0 0}.tribe-events-admin-quick-nav{background:#fff;border:1px solid #e1e1e4;border-radius:16px;box-sizing:border-box;display:block;margin:40px 0 78px;padding:18px 23px 2px}.tribe-events-admin-quick-nav__link{color:#3d54ff;font-size:16px;font-weight:700;line-height:18px;text-align:center;text-decoration:none}.tribe-events-admin-quick-nav__link:hover{color:#161b7d}.tribe-events-admin-quick-nav__link-item{display:block;padding-bottom:19px}.tribe-events-admin-quick-nav__links{display:inline}.tribe-events-admin-quick-nav__title{color:rgba(15,16,49,.72);display:inline-block;font-size:14px;font-weight:400;line-height:16px;padding-bottom:14px;text-transform:uppercase}.tribe-events-admin-title{padding-top:14px}.tribe-events-admin-title__description{color:#0f1031;font-size:16px;font-weight:400;line-height:24px;max-width:584px;padding-top:15px}.tribe-events-admin-title__heading{color:#0f1031;display:inline-block;font-size:24px;font-weight:700;line-height:28px;margin:5px 0 0}.tribe-events-admin-title__logo{margin-right:8px;vertical-align:top;width:34px}.tribe-events-admin-notice{background-color:#3d54ff;height:65px}.tribe-events-admin-notice .tribe-events-admin-content-wrapper{padding-bottom:0;padding-top:8px}.tribe-events-admin-notice p{color:#fff;display:inline-block;font-family:Helvetica;font-size:16px;line-height:18px;margin-top:0;padding-bottom:12px;padding-left:16px;vertical-align:middle;width:calc(100% - 60px)}.tribe-events-admin-notice__logo{display:inline-block}.tribe-events-admin-tickets .tribe-events-admin-section-header{font-size:28px;line-height:32px}.tribe-events-admin-tickets .tribe-events-admin-graphic--desktop-only{width:365px}.tribe-events-admin-tickets .tribe-events-admin-graphic--mobile-only{top:230px;width:300px}.tribe-events-admin-tickets .tribe-events-admin-title__heading{margin-top:0}.tribe-events-admin-tickets .tribe-events-admin-title__logo{margin-right:4px;width:32px}.tribe-events-admin-kb{margin:10px 0 0}.tribe-events-admin-kb-card{border:1px solid #e1e1e4;border-radius:20px}.tribe-events-admin-kb-card__image{height:auto;width:100%}.tribe-events-admin-kb-card__title{color:#0f1031;flex-grow:0;font-size:20px;font-weight:700;line-height:1.2;margin:0;padding:20px 28px 10px}.tribe-events-admin-kb-card__links{margin:0;padding:0 28px 25px}.tribe-events-admin-kb-card__links li{margin:0 0 10px}.tribe-events-admin-kb-card__links li a{color:#334aff;font-size:14px;line-height:1.2;text-decoration:none}.tribe-events-admin-kb-card__links li a:focus{box-shadow:none;outline:none}.tribe-events-admin-kb-card__links li a:hover{color:#1c39bb}.tribe-events-admin-section-header{align-items:center;display:flex;justify-content:space-between;margin:50px 0 0}.tribe-events-admin-section-header h3{color:#0f1031;font-size:28px;font-weight:700;line-height:1}.tribe-events-admin-section-header a{border-bottom:2px solid #334aff;color:#334aff;font-size:14px;padding-bottom:2px;text-decoration:none}.tribe-events-admin-section-header a:focus{box-shadow:none;outline:none}.tribe-events-admin-section-header a:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin-faq{margin:10px 0 0}.tribe-events-admin-faq-card{border:1px solid #e1e1e4;border-radius:20px;display:flex;justify-content:space-between;padding:24px 15px 19px 19px}.tribe-events-admin-faq-card a{color:#0f1031}.tribe-events-admin-faq-card a:focus{box-shadow:none;outline:none}.tribe-events-admin-faq-card a:hover{color:#1c39bb}.tribe-events-admin-faq-card__icon img{height:22px;width:16px}.tribe-events-admin-faq-card__content{margin-left:10px}.tribe-events-admin-faq__question,.tribe-events-admin-faq__question a{color:#334aff;font-size:16px;text-decoration:none}.tribe-events-admin-faq__question a:focus{box-shadow:none;outline:none}.tribe-events-admin-faq__question a:hover{color:#1c39bb}.tribe-events-admin-faq__answer{color:#0f1031;font-size:13px;margin-top:18px}.tribe-events-admin-extensions-title{color:#0f1031;font-size:16px;line-height:1.5;margin:0 0 30px;max-width:70%}.tribe-events-admin-extensions{margin:10px 0 0}.tribe-events-admin-extensions-card{border:1px solid #e1e1e4;border-radius:20px;border-top:8px solid #334aff;padding:48px 35px 24px 25px}.tribe-events-admin-extensions-card__title{font-size:20px;margin:0}.tribe-events-admin-extensions-card__title a{color:#0f1031;font-family:Helvetica;font-size:20px;font-weight:700;line-height:1.2;text-decoration:none}.tribe-events-admin-extensions-card__title a:active,.tribe-events-admin-extensions-card__title a:focus,.tribe-events-admin-extensions-card__title a:hover{box-shadow:none;color:#334aff}.tribe-events-admin-extensions-card__description{color:#0f1031;font-family:Helvetica;font-size:14px;line-height:1.43;margin:20px 0}.tribe-events-admin-cta{align-items:center;border:1px solid #e1e1e4;border-radius:20px;display:flex;justify-content:space-between;margin:60px 0}.tribe-events-admin-cta__image{height:152px;-o-object-fit:contain;object-fit:contain;width:auto}.tribe-events-admin-cta__content,.tribe-events-admin__troubleshooting-cta{align-items:center;display:flex;flex-direction:column;justify-content:center;padding:20px 0;width:100%}.tribe-events-admin-cta__content-title{color:#0f1031;font-size:28px;font-weight:700;line-height:normal;margin:0 0 10px;text-align:center}.tribe-events-admin-cta__content-subtitle{color:#0f1031;font-size:16px;line-height:1.5;margin-bottom:10px;text-align:center}.tribe-events-admin-cta__content-description a{border-bottom:2px solid #334aff;color:#334aff;font-size:16px;font-weight:700;padding-bottom:2px;text-decoration:none}.tribe-events-admin-cta__content-description a:focus{box-shadow:none;outline:none}.tribe-events-admin-cta__content-description a:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin-footer-logo{display:inline-block;vertical-align:middle;width:228px}.tribe-events-admin-step{margin:10px 0 0}.tribe-events-admin-step-card{border:1px solid #e1e1e4;border-radius:20px;display:flex;justify-content:space-between;padding:24px 15px 19px 19px}.tribe-events-admin-step-card a{border-bottom:2px solid #334aff;color:#334aff;padding-bottom:2px;text-decoration:none}.tribe-events-admin-step-card a:focus{box-shadow:none;outline:none}.tribe-events-admin-step-card a:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin-step-card__icon img{height:43px;margin-right:5px;width:42px}.tribe-events-admin-step-card__content{margin-left:10px}.tribe-events-admin-step__title{color:#0f1031;font-size:20px;font-weight:700;line-height:1.2;margin-bottom:10px}.tribe-events-admin-step__answer{color:#0f1031;font-size:13px;margin-top:18px}.tribe-events-admin__system-information{display:grid;grid-gap:15px 30px;gap:15px 30px;grid-template-areas:". .";grid-template-columns:repeat(2,minmax(0,1fr));grid-template-rows:1fr;margin:100px 0;position:relative}.tribe-events-admin__troubleshooting-title{color:#0f1031;font-size:28px;font-weight:700;line-height:1;margin:0}.tribe-events-admin__troubleshooting-description{color:#0f1031;font-size:18px;line-height:1.2;line-height:1.44;margin:20px 0}.tribe-events-admin__system-information-select{display:flex;margin:30px 0 20px}.tribe-events-admin__system-information-select input[type=checkbox]{margin:0 10px 0 0}.tribe-events-admin__system-information-select label{color:#0f1031;font-size:16px;line-height:1.2}.tribe-events-admin__system-information-content small{color:#0f1031;font-size:12px;line-height:1.2}.tribe-events-admin__recent-template-changes .template-updates-wrapper,.tribe-events-admin__system-information-widget{background:#0f1031;border-radius:16px;color:#fff;font-size:14px;line-height:1.14;max-height:280px;overflow:scroll;-ms-overflow-style:none;padding:12px 0 0 27px;scrollbar-width:none}.tribe-events-admin__system-information-widget a{color:#334aff}.tribe-events-admin__system-information-widget a:hover{opacity:.8}.tribe-events-admin__recent-template-changes .template-updates-wrapper{padding:30px 0 30px 27px}.tribe-events-admin__recent-template-changes .template-updates-wrapper::-webkit-scrollbar,.tribe-events-admin__system-information-widget::-webkit-scrollbar{display:none}.tribe-events-admin__system-information-widget-copy{bottom:10px;position:absolute}.tribe-events-admin__system-information-widget-copy button{background-color:#334aff;border:none;border-radius:100px;color:#fff;cursor:pointer;font-size:16px;font-weight:700;outline:none;padding:18px 25px;text-align:center}.tribe-events-admin__system-information-widget-copy button:hover{background-color:#1c39bb}.tribe-events-admin__system-information-widget-copy button .dashicons,.tribe-events-admin__system-information-widget-copy button .dashicons-before:before{display:none}.tribe-events-admin__system-information-widget-copy button .optin-success{color:#fff;font-size:16px;font-weight:700;text-align:center}.tribe-events-admin__recent-template-changes p{color:#0f1031;font-size:18px;line-height:1.2;line-height:1.44;margin:20px 0}.tribe-events-admin__recent-log{margin-top:50px}.tribe-events-admin__troubleshooting-event-log-wrapper label{color:#0f1031;display:block;font-size:16px;line-height:1.63;margin-bottom:10px}.tribe-events-admin__troubleshooting-event-log-wrapper #tribe-log-controls{margin:20px 0 10px}.tribe-events-admin__troubleshooting-event-log-wrapper #tribe-log-viewer{background:#0f1031;border-radius:16px;color:#fff;font-size:14px;line-height:1.14;max-height:280px;min-height:60px;overflow:scroll;-ms-overflow-style:none;padding:12px 0 0 27px;scrollbar-width:none}.tribe-events-admin__troubleshooting-event-log-wrapper #tribe-log-viewer::-webkit-scrollbar{display:none}.tribe-events-admin__troubleshooting-event-log-wrapper .download_log{border-bottom:2px solid #334aff;color:#334aff;font-size:16px;padding-bottom:2px;text-decoration:none}.tribe-events-admin__troubleshooting-event-log-wrapper .download_log:focus{box-shadow:none;outline:none}.tribe-events-admin__troubleshooting-event-log-wrapper .download_log:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin__troubleshooting-event-log-wrapper .tribe-events-admin__recent-log-filters-select-wrapper:after{display:none}.tribe-events-admin__recent-log-filters{display:flex;padding:20px 0 40px}.tribe-events-admin__recent-log-filters-field{margin-right:40px}.tribe-events-admin__recent-log-filters-select-wrapper:after{content:url(../images/help/polygon.svg);height:13px;pointer-events:none;position:absolute;right:22px;top:20px;width:14px}.tribe-events-admin__recent-log-filters-select-wrapper .select2-container--default .select2-selection--single{border:1px solid #e1e1e4!important;border-radius:16px;color:#0f1031;font-size:14px;line-height:1.14;padding:0 25px 0 15px!important}.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls{margin-bottom:20px;padding:0}.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:first-child,.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:nth-child(2),.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:nth-child(3){padding-right:75px}.tribe-events-admin__recent-log-filters-select-wrapper .select2-selection__clear{display:none}.tribe-events-admin__recent-log-filters-select-wrapper .select2-container--default .select2-selection--single .select2-selection__arrow{right:5px}.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple,.tribe-events-admin__recent-log-filters-select-wrapper .select2-container--default.select2-container--open.select2-container--below .select2-selection--single{border-bottom-left-radius:16px;border-bottom-right-radius:16px}.tribe-events-admin__recent-log-filters-select-wrapper .select2-container .select2-selection--single .select2-selection__rendered{width:100%}.tribe-events-admin__recent-log-filters-select-wrapper select.focus-visible,.tribe-events-admin__recent-log-filters-select-wrapper select:focus-visible{outline:none}.tribe-events-admin__recent-log-filters-select-wrapper select option{color:#0f1031;font-size:14px;line-height:1.14}.tribe-events-admin__ea-status{margin-top:50px}.tribe-events-admin__issues-found-card{background-color:#f3eee8;border-radius:8px;margin-bottom:20px}.tribe-events-admin__issues-found-card:last-of-type{margin-bottom:100px}.tribe-events-admin__issues-found-card-title{align-items:center;cursor:pointer;display:flex;padding:10px 20px 10px 17px;position:relative}.tribe-events-admin__issues-found-card-title img{height:21px;margin-right:14px;-o-object-fit:contain;object-fit:contain;width:21px}.tribe-events-admin__issues-found-card-title h3{margin:0}.tribe-events-admin__issues-found-card-title span{color:#0f1031;display:block}.tribe-events-admin__issues-found-card-title i{background-image:url(../images/help/arrow-down.svg);background-position:50%;background-repeat:no-repeat;background-size:contain;height:15px;margin:12px 20px;position:absolute;right:0;top:0;transition:all .3s ease;width:15px}.tribe-events-admin__issues-found-card-title.active i{background-image:url(../images/help/arrow-up.svg);background-repeat:no-repeat;top:5px}.tribe-events-admin__issues-found-card-description{display:none;padding:0 20px 20px 55px}.tribe-events-admin__issues-found-card-description p{color:#0f1031;font-size:16px;margin:0}.tribe-events-admin__issues-found-card-description-actions{display:flex;padding:20px 0 10px}.tribe-events-admin__issues-found-card-description-actions a{border-bottom:2px solid #334aff;color:#334aff;font-size:16px;margin-right:20px;padding-bottom:5px;text-decoration:none}.tribe-events-admin__issues-found-card-description-actions a:focus{box-shadow:none;outline:none}.tribe-events-admin__issues-found-card-description-actions a:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin__ea-status-table-wrapper{overflow-x:auto}.tribe-events-admin__ea-status-table{border:1px solid #e1e1e4;border-radius:16px;margin:30px 0 40px;overflow:hidden}.tribe-events-admin__ea-status-table a{border-bottom:2px solid #334aff;color:#334aff;padding-bottom:2px;text-decoration:none}.tribe-events-admin__ea-status-table a:focus{box-shadow:none;outline:none}.tribe-events-admin__ea-status-table a:hover{border-bottom:2px solid #1c39bb;color:#1c39bb}.tribe-events-admin__ea-status-table tr{display:flex;align-items:center}.tribe-events-admin__ea-status-table th{color:#0f1031;font-weight:700;line-height:1.17;margin-top:10px;padding:5px 25px}.tribe-events-admin__ea-status-table td{align-items:center;color:#0f1031;display:flex;font-size:16px;line-height:1.63;padding:10px 25px;width:25%}.tribe-events-admin__ea-status-table td:nth-child(2){width:45%}.tribe-events-admin__ea-status-table td:nth-child(3){display:flex;justify-content:flex-end;width:30%}.tribe-events-admin__ea-status-table-dark{background-color:#f9f7f4}.tribe-events-admin__ea-status-table td img{height:21px;margin-right:14px;-o-object-fit:contain;object-fit:contain;width:21px}.tribe_events_page_tec-troubleshooting{background-color:#fff}#tribe-community,#tribe-ticketing{display:none}.tribe-events-admin__troubleshooting-notice{background-color:#161b7d;color:#fff;font-size:16px;line-height:1;margin-left:-1.55vw;padding:24px 0}.tribe-events-admin__troubleshooting-notice_title{margin:0 auto;max-width:1024px;padding-left:25px;width:90%}.tribe-events-admin__troubleshooting-notice_title a{border-bottom:2px solid #fff;color:#fff;font-size:16px;line-height:1;padding-bottom:2px;text-decoration:none}.tribe-events-admin__troubleshooting-notice_title a:focus{box-shadow:none;outline:none}.tribe-events-admin__troubleshooting-notice_title a:hover{border-bottom:2px solid #f3eee8;color:#f3eee8}.tribe_events_page_tribe-help #tec-help-community,.tribe_events_page_tribe-help #tec-help-ticketing{display:none}.tribe_events_page_tribe-help .tribe-events-admin-title{padding-top:25px}.tribe_events_page_tribe-help .tribe-events-admin-title img{height:67px}body.tribe-welcome #fs_connect{border:1px solid #e1e1e4;border-radius:16px;box-shadow:none;box-sizing:border-box;margin-left:22px}body.tribe-welcome #fs_connect .fs-actions{background-color:transparent}body.tribe-welcome #fs_connect .fs-permissions{border-top:1px solid #e1e1e4;margin:0 16px}body.tribe-welcome #fs_connect button{background-color:#3d54ff;border-color:#3d54ff}body.tribe-welcome #fs_connect .button-secondary{background:#fff;border-color:#3d54ff;color:#3d54ff}body.tribe-welcome #fs_connect a{color:#3d54ff}body.tribe-welcome #fs_connect a:focus{box-shadow:none;outline:none}body.tribe-welcome #fs_connect a:hover{color:#161b7d}@media only screen and (-o-min-device-pixel-ratio:2/1),only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min--moz-device-pixel-ratio:2),only screen and (min-device-pixel-ratio:2){#tribe-loading span{background-image:url(../images/tribe-loading@2x.gif)}}@media screen and (max-width:782px){.tribe-half-column,.tribe-row .tribe-half-column:last-child{margin:0 0 20px;width:100%}input[type=email]{width:100%}.events-cal .subsubsub{float:none}.events-cal .search-box{width:98%}.events-cal #search-submit{width:100%}.events-cal .tablenav.top{display:none}}@media screen and (min-width:500px){.api-check .tribe-mascot{display:block}.api-check .notice-content{margin-right:180px}}@media screen and (min-width:320px){.tribe-marketing-notice .tribe-marketing-notice__icon{display:block}.notice-tribe-banner .tribe-marketing-notice__content{margin-left:22px}}@media screen and (min-width:600px) and (max-width:782px){.tribe-marketing-notice .tribe-marketing-notice__content{margin-left:145px}.notice-tribe-banner .tribe-marketing-notice__content{margin-left:22px;padding:0}}@media screen and (min-width:782px){.tribe-marketing-notice .tribe-marketing-notice__content{margin-left:130px}.notice-tribe-banner .tribe-marketing-notice__content{margin-left:22px;padding:0}.events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice,.tribe-welcome .notice-tribe-banner .tribe-marketing-notice,.tribe_events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice{max-width:642px}}@media screen and (min-width:400px){.notice-tribe-banner .tribe-marketing-notice__icon{width:67px}}@media screen and (min-width:800px){.notice-tribe-banner h3{display:inline-block;font-size:1rem;margin:0 .5rem 0 0}.notice-tribe-banner a{line-height:1.5}.notice-tribe-banner a,.notice-tribe-banner p{font-size:1rem}.notice-tribe-banner p{margin:0 .5rem 0 0}.notice-tribe-banner .tribe-marketing-notice__cta{display:inline-block;margin-left:.5rem}}@media screen and (min-width:1215px){.events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice,.tribe_events_page_tribe-app-shop .notice-tribe-banner .tribe-marketing-notice{max-width:992px}.tribe-welcome .notice-tribe-banner .tribe-marketing-notice{max-width:1036px}}@media screen and (min-width:710px){.tribe-events-admin-content-wrapper{width:670px}.tribe-events-admin-card--2up{display:inline-block;width:calc(50% - 20px)}.tribe-events-admin-card--2up.tribe-events-admin-card--first{margin-right:36px}.tribe-events-admin-card--2up.tribe-events-admin-card--last{margin-right:0}.tribe-events-admin-card--2up .tribe-events-admin-card__image{height:100px;margin-bottom:12px}.tribe-events-admin-card--2up .tribe-events-admin-card__title{margin-bottom:27px;max-width:340px}.tribe-events-admin-card--3up{display:inline-block;margin-bottom:32px;width:calc(50% - 18px)}.tribe-events-admin-card--3up.tribe-events-admin-card--first{margin-right:32px}.tribe-events-admin-card--3up.tribe-events-admin-card--middle{margin-right:0}.tribe-events-admin-card__title{font-size:20px;line-height:23px}.tribe-events-admin-section-header{font-size:28px;line-height:32px;margin-bottom:21px}.tribe-events-admin-card--1up{display:inline-block;margin-left:32px;width:calc(50% - 18px)}.tribe-events-admin-card--1up .tribe-events-admin-card__description{height:71px}.tribe-events-admin-card--1up .tribe-events-admin-card__image{margin-bottom:28px}.tribe-events-admin-card--no-pad{height:154px;padding:0}.tribe-events-admin-card--no-pad .tribe-events-admin-card__title{margin-left:50%;padding:42px 0 10px}.tribe-events-admin-card--no-pad .tribe-events-admin-card__description{margin-left:50%}.tribe-events-admin-card--promo-blue{display:block;margin-left:0;min-height:170px;width:100%}.tribe-events-admin-card--promo-blue .tribe-events-admin-card__description{float:left;max-width:300px}.tribe-events-admin-graphic{max-width:250px;top:0}.tribe-events-admin-graphic--desktop-only{display:block}.tribe-events-admin-graphic--mobile-only{display:none}.tribe-events-admin-card__form{float:right;width:300px}input[type=email].tribe-events-admin-card__input{width:300px}.tribe-events-admin-title{padding-top:50px}.tribe-events-admin-title__description{padding-top:15px}.tribe-events-admin-title__heading{font-size:48px;line-height:55px;margin:0}.tribe-events-admin-title__logo{margin-right:14px;padding-top:5px;width:40px}.tribe-events-admin-tickets .tribe-events-admin-card__title{font-size:18px}.tribe-events-admin-tickets .tribe-events-admin-card--2up .tribe-events-admin-card__title{font-size:18px;height:66px}.tribe-events-admin-tickets .tribe-events-admin-title__logo{margin-right:8px;padding-top:4px;width:60px}}@media screen and (min-width:1217px){.tribe-events-admin-content-wrapper{max-width:1060px;width:100%}.tribe-events-admin-card--2up{margin-right:36px;width:486px}.tribe-events-admin-card--3up{width:310px}.tribe-events-admin-card--3up.tribe-events-admin-card--first,.tribe-events-admin-card--3up.tribe-events-admin-card--middle{margin-right:36px}.tribe-events-admin-card--3up.tribe-events-admin-card--last{margin-right:0}.tribe-events-admin-quick-nav{padding:0 36px}.tribe-events-admin-card--1up{margin:0 0 36px;padding:33px 44px 30px;text-align:left;width:1012px}.tribe-events-admin-card--1up .tribe-events-admin-card__description{height:auto}.tribe-events-admin-card--1up .tribe-events-admin-card__image{float:left;margin:0 48px 10px 0}.tribe-events-admin-card--no-pad{padding:0}.tribe-events-admin-card--no-pad .tribe-events-admin-card__image{margin:0;padding:0}.tribe-events-admin-card--no-pad .tribe-events-admin-card__title{margin-left:50%;padding:42px 0 10px}.tribe-events-admin-card--no-pad .tribe-events-admin-card__description{margin-left:50%}.tribe-events-admin-card--promo-blue{min-height:150px}.tribe-events-admin-card--promo-blue .tribe-events-admin-card__description{max-width:450px}.tribe-events-admin-graphic{max-width:none}.tribe-events-admin-card__form,input[type=email].tribe-events-admin-card__input{width:365px}.tribe-events-admin-quick-nav{border-radius:100px;display:inline-block;height:54px;margin:24px 0 94px;max-width:1010px;padding:0 36px 0 0}.tribe-events-admin-quick-nav__link-item{display:inline-block;padding:18px 10px 0}.tribe-events-admin-quick-nav__title{padding:19px 6px 17px 32px}.tribe-events-admin-tickets .tribe-events-admin-card--2up .tribe-events-admin-card__title{height:auto}}@media screen and (max-width:768px){.tribe-events-admin-header__logo-word-mark{width:285px}.tribe-events-admin-header__right-image{height:160px}.tribe-events-admin-header__description{max-width:100%}.tribe-events-admin-tab-nav li{margin-right:20px}.tribe-events-admin-tab-nav .selected{border-bottom:2px solid #334aff;padding-bottom:10px}.tribe-events-admin-2col-grid{grid-template-areas:".";grid-template-columns:repeat(1,minmax(0,1fr))}.tribe-events-admin-3col-grid{grid-template-areas:". .";grid-template-columns:repeat(2,minmax(0,1fr))}.tribe-events-admin-extensions-title{max-width:100%}.tribe-events-admin-cta{align-items:flex-start;flex-direction:column;overflow:hidden}.tribe-events-admin-footer-logo{width:225px}.tribe-events-admin__system-information{grid-template-areas:".";grid-template-columns:repeat(1,minmax(0,1fr));margin:50px 0}}@media screen and (max-width:480px){.tribe-events-admin-header__logo-word-mark{width:260px}.tribe-events-admin-header__right-image{height:120px}.tribe-events-admin-header__title{font-size:35px}.tribe-events-admin-header__description{max-width:100%}.tribe-events-admin-tab-nav{border:1px solid #e1e1e4;border-radius:20px;flex-direction:column;padding:18px 22px}.tribe-events-admin-tab-nav li{margin-bottom:18px;margin-right:0}.tribe-events-admin-tab-nav .selected{border-bottom:2px solid #334aff;padding-bottom:10px;width:-moz-fit-content;width:fit-content}.tribe-events-admin__line{border:none}.tribe-events-admin-products-card,.tribe-events-admin-products-description{display:none}.tribe-events-admin-container,.tribe-events-admin-content-wrapper.tribe-events-admin-container{max-width:90%}.tribe-events-admin-2col-grid,.tribe-events-admin-3col-grid,.tribe-events-admin-4col-grid{grid-template-areas:".";grid-template-columns:repeat(1,minmax(0,1fr))}.tribe-events-admin-section-header{margin:0}.tribe-events-admin-extensions-title{max-width:100%}.tribe-events-admin-cta__image{height:auto;width:90%}.tribe-events-admin-cta__content,.tribe-events-admin__troubleshooting-cta{align-items:flex-start;padding:32px 23px 45px;width:auto}.tribe-events-admin-cta__content-title{font-size:22px;text-align:left}.tribe-events-admin-cta__content-subtitle{text-align:left}.tribe-events-admin-footer-logo{width:210px}.tribe-events-admin__system-information{grid-template-areas:".";grid-template-columns:repeat(1,minmax(0,1fr));margin:50px 0}.tribe-events-admin__troubleshooting-notice{margin-left:-20px}.tribe-events-admin__troubleshooting-notice_title{max-width:90%}}@media screen and (min-width:1200px){.tribe-events-admin-products-card__group{max-width:47%}}@media screen and (min-width:500px) and (max-width:1080px){.tribe-events-admin-4col-grid{grid-template-areas:". .";grid-template-columns:repeat(2,minmax(0,1fr))}}@media screen and (max-width:1080px){.tribe-events-admin-cta__content-title{font-size:24px}}@media only screen and (max-width:1920px){.tribe-events-admin__system-information-widget-copy{right:20.5vw}}@media only screen and (max-width:1280px){.tribe-events-admin__system-information-widget-copy{right:22vw}}@media only screen and (max-width:768px){.tribe-events-admin__system-information-widget-copy{left:10px;right:auto}.tribe-events-admin__recent-log-filters{flex-direction:column}.tribe-events-admin__recent-log-filters-field{margin-bottom:30px;margin-right:0}.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:first-child,.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:nth-child(2),.tribe-events-admin__recent-log-filters-select-wrapper #tribe-log-controls div:nth-child(3){padding-right:30px}.tribe-events-admin__issues-found-card-title h3{max-width:90%}}@media only screen and (max-width:480px){.tribe-events-admin__system-information-widget-copy{left:10px;right:auto}.tribe-events-admin__recent-log-filters{flex-direction:column}.tribe-events-admin__recent-log-filters-field{margin-bottom:30px;margin-right:0}.tribe-events-admin__recent-log-filters-select-wrapper:after{right:25px}.tribe-events-admin__issues-found-card-title h3{max-width:80%}.tribe-events-admin__ea-status-table{overflow:scroll}.tribe-events-admin__ea-status-table td{min-width:150px}.tribe-events-admin__ea-status-table td:nth-child(2),.tribe-events-admin__ea-status-table td:nth-child(3){width:100%}}
common/src/resources/css/variables-full.min.css ADDED
@@ -0,0 +1 @@
 
1
+ :root{--tec-border-radius-default:4px;--tec-border-width-week-event:2px;--border-radius-default:var(--tec-border-radius-default);--border-width-week-event:var(--tec-border-width-week-event);--tec-box-shadow-default:0 2px 5px 0 var(--tec-color-box-shadow);--tec-box-shadow-tooltip:0 2px 12px 0 var(--tec-color-box-shadow);--tec-box-shadow-card:0 1px 6px 2px var(--tec-color-box-shadow);--tec-box-shadow-multiday:16px 6px 6px -2px var(--tec-color-box-shadow-secondary);--box-shadow-default:var(--tec-box-shadow-default);--box-shadow-tooltip:var(--tec-box-shadow-tooltip);--box-shadow-card:var(--tec-box-shadow-card);--box-shadow-multiday:var(--tec-box-shadow-multiday);--tec-form-color-background:var(--tec-color-background);--tec-form-color-border-default:var(--tec-color-text-primary);--tec-form-color-border-active:var(--tec-color-accent-secondary);--tec-form-color-border-secondary:var(--tec-color-border-tertiary);--tec-form-color-accent-primary:var(--tec-color-accent-primary);--tec-form-box-shadow-default:var(--tec-box-shadow-default);--form-color-background:var(--tec-form-color-background);--form-color-border-default:var(--tec-form-color-border-default);--form-color-border-active:var(--tec-form-color-border-active);--form-color-border-secondary:var(--tec-form-color-border-secondary);--form-color-accent-primary:var(--tec-form-color-accent-primary);--form-box-shadow-default:var(--tec-form-box-shadow-default);--tec-opacity-background:0.07;--tec-opacity-select-highlighted:0.3;--tec-opacity-icon-hover:0.8;--tec-opacity-icon-active:0.9;--tec-opacity-default:1;--opacity-background:var(--tec-opacity-background);--opacity-select-highlighted:var(--tec-opacity-select-highlighted);--opacity-icon-hover:var(--tec-opacity-icon-hover);--opacity-icon-active:var(--tec-opacity-icon-active);--opacity-default:var(--tec-opacity-default);--tec-transition:all 0.2s ease;--tec-transition-background-color:background-color 0.2s ease;--tec-transition-color-border-color:color 0.2s ease,border-color 0.2s ease;--tec-transition-transform:transform 0.2s ease;--tec-transition-border-color:border-color 0.2s ease;--tec-transition-color:color 0.2s ease;--tec-transition-opacity:opacity 0.2s ease;--transition:var(--tec-transition);--transition-background-color:var(--tec-transition-background-color);--transition-color-border-color:var(--tec-transition-color-border-color);--transition-transform:var(--tec-transition-transform);--transition-border-color:var(--tec-transition-border-color);--transition-color:var(--tec-transition-color);--transition-opacity:var(--tec-transition-opacity);--tec-font-family-sans-serif:"Helvetica Neue",Helvetica,-apple-system,BlinkMacSystemFont,Roboto,Arial,sans-serif;--tec-font-weight-regular:400;--tec-font-weight-bold:700;--tec-font-size-0:11px;--tec-font-size-1:12px;--tec-font-size-2:14px;--tec-font-size-3:16px;--tec-font-size-4:18px;--tec-font-size-5:20px;--tec-font-size-6:22px;--tec-font-size-7:24px;--tec-font-size-8:28px;--tec-font-size-9:32px;--tec-font-size-10:42px;--tec-line-height-0:1.38;--tec-line-height-1:1.42;--tec-line-height-2:1.5;--tec-line-height-3:1.62;--font-family-sans-serif:var(--tec-font-family-sans-serif);--font-family-base:var(--tec-font-family-sans-serif);--font-weight-regular:var(--tec-font-weight-regular);--font-weight-bold:var(--tec-font-weight-bold);--font-size-0:var(--tec-font-size-0);--font-size-1:var(--tec-font-size-1);--font-size-2:var(--tec-font-size-2);--font-size-3:var(--tec-font-size-3);--font-size-4:var(--tec-font-size-4);--font-size-5:var(--tec-font-size-5);--font-size-6:var(--tec-font-size-6);--font-size-7:var(--tec-font-size-7);--font-size-8:var(--tec-font-size-8);--font-size-9:var(--tec-font-size-9);--font-size-10:var(--tec-font-size-10);--line-height-0:var(--tec-line-height-0);--line-height-1:var(--tec-line-height-1);--line-height-2:var(--tec-line-height-2);--line-height-3:var(--tec-line-height-3)}
common/src/resources/css/variables-skeleton.min.css ADDED
@@ -0,0 +1 @@
 
1
+ :root{--tec-grid-gutter:48px;--tec-grid-gutter-negative:calc(var(--tec-grid-gutter)*-1);--tec-grid-gutter-half:calc(var(--tec-grid-gutter)/2);--tec-grid-gutter-half-negative:calc(var(--tec-grid-gutter-half)*-1);--tec-grid-gutter-small:42px;--tec-grid-gutter-small-negative:calc(var(--tec-grid-gutter-small)*-1);--tec-grid-gutter-small-half:calc(var(--tec-grid-gutter-small)/2);--tec-grid-gutter-small-half-negative:calc(var(--tec-grid-gutter-small-half)*-1);--tec-grid-gutter-page:42px;--tec-grid-gutter-page-small:19.5px;--tec-grid-width-default:1176px;--tec-grid-width-min:320px;--tec-grid-width:calc(var(--tec-grid-width-default) + var(--tec-grid-gutter-page)*2);--tec-grid-width-1-of-2:50%;--tec-grid-width-1-of-3:33.333%;--tec-grid-width-1-of-4:25%;--tec-grid-width-1-of-5:20%;--tec-grid-width-1-of-7:14.285%;--tec-grid-width-1-of-8:12.5%;--tec-grid-width-1-of-9:11.111%;--grid-gutter:var(--tec-grid-gutter);--grid-gutter-negative:var(--tec-grid-gutter-negative);--grid-gutter-half:var(--tec-grid-gutter-half);--grid-gutter-half-negative:var(--tec-grid-gutter-half-negative);--grid-gutter-small:var(--tec-grid-gutter-small);--grid-gutter-small-negative:var(--tec-grid-gutter-small-negative);--grid-gutter-small-half:var(--tec-grid-gutter-small-half);--grid-gutter-small-half-negative:var(--tec-grid-gutter-small-half-negative);--grid-gutter-page:var(--tec-grid-gutter-page);--grid-gutter-page-small:var(--tec-grid-gutter-page-small);--grid-width-default:var(--tec-grid-width-default);--grid-width-min:var(--tec-grid-width-min);--grid-width:var(--tec-grid-width);--grid-width-1-of-2:var(--tec-grid-width-1-of-2);--grid-width-1-of-3:var(--tec-grid-width-1-of-3);--grid-width-1-of-4:var(--tec-grid-width-1-of-4);--grid-width-1-of-5:var(--tec-grid-width-1-of-5);--grid-width-1-of-7:var(--tec-grid-width-1-of-7);--grid-width-1-of-8:var(--tec-grid-width-1-of-8);--grid-width-1-of-9:var(--tec-grid-width-1-of-9);--tec-spacer-0:4px;--tec-spacer-1:8px;--tec-spacer-2:12px;--tec-spacer-3:16px;--tec-spacer-4:20px;--tec-spacer-5:24px;--tec-spacer-6:28px;--tec-spacer-7:32px;--tec-spacer-8:40px;--tec-spacer-9:48px;--tec-spacer-10:56px;--tec-spacer-11:64px;--tec-spacer-12:80px;--tec-spacer-13:96px;--tec-spacer-14:160px;--spacer-0:var(--tec-spacer-0);--spacer-1:var(--tec-spacer-1);--spacer-2:var(--tec-spacer-2);--spacer-3:var(--tec-spacer-3);--spacer-4:var(--tec-spacer-4);--spacer-5:var(--tec-spacer-5);--spacer-6:var(--tec-spacer-6);--spacer-7:var(--tec-spacer-7);--spacer-8:var(--tec-spacer-8);--spacer-9:var(--tec-spacer-9);--spacer-10:var(--tec-spacer-10);--spacer-11:var(--tec-spacer-11);--spacer-12:var(--tec-spacer-12);--spacer-13:var(--tec-spacer-13);--spacer-14:var(--tec-spacer-14);--tec-z-index-spinner-container:100;--tec-z-index-views-selector:30;--tec-z-index-dropdown:30;--tec-z-index-events-bar-button:20;--tec-z-index-search:10;--tec-z-index-filters:9;--tec-z-index-scroller:7;--tec-z-index-week-event-hover:5;--tec-z-index-map-event-hover:5;--tec-z-index-map-event-hover-actions:6;--tec-z-index-multiday-event:5;--tec-z-index-multiday-event-bar:2;--z-index-spinner-container:var(--tec-z-index-spinner-container);--z-index-views-selector:var(--tec-z-index-views-selector);--z-index-dropdown:var(--tec-z-index-dropdown);--z-index-events-bar-button:var(--tec-z-index-events-bar-button);--z-index-search:var(--tec-z-index-search);--z-index-filters:var(--tec-z-index-filters);--z-index-scroller:var(--tec-z-index-scroller);--z-index-week-event-hover:var(--tec-z-index-week-event-hover);--z-index-map-event-hover:var(--tec-z-index-map-event-hover);--z-index-map-event-hover-actions:var(--tec-z-index-map-event-hover-actions);--z-index-multiday-event:var(--tec-z-index-multiday-event);--z-index-multiday-event-bar:var(--tec-z-index-multiday-event-bar);--tec-color-text-primary:#141827;--tec-color-text-primary-light:rgba(20,24,39,.62);--tec-color-text-secondary:#5d5d5d;--tec-color-text-disabled:#d5d5d5;--tec-color-text-events-title:var(--tec-color-text-primary);--tec-color-text-event-title:var(--tec-color-text-events-title);--tec-color-text-event-date:var(--tec-color-text-primary);--tec-color-text-secondary-event-date:var(--tec-color-text-secondary);--tec-color-icon-primary:#5d5d5d;--tec-color-icon-primary-alt:#757575;--tec-color-icon-secondary:#bababa;--tec-color-icon-active:#141827;--tec-color-icon-disabled:#d5d5d5;--tec-color-icon-focus:#334aff;--tec-color-icon-error:#da394d;--tec-color-event-icon:#141827;--tec-color-event-icon-hover:#334aff;--tec-color-accent-primary:#334aff;--tec-color-accent-primary-hover:rgba(51,74,255,.8);--tec-color-accent-primary-active:rgba(51,74,255,.9);--tec-color-accent-primary-background:rgba(51,74,255,.07);--tec-color-accent-secondary:#141827;--tec-color-accent-secondary-hover:rgba(20,24,39,.8);--tec-color-accent-secondary-active:rgba(20,24,39,.9);--tec-color-accent-secondary-background:rgba(20,24,39,.07);--tec-color-button-primary:var(--tec-color-accent-primary);--tec-color-button-primary-hover:var(--tec-color-accent-primary-hover);--tec-color-button-primary-active:var(--tec-color-accent-primary-active);--tec-color-button-primary-background:var(--tec-color-accent-primary-background);--tec-color-button-secondary:var(--tec-color-accent-secondary);--tec-color-button-secondary-hover:var(--tec-color-accent-secondary-hover);--tec-color-button-secondary-active:var(--tec-color-accent-secondary-active);--tec-color-button-secondary-background:var(--tec-color-accent-secondary-background);--tec-color-link-primary:var(--tec-color-text-primary);--tec-color-link-accent:var(--tec-color-accent-primary);--tec-color-link-accent-hover:rgba(51,74,255,.8);--tec-color-border-default:#d5d5d5;--tec-color-border-secondary:#e4e4e4;--tec-color-border-tertiary:#7d7d7d;--tec-color-border-hover:#5d5d5d;--tec-color-border-active:#141827;--tec-color-background:#fff;--tec-color-background-events:transparent;--tec-color-background-transparent:hsla(0,0%,100%,.6);--tec-color-background-secondary:#f7f6f6;--tec-color-background-messages:rgba(20,24,39,.07);--tec-color-background-secondary-hover:#f0eeee;--tec-color-background-error:rgba(218,57,77,.08);--tec-color-box-shadow:rgba(0,0,0,.14);--tec-color-box-shadow-secondary:rgba(0,0,0,.1);--tec-color-scroll-track:rgba(0,0,0,.25);--tec-color-scroll-bar:rgba(0,0,0,.5);--tec-color-background-primary-multiday:rgba(51,74,255,.24);--tec-color-background-primary-multiday-hover:rgba(51,74,255,.34);--tec-color-background-secondary-multiday:rgba(20,24,39,.24);--tec-color-background-secondary-multiday-hover:rgba(20,24,39,.34);--tec-color-accent-primary-week-event:rgba(51,74,255,.1);--tec-color-accent-primary-week-event-hover:rgba(51,74,255,.2);--tec-color-accent-primary-week-event-featured:rgba(51,74,255,.04);--tec-color-accent-primary-week-event-featured-hover:rgba(51,74,255,.14);--tec-color-background-secondary-datepicker:var(--tec-color-background-secondary);--tec-color-accent-primary-background-datepicker:var(--tec-color-accent-primary-background);--color-text-primary:var(--tec-color-text-primary);--color-text-primary-light:var(--tec-color-text-primary-light);--color-text-secondary:var(--tec-color-text-secondary);--color-text-disabled:var(--tec-color-text-disabled);--color-icon-primary:var(--tec-color-icon-primary);--color-icon-primary-alt:var(--tec-color-icon-primary);--color-icon-secondary:var(--tec-color-icon-secondary);--color-icon-active:var(--tec-color-icon-active);--color-icon-disabled:var(--tec-color-icon-disabled);--color-icon-focus:var(--tec-color-icon-focus);--color-icon-error:var(--tec-color-icon-error);--color-accent-primary:var(--tec-color-accent-primary);--color-accent-primary-hover:var(--tec-color-accent-primary-hover);--color-accent-primary-active:var(--tec-color-accent-primary-active);--color-accent-primary-background:var(--tec-color-accent-primary-background);--color-accent-primary-multiday:var(--tec-color-accent-primary-multiday);--color-accent-primary-multiday-hover:var(--tec-color-accent-primary-multiday-hover);--color-accent-primary-week-event:var(--tec-color-accent-primary-week-event);--color-accent-primary-week-event-hover:var(--tec-color-accent-primary-week-event-hover);--color-accent-primary-week-event-featured:var(--tec-color-accent-primary-week-event-featured);--color-accent-primary-week-event-featured-hover:var(--tec-color-accent-primary-week-event-featured-hover);--color-accent-secondary:var(--tec-color-accent-secondary);--color-accent-secondary-hover:var(--tec-color-accent-secondary-hover);--color-accent-secondary-active:var(--tec-color-accent-secondary-active);--color-accent-secondary-background:var(--tec-color-accent-secondary-background);--color-border-default:var(--tec-color-border-default);--color-border-secondary:var(--tec-color-border-secondary);--color-border-tertiary:var(--tec-color-border-tertiary);--color-border-hover:var(--tec-color-border-hover);--color-border-active:var(--tec-color-border-active);--color-background:var(--tec-color-background);--color-background-transparent:var(--tec-color-background-transparent);--color-background-secondary:var(--tec-color-background-secondary);--color-background-messages:var(--tec-color-background-messages);--color-background-secondary-hover:var(--tec-color-background-secondary-hover);--color-background-error:var(--tec-color-icon-error);--color-box-shadow:var(--tec-color-box-shadow);--color-box-shadow-secondary:var(--tec-color-box-shadow-secondary);--color-scroll-track:var(--tec-color-scroll-track);--color-scroll-bar:var(--tec-color-scroll-bar)}
common/vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInitaee01d981b64ab474e5e655b123ccdaf::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit45000f0908896b286907423ec7c5ab9b::getLoader();
common/vendor/autoload_52.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once dirname(__FILE__) . '/composer'.'/autoload_real_52.php';
6
 
7
- return ComposerAutoloaderInitd5e39499ce3b1c1732409f4fe733064e::getLoader();
4
 
5
  require_once dirname(__FILE__) . '/composer'.'/autoload_real_52.php';
6
 
7
+ return ComposerAutoloaderInit78905504a638b87540454f23ee595a11::getLoader();
common/vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInitaee01d981b64ab474e5e655b123ccdaf
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInitaee01d981b64ab474e5e655b123ccdaf
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInitaee01d981b64ab474e5e655b123ccdaf', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInitaee01d981b64ab474e5e655b123ccdaf', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInitaee01d981b64ab474e5e655b123ccdaf::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit45000f0908896b286907423ec7c5ab9b
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit45000f0908896b286907423ec7c5ab9b', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit45000f0908896b286907423ec7c5ab9b', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit45000f0908896b286907423ec7c5ab9b::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
common/vendor/composer/autoload_real_52.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real_52.php generated by xrstf/composer-php52
4
 
5
- class ComposerAutoloaderInitd5e39499ce3b1c1732409f4fe733064e {
6
  private static $loader;
7
 
8
  public static function loadClassLoader($class) {
@@ -19,9 +19,9 @@ class ComposerAutoloaderInitd5e39499ce3b1c1732409f4fe733064e {
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInitd5e39499ce3b1c1732409f4fe733064e', 'loadClassLoader'), true /*, true */);
23
  self::$loader = $loader = new xrstf_Composer52_ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInitd5e39499ce3b1c1732409f4fe733064e', 'loadClassLoader'));
25
 
26
  $vendorDir = dirname(dirname(__FILE__));
27
  $baseDir = dirname($vendorDir);
2
 
3
  // autoload_real_52.php generated by xrstf/composer-php52
4
 
5
+ class ComposerAutoloaderInit78905504a638b87540454f23ee595a11 {
6
  private static $loader;
7
 
8
  public static function loadClassLoader($class) {
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit78905504a638b87540454f23ee595a11', 'loadClassLoader'), true /*, true */);
23
  self::$loader = $loader = new xrstf_Composer52_ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit78905504a638b87540454f23ee595a11', 'loadClassLoader'));
25
 
26
  $vendorDir = dirname(dirname(__FILE__));
27
  $baseDir = dirname($vendorDir);
common/vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInitaee01d981b64ab474e5e655b123ccdaf
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'T' =>
@@ -242,10 +242,10 @@ class ComposerStaticInitaee01d981b64ab474e5e655b123ccdaf
242
  public static function getInitializer(ClassLoader $loader)
243
  {
244
  return \Closure::bind(function () use ($loader) {
245
- $loader->prefixLengthsPsr4 = ComposerStaticInitaee01d981b64ab474e5e655b123ccdaf::$prefixLengthsPsr4;
246
- $loader->prefixDirsPsr4 = ComposerStaticInitaee01d981b64ab474e5e655b123ccdaf::$prefixDirsPsr4;
247
- $loader->prefixesPsr0 = ComposerStaticInitaee01d981b64ab474e5e655b123ccdaf::$prefixesPsr0;
248
- $loader->classMap = ComposerStaticInitaee01d981b64ab474e5e655b123ccdaf::$classMap;
249
 
250
  }, null, ClassLoader::class);
251
  }
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit45000f0908896b286907423ec7c5ab9b
8
  {
9
  public static $prefixLengthsPsr4 = array (
10
  'T' =>
242
  public static function getInitializer(ClassLoader $loader)
243
  {
244
  return \Closure::bind(function () use ($loader) {
245
+ $loader->prefixLengthsPsr4 = ComposerStaticInit45000f0908896b286907423ec7c5ab9b::$prefixLengthsPsr4;
246
+ $loader->prefixDirsPsr4 = ComposerStaticInit45000f0908896b286907423ec7c5ab9b::$prefixDirsPsr4;
247
+ $loader->prefixesPsr0 = ComposerStaticInit45000f0908896b286907423ec7c5ab9b::$prefixesPsr0;
248
+ $loader->classMap = ComposerStaticInit45000f0908896b286907423ec7c5ab9b::$classMap;
249
 
250
  }, null, ClassLoader::class);
251
  }
event-tickets.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Event Tickets
4
  Plugin URI: https://evnt.is/1acb
5
  Description: Event Tickets allows you to sell basic tickets and collect RSVPs from any post, page, or event.
6
- Version: 5.1.8
7
  Author: The Events Calendar
8
  Author URI: https://evnt.is/1aor
9
  License: GPLv2 or later
3
  Plugin Name: Event Tickets
4
  Plugin URI: https://evnt.is/1acb
5
  Description: Event Tickets allows you to sell basic tickets and collect RSVPs from any post, page, or event.
6
+ Version: 5.1.9
7
  Author: The Events Calendar
8
  Author URI: https://evnt.is/1aor
9
  License: GPLv2 or later
lang/event-tickets-cs_CZ.mo CHANGED
Binary file
lang/event-tickets-es_ES.mo CHANGED
Binary file
lang/event-tickets-fi.mo CHANGED
Binary file
lang/event-tickets-fr_CA.mo DELETED
Binary file
lang/event-tickets-ja.mo CHANGED
Binary file
lang/event-tickets-nl_NL.mo CHANGED
Binary file
lang/event-tickets.pot CHANGED
@@ -2,176 +2,64 @@
2
  # This file is distributed under the same license as the Event Tickets package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Event Tickets 5.2.1\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/event-tickets\n"
7
- "POT-Creation-Date: 2021-08-24 07:08:07+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
- "PO-Revision-Date: 2021-08-24 07:08\n"
12
  "Last-Translator: \n"
13
  "Language-Team: \n"
14
 
15
- #. #-#-#-#-# event-tickets.pot (Event Tickets 5.2.1) #-#-#-#-#
16
  #. Plugin Name of the plugin/theme
17
- #: event-tickets.php:62 src/Tribe/Admin/Notices.php:92 src/Tribe/Main.php:683
18
  #: src/Tribe/Privacy.php:59 src/admin-views/admin-welcome-message.php:58
19
  msgid "Event Tickets"
20
  msgstr ""
21
 
22
- #: src/Tickets/Commerce/Gateways/Legacy/Gateway.php:38
23
- msgid "PayPal Standard (Legacy)"
24
- msgstr ""
25
-
26
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:78
27
- #: src/admin-views/tribe-commerce-settings.php:40
28
- msgid "these instructions"
29
- msgstr ""
30
-
31
- #. Translators: %1$s: The word "ticket" in lowercase, %2$s: The "these
32
- #. instructions" link.
33
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:82
34
- msgctxt "tickets fields settings PayPal setup"
35
- msgid ""
36
- "Ie Tickets Commerce to sell %1$s, you must configure your PayPal account to "
37
- "communicate with your WordPress site. If you need help getting set up, "
38
- "follow %2$s"
39
- msgstr ""
40
-
41
- #. Translators: %s: The site link.
42
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:94
43
- #: src/admin-views/tribe-commerce-settings.php:47
44
- msgid "Your site address is: %s"
45
- msgstr ""
46
-
47
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:99
48
- #: src/admin-views/tribe-commerce-settings.php:45
49
- msgid ""
50
- "Have you entered this site's address in the Notification URL field in IPN "
51
- "Settings?"
52
- msgstr ""
53
-
54
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:108
55
- #: src/admin-views/tribe-commerce-settings.php:117
56
- msgid "PayPal configuration status:"
57
- msgstr ""
58
-
59
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:111
60
- #: src/admin-views/tribe-commerce-settings.php:120
61
- msgid ""
62
- "For help creating and configuring your account, call PayPal at "
63
- "1-844-720-4038 (USA)"
64
- msgstr ""
65
-
66
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:117
67
- msgid "Configure PayPal Legacy:"
68
- msgstr ""
69
-
70
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:123
71
- #: src/admin-views/tribe-commerce-settings.php:83
72
- msgid "PayPal email to receive payments:"
73
- msgstr ""
74
-
75
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:131
76
- #: src/admin-views/tribe-commerce-settings.php:91
77
- msgid ""
78
- "Have you enabled instant payment notifications (IPN) in your PayPal "
79
- "account's Selling Tools?"
80
- msgstr ""
81
-
82
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:133
83
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:145
84
- #: src/Tribe/Attendees.php:549 src/admin-views/tribe-commerce-settings.php:93
85
- #: src/admin-views/tribe-commerce-settings.php:105
86
- msgid "Yes"
87
- msgstr ""
88
-
89
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:134
90
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:146
91
- #: src/admin-views/tribe-commerce-settings.php:94
92
- #: src/admin-views/tribe-commerce-settings.php:106
93
- msgid "No"
94
- msgstr ""
95
-
96
- #. Translators: %s: The PayPal notification history link.
97
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:169
98
- #: src/admin-views/tribe-commerce-settings.php:209
99
- msgid ""
100
- "You can see and manage your IPN Notifications history from the IPN "
101
- "Notifications settings area (%s)."
102
- msgstr ""
103
-
104
- #. Translators: %s: The PayPal notification settings link.
105
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:176
106
- #: src/admin-views/tribe-commerce-settings.php:221
107
- msgid ""
108
- "Override the default IPN notify URL with this value. This value must be the "
109
- "same set in PayPal IPN Notifications settings area (%s)."
110
- msgstr ""
111
-
112
- #: src/Tickets/Commerce/Gateways/Legacy/Settings.php:191
113
- #: src/admin-views/tribe-commerce-settings.php:219
114
- msgid "IPN Notify URL"
115
- msgstr ""
116
-
117
- #: src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php:110
118
- msgid "Unexpected response from PayPal when onboarding"
119
- msgstr ""
120
-
121
- #: src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php:117
122
- msgid "PayPal account onboarded"
123
- msgstr ""
124
-
125
- #: src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php:136
126
- msgid "Must include valid 2-character country code"
127
- msgstr ""
128
-
129
- #: src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php:159
130
- msgid "Partner details not found"
131
- msgstr ""
132
-
133
- #: src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php:187
134
- msgid "PayPal account disconnected"
135
  msgstr ""
136
 
137
- #: src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php:277
138
  msgid ""
139
  "Make sure to complete the entire PayPal process. Do not close the window you "
140
  "have finished the process."
141
  msgstr ""
142
 
143
- #: src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php:278
144
  msgid ""
145
  "The last screen of the PayPal connect process includes a button to be sent "
146
  "back to your site. It is important you click this and do not close the "
147
  "window yourself."
148
  msgstr ""
149
 
150
- #: src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php:279
151
  msgid "If you’re still having problems connecting:"
152
  msgstr ""
153
 
154
- #: src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php:285
155
  msgid "Having trouble connecting to PayPal?"
156
  msgstr ""
157
 
158
- #: src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php:300
159
- msgid "Access not allowed"
160
- msgstr ""
161
-
162
- #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:39
163
  msgid "Disconnect PayPal Account"
164
  msgstr ""
165
 
166
- #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:40
167
  msgid "Are you sure you want to disconnect your PayPal account?"
168
  msgstr ""
169
 
170
- #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:41
171
  msgid "You’re connected to PayPal! Here’s what’s next..."
172
  msgstr ""
173
 
174
- #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:43
175
  msgid ""
176
  "PayPal allows you to accept credit or debit cards directly on your website. "
177
  "Because of\n"
@@ -183,307 +71,366 @@ msgid ""
183
  "comprised of, but not limited to:"
184
  msgstr ""
185
 
186
- #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:53
187
  msgid ""
188
  "Using a trusted, secure hosting provider – preferably one which claims and "
189
  "actively promotes PCI compliance."
190
  msgstr ""
191
 
192
- #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:54
193
  msgid ""
194
  "Maintain security best practices when setting passwords and limit access to "
195
  "your server."
196
  msgstr ""
197
 
198
- #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:55
199
  msgid "Implement an SSL certificate to keep your payments secure."
200
  msgstr ""
201
 
202
- #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:56
203
  msgid "Keep plugins up to date to ensure latest security fixes are present."
204
  msgstr ""
205
 
206
- #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:59
207
  msgid ""
208
  "You have connected your account for test mode. You will need to connect "
209
  "again once you are in live mode."
210
  msgstr ""
211
 
212
- #: src/Tickets/Commerce/Gateways/PayPal/Gateway.php:34
213
  msgid "PayPal Commerce"
214
  msgstr ""
215
 
216
- #. Translators: %s: The missing keys and header information.
217
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/DataTransferObjects/PayPalWebhookHeaders.php:91
218
- msgid "Missing PayPal webhook header: %s"
219
- msgstr ""
220
-
221
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Models/PayPalOrder.php:162
222
  msgid "To create a PayPalOrder object, please provide valid %1$s"
223
  msgstr ""
224
 
225
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Models/PayPalPayment.php:112
226
  msgid ""
227
  "To create a PayPalPayment object, please provide valid id, amount, status, "
228
  "create_time, update_time and links"
229
  msgstr ""
230
 
231
- #. Translators: %s: The error message.
232
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php:63
233
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php:109
234
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:106
235
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:155
236
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:204
237
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:273
238
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:364
239
- msgid "PayPal request error: %s"
240
  msgstr ""
241
 
242
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php:74
243
- msgid "Unexpected PayPal response when getting token from client credentials"
244
  msgstr ""
245
 
246
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php:120
247
- msgid "Unexpected PayPal response when getting token from authorization code"
248
  msgstr ""
249
 
250
- #. Translators: %s: The error message.
251
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php:149
252
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php:190
253
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php:228
254
- msgid "PayPal Commerce Connect request error: %s"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  msgstr ""
256
 
257
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php:160
258
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php:201
259
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php:239
260
- msgid "Unexpected PayPal Commerce Connect response"
261
  msgstr ""
262
 
263
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalOrder.php:172
264
  msgid ""
265
- "To create a paypal order, please provide formId, paymentAmount and payer"
 
 
 
266
  msgstr ""
267
 
268
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:117
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
  msgid "Unexpected PayPal response when verifying signature"
270
  msgstr ""
271
 
272
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:166
273
  msgid "Unexpected PayPal response when getting list of webhooks"
274
  msgstr ""
275
 
276
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:217
277
  msgid "The PayPal webhook does not exist"
278
  msgstr ""
279
 
280
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:220
281
  msgid "Unexpected PayPal response when getting webhook"
282
  msgstr ""
283
 
284
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:298
285
  msgid ""
286
  "PayPal webhook limit has been reached, you need to go into your developer."
287
  "paypal.com account and remove webhooks from the associated account"
288
  msgstr ""
289
 
290
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:302
291
  msgid "Unexpected PayPal response when creating webhook"
292
  msgstr ""
293
 
294
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:380
295
  msgid ""
296
  "The PayPal webhook was not able to be updated because it did not exist, "
297
  "attempting to create it now"
298
  msgstr ""
299
 
300
- #: src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Webhooks.php:388
301
  msgid "Unexpected PayPal response when updating webhook"
302
  msgstr ""
303
 
304
- #: src/Tickets/Commerce/Gateways/PayPal/Settings.php:103
305
  msgid "-- Please select a country --"
306
  msgstr ""
307
 
308
- #: src/Tickets/Commerce/Gateways/PayPal/Settings.php:115
309
- msgid "Account Country"
 
310
  msgstr ""
311
 
312
- #: src/Tickets/Commerce/Gateways/PayPal/Settings.php:116
313
- msgid "This is the country your site operates from."
 
314
  msgstr ""
315
 
316
- #: src/Tickets/Commerce/Gateways/PayPal/Settings.php:125
317
- msgid "PayPal Connection"
318
  msgstr ""
319
 
320
- #. Translators: %s: The PayPal telephone number.
321
- #: src/Tickets/Commerce/Gateways/PayPal/Settings.php:193
322
- msgid "Please call a PayPal support representative at %s"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  msgstr ""
324
 
325
- #: src/Tickets/Commerce/Gateways/PayPal/Settings.php:197
 
326
  msgid ""
327
- "Please reach out to PayPal support from your PayPal account Resolution Center"
 
328
  msgstr ""
329
 
330
- #: src/Tickets/Commerce/Gateways/PayPal/Settings.php:200
331
- msgid " and relay the following message:"
 
332
  msgstr ""
333
 
334
  #. Translators: %s: The PayPal payment event.
335
- #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/PaymentEventListener.php:97
336
  msgid "Mismatched event type for webhook event: %s"
337
  msgstr ""
338
 
339
  #. Translators: %s: The PayPal payment event.
340
- #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/PaymentEventListener.php:112
341
  msgid "Missing PayPal payment for webhook event: %s"
342
  msgstr ""
343
 
344
  #. Translators: %s: The PayPal payment ID.
345
- #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/PaymentEventListener.php:128
346
  msgid "Missing order for PayPal payment from webhook: %s"
347
  msgstr ""
348
 
349
  #. Translators: %1$s: The status name; %2$s: The payment information.
350
- #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/PaymentEventListener.php:153
351
  msgid "Change %1$s in PayPal from webhook: %2$s"
352
  msgstr ""
353
 
354
  #. Translators: %s: The error message.
355
- #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/PaymentEventListener.php:232
356
  msgid "PayPal capture request error: %s"
357
  msgstr ""
358
 
359
- #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/PaymentEventListener.php:243
360
  msgid "Unexpected PayPal capture response"
361
  msgstr ""
362
 
363
- #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/WebhookChecker.php:98
364
  msgid ""
365
  "There was a problem updating your PayPal Payments webhook. Please disconnect "
366
  "your account and reconnect it."
367
  msgstr ""
368
 
369
  #. Translators: %s: The event type.
370
- #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/WebhooksRoute.php:102
371
  msgid "PayPal webhook event type not registered or supported: %s"
372
  msgstr ""
373
 
374
  #. Translators: %s: The event type.
375
- #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/WebhooksRoute.php:114
376
  msgid "Received PayPal webhook event for type: %s"
377
  msgstr ""
378
 
379
- #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/WebhooksRoute.php:123
380
  msgid "Failed PayPal webhook event verification"
381
  msgstr ""
382
 
383
  #. Translators: %s: The event type.
384
- #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/WebhooksRoute.php:137
385
  msgid "Error processing webhook: %s"
386
  msgstr ""
387
 
388
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:121
389
- msgid ""
390
- "There was a problem with PayPal return url and we could not find valid "
391
- "merchant ID. Paypal return URL is:"
392
- msgstr ""
393
-
394
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:201
395
- msgid ""
396
- "There was a problem with creating webhook on PayPal. A gateway error log "
397
- "also added to get details information about PayPal response."
398
- msgstr ""
399
-
400
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:224
401
- msgid "PayPal Commerce account connected successfully."
402
- msgstr ""
403
-
404
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:296
405
- msgid "PayPal client access token API request response is:"
406
- msgstr ""
407
-
408
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:302
409
- msgid "PayPal client rest api credentials API request response is:"
410
- msgstr ""
411
-
412
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:306
413
- msgid ""
414
- "There was a problem with PayPal client rest API request and we could not "
415
- "find valid client id and secret."
416
- msgstr ""
417
-
418
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:359
419
- msgid "PayPal merchant status check API request response is:"
420
- msgstr ""
421
-
422
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:364
423
- msgid ""
424
- "A valid SSL certificate is required to accept payments and set up your "
425
- "PayPal account. Once a\n"
426
- "\t\t\t\t\tcertificate is installed and the site is using https, please "
427
- "disconnect and reconnect your account."
428
  msgstr ""
429
 
430
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:369
431
- msgid ""
432
- "There was a problem with the status check for your account. Please try "
433
- "disconnecting and connecting again. If the problem persists, please contact "
434
- "support."
435
  msgstr ""
436
 
437
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:382
438
- msgid "Set up an account to receive payment from PayPal"
439
  msgstr ""
440
 
441
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:386
442
- msgid "Confirm your primary email address"
 
 
 
443
  msgstr ""
444
 
445
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:394
446
- msgid ""
447
- "Your account was expected to be able to accept custom payments, but is not. "
448
- "Please make sure your\n"
449
- "\t\t\t\taccount country matches the country setting. If the problem "
450
- "persists, please contact PayPal."
451
  msgstr ""
452
 
453
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:412
454
- msgid "Reach out to PayPal to enable PPCP_CUSTOM for your account"
 
 
455
  msgstr ""
456
 
457
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:424
458
- msgid "Reach out to PayPal to resolve the following capabilities:"
 
459
  msgstr ""
460
 
461
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:472
462
- msgid "logged data"
 
463
  msgstr ""
464
 
465
- #. Translators: %1$s: The logged data link.
466
- #: src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php:479
467
- msgid ""
468
- "There was a problem setting up the webhooks for your PayPal account. Please "
469
- "try disconnecting and reconnecting your PayPal account. If the problem "
470
- "persists, please contact support and provide them with the latest %1$s"
471
  msgstr ""
472
 
473
- #: src/Tickets/Commerce/Settings.php:117 src/Tribe/Admin/Notices.php:214
474
- #: src/Tribe/Main.php:658 src/admin-views/admin-welcome-message.php:56
475
  #: src/admin-views/tribe-commerce-settings.php:4
476
  msgid "Event Tickets Plus"
477
  msgstr ""
478
 
479
- #: src/Tickets/Commerce/Settings.php:121
480
  #: src/admin-views/tribe-commerce-settings.php:9
481
  msgid "Check it out!"
482
  msgstr ""
483
 
484
  #. Translators: %1$s: The Event Tickets Plus link, %2$s: The word "ticket" in
485
  #. lowercase, %3$s: The "Check it out!" link.
486
- #: src/Tickets/Commerce/Settings.php:125
487
  msgctxt "about Tickets Commerce"
488
  msgid ""
489
  "Tickets Commerce is a light implementation of a commerce gateway using "
@@ -494,48 +441,40 @@ msgid ""
494
  "%3$s"
495
  msgstr ""
496
 
497
- #: src/Tickets/Commerce/Settings.php:144
498
- msgid "-- No page set --"
499
- msgstr ""
500
-
501
- #: src/Tickets/Commerce/Settings.php:162
502
- msgid "Tickets Commerce"
503
- msgstr ""
504
-
505
- #: src/Tickets/Commerce/Settings.php:170
506
  msgid "Enable Tickets Commerce"
507
  msgstr ""
508
 
509
- #: src/Tickets/Commerce/Settings.php:171
510
- msgid "Check this box if you wish to turn on Tickets Commerce functionality."
511
  msgstr ""
512
 
513
- #: src/Tickets/Commerce/Settings.php:184
514
  msgid "Enable Test Mode"
515
  msgstr ""
516
 
517
- #: src/Tickets/Commerce/Settings.php:185
518
  msgid ""
519
  "Enables Test mode for testing payments. Any payments made will be done on "
520
  "\"sandbox\" accounts."
521
  msgstr ""
522
 
523
- #: src/Tickets/Commerce/Settings.php:191
524
  #: src/admin-views/tribe-commerce-settings.php:136
525
  msgid "Currency Code"
526
  msgstr ""
527
 
528
- #: src/Tickets/Commerce/Settings.php:192
529
  msgid "The currency that will be used for Tickets Commerce transactions."
530
  msgstr ""
531
 
532
- #: src/Tickets/Commerce/Settings.php:199
533
  #: src/admin-views/tribe-commerce-settings.php:144
534
  msgid "Stock Handling"
535
  msgstr ""
536
 
537
  #. Translators: %s: The word "ticket" in lowercase.
538
- #: src/Tickets/Commerce/Settings.php:203
539
  msgctxt "tickets fields settings paypal stock handling"
540
  msgid ""
541
  "When a customer purchases a %s, the payment gateway might flag the order as "
@@ -544,61 +483,61 @@ msgid ""
544
  msgstr ""
545
 
546
  #. Translators: %s: The word "ticket" in lowercase.
547
- #: src/Tickets/Commerce/Settings.php:212
548
  #: src/admin-views/tribe-commerce-settings.php:150
549
  msgid "Decrease available %s stock as soon as a Pending order is created."
550
  msgstr ""
551
 
552
  #. Translators: %s: The word "ticket" in lowercase.
553
- #: src/Tickets/Commerce/Settings.php:217
554
  msgid ""
555
  "Only decrease available %s stock if an order is confirmed as Completed by "
556
  "the payment gateway."
557
  msgstr ""
558
 
559
- #: src/Tickets/Commerce/Settings.php:225
560
  msgid "Checkout page"
561
  msgstr ""
562
 
563
  #. Translators: %s: The [shortcode] for the success page.
564
- #: src/Tickets/Commerce/Settings.php:229
565
  msgid ""
566
  "This is the page where customers go to complete their purchase. Use the %s "
567
  "shortcode to display the checkout experience in the page content."
568
  msgstr ""
569
 
570
- #: src/Tickets/Commerce/Settings.php:240
571
  #: src/admin-views/tribe-commerce-settings.php:162
572
  msgid "Success page"
573
  msgstr ""
574
 
575
  #. Translators: %s: The [shortcode] for the success page.
576
- #: src/Tickets/Commerce/Settings.php:244
577
  msgid ""
578
  "After a successful order, users will be redirected to this page. Use the %s "
579
  "shortcode to display the order confirmation to the user in the page content."
580
  msgstr ""
581
 
582
- #: src/Tickets/Commerce/Settings.php:255
583
  #: src/admin-views/tribe-commerce-settings.php:176
584
  msgid "Confirmation email sender address"
585
  msgstr ""
586
 
587
  #. Translators: %s: The word "tickets" in lowercase.
588
- #: src/Tickets/Commerce/Settings.php:259
589
  msgctxt "tickets fields settings confirmation email"
590
  msgid ""
591
  "Email address that %s customers will receive confirmation from. Leave empty "
592
  "to use the default WordPress site email address."
593
  msgstr ""
594
 
595
- #: src/Tickets/Commerce/Settings.php:270
596
  #: src/admin-views/tribe-commerce-settings.php:185
597
  msgid "Confirmation email sender name"
598
  msgstr ""
599
 
600
  #. Translators: %s: The word "ticket" in lowercase.
601
- #: src/Tickets/Commerce/Settings.php:274
602
  #: src/admin-views/tribe-commerce-settings.php:186
603
  msgctxt "tickets fields settings paypal email sender"
604
  msgid ""
@@ -606,13 +545,13 @@ msgid ""
606
  "purchase."
607
  msgstr ""
608
 
609
- #: src/Tickets/Commerce/Settings.php:285
610
  #: src/admin-views/tribe-commerce-settings.php:194
611
  msgid "Confirmation email subject"
612
  msgstr ""
613
 
614
  #. Translators: %s: The word "ticket" in lowercase.
615
- #: src/Tickets/Commerce/Settings.php:289
616
  #: src/admin-views/tribe-commerce-settings.php:195
617
  msgctxt "tickets fields settings paypal email subject"
618
  msgid ""
@@ -621,12 +560,96 @@ msgid ""
621
  msgstr ""
622
 
623
  #. Translators: %s: The word "tickets" in lowercase.
624
- #: src/Tickets/Commerce/Settings.php:297
625
  #: src/admin-views/tribe-commerce-settings.php:197
626
  msgctxt "tickets fields settings paypal email subject"
627
  msgid "You have %s!"
628
  msgstr ""
629
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
630
  #: src/Tribe/Abstract_Attendance_Totals.php:65
631
  msgctxt "total sold tooltip"
632
  msgid "Includes all ticketed attendees regardless of order status."
@@ -637,13 +660,6 @@ msgctxt "total complete tooltip"
637
  msgid "Includes ticketed attendees with orders marked Completed."
638
  msgstr ""
639
 
640
- #: src/Tribe/Admin/Columns/Tickets.php:56
641
- #: src/Tribe/Admin/Manager/Service_Provider.php:173 src/Tribe/Attendees.php:212
642
- #: src/Tribe/Commerce/PayPal/Main.php:458
643
- #: src/Tribe/Tabbed_View/Attendee_Report_Tab.php:22 src/admin-views/list.php:95
644
- msgid "Attendees"
645
- msgstr ""
646
-
647
  #: src/Tribe/Admin/Manager/Service_Provider.php:56
648
  msgid "Insecure request."
649
  msgstr ""
@@ -889,29 +905,29 @@ msgstr ""
889
  msgid "Unticketed"
890
  msgstr ""
891
 
892
- #: src/Tribe/Assets.php:192 src/views/tickets/tpp-success.php:97
893
  msgid "%s header image"
894
  msgstr ""
895
 
896
- #: src/Tribe/Assets.php:193
897
  msgid "Set as %s header"
898
  msgstr ""
899
 
900
- #: src/Tribe/Assets.php:249
901
  msgid "Are you sure you want to delete this ticket? This cannot be undone."
902
  msgstr ""
903
 
904
- #: src/Tribe/Assets.php:255
905
  msgid ""
906
  "It looks like you have modified your shared capacity setting but have not "
907
  "saved or updated the post."
908
  msgstr ""
909
 
910
- #: src/Tribe/Assets.php:275 src/Tribe/Metabox.php:575
911
  msgid "Please enter in without thousand separators and currency symbols."
912
  msgstr ""
913
 
914
- #: src/Tribe/Assets.php:467
915
  msgid ""
916
  "There is unsaved attendee information. Are you sure you want to continue?"
917
  msgstr ""
@@ -1029,6 +1045,11 @@ msgctxt "attendee export"
1029
  msgid "Purchaser Email Address"
1030
  msgstr ""
1031
 
 
 
 
 
 
1032
  #: src/Tribe/Attendees.php:660
1033
  msgid "attendees"
1034
  msgstr ""
@@ -1340,27 +1361,11 @@ msgstr ""
1340
  msgid "U.S. Dollar (USD)"
1341
  msgstr ""
1342
 
1343
- #. Translators: %1$s: the post/event title, %2$d: the post/event ID.
1344
- #: src/Tribe/Commerce/Orders_Tabbed_View.php:36
1345
- #: src/admin-views/attendees.php:34
1346
- msgctxt "attendees report screen heading"
1347
- msgid "Attendees for: %1$s [#%2$d]"
1348
- msgstr ""
1349
-
1350
- #: src/Tribe/Commerce/PayPal/Attendance_Totals.php:77
1351
- #: src/Tribe/RSVP/Attendance_Totals.php:49
1352
- msgctxt "attendee summary"
1353
- msgid "Total %s:"
1354
- msgstr ""
1355
-
1356
- #: src/Tribe/Commerce/PayPal/Attendance_Totals.php:78
1357
- msgctxt "attendee summary"
1358
- msgid "Complete:"
1359
- msgstr ""
1360
-
1361
- #: src/Tribe/Commerce/PayPal/Attendance_Totals.php:79
1362
- msgctxt "attendee summary"
1363
- msgid "Cancelled:"
1364
  msgstr ""
1365
 
1366
  #: src/Tribe/Commerce/PayPal/Endpoints/Success_Template.php:99
@@ -1403,12 +1408,6 @@ msgid ""
1403
  "%s(s) in an email."
1404
  msgstr ""
1405
 
1406
- #: src/Tribe/Commerce/PayPal/Frontend/Tickets_Form.php:75
1407
- msgid ""
1408
- "Your PayPal %1$s has been received! Check your email for your PayPal %1$s "
1409
- "confirmation."
1410
- msgstr ""
1411
-
1412
  #: src/Tribe/Commerce/PayPal/Handler/IPN.php:143
1413
  msgctxt "a PayPal configuration status"
1414
  msgid "complete"
@@ -1438,10 +1437,6 @@ msgctxt "ticket provider"
1438
  msgid "Tribe Commerce"
1439
  msgstr ""
1440
 
1441
- #: src/Tribe/Commerce/PayPal/Main.php:442
1442
- msgid "Tickets"
1443
- msgstr ""
1444
-
1445
  #: src/Tribe/Commerce/PayPal/Main.php:444
1446
  msgid "Tribe Commerce Tickets"
1447
  msgstr ""
@@ -1450,46 +1445,6 @@ msgstr ""
1450
  msgid "Tribe Commerce Ticket"
1451
  msgstr ""
1452
 
1453
- #: src/Tribe/Commerce/PayPal/Main.php:470
1454
- msgid "Orders"
1455
- msgstr ""
1456
-
1457
- #: src/Tribe/Commerce/PayPal/Main.php:1726
1458
- msgid "Sales report"
1459
- msgstr ""
1460
-
1461
- #: src/Tribe/Commerce/PayPal/Main.php:1752
1462
- msgid "Report"
1463
- msgstr ""
1464
-
1465
- #: src/Tribe/Commerce/PayPal/Main.php:1910 src/Tribe/RSVP.php:2355
1466
- msgid "Return to the %1$sAttendees Report%2$s."
1467
- msgstr ""
1468
-
1469
- #: src/Tribe/Commerce/PayPal/Main.php:1917 src/Tribe/RSVP.php:2362
1470
- msgid "Post updated. %1$s"
1471
- msgstr ""
1472
-
1473
- #: src/Tribe/Commerce/PayPal/Main.php:1921 src/Tribe/RSVP.php:2366
1474
- msgid "Post published. %1$s"
1475
- msgstr ""
1476
-
1477
- #: src/Tribe/Commerce/PayPal/Main.php:1924 src/Tribe/RSVP.php:2369
1478
- msgid "Post submitted."
1479
- msgstr ""
1480
-
1481
- #: src/Tribe/Commerce/PayPal/Main.php:1925 src/Tribe/RSVP.php:2370
1482
- msgid "Post scheduled."
1483
- msgstr ""
1484
-
1485
- #: src/Tribe/Commerce/PayPal/Main.php:1926 src/Tribe/RSVP.php:2371
1486
- msgid "Post draft updated."
1487
- msgstr ""
1488
-
1489
- #: src/Tribe/Commerce/PayPal/Main.php:2961 src/Tribe/RSVP.php:2014
1490
- msgid "(deleted)"
1491
- msgstr ""
1492
-
1493
  #: src/Tribe/Commerce/PayPal/Notices.php:43
1494
  msgid "PayPal is using PDT data but you have not set the PDT identity token"
1495
  msgstr ""
@@ -1517,11 +1472,6 @@ msgstr ""
1517
  msgid "Search Orders"
1518
  msgstr ""
1519
 
1520
- #: src/Tribe/Commerce/PayPal/Orders/Sales.php:258
1521
- #: src/admin-views/tpp-orders.php:173
1522
- msgid "Completed"
1523
- msgstr ""
1524
-
1525
  #: src/Tribe/Commerce/PayPal/Orders/Sales.php:262
1526
  msgid "Not completed"
1527
  msgstr ""
@@ -1612,14 +1562,6 @@ msgstr ""
1612
  msgid "Sell only available"
1613
  msgstr ""
1614
 
1615
- #: src/Tribe/Commerce/PayPal/Tickets_View.php:106
1616
- msgid "This ticket is no longer active."
1617
- msgstr ""
1618
-
1619
- #: src/Tribe/Commerce/PayPal/Tickets_View.php:137
1620
- msgid "unavailable"
1621
- msgstr ""
1622
-
1623
  #: src/Tribe/Editor/Attendee_Registration.php:127
1624
  msgid "return to the content editor"
1625
  msgstr ""
@@ -1781,113 +1723,113 @@ msgstr ""
1781
  msgid "Free"
1782
  msgstr ""
1783
 
1784
- #: src/Tribe/Main.php:145
1785
  msgctxt "provider_plugin_name"
1786
  msgid "Tickets"
1787
  msgstr ""
1788
 
1789
- #: src/Tribe/Main.php:422
1790
  msgid ""
1791
  "When The Events Calendar and Event Tickets are both activated, The Events "
1792
  "Calendar must be running version %1$s or greater. Please %2$supdate now.%3$s"
1793
  msgstr ""
1794
 
1795
- #: src/Tribe/Main.php:485
1796
  msgid ""
1797
  "Sorry, Event Tickets requires WordPress %s or higher. Please upgrade your "
1798
  "WordPress install."
1799
  msgstr ""
1800
 
1801
- #: src/Tribe/Main.php:489
1802
  msgid ""
1803
  "Sorry, Event Tickets requires PHP %s or higher. Talk to your Web host about "
1804
  "moving you to a newer version of PHP."
1805
  msgstr ""
1806
 
1807
- #: src/Tribe/Main.php:613
1808
  msgid "Support for Event Tickets"
1809
  msgstr ""
1810
 
1811
- #: src/Tribe/Main.php:615
1812
  msgid "Settings overview"
1813
  msgstr ""
1814
 
1815
- #: src/Tribe/Main.php:616
1816
  msgid "Features overview"
1817
  msgstr ""
1818
 
1819
- #: src/Tribe/Main.php:617
1820
  msgid "Troubleshooting common problems"
1821
  msgstr ""
1822
 
1823
- #: src/Tribe/Main.php:618
1824
  msgid "Customizing Event Tickets"
1825
  msgstr ""
1826
 
1827
- #: src/Tribe/Main.php:635
1828
  msgid "New User Primer"
1829
  msgstr ""
1830
 
1831
- #: src/Tribe/Main.php:637
1832
  msgctxt "help feature box section"
1833
  msgid ""
1834
  "We are committed to helping you sell %1$s for your event. Check out our "
1835
  "handy %2$s to get started."
1836
  msgstr ""
1837
 
1838
- #: src/Tribe/Main.php:654
1839
  msgid "open-source forum on WordPress.org"
1840
  msgstr ""
1841
 
1842
- #: src/Tribe/Main.php:655
1843
  msgid ""
1844
  "If you have tried the above steps and are still having trouble, you can post "
1845
  "a new thread to our %s. Our support staff monitors these forums once a week "
1846
  "and would be happy to assist you there."
1847
  msgstr ""
1848
 
1849
- #: src/Tribe/Main.php:657
1850
  msgid "premium support on our website"
1851
  msgstr ""
1852
 
1853
- #: src/Tribe/Main.php:659
1854
  msgid ""
1855
  "Looking for more immediate support? We offer %1$s with the purchase of any "
1856
  "of our premium plugins (like %2$s). Pick up a license and you can post there "
1857
  "directly and expect a response within 24-48 hours during weekdays."
1858
  msgstr ""
1859
 
1860
- #: src/Tribe/Main.php:661 src/Tribe/Main.php:666
1861
  msgid "post a thread"
1862
  msgstr ""
1863
 
1864
- #: src/Tribe/Main.php:662
1865
  msgid ""
1866
  "Already have Event Tickets Plus? You can %s in our premium support forums. "
1867
  "Our support team monitors the forums and will respond to your thread within "
1868
  "24-48 hours (during the week)."
1869
  msgstr ""
1870
 
1871
- #: src/Tribe/Main.php:667
1872
  msgid ""
1873
  "If you have a valid license for one of our paid plugins, you can %s in our "
1874
  "premium support forums. Our support team monitors the forums and will "
1875
  "respond to your thread within 24-48 hours (during the week)."
1876
  msgstr ""
1877
 
1878
- #: src/Tribe/Main.php:689
1879
  msgid "Event Tickets - Legacy"
1880
  msgstr ""
1881
 
1882
- #: src/Tribe/Main.php:825
1883
  msgid "Welcome to Event Tickets!"
1884
  msgstr ""
1885
 
1886
- #: src/Tribe/Main.php:978
1887
  msgid "Buy"
1888
  msgstr ""
1889
 
1890
- #: src/Tribe/Main.php:1057
1891
  msgid ""
1892
  "When Event Tickets and Event Tickets Plus are both activated, Event Tickets "
1893
  "Plus must be running version %1$s or greater. Please %2$smanually update now"
@@ -2490,18 +2432,6 @@ msgstr ""
2490
  msgid "List of meta for each ticket to be saved for Attendee Registration"
2491
  msgstr ""
2492
 
2493
- #: src/Tribe/REST/V1/Endpoints/Commerce/PayPal_Webhook.php:48
2494
- msgid "Processes the Webhook as long as it includes valid Payment Event data"
2495
- msgstr ""
2496
-
2497
- #: src/Tribe/REST/V1/Endpoints/Commerce/PayPal_Webhook.php:55
2498
- msgid "Whether the processing was successful"
2499
- msgstr ""
2500
-
2501
- #: src/Tribe/REST/V1/Endpoints/Commerce/PayPal_Webhook.php:64
2502
- msgid "The webhook was invalid and was not processed"
2503
- msgstr ""
2504
-
2505
  #: src/Tribe/REST/V1/Endpoints/Single_Attendee.php:19
2506
  msgid "Returns the data of the attendee with the specified post ID"
2507
  msgstr ""
@@ -3153,7 +3083,7 @@ msgid "Select a User:"
3153
  msgstr ""
3154
 
3155
  #: src/admin-views/attendees-email.php:36
3156
- #: src/views/modal/registration-js.php:126
3157
  msgid "or"
3158
  msgstr ""
3159
 
@@ -3187,6 +3117,33 @@ msgstr ""
3187
  msgid "Search attendees"
3188
  msgstr ""
3189
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3190
  #: src/admin-views/editor/button-view-orders.php:46
3191
  msgid "View Orders"
3192
  msgstr ""
@@ -3272,12 +3229,6 @@ msgctxt "ticket type label"
3272
  msgid "%s Type:"
3273
  msgstr ""
3274
 
3275
- #: src/admin-views/editor/list-row.php:99
3276
- #: src/admin-views/rsvp-metabox-capacity.php:10
3277
- #: src/admin-views/tpp-metabox-capacity.php:16
3278
- msgid "Capacity:"
3279
- msgstr ""
3280
-
3281
  #: src/admin-views/editor/list-row.php:104
3282
  msgid "Available:"
3283
  msgstr ""
@@ -3674,6 +3625,74 @@ msgid ""
3674
  "statuses:"
3675
  msgstr ""
3676
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3677
  #: src/admin-views/privacy.php:16
3678
  msgid "Hello,"
3679
  msgstr ""
@@ -3809,11 +3828,6 @@ msgid ""
3809
  "to these external services. These services may be located abroad."
3810
  msgstr ""
3811
 
3812
- #: src/admin-views/rsvp-metabox-capacity.php:19
3813
- #: src/admin-views/tpp-metabox-capacity.php:25
3814
- msgid "Leave blank for unlimited"
3815
- msgstr ""
3816
-
3817
  #: src/admin-views/rsvp-metabox-not-going.php:17
3818
  msgid "Can't Go:"
3819
  msgstr ""
@@ -3907,49 +3921,27 @@ msgstr ""
3907
  msgid "Connected for payments as"
3908
  msgstr ""
3909
 
3910
- #: src/admin-views/settings/tickets-commerce/paypal-commerce/connect-with-paypal.php:62
3911
- msgid "Disconnect"
3912
- msgstr ""
3913
-
3914
  #: src/admin-views/settings/tickets-commerce/paypal-commerce/connect-with-paypal.php:68
3915
  msgid "APIs Connected:"
3916
  msgstr ""
3917
 
3918
- #: src/admin-views/settings/tickets-commerce/paypal-commerce/connect-with-paypal.php:70
3919
- msgid "Payments"
3920
- msgstr ""
3921
-
3922
  #: src/admin-views/settings/tickets-commerce/paypal-commerce/connect-with-paypal.php:71
3923
  msgid "Refunds"
3924
  msgstr ""
3925
 
3926
- #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:17
3927
- msgid "Accept payments with PayPal Commerce"
3928
- msgstr ""
3929
-
3930
- #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:19
3931
- msgid ""
3932
- "Allow your customers to pay using Debit or Credit Cards directly on your "
3933
- "website."
3934
- msgstr ""
3935
-
3936
- #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:23
3937
  msgid "PayPal Logo Image"
3938
  msgstr ""
3939
 
3940
- #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:28
3941
  msgid "Credit and Debit Card payments"
3942
  msgstr ""
3943
 
3944
- #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:31
3945
  msgid "Easy no-API key connection"
3946
  msgstr ""
3947
 
3948
- #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:34
3949
- msgid "Accept payments from around the world"
3950
- msgstr ""
3951
-
3952
- #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:37
3953
  msgid "Supports 3D Secure payments"
3954
  msgstr ""
3955
 
@@ -3966,14 +3958,6 @@ msgstr ""
3966
  msgid "Click to hide history"
3967
  msgstr ""
3968
 
3969
- #: src/admin-views/tpp-metabox-sku.php:20
3970
- msgid "SKU:"
3971
- msgstr ""
3972
-
3973
- #: src/admin-views/tpp-metabox-sku.php:33
3974
- msgid "A unique identifying code for each %s type you're selling"
3975
- msgstr ""
3976
-
3977
  #: src/admin-views/tpp-orders.php:32
3978
  msgid "Orders Report"
3979
  msgstr ""
@@ -4006,6 +3990,10 @@ msgid ""
4006
  "%3$s"
4007
  msgstr ""
4008
 
 
 
 
 
4009
  #: src/admin-views/tribe-commerce-settings.php:41
4010
  msgctxt "tickets fields settings PayPal setup"
4011
  msgid ""
@@ -4014,6 +4002,16 @@ msgid ""
4014
  "set up, follow %2$s"
4015
  msgstr ""
4016
 
 
 
 
 
 
 
 
 
 
 
4017
  #: src/admin-views/tribe-commerce-settings.php:55
4018
  msgid "Tribe Commerce"
4019
  msgstr ""
@@ -4030,6 +4028,31 @@ msgstr ""
4030
  msgid "Configure PayPal:"
4031
  msgstr ""
4032
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4033
  #: src/admin-views/tribe-commerce-settings.php:129
4034
  msgid "PayPal Sandbox"
4035
  msgstr ""
@@ -4069,6 +4092,22 @@ msgid ""
4069
  "empty to use the default WordPress site email address."
4070
  msgstr ""
4071
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4072
  #. Translators: %1$s: dynamic "RSVP" text.
4073
  #: src/admin-views/tribe-options-display.php:28
4074
  msgctxt "title of settings section"
@@ -4637,18 +4676,18 @@ msgstr ""
4637
  msgid "One Moment..."
4638
  msgstr ""
4639
 
4640
- #: src/views/modal/registration-js.php:40 src/views/modal/registration.php:23
4641
  msgid "Attendee Details"
4642
  msgstr ""
4643
 
4644
- #: src/views/modal/registration-js.php:50
4645
  #: src/views/registration-js/content.php:100
4646
  msgctxt ""
4647
  "Note about missing required fields, %s is the html-wrapped number of tickets."
4648
  msgid "You have %s ticket(s) with a field that requires information."
4649
  msgstr ""
4650
 
4651
- #: src/views/modal/registration-js.php:97
4652
  #: src/views/registration-js/content.php:196
4653
  msgctxt ""
4654
  "Note that there are more tickets in the cart, %s is the html-wrapped number."
@@ -4657,20 +4696,20 @@ msgid ""
4657
  "information."
4658
  msgstr ""
4659
 
4660
- #: src/views/modal/registration-js.php:116 src/views/modal/registration.php:35
4661
  #: src/views/registration/content.php:111
4662
  msgid "Save and Checkout"
4663
  msgstr ""
4664
 
4665
- #: src/views/modal/registration-js.php:124
4666
  msgid "Save and View Cart"
4667
  msgstr ""
4668
 
4669
- #: src/views/modal/registration-js.php:132
4670
  msgid "Checkout Now"
4671
  msgstr ""
4672
 
4673
- #: src/views/modal/registration.php:37 src/views/registration/content.php:113
4674
  msgid "Save Attendee Info"
4675
  msgstr ""
4676
 
@@ -4962,6 +5001,63 @@ msgstr ""
4962
  msgid "Buy now"
4963
  msgstr ""
4964
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4965
  #: src/views/v2/rsvp/actions/full.php:22
4966
  msgid "RSVP Closed"
4967
  msgstr ""
2
  # This file is distributed under the same license as the Event Tickets package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Event Tickets 5.1.9\n"
6
  "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/event-tickets\n"
7
+ "POT-Creation-Date: 2021-08-31 16:17:29+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=UTF-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2021-08-31 16:17\n"
12
  "Last-Translator: \n"
13
  "Language-Team: \n"
14
 
15
+ #. #-#-#-#-# event-tickets.pot (Event Tickets 5.1.9) #-#-#-#-#
16
  #. Plugin Name of the plugin/theme
17
+ #: event-tickets.php:62 src/Tribe/Admin/Notices.php:92 src/Tribe/Main.php:691
18
  #: src/Tribe/Privacy.php:59 src/admin-views/admin-welcome-message.php:58
19
  msgid "Event Tickets"
20
  msgstr ""
21
 
22
+ #: src/Tickets/Commerce/Attendee.php:176 src/Tribe/Admin/Columns/Tickets.php:56
23
+ #: src/Tribe/Admin/Manager/Service_Provider.php:173 src/Tribe/Attendees.php:212
24
+ #: src/Tribe/Commerce/PayPal/Main.php:458
25
+ #: src/Tribe/Tabbed_View/Attendee_Report_Tab.php:22 src/admin-views/list.php:95
26
+ msgid "Attendees"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  msgstr ""
28
 
29
+ #: src/Tickets/Commerce/Gateways/PayPal/Ajax_Request_Handler.php:30
30
  msgid ""
31
  "Make sure to complete the entire PayPal process. Do not close the window you "
32
  "have finished the process."
33
  msgstr ""
34
 
35
+ #: src/Tickets/Commerce/Gateways/PayPal/Ajax_Request_Handler.php:31
36
  msgid ""
37
  "The last screen of the PayPal connect process includes a button to be sent "
38
  "back to your site. It is important you click this and do not close the "
39
  "window yourself."
40
  msgstr ""
41
 
42
+ #: src/Tickets/Commerce/Gateways/PayPal/Ajax_Request_Handler.php:32
43
  msgid "If you’re still having problems connecting:"
44
  msgstr ""
45
 
46
+ #: src/Tickets/Commerce/Gateways/PayPal/Ajax_Request_Handler.php:38
47
  msgid "Having trouble connecting to PayPal?"
48
  msgstr ""
49
 
50
+ #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:42
 
 
 
 
51
  msgid "Disconnect PayPal Account"
52
  msgstr ""
53
 
54
+ #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:43
55
  msgid "Are you sure you want to disconnect your PayPal account?"
56
  msgstr ""
57
 
58
+ #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:44
59
  msgid "You’re connected to PayPal! Here’s what’s next..."
60
  msgstr ""
61
 
62
+ #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:46
63
  msgid ""
64
  "PayPal allows you to accept credit or debit cards directly on your website. "
65
  "Because of\n"
71
  "comprised of, but not limited to:"
72
  msgstr ""
73
 
74
+ #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:56
75
  msgid ""
76
  "Using a trusted, secure hosting provider – preferably one which claims and "
77
  "actively promotes PCI compliance."
78
  msgstr ""
79
 
80
+ #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:57
81
  msgid ""
82
  "Maintain security best practices when setting passwords and limit access to "
83
  "your server."
84
  msgstr ""
85
 
86
+ #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:58
87
  msgid "Implement an SSL certificate to keep your payments secure."
88
  msgstr ""
89
 
90
+ #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:59
91
  msgid "Keep plugins up to date to ensure latest security fixes are present."
92
  msgstr ""
93
 
94
+ #: src/Tickets/Commerce/Gateways/PayPal/Assets.php:62
95
  msgid ""
96
  "You have connected your account for test mode. You will need to connect "
97
  "again once you are in live mode."
98
  msgstr ""
99
 
100
+ #: src/Tickets/Commerce/Gateways/PayPal/Gateway.php:43
101
  msgid "PayPal Commerce"
102
  msgstr ""
103
 
104
+ #: src/Tickets/Commerce/Gateways/PayPal/Models/PayPal_Order.php:160
 
 
 
 
 
105
  msgid "To create a PayPalOrder object, please provide valid %1$s"
106
  msgstr ""
107
 
108
+ #: src/Tickets/Commerce/Gateways/PayPal/Models/PayPal_Payment.php:113
109
  msgid ""
110
  "To create a PayPalPayment object, please provide valid id, amount, status, "
111
  "create_time, update_time and links"
112
  msgstr ""
113
 
114
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:38
115
+ msgid ""
116
+ "There was a problem with creating webhook on PayPal. A gateway error log "
117
+ "also added to get details information about PayPal response."
 
 
 
 
 
118
  msgstr ""
119
 
120
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:68
121
+ msgid "PayPal client access token API request response is:"
122
  msgstr ""
123
 
124
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:74
125
+ msgid "PayPal client rest API credentials API request response is:"
126
  msgstr ""
127
 
128
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:78
129
+ msgid ""
130
+ "There was a problem with PayPal client rest API request and we could not "
131
+ "find valid client id and secret."
132
+ msgstr ""
133
+
134
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:107
135
+ msgid "PayPal merchant status check API request response is:"
136
+ msgstr ""
137
+
138
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:112
139
+ msgid ""
140
+ "A valid SSL certificate is required to accept payments and set up your "
141
+ "PayPal account. Once a\n"
142
+ "\t\t\t\t\tcertificate is installed and the site is using https, please "
143
+ "disconnect and reconnect your account."
144
+ msgstr ""
145
+
146
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:117
147
+ msgid ""
148
+ "There was a problem with the status check for your account. Please try "
149
+ "disconnecting and connecting again. If the problem persists, please contact "
150
+ "support."
151
+ msgstr ""
152
+
153
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:130
154
+ msgid "Set up an account to receive payment from PayPal"
155
  msgstr ""
156
 
157
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:134
158
+ msgid "Confirm your primary email address"
 
 
159
  msgstr ""
160
 
161
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:142
162
  msgid ""
163
+ "Your account was expected to be able to accept custom payments, but is not. "
164
+ "Please make sure your\n"
165
+ "\t\t\t\taccount country matches the country setting. If the problem "
166
+ "persists, please contact PayPal."
167
  msgstr ""
168
 
169
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:160
170
+ msgid "Reach out to PayPal to enable PPCP_CUSTOM for your account"
171
+ msgstr ""
172
+
173
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:172
174
+ msgid "Reach out to PayPal to resolve the following capabilities:"
175
+ msgstr ""
176
+
177
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:200
178
+ msgid "logged data"
179
+ msgstr ""
180
+
181
+ #. Translators: %1$s: The logged data link.
182
+ #: src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php:207
183
+ msgid ""
184
+ "There was a problem setting up the webhooks for your PayPal account. Please "
185
+ "try disconnecting and reconnecting your PayPal account. If the problem "
186
+ "persists, please contact support and provide them with the latest %1$s"
187
+ msgstr ""
188
+
189
+ #: src/Tickets/Commerce/Gateways/PayPal/REST/On_Boarding_Endpoint.php:139
190
+ msgid "Unexpected response from PayPal when on boarding"
191
+ msgstr ""
192
+
193
+ #: src/Tickets/Commerce/Gateways/PayPal/REST/Order_Endpoint.php:234
194
+ msgid "Order ID in PayPal"
195
+ msgstr ""
196
+
197
+ #: src/Tickets/Commerce/Gateways/PayPal/REST/Webhook_Endpoint.php:73
198
+ msgid "Processes the Webhook as long as it includes valid Payment Event data"
199
+ msgstr ""
200
+
201
+ #: src/Tickets/Commerce/Gateways/PayPal/REST/Webhook_Endpoint.php:80
202
+ msgid "Whether the processing was successful"
203
+ msgstr ""
204
+
205
+ #: src/Tickets/Commerce/Gateways/PayPal/REST/Webhook_Endpoint.php:89
206
+ msgid "The webhook was invalid and was not processed"
207
+ msgstr ""
208
+
209
+ #. Translators: %s: The error message.
210
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Authorization.php:69
211
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:100
212
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:149
213
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:198
214
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:267
215
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:359
216
+ msgid "PayPal request error: %s"
217
+ msgstr ""
218
+
219
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Authorization.php:80
220
+ msgid "Unexpected PayPal response when getting token from client credentials"
221
+ msgstr ""
222
+
223
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:111
224
  msgid "Unexpected PayPal response when verifying signature"
225
  msgstr ""
226
 
227
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:160
228
  msgid "Unexpected PayPal response when getting list of webhooks"
229
  msgstr ""
230
 
231
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:211
232
  msgid "The PayPal webhook does not exist"
233
  msgstr ""
234
 
235
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:214
236
  msgid "Unexpected PayPal response when getting webhook"
237
  msgstr ""
238
 
239
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:292
240
  msgid ""
241
  "PayPal webhook limit has been reached, you need to go into your developer."
242
  "paypal.com account and remove webhooks from the associated account"
243
  msgstr ""
244
 
245
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:296
246
  msgid "Unexpected PayPal response when creating webhook"
247
  msgstr ""
248
 
249
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:375
250
  msgid ""
251
  "The PayPal webhook was not able to be updated because it did not exist, "
252
  "attempting to create it now"
253
  msgstr ""
254
 
255
+ #: src/Tickets/Commerce/Gateways/PayPal/Repositories/Webhooks.php:383
256
  msgid "Unexpected PayPal response when updating webhook"
257
  msgstr ""
258
 
259
+ #: src/Tickets/Commerce/Gateways/PayPal/Settings.php:33
260
  msgid "-- Please select a country --"
261
  msgstr ""
262
 
263
+ #. Translators: %s: The PayPal telephone number.
264
+ #: src/Tickets/Commerce/Gateways/PayPal/Settings.php:82
265
+ msgid "Please call a PayPal support representative at %s"
266
  msgstr ""
267
 
268
+ #: src/Tickets/Commerce/Gateways/PayPal/Settings.php:86
269
+ msgid ""
270
+ "Please reach out to PayPal support from your PayPal account Resolution Center"
271
  msgstr ""
272
 
273
+ #: src/Tickets/Commerce/Gateways/PayPal/Settings.php:89
274
+ msgid " and relay the following message:"
275
  msgstr ""
276
 
277
+ #: src/Tickets/Commerce/Gateways/PayPal/Tickets_Form.php:77
278
+ #: src/Tribe/Commerce/PayPal/Main.php:1910 src/Tribe/RSVP.php:2355
279
+ msgid "Return to the %1$sAttendees Report%2$s."
280
+ msgstr ""
281
+
282
+ #: src/Tickets/Commerce/Gateways/PayPal/Tickets_Form.php:84
283
+ #: src/Tribe/Commerce/PayPal/Main.php:1917 src/Tribe/RSVP.php:2362
284
+ msgid "Post updated. %1$s"
285
+ msgstr ""
286
+
287
+ #: src/Tickets/Commerce/Gateways/PayPal/Tickets_Form.php:88
288
+ #: src/Tribe/Commerce/PayPal/Main.php:1921 src/Tribe/RSVP.php:2366
289
+ msgid "Post published. %1$s"
290
+ msgstr ""
291
+
292
+ #: src/Tickets/Commerce/Gateways/PayPal/Tickets_Form.php:91
293
+ #: src/Tribe/Commerce/PayPal/Main.php:1924 src/Tribe/RSVP.php:2369
294
+ msgid "Post submitted."
295
+ msgstr ""
296
+
297
+ #: src/Tickets/Commerce/Gateways/PayPal/Tickets_Form.php:92
298
+ #: src/Tribe/Commerce/PayPal/Main.php:1925 src/Tribe/RSVP.php:2370
299
+ msgid "Post scheduled."
300
+ msgstr ""
301
+
302
+ #: src/Tickets/Commerce/Gateways/PayPal/Tickets_Form.php:93
303
+ #: src/Tribe/Commerce/PayPal/Main.php:1926 src/Tribe/RSVP.php:2371
304
+ msgid "Post draft updated."
305
  msgstr ""
306
 
307
+ #: src/Tickets/Commerce/Gateways/PayPal/Tickets_Form.php:149
308
+ #: src/Tribe/Commerce/PayPal/Frontend/Tickets_Form.php:75
309
  msgid ""
310
+ "Your PayPal %1$s has been received! Check your email for your PayPal %1$s "
311
+ "confirmation."
312
  msgstr ""
313
 
314
+ #. Translators: %s: The missing keys and header information.
315
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Headers.php:92
316
+ msgid "Missing PayPal webhook header: %s"
317
  msgstr ""
318
 
319
  #. Translators: %s: The PayPal payment event.
320
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/Payment_Event_Listener.php:97
321
  msgid "Mismatched event type for webhook event: %s"
322
  msgstr ""
323
 
324
  #. Translators: %s: The PayPal payment event.
325
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/Payment_Event_Listener.php:112
326
  msgid "Missing PayPal payment for webhook event: %s"
327
  msgstr ""
328
 
329
  #. Translators: %s: The PayPal payment ID.
330
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/Payment_Event_Listener.php:128
331
  msgid "Missing order for PayPal payment from webhook: %s"
332
  msgstr ""
333
 
334
  #. Translators: %1$s: The status name; %2$s: The payment information.
335
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/Payment_Event_Listener.php:153
336
  msgid "Change %1$s in PayPal from webhook: %2$s"
337
  msgstr ""
338
 
339
  #. Translators: %s: The error message.
340
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/Payment_Event_Listener.php:230
341
  msgid "PayPal capture request error: %s"
342
  msgstr ""
343
 
344
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/Payment_Event_Listener.php:241
345
  msgid "Unexpected PayPal capture response"
346
  msgstr ""
347
 
348
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Webhook_Checker.php:98
349
  msgid ""
350
  "There was a problem updating your PayPal Payments webhook. Please disconnect "
351
  "your account and reconnect it."
352
  msgstr ""
353
 
354
  #. Translators: %s: The event type.
355
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Webhooks_Route.php:99
356
  msgid "PayPal webhook event type not registered or supported: %s"
357
  msgstr ""
358
 
359
  #. Translators: %s: The event type.
360
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Webhooks_Route.php:111
361
  msgid "Received PayPal webhook event for type: %s"
362
  msgstr ""
363
 
364
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Webhooks_Route.php:120
365
  msgid "Failed PayPal webhook event verification"
366
  msgstr ""
367
 
368
  #. Translators: %s: The event type.
369
+ #: src/Tickets/Commerce/Gateways/PayPal/Webhooks/Webhooks_Route.php:134
370
  msgid "Error processing webhook: %s"
371
  msgstr ""
372
 
373
+ #: src/Tickets/Commerce/Models/Attendee_Model.php:69
374
+ #: src/Tribe/Commerce/PayPal/Main.php:2961 src/Tribe/RSVP.php:2014
375
+ msgid "(deleted)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  msgstr ""
377
 
378
+ #: src/Tickets/Commerce/Module.php:19
379
+ msgid "Tickets Commerce"
 
 
 
380
  msgstr ""
381
 
382
+ #: src/Tickets/Commerce/Order.php:143 src/Tribe/Commerce/PayPal/Main.php:470
383
+ msgid "Orders"
384
  msgstr ""
385
 
386
+ #: src/Tickets/Commerce/Reports/Attendance_Totals.php:84
387
+ #: src/Tribe/Commerce/PayPal/Attendance_Totals.php:77
388
+ #: src/Tribe/RSVP/Attendance_Totals.php:49
389
+ msgctxt "attendee summary"
390
+ msgid "Total %s:"
391
  msgstr ""
392
 
393
+ #: src/Tickets/Commerce/Reports/Attendance_Totals.php:85
394
+ #: src/Tribe/Commerce/PayPal/Attendance_Totals.php:78
395
+ msgctxt "attendee summary"
396
+ msgid "Complete:"
 
 
397
  msgstr ""
398
 
399
+ #: src/Tickets/Commerce/Reports/Attendance_Totals.php:86
400
+ #: src/Tribe/Commerce/PayPal/Attendance_Totals.php:79
401
+ msgctxt "attendee summary"
402
+ msgid "Cancelled:"
403
  msgstr ""
404
 
405
+ #: src/Tickets/Commerce/Reports/Event.php:53
406
+ #: src/Tribe/Commerce/PayPal/Main.php:1726
407
+ msgid "Sales report"
408
  msgstr ""
409
 
410
+ #: src/Tickets/Commerce/Reports/Ticket.php:38
411
+ #: src/Tribe/Commerce/PayPal/Main.php:1752
412
+ msgid "Report"
413
  msgstr ""
414
 
415
+ #: src/Tickets/Commerce/Settings.php:119
416
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/connect-with-paypal.php:70
417
+ msgid "Payments"
 
 
 
418
  msgstr ""
419
 
420
+ #: src/Tickets/Commerce/Settings.php:134 src/Tribe/Admin/Notices.php:214
421
+ #: src/Tribe/Main.php:666 src/admin-views/admin-welcome-message.php:56
422
  #: src/admin-views/tribe-commerce-settings.php:4
423
  msgid "Event Tickets Plus"
424
  msgstr ""
425
 
426
+ #: src/Tickets/Commerce/Settings.php:138
427
  #: src/admin-views/tribe-commerce-settings.php:9
428
  msgid "Check it out!"
429
  msgstr ""
430
 
431
  #. Translators: %1$s: The Event Tickets Plus link, %2$s: The word "ticket" in
432
  #. lowercase, %3$s: The "Check it out!" link.
433
+ #: src/Tickets/Commerce/Settings.php:142
434
  msgctxt "about Tickets Commerce"
435
  msgid ""
436
  "Tickets Commerce is a light implementation of a commerce gateway using "
441
  "%3$s"
442
  msgstr ""
443
 
444
+ #: src/Tickets/Commerce/Settings.php:154
 
 
 
 
 
 
 
 
445
  msgid "Enable Tickets Commerce"
446
  msgstr ""
447
 
448
+ #: src/Tickets/Commerce/Settings.php:199
449
+ msgid "-- No page set --"
450
  msgstr ""
451
 
452
+ #: src/Tickets/Commerce/Settings.php:214
453
  msgid "Enable Test Mode"
454
  msgstr ""
455
 
456
+ #: src/Tickets/Commerce/Settings.php:215
457
  msgid ""
458
  "Enables Test mode for testing payments. Any payments made will be done on "
459
  "\"sandbox\" accounts."
460
  msgstr ""
461
 
462
+ #: src/Tickets/Commerce/Settings.php:221
463
  #: src/admin-views/tribe-commerce-settings.php:136
464
  msgid "Currency Code"
465
  msgstr ""
466
 
467
+ #: src/Tickets/Commerce/Settings.php:222
468
  msgid "The currency that will be used for Tickets Commerce transactions."
469
  msgstr ""
470
 
471
+ #: src/Tickets/Commerce/Settings.php:229
472
  #: src/admin-views/tribe-commerce-settings.php:144
473
  msgid "Stock Handling"
474
  msgstr ""
475
 
476
  #. Translators: %s: The word "ticket" in lowercase.
477
+ #: src/Tickets/Commerce/Settings.php:233
478
  msgctxt "tickets fields settings paypal stock handling"
479
  msgid ""
480
  "When a customer purchases a %s, the payment gateway might flag the order as "
483
  msgstr ""
484
 
485
  #. Translators: %s: The word "ticket" in lowercase.
486
+ #: src/Tickets/Commerce/Settings.php:242
487
  #: src/admin-views/tribe-commerce-settings.php:150
488
  msgid "Decrease available %s stock as soon as a Pending order is created."
489
  msgstr ""
490
 
491
  #. Translators: %s: The word "ticket" in lowercase.
492
+ #: src/Tickets/Commerce/Settings.php:247
493
  msgid ""
494
  "Only decrease available %s stock if an order is confirmed as Completed by "
495
  "the payment gateway."
496
  msgstr ""
497
 
498
+ #: src/Tickets/Commerce/Settings.php:255
499
  msgid "Checkout page"
500
  msgstr ""
501
 
502
  #. Translators: %s: The [shortcode] for the success page.
503
+ #: src/Tickets/Commerce/Settings.php:259
504
  msgid ""
505
  "This is the page where customers go to complete their purchase. Use the %s "
506
  "shortcode to display the checkout experience in the page content."
507
  msgstr ""
508
 
509
+ #: src/Tickets/Commerce/Settings.php:270
510
  #: src/admin-views/tribe-commerce-settings.php:162
511
  msgid "Success page"
512
  msgstr ""
513
 
514
  #. Translators: %s: The [shortcode] for the success page.
515
+ #: src/Tickets/Commerce/Settings.php:274
516
  msgid ""
517
  "After a successful order, users will be redirected to this page. Use the %s "
518
  "shortcode to display the order confirmation to the user in the page content."
519
  msgstr ""
520
 
521
+ #: src/Tickets/Commerce/Settings.php:285
522
  #: src/admin-views/tribe-commerce-settings.php:176
523
  msgid "Confirmation email sender address"
524
  msgstr ""
525
 
526
  #. Translators: %s: The word "tickets" in lowercase.
527
+ #: src/Tickets/Commerce/Settings.php:289
528
  msgctxt "tickets fields settings confirmation email"
529
  msgid ""
530
  "Email address that %s customers will receive confirmation from. Leave empty "
531
  "to use the default WordPress site email address."
532
  msgstr ""
533
 
534
+ #: src/Tickets/Commerce/Settings.php:300
535
  #: src/admin-views/tribe-commerce-settings.php:185
536
  msgid "Confirmation email sender name"
537
  msgstr ""
538
 
539
  #. Translators: %s: The word "ticket" in lowercase.
540
+ #: src/Tickets/Commerce/Settings.php:304
541
  #: src/admin-views/tribe-commerce-settings.php:186
542
  msgctxt "tickets fields settings paypal email sender"
543
  msgid ""
545
  "purchase."
546
  msgstr ""
547
 
548
+ #: src/Tickets/Commerce/Settings.php:315
549
  #: src/admin-views/tribe-commerce-settings.php:194
550
  msgid "Confirmation email subject"
551
  msgstr ""
552
 
553
  #. Translators: %s: The word "ticket" in lowercase.
554
+ #: src/Tickets/Commerce/Settings.php:319
555
  #: src/admin-views/tribe-commerce-settings.php:195
556
  msgctxt "tickets fields settings paypal email subject"
557
  msgid ""
560
  msgstr ""
561
 
562
  #. Translators: %s: The word "tickets" in lowercase.
563
+ #: src/Tickets/Commerce/Settings.php:327
564
  #: src/admin-views/tribe-commerce-settings.php:197
565
  msgctxt "tickets fields settings paypal email subject"
566
  msgid "You have %s!"
567
  msgstr ""
568
 
569
+ #: src/Tickets/Commerce/Status/Action_Required.php:29
570
+ msgid "Action Required"
571
+ msgstr ""
572
+
573
+ #: src/Tickets/Commerce/Status/Approved.php:29
574
+ msgid "Approved"
575
+ msgstr ""
576
+
577
+ #: src/Tickets/Commerce/Status/Completed.php:27
578
+ #: src/Tribe/Commerce/PayPal/Orders/Sales.php:258
579
+ #: src/admin-views/tpp-orders.php:173
580
+ msgid "Completed"
581
+ msgstr ""
582
+
583
+ #: src/Tickets/Commerce/Status/Created.php:30
584
+ msgid "Created"
585
+ msgstr ""
586
+
587
+ #: src/Tickets/Commerce/Status/Denied.php:28
588
+ msgid "Denied"
589
+ msgstr ""
590
+
591
+ #: src/Tickets/Commerce/Status/Not_Completed.php:28
592
+ msgid "Not Completed"
593
+ msgstr ""
594
+
595
+ #: src/Tickets/Commerce/Status/Pending.php:33
596
+ msgid "Pending"
597
+ msgstr ""
598
+
599
+ #: src/Tickets/Commerce/Status/Pending.php:92
600
+ msgid "This order contained an invalid Ticket (ID: %1$d)"
601
+ msgstr ""
602
+
603
+ #: src/Tickets/Commerce/Status/Pending.php:107
604
+ msgid "This order contained a Ticket with an invalid Event (Event ID: %1$d)"
605
+ msgstr ""
606
+
607
+ #: src/Tickets/Commerce/Status/Pending.php:121
608
+ msgid "Cannot purchase zero of \"%1$s\""
609
+ msgstr ""
610
+
611
+ #: src/Tickets/Commerce/Status/Pending.php:138
612
+ msgid "Insufficient stock for \"%1$s\""
613
+ msgstr ""
614
+
615
+ #: src/Tickets/Commerce/Status/Refunded.php:27
616
+ msgid "Refunded"
617
+ msgstr ""
618
+
619
+ #: src/Tickets/Commerce/Status/Reversed.php:27
620
+ msgid "Reversed"
621
+ msgstr ""
622
+
623
+ #: src/Tickets/Commerce/Status/Undefined.php:28
624
+ msgid "Undefined"
625
+ msgstr ""
626
+
627
+ #: src/Tickets/Commerce/Status/Voided.php:29
628
+ msgid "Voided"
629
+ msgstr ""
630
+
631
+ #: src/Tickets/Commerce/Ticket.php:118 src/Tribe/Commerce/PayPal/Main.php:442
632
+ msgid "Tickets"
633
+ msgstr ""
634
+
635
+ #: src/Tickets/Commerce/Ticket.php:120
636
+ msgid "Tickets Commerce Tickets"
637
+ msgstr ""
638
+
639
+ #: src/Tickets/Commerce/Ticket.php:121
640
+ msgid "Tickets Commerce Ticket"
641
+ msgstr ""
642
+
643
+ #: src/Tickets/Commerce/Tickets_View.php:109
644
+ #: src/Tribe/Commerce/PayPal/Tickets_View.php:106
645
+ msgid "This ticket is no longer active."
646
+ msgstr ""
647
+
648
+ #: src/Tickets/Commerce/Tickets_View.php:140
649
+ #: src/Tribe/Commerce/PayPal/Tickets_View.php:137
650
+ msgid "unavailable"
651
+ msgstr ""
652
+
653
  #: src/Tribe/Abstract_Attendance_Totals.php:65
654
  msgctxt "total sold tooltip"
655
  msgid "Includes all ticketed attendees regardless of order status."
660
  msgid "Includes ticketed attendees with orders marked Completed."
661
  msgstr ""
662
 
 
 
 
 
 
 
 
663
  #: src/Tribe/Admin/Manager/Service_Provider.php:56
664
  msgid "Insecure request."
665
  msgstr ""
905
  msgid "Unticketed"
906
  msgstr ""
907
 
908
+ #: src/Tribe/Assets.php:196 src/views/tickets/tpp-success.php:97
909
  msgid "%s header image"
910
  msgstr ""
911
 
912
+ #: src/Tribe/Assets.php:197
913
  msgid "Set as %s header"
914
  msgstr ""
915
 
916
+ #: src/Tribe/Assets.php:253
917
  msgid "Are you sure you want to delete this ticket? This cannot be undone."
918
  msgstr ""
919
 
920
+ #: src/Tribe/Assets.php:259
921
  msgid ""
922
  "It looks like you have modified your shared capacity setting but have not "
923
  "saved or updated the post."
924
  msgstr ""
925
 
926
+ #: src/Tribe/Assets.php:279 src/Tribe/Metabox.php:575
927
  msgid "Please enter in without thousand separators and currency symbols."
928
  msgstr ""
929
 
930
+ #: src/Tribe/Assets.php:472
931
  msgid ""
932
  "There is unsaved attendee information. Are you sure you want to continue?"
933
  msgstr ""
1045
  msgid "Purchaser Email Address"
1046
  msgstr ""
1047
 
1048
+ #: src/Tribe/Attendees.php:549 src/admin-views/tribe-commerce-settings.php:93
1049
+ #: src/admin-views/tribe-commerce-settings.php:105
1050
+ msgid "Yes"
1051
+ msgstr ""
1052
+
1053
  #: src/Tribe/Attendees.php:660
1054
  msgid "attendees"
1055
  msgstr ""
1361
  msgid "U.S. Dollar (USD)"
1362
  msgstr ""
1363
 
1364
+ #. Translators: %1$s: the post/event title, %2$d: the post/event ID.
1365
+ #: src/Tribe/Commerce/Orders_Tabbed_View.php:36
1366
+ #: src/admin-views/attendees.php:34
1367
+ msgctxt "attendees report screen heading"
1368
+ msgid "Attendees for: %1$s [#%2$d]"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1369
  msgstr ""
1370
 
1371
  #: src/Tribe/Commerce/PayPal/Endpoints/Success_Template.php:99
1408
  "%s(s) in an email."
1409
  msgstr ""
1410
 
 
 
 
 
 
 
1411
  #: src/Tribe/Commerce/PayPal/Handler/IPN.php:143
1412
  msgctxt "a PayPal configuration status"
1413
  msgid "complete"
1437
  msgid "Tribe Commerce"
1438
  msgstr ""
1439
 
 
 
 
 
1440
  #: src/Tribe/Commerce/PayPal/Main.php:444
1441
  msgid "Tribe Commerce Tickets"
1442
  msgstr ""
1445
  msgid "Tribe Commerce Ticket"
1446
  msgstr ""
1447
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1448
  #: src/Tribe/Commerce/PayPal/Notices.php:43
1449
  msgid "PayPal is using PDT data but you have not set the PDT identity token"
1450
  msgstr ""
1472
  msgid "Search Orders"
1473
  msgstr ""
1474
 
 
 
 
 
 
1475
  #: src/Tribe/Commerce/PayPal/Orders/Sales.php:262
1476
  msgid "Not completed"
1477
  msgstr ""
1562
  msgid "Sell only available"
1563
  msgstr ""
1564
 
 
 
 
 
 
 
 
 
1565
  #: src/Tribe/Editor/Attendee_Registration.php:127
1566
  msgid "return to the content editor"
1567
  msgstr ""
1723
  msgid "Free"
1724
  msgstr ""
1725
 
1726
+ #: src/Tribe/Main.php:144
1727
  msgctxt "provider_plugin_name"
1728
  msgid "Tickets"
1729
  msgstr ""
1730
 
1731
+ #: src/Tribe/Main.php:430
1732
  msgid ""
1733
  "When The Events Calendar and Event Tickets are both activated, The Events "
1734
  "Calendar must be running version %1$s or greater. Please %2$supdate now.%3$s"
1735
  msgstr ""
1736
 
1737
+ #: src/Tribe/Main.php:493
1738
  msgid ""
1739
  "Sorry, Event Tickets requires WordPress %s or higher. Please upgrade your "
1740
  "WordPress install."
1741
  msgstr ""
1742
 
1743
+ #: src/Tribe/Main.php:497
1744
  msgid ""
1745
  "Sorry, Event Tickets requires PHP %s or higher. Talk to your Web host about "
1746
  "moving you to a newer version of PHP."
1747
  msgstr ""
1748
 
1749
+ #: src/Tribe/Main.php:621
1750
  msgid "Support for Event Tickets"
1751
  msgstr ""
1752
 
1753
+ #: src/Tribe/Main.php:623
1754
  msgid "Settings overview"
1755
  msgstr ""
1756
 
1757
+ #: src/Tribe/Main.php:624
1758
  msgid "Features overview"
1759
  msgstr ""
1760
 
1761
+ #: src/Tribe/Main.php:625
1762
  msgid "Troubleshooting common problems"
1763
  msgstr ""
1764
 
1765
+ #: src/Tribe/Main.php:626
1766
  msgid "Customizing Event Tickets"
1767
  msgstr ""
1768
 
1769
+ #: src/Tribe/Main.php:643
1770
  msgid "New User Primer"
1771
  msgstr ""
1772
 
1773
+ #: src/Tribe/Main.php:645
1774
  msgctxt "help feature box section"
1775
  msgid ""
1776
  "We are committed to helping you sell %1$s for your event. Check out our "
1777
  "handy %2$s to get started."
1778
  msgstr ""
1779
 
1780
+ #: src/Tribe/Main.php:662
1781
  msgid "open-source forum on WordPress.org"
1782
  msgstr ""
1783
 
1784
+ #: src/Tribe/Main.php:663
1785
  msgid ""
1786
  "If you have tried the above steps and are still having trouble, you can post "
1787
  "a new thread to our %s. Our support staff monitors these forums once a week "
1788
  "and would be happy to assist you there."
1789
  msgstr ""
1790
 
1791
+ #: src/Tribe/Main.php:665
1792
  msgid "premium support on our website"
1793
  msgstr ""
1794
 
1795
+ #: src/Tribe/Main.php:667
1796
  msgid ""
1797
  "Looking for more immediate support? We offer %1$s with the purchase of any "
1798
  "of our premium plugins (like %2$s). Pick up a license and you can post there "
1799
  "directly and expect a response within 24-48 hours during weekdays."
1800
  msgstr ""
1801
 
1802
+ #: src/Tribe/Main.php:669 src/Tribe/Main.php:674
1803
  msgid "post a thread"
1804
  msgstr ""
1805
 
1806
+ #: src/Tribe/Main.php:670
1807
  msgid ""
1808
  "Already have Event Tickets Plus? You can %s in our premium support forums. "
1809
  "Our support team monitors the forums and will respond to your thread within "
1810
  "24-48 hours (during the week)."
1811
  msgstr ""
1812
 
1813
+ #: src/Tribe/Main.php:675
1814
  msgid ""
1815
  "If you have a valid license for one of our paid plugins, you can %s in our "
1816
  "premium support forums. Our support team monitors the forums and will "
1817
  "respond to your thread within 24-48 hours (during the week)."
1818
  msgstr ""
1819
 
1820
+ #: src/Tribe/Main.php:697
1821
  msgid "Event Tickets - Legacy"
1822
  msgstr ""
1823
 
1824
+ #: src/Tribe/Main.php:833
1825
  msgid "Welcome to Event Tickets!"
1826
  msgstr ""
1827
 
1828
+ #: src/Tribe/Main.php:986
1829
  msgid "Buy"
1830
  msgstr ""
1831
 
1832
+ #: src/Tribe/Main.php:1065
1833
  msgid ""
1834
  "When Event Tickets and Event Tickets Plus are both activated, Event Tickets "
1835
  "Plus must be running version %1$s or greater. Please %2$smanually update now"
2432
  msgid "List of meta for each ticket to be saved for Attendee Registration"
2433
  msgstr ""
2434
 
 
 
 
 
 
 
 
 
 
 
 
 
2435
  #: src/Tribe/REST/V1/Endpoints/Single_Attendee.php:19
2436
  msgid "Returns the data of the attendee with the specified post ID"
2437
  msgstr ""
3083
  msgstr ""
3084
 
3085
  #: src/admin-views/attendees-email.php:36
3086
+ #: src/views/modal/registration-js.php:129
3087
  msgid "or"
3088
  msgstr ""
3089
 
3117
  msgid "Search attendees"
3118
  msgstr ""
3119
 
3120
+ #: src/admin-views/commerce/gateways/paypal/signup-link.php:25
3121
+ msgid "Connect Automatically with <i>PayPal</i>"
3122
+ msgstr ""
3123
+
3124
+ #: src/admin-views/commerce/metabox/capacity.php:16
3125
+ #: src/admin-views/editor/list-row.php:99
3126
+ #: src/admin-views/rsvp-metabox-capacity.php:10
3127
+ #: src/admin-views/tpp-metabox-capacity.php:16
3128
+ msgid "Capacity:"
3129
+ msgstr ""
3130
+
3131
+ #: src/admin-views/commerce/metabox/capacity.php:25
3132
+ #: src/admin-views/rsvp-metabox-capacity.php:19
3133
+ #: src/admin-views/tpp-metabox-capacity.php:25
3134
+ msgid "Leave blank for unlimited"
3135
+ msgstr ""
3136
+
3137
+ #: src/admin-views/commerce/metabox/sku.php:23
3138
+ #: src/admin-views/tpp-metabox-sku.php:20
3139
+ msgid "SKU:"
3140
+ msgstr ""
3141
+
3142
+ #: src/admin-views/commerce/metabox/sku.php:36
3143
+ #: src/admin-views/tpp-metabox-sku.php:33
3144
+ msgid "A unique identifying code for each %s type you're selling"
3145
+ msgstr ""
3146
+
3147
  #: src/admin-views/editor/button-view-orders.php:46
3148
  msgid "View Orders"
3149
  msgstr ""
3229
  msgid "%s Type:"
3230
  msgstr ""
3231
 
 
 
 
 
 
 
3232
  #: src/admin-views/editor/list-row.php:104
3233
  msgid "Available:"
3234
  msgstr ""
3625
  "statuses:"
3626
  msgstr ""
3627
 
3628
+ #: src/admin-views/payments/tickets-commerce.php:25
3629
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/connect-with-paypal.php:62
3630
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:27
3631
+ msgid "Disconnect"
3632
+ msgstr ""
3633
+
3634
+ #: src/admin-views/payments/tickets-commerce.php:26
3635
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:28
3636
+ msgid "Refresh Access Token"
3637
+ msgstr ""
3638
+
3639
+ #: src/admin-views/payments/tickets-commerce.php:27
3640
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:29
3641
+ msgid "Refresh User Info"
3642
+ msgstr ""
3643
+
3644
+ #: src/admin-views/payments/tickets-commerce.php:28
3645
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:31
3646
+ msgid "PayPal Status: Connected"
3647
+ msgstr ""
3648
+
3649
+ #: src/admin-views/payments/tickets-commerce.php:29
3650
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:32
3651
+ msgid "Connected as: %1$s"
3652
+ msgstr ""
3653
+
3654
+ #: src/admin-views/payments/tickets-commerce.php:32
3655
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:35
3656
+ msgid "Accept online payments with PayPal!"
3657
+ msgstr ""
3658
+
3659
+ #: src/admin-views/payments/tickets-commerce.php:33
3660
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:37
3661
+ msgid ""
3662
+ "Start selling tickets to your events today with PayPal. Attendees can "
3663
+ "purchase tickets directly on your site using debt or credit cards with no "
3664
+ "additional fees."
3665
+ msgstr ""
3666
+
3667
+ #: src/admin-views/payments/tickets-commerce.php:41
3668
+ msgid "Credit and debit card payments"
3669
+ msgstr ""
3670
+
3671
+ #: src/admin-views/payments/tickets-commerce.php:42
3672
+ msgid "Easy, no API key connection"
3673
+ msgstr ""
3674
+
3675
+ #: src/admin-views/payments/tickets-commerce.php:43
3676
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:52
3677
+ msgid "Accept payments from around the world"
3678
+ msgstr ""
3679
+
3680
+ #: src/admin-views/payments/tickets-commerce.php:44
3681
+ msgid "Support 3D Secure Payments"
3682
+ msgstr ""
3683
+
3684
+ #: src/admin-views/payments/tickets-commerce.php:57
3685
+ msgid "Enable TicketsCommerce"
3686
+ msgstr ""
3687
+
3688
+ #: src/admin-views/payments/tickets-commerce.php:61
3689
+ msgid ""
3690
+ "TicketsCommerce allows you to accept payments for tickets with Event Tickets "
3691
+ "and Event Tickets Plus. Configure payments through PayPal, allowing users to "
3692
+ "pay with credit card or their PayPal account. Learn More about payment "
3693
+ "processing with TicketsCommerce."
3694
+ msgstr ""
3695
+
3696
  #: src/admin-views/privacy.php:16
3697
  msgid "Hello,"
3698
  msgstr ""
3828
  "to these external services. These services may be located abroad."
3829
  msgstr ""
3830
 
 
 
 
 
 
3831
  #: src/admin-views/rsvp-metabox-not-going.php:17
3832
  msgid "Can't Go:"
3833
  msgstr ""
3921
  msgid "Connected for payments as"
3922
  msgstr ""
3923
 
 
 
 
 
3924
  #: src/admin-views/settings/tickets-commerce/paypal-commerce/connect-with-paypal.php:68
3925
  msgid "APIs Connected:"
3926
  msgstr ""
3927
 
 
 
 
 
3928
  #: src/admin-views/settings/tickets-commerce/paypal-commerce/connect-with-paypal.php:71
3929
  msgid "Refunds"
3930
  msgstr ""
3931
 
3932
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:43
 
 
 
 
 
 
 
 
 
 
3933
  msgid "PayPal Logo Image"
3934
  msgstr ""
3935
 
3936
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:46
3937
  msgid "Credit and Debit Card payments"
3938
  msgstr ""
3939
 
3940
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:49
3941
  msgid "Easy no-API key connection"
3942
  msgstr ""
3943
 
3944
+ #: src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php:55
 
 
 
 
3945
  msgid "Supports 3D Secure payments"
3946
  msgstr ""
3947
 
3958
  msgid "Click to hide history"
3959
  msgstr ""
3960
 
 
 
 
 
 
 
 
 
3961
  #: src/admin-views/tpp-orders.php:32
3962
  msgid "Orders Report"
3963
  msgstr ""
3990
  "%3$s"
3991
  msgstr ""
3992
 
3993
+ #: src/admin-views/tribe-commerce-settings.php:40
3994
+ msgid "these instructions"
3995
+ msgstr ""
3996
+
3997
  #: src/admin-views/tribe-commerce-settings.php:41
3998
  msgctxt "tickets fields settings PayPal setup"
3999
  msgid ""
4002
  "set up, follow %2$s"
4003
  msgstr ""
4004
 
4005
+ #: src/admin-views/tribe-commerce-settings.php:45
4006
+ msgid ""
4007
+ "Have you entered this site's address in the Notification URL field in IPN "
4008
+ "Settings?"
4009
+ msgstr ""
4010
+
4011
+ #: src/admin-views/tribe-commerce-settings.php:47
4012
+ msgid "Your site address is: %s"
4013
+ msgstr ""
4014
+
4015
  #: src/admin-views/tribe-commerce-settings.php:55
4016
  msgid "Tribe Commerce"
4017
  msgstr ""
4028
  msgid "Configure PayPal:"
4029
  msgstr ""
4030
 
4031
+ #: src/admin-views/tribe-commerce-settings.php:83
4032
+ msgid "PayPal email to receive payments:"
4033
+ msgstr ""
4034
+
4035
+ #: src/admin-views/tribe-commerce-settings.php:91
4036
+ msgid ""
4037
+ "Have you enabled instant payment notifications (IPN) in your PayPal "
4038
+ "account's Selling Tools?"
4039
+ msgstr ""
4040
+
4041
+ #: src/admin-views/tribe-commerce-settings.php:94
4042
+ #: src/admin-views/tribe-commerce-settings.php:106
4043
+ msgid "No"
4044
+ msgstr ""
4045
+
4046
+ #: src/admin-views/tribe-commerce-settings.php:117
4047
+ msgid "PayPal configuration status:"
4048
+ msgstr ""
4049
+
4050
+ #: src/admin-views/tribe-commerce-settings.php:120
4051
+ msgid ""
4052
+ "For help creating and configuring your account, call PayPal at "
4053
+ "1-844-720-4038 (USA)"
4054
+ msgstr ""
4055
+
4056
  #: src/admin-views/tribe-commerce-settings.php:129
4057
  msgid "PayPal Sandbox"
4058
  msgstr ""
4092
  "empty to use the default WordPress site email address."
4093
  msgstr ""
4094
 
4095
+ #: src/admin-views/tribe-commerce-settings.php:209
4096
+ msgid ""
4097
+ "You can see and manage your IPN Notifications history from the IPN "
4098
+ "Notifications settings area (%s)."
4099
+ msgstr ""
4100
+
4101
+ #: src/admin-views/tribe-commerce-settings.php:219
4102
+ msgid "IPN Notify URL"
4103
+ msgstr ""
4104
+
4105
+ #: src/admin-views/tribe-commerce-settings.php:221
4106
+ msgid ""
4107
+ "Override the default IPN notify URL with this value. This value must be the "
4108
+ "same set in PayPal IPN Notifications settings area (%s)."
4109
+ msgstr ""
4110
+
4111
  #. Translators: %1$s: dynamic "RSVP" text.
4112
  #: src/admin-views/tribe-options-display.php:28
4113
  msgctxt "title of settings section"
4676
  msgid "One Moment..."
4677
  msgstr ""
4678
 
4679
+ #: src/views/modal/registration-js.php:43 src/views/modal/registration.php:24
4680
  msgid "Attendee Details"
4681
  msgstr ""
4682
 
4683
+ #: src/views/modal/registration-js.php:53
4684
  #: src/views/registration-js/content.php:100
4685
  msgctxt ""
4686
  "Note about missing required fields, %s is the html-wrapped number of tickets."
4687
  msgid "You have %s ticket(s) with a field that requires information."
4688
  msgstr ""
4689
 
4690
+ #: src/views/modal/registration-js.php:100
4691
  #: src/views/registration-js/content.php:196
4692
  msgctxt ""
4693
  "Note that there are more tickets in the cart, %s is the html-wrapped number."
4696
  "information."
4697
  msgstr ""
4698
 
4699
+ #: src/views/modal/registration-js.php:119 src/views/modal/registration.php:36
4700
  #: src/views/registration/content.php:111
4701
  msgid "Save and Checkout"
4702
  msgstr ""
4703
 
4704
+ #: src/views/modal/registration-js.php:127
4705
  msgid "Save and View Cart"
4706
  msgstr ""
4707
 
4708
+ #: src/views/modal/registration-js.php:135
4709
  msgid "Checkout Now"
4710
  msgstr ""
4711
 
4712
+ #: src/views/modal/registration.php:38 src/views/registration/content.php:113
4713
  msgid "Save Attendee Info"
4714
  msgstr ""
4715
 
5001
  msgid "Buy now"
5002
  msgstr ""
5003
 
5004
+ #. Translators: %1$s: Opening span for "Quantity:" string; %2$s: Closing span
5005
+ #. for "Quantity:" string; %3$s: Opening span for the quantity; %4$s: The
5006
+ #. quantity; %5$s: Closing span for the quantity.
5007
+ #: src/views/v2/commerce/checkout/cart/footer/quantity.php:29
5008
+ msgid "%1$sQuantity: %2$s%3$s%4$s%5$s"
5009
+ msgstr ""
5010
+
5011
+ #. Translators: %1$s: Opening span for "Total:" string; %2$s: Closing span for
5012
+ #. "Total:" string; %3$s: Opening span for the total value; %4$s: The total
5013
+ #. value; %5$s: Closing span for the total value.
5014
+ #: src/views/v2/commerce/checkout/cart/footer/total.php:29
5015
+ msgid "%1$sTotal: %2$s%3$s%4$s%5$s"
5016
+ msgstr ""
5017
+
5018
+ #: src/views/v2/commerce/checkout/cart/item/details/toggle.php:36
5019
+ msgid "Open the ticket description in checkout."
5020
+ msgstr ""
5021
+
5022
+ #: src/views/v2/commerce/checkout/cart/item/details/toggle.php:39
5023
+ msgctxt "Opens the ticket description"
5024
+ msgid "More info"
5025
+ msgstr ""
5026
+
5027
+ #: src/views/v2/commerce/checkout/cart/item/details/toggle.php:48
5028
+ msgid "Close the ticket description in checkout."
5029
+ msgstr ""
5030
+
5031
+ #: src/views/v2/commerce/checkout/cart/item/details/toggle.php:51
5032
+ msgctxt "Closes the ticket description"
5033
+ msgid "Less info"
5034
+ msgstr ""
5035
+
5036
+ #: src/views/v2/commerce/checkout/header.php:31
5037
+ msgid "Purchase Tickets"
5038
+ msgstr ""
5039
+
5040
+ #: src/views/v2/commerce/checkout/header.php:38
5041
+ msgid "modify attendees"
5042
+ msgstr ""
5043
+
5044
+ #: src/views/v2/commerce/checkout/header.php:42
5045
+ msgid "back to event"
5046
+ msgstr ""
5047
+
5048
+ #: src/views/v2/commerce/checkout/must-login/login.php:32
5049
+ msgid "Log in to complete your purchase"
5050
+ msgstr ""
5051
+
5052
+ #: src/views/v2/commerce/checkout/must-login/registration.php:37
5053
+ msgctxt "or <- create a new account"
5054
+ msgid "or "
5055
+ msgstr ""
5056
+
5057
+ #: src/views/v2/commerce/checkout/must-login/registration.php:39
5058
+ msgid "create a new account"
5059
+ msgstr ""
5060
+
5061
  #: src/views/v2/rsvp/actions/full.php:22
5062
  msgid "RSVP Closed"
5063
  msgstr ""
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === Event Tickets ===
2
 
3
- Contributors: theeventscalendar, brianjessee, camwynsp, paulkim, sc0ttkclark, aguseo, bordoni, borkweb, GeoffBel, geoffgraham, jentheo, leahkoerper, lucatume, neillmcshea, patriciahillebrandt, vicskf, zbtirrell, juanfra
4
  Tags: tickets, registration, The Events Calendar, RSVP, ticket sales, attendee management
5
  Requires at least: 4.9.18
6
  Tested up to: 5.8.0
7
- Stable tag: 5.1.8
8
  Requires PHP: 5.6
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -178,6 +178,13 @@ Check out our extensive [knowledgebase](https://evnt.is/18wm) for articles on us
178
 
179
  == Changelog ==
180
 
 
 
 
 
 
 
 
181
  = [5.1.8] 2021-08-24 =
182
 
183
  * Tweak - Add new event repository schema for finding all events with RSVPs or Tickets.
1
  === Event Tickets ===
2
 
3
+ Contributors: theeventscalendar, brianjessee, camwynsp, paulkim, aguseo, bordoni, borkweb, GeoffBel, geoffgraham, jentheo, leahkoerper, lucatume, neillmcshea, vicskf, zbtirrell, juanfra
4
  Tags: tickets, registration, The Events Calendar, RSVP, ticket sales, attendee management
5
  Requires at least: 4.9.18
6
  Tested up to: 5.8.0
7
+ Stable tag: 5.1.9
8
  Requires PHP: 5.6
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
178
 
179
  == Changelog ==
180
 
181
+ = [5.1.9] 2021-08-31 =
182
+
183
+ * Fix - Fixed cart calculation inconsistency with WooCommerce when the "Number of decimals" setting was set to `0`. [ETP-324]
184
+ * Fix - Removed RSVP V2 preview templates and functionality. [ET-1162]
185
+ * Fix - Updated deprecated hook `block_categories` to use `block_categories_all`. [ET-1156]
186
+ * Language - 37 new strings added, 162 updated, 6 fuzzied, and 20 obsoleted
187
+
188
  = [5.1.8] 2021-08-24 =
189
 
190
  * Tweak - Add new event repository schema for finding all events with RSVPs or Tickets.
src/Tickets/Commerce.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets;
4
+
5
+ /**
6
+ * Class Commerce
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets
11
+ */
12
+ class Commerce {
13
+ /**
14
+ * Internal Commerce Provider Identifier for Tickets Commerce.
15
+ *
16
+ * @since 5.1.9
17
+ *
18
+ * @var string
19
+ */
20
+ const PROVIDER = 'tickets-commerce';
21
+
22
+ /**
23
+ * Internal abbreviation for Ticket Commerce.
24
+ *
25
+ * @since 5.1.9
26
+ *
27
+ * @var string
28
+ */
29
+ const ABBR = 'tc';
30
+ }
src/Tickets/Commerce/Assets.php CHANGED
@@ -26,13 +26,50 @@ class Assets extends tad_DI52_ServiceProvider {
26
  * @since 5.1.6
27
  */
28
  public function register() {
 
 
 
29
  tribe_asset(
30
- \Tribe__Tickets__Main::instance(),
31
  'tribe-tickets-admin-commerce-settings',
32
  'admin/tickets-commerce-settings.js',
33
  [ 'jquery' ],
34
  'admin_enqueue_scripts'
35
  );
36
- }
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  }
26
  * @since 5.1.6
27
  */
28
  public function register() {
29
+ /** @var Tribe__Tickets__Main $tickets_main */
30
+ $tickets_main = tribe( 'tickets.main' );
31
+
32
  tribe_asset(
33
+ $tickets_main,
34
  'tribe-tickets-admin-commerce-settings',
35
  'admin/tickets-commerce-settings.js',
36
  [ 'jquery' ],
37
  'admin_enqueue_scripts'
38
  );
 
39
 
40
+ // Tickets Commerce main styles.
41
+ tribe_asset(
42
+ $tickets_main,
43
+ 'tribe-tickets-commerce-style',
44
+ 'tickets-commerce.css',
45
+ [
46
+ 'tribe-common-skeleton-style',
47
+ 'tribe-common-full-style',
48
+ ],
49
+ null,
50
+ [
51
+ 'groups' => [
52
+ 'tribe-tickets-commerce',
53
+ 'tribe-tickets-commerce-checkout',
54
+ ],
55
+ ]
56
+ );
57
+
58
+ tribe_asset(
59
+ $tickets_main,
60
+ 'tribe-tickets-commerce-js',
61
+ 'v2/tickets-commerce.js',
62
+ [
63
+ 'jquery',
64
+ 'tribe-common',
65
+ ],
66
+ null,
67
+ [
68
+ 'groups' => [
69
+ 'tribe-tickets-commerce',
70
+ 'tribe-tickets-commerce-checkout',
71
+ ],
72
+ ]
73
+ );
74
+ }
75
  }
src/Tickets/Commerce/Attendee.php ADDED
@@ -0,0 +1,471 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce;
4
+
5
+ use TEC\Tickets\Commerce;
6
+
7
+ /**
8
+ * Class Attendee
9
+ *
10
+ * @since 5.1.9
11
+ *
12
+ * @package TEC\Tickets\Commerce
13
+ */
14
+ class Attendee {
15
+ /**
16
+ * Tickets Commerce Attendee Post Type slug.
17
+ *
18
+ * @since 5.1.9
19
+ *
20
+ * @var string
21
+ */
22
+ const POSTTYPE = 'tec_tc_attendee';
23
+
24
+ /**
25
+ * Which meta holds the Relation ship between an attendee and which user it's registered to.
26
+ *
27
+ * @since 5.1.9
28
+ *
29
+ * @var string
30
+ */
31
+ public static $user_relation_meta_key = '_tribe_tickets_attendee_user_id';
32
+
33
+ /**
34
+ * Which meta holds the Relation ship between an attendee and which event it's registered to.
35
+ *
36
+ * @since 5.1.9
37
+ *
38
+ * @var string
39
+ */
40
+ public static $event_relation_meta_key = '_tec_tickets_commerce_event';
41
+
42
+ /**
43
+ * Which meta holds the Relation ship between an attendee and which ticket it was created from.
44
+ *
45
+ * @since 5.1.9
46
+ *
47
+ * @var string
48
+ */
49
+ public static $ticket_relation_meta_key = '_tec_tickets_commerce_ticket';
50
+
51
+ /**
52
+ * Which meta holds the Relation ship between an attendee and which order it belongs to.
53
+ *
54
+ * @since 5.1.9
55
+ *
56
+ * @var string
57
+ */
58
+ public static $order_relation_meta_key = '_tec_tickets_commerce_order';
59
+
60
+ /**
61
+ * Which meta holds the purchaser name for an attendee.
62
+ *
63
+ * @since 5.1.9
64
+ *
65
+ * @var string
66
+ */
67
+ public static $purchaser_name_meta_key = '_tec_tickets_commerce_purchaser_name';
68
+
69
+ /**
70
+ * Which meta holds the purchaser email for an attendee.
71
+ *
72
+ * @since 5.1.9
73
+ *
74
+ * @var string
75
+ */
76
+ public static $purchaser_email_meta_key = '_tec_tickets_commerce_purchaser_email';
77
+
78
+ /**
79
+ * Which meta holds the security code for an attendee.
80
+ *
81
+ * @since 5.1.9
82
+ *
83
+ * @var string
84
+ */
85
+ public static $security_code_meta_key = '_tec_tickets_commerce_security_code';
86
+
87
+ /**
88
+ * Which meta holds the status value for an attendee.
89
+ *
90
+ * @since 5.1.9
91
+ *
92
+ * @var string
93
+ */
94
+ public static $status_meta_key = '_tec_tickets_commerce_status';
95
+
96
+ /**
97
+ * Which meta holds the optout value for an attendee.
98
+ *
99
+ * @since 5.1.9
100
+ *
101
+ * @var string
102
+ */
103
+ public static $optout_meta_key = '_tec_tickets_commerce_optout';
104
+
105
+ /**
106
+ * Which meta holds the checked in status for an attendee.
107
+ *
108
+ * @since 5.1.9
109
+ *
110
+ * @var string
111
+ */
112
+ public static $checked_in_meta_key = '_tec_tickets_commerce_checked_in';
113
+
114
+ /**
115
+ * Which meta holds the checked in status for an attendee.
116
+ *
117
+ * @since 5.1.9
118
+ *
119
+ * @var string
120
+ */
121
+ public static $deleted_ticket_meta_key = '_tribe_deleted_product_name';
122
+
123
+ /**
124
+ * Indicates if a ticket for this attendee was sent out via email.
125
+ *
126
+ * @since 5.1.9
127
+ *
128
+ * @var string
129
+ */
130
+ public static $ticket_sent_meta_key = '_tec_tickets_commerce_attendee_ticket_sent';
131
+
132
+ /**
133
+ * Meta key holding an indication if this attendee was subscribed.
134
+ *
135
+ * @since 5.1.9
136
+ *
137
+ * @var string
138
+ */
139
+ public static $subscribed_meta_key = '_tribe_tickets_subscribed';
140
+
141
+ /**
142
+ * Meta key holding the first name for the attendee. (not purchaser)
143
+ *
144
+ * @since 5.1.9
145
+ *
146
+ * @var string
147
+ */
148
+ public static $first_name_meta_key = '_tec_tickets_commerce_first_name';
149
+
150
+ /**
151
+ * Meta key holding the last name for the attendee. (not purchaser)
152
+ *
153
+ * @since 5.1.9
154
+ *
155
+ * @var string
156
+ */
157
+ public static $last_name_meta_key = '_tec_tickets_commerce_last_name';
158
+
159
+ /**
160
+ * Meta key holding the email for the attendee. (not purchaser)
161
+ *
162
+ * @since 5.1.9
163
+ *
164
+ * @var string
165
+ */
166
+ public static $email_meta_key = '_tec_tickets_commerce_email';
167
+
168
+
169
+ /**
170
+ * Register this Class post type into WP.
171
+ *
172
+ * @since 5.1.9
173
+ */
174
+ public function register_post_type() {
175
+ $post_type_args = [
176
+ 'label' => __( 'Attendees', 'event-tickets' ),
177
+ 'public' => false,
178
+ 'show_ui' => false,
179
+ 'show_in_menu' => false,
180
+ 'query_var' => false,
181
+ 'rewrite' => false,
182
+ 'capability_type' => 'post',
183
+ 'has_archive' => false,
184
+ 'hierarchical' => false,
185
+ ];
186
+
187
+ /**
188
+ * Filter the arguments that craft the attendee post type.
189
+ *
190
+ * @see register_post_type
191
+ *
192
+ * @since 5.1.9
193
+ *
194
+ * @param array $post_type_args Post type arguments, passed to register_post_type()
195
+ */
196
+ $post_type_args = apply_filters( 'tec_tickets_commerce_attendee_post_type_args', $post_type_args );
197
+
198
+ register_post_type( static::POSTTYPE, $post_type_args );
199
+ }
200
+
201
+ /**
202
+ * If the post that was moved to the trash was an PayPal Ticket attendee post type, redirect to
203
+ * the Attendees Report rather than the PayPal Ticket attendees post list (because that's kind of
204
+ * confusing)
205
+ *
206
+ * @since 5.1.9
207
+ *
208
+ * @param int $post_id WP_Post ID
209
+ */
210
+ public function maybe_redirect_to_attendees_report( $post_id ) {
211
+ $post = get_post( $post_id );
212
+
213
+ if ( static::POSTTYPE !== $post->post_type ) {
214
+ return;
215
+ }
216
+
217
+ $args = array(
218
+ 'post_type' => 'tribe_events',
219
+ 'page' => \Tribe__Tickets__Tickets_Handler::$attendees_slug,
220
+ 'event_id' => get_post_meta( $post_id, static::$event_relation_meta_key, true ),
221
+ );
222
+
223
+ $url = add_query_arg( $args, admin_url( 'edit.php' ) );
224
+ $url = esc_url_raw( $url );
225
+
226
+ wp_redirect( $url );
227
+ tribe_exit();
228
+ }
229
+
230
+ /**
231
+ * Update the Ticket Commerce values for this user.
232
+ *
233
+ * Note that, within this method, $order_id refers to the attendee or ticket ID
234
+ * (it does not refer to an "order" in the sense of a transaction that may include
235
+ * multiple tickets, as is the case in some other methods for instance).
236
+ *
237
+ * @todo Adjust to the Ticket Commerce data.
238
+ *
239
+ * @since 5.1.9
240
+ *
241
+ * @param array $attendee_data Information that we are trying to save.
242
+ * @param int $attendee_id The attendee ID.
243
+ * @param int $post_id The event/post ID.
244
+ */
245
+ public function update_attendee_data( $attendee_data, $attendee_id, $post_id ) {
246
+ // Bail if the user is not logged in.
247
+ if ( ! is_user_logged_in() ) {
248
+ return;
249
+ }
250
+
251
+ $user_id = get_current_user_id();
252
+
253
+ $ticket_attendees = $this->tickets_view->get_post_ticket_attendees( $post_id, $user_id );
254
+ $ticket_attendee_ids = wp_list_pluck( $ticket_attendees, 'attendee_id' );
255
+
256
+ // This makes sure we don't save attendees for attendees that are not from this current user and event.
257
+ if ( ! in_array( $attendee_id, $ticket_attendee_ids, true ) ) {
258
+ return;
259
+ }
260
+
261
+ $attendee_data_to_save = [];
262
+
263
+ // Only update full name if set.
264
+ if ( ! empty( $attendee_data['full_name'] ) ) {
265
+ $attendee_data_to_save['full_name'] = sanitize_text_field( $attendee_data['full_name'] );
266
+ }
267
+
268
+ // Only update email if set.
269
+ if ( ! empty( $attendee_data['email'] ) ) {
270
+ $attendee_data['email'] = sanitize_email( $attendee_data['email'] );
271
+
272
+ // Only update email if valid.
273
+ if ( is_email( $attendee_data['email'] ) ) {
274
+ $attendee_data_to_save['email'] = $attendee_data['email'];
275
+ }
276
+ }
277
+
278
+ // Only update optout if set.
279
+ if ( isset( $attendee_data['optout'] ) ) {
280
+ $attendee_data_to_save['optout'] = (int) tribe_is_truthy( $attendee_data['optout'] );
281
+ }
282
+
283
+ // Only update if there's data to set.
284
+ if ( empty( $attendee_data_to_save ) ) {
285
+ return;
286
+ }
287
+
288
+ tribe( Module::class )->update_attendee( $attendee_id, $attendee_data_to_save );
289
+ }
290
+
291
+ /**
292
+ * Triggers the sending of ticket emails after PayPal Ticket information is updated.
293
+ *
294
+ * This is useful if a user initially suggests they will not be attending
295
+ * an event (in which case we do not send tickets out) but where they
296
+ * incrementally amend the status of one or more of those tickets to
297
+ * attending, at which point we should send tickets out for any of those
298
+ * newly attending persons.
299
+ *
300
+ * @since 5.1.9
301
+ *
302
+ * @param int $event_id
303
+ */
304
+ public function maybe_send_tickets_after_status_change( $event_id ) {
305
+ $transaction_ids = array();
306
+
307
+ foreach ( tribe( Module::class )->get_event_attendees( $event_id ) as $attendee ) {
308
+ $transaction = get_post_meta( $attendee['attendee_id'], static::$order_relation_meta_key, true );
309
+
310
+ if ( ! empty( $transaction ) ) {
311
+ $transaction_ids[ $transaction ] = $transaction;
312
+ }
313
+ }
314
+
315
+ foreach ( $transaction_ids as $transaction ) {
316
+ // This method takes care of intelligently sending out emails only when
317
+ // required, for attendees that have not yet received their tickets
318
+ tribe( Module::class )->send_tickets_email( $transaction, $event_id );
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Add our class to the list of classes for the attendee registration form
324
+ *
325
+ * @since TBd
326
+ *
327
+ * @param array $classes existing array of classes
328
+ *
329
+ * @return array $classes with our class added
330
+ */
331
+ public function registration_form_class( $classes ) {
332
+ $classes[ static::POSTTYPE ] = \TEC\Tickets\Commerce::ABBR;
333
+
334
+ return $classes;
335
+ }
336
+
337
+ /**
338
+ * Filter the provider object to return this class if tickets are for this provider.
339
+ *
340
+ * @since 5.1.9
341
+ *
342
+ * @param object $provider_obj
343
+ * @param string $provider
344
+ *
345
+ * @return object
346
+ */
347
+ public function registration_cart_provider( $provider_obj, $provider ) {
348
+ $options = [
349
+ \TEC\Tickets\Commerce::ABBR,
350
+ static::POSTTYPE,
351
+ \TEC\Tickets\Commerce::PROVIDER,
352
+ static::class,
353
+ ];
354
+
355
+ if ( in_array( $provider, $options, true ) ) {
356
+ return tribe( Module::class );
357
+ }
358
+
359
+ return $provider_obj;
360
+ }
361
+
362
+ /**
363
+ * Whether a specific attendee is valid toward inventory decrease or not.
364
+ *
365
+ * By default only attendees generated as part of a Completed order will count toward
366
+ * an inventory decrease but, if the option to reserve stock for Pending Orders is activated,
367
+ * then those attendees generated as part of a Pending Order will, for a limited time after the
368
+ * order creation, cause the inventory to be decreased.
369
+ *
370
+ * @todo TribeCommerceLegacy: Move this method a Flag action.
371
+ *
372
+ * @since 5.1.9
373
+ *
374
+ * @param array $attendee
375
+ *
376
+ * @return bool
377
+ */
378
+ public function decreases_inventory( $attendee ) {
379
+ $order_status = \Tribe__Utils__Array::get( $attendee, 'order_status', 'undefined' );
380
+ $order_id = \Tribe__Utils__Array::get( $attendee, 'order_id', false );
381
+ $attendee_id = \Tribe__Utils__Array::get( $attendee, 'attendee_id', false );
382
+
383
+ /**
384
+ * Whether the pending Order stock reserve logic should be ignored completely or not.
385
+ *
386
+ * If set to `true` then the behaviour chosen in the Settings will apply, if `false`
387
+ * only Completed tickets will count to decrease the inventory. This is useful when
388
+ *
389
+ * @todo TribeCommerceLegacy: Move this method a Flag action.
390
+ *
391
+ * @since 5.1.9
392
+ *
393
+ * @param bool $ignore_pending
394
+ * @param array $attendee An array of data defining the current Attendee
395
+ */
396
+ $ignore_pending = apply_filters( 'tec_tickets_commerce_pending_stock_ignore', false );
397
+
398
+ $purchase_time = false;
399
+ $order = false;
400
+
401
+ if (
402
+ 'on-pending' === tribe_get_option( 'ticket-paypal-stock-handling', 'on-complete' )
403
+ && ! $ignore_pending
404
+ && Order_Statuses::$pending === $order_status
405
+ && false !== $order_id
406
+ ) {
407
+ $purchase_time = \Tribe__Utils__Array::get( $attendee, 'purchase_time', false );
408
+
409
+ $order = \Tribe__Tickets__Commerce__PayPal__Order::from_attendee_id(
410
+ $attendee_id,
411
+ [
412
+ // Get no meta fields.
413
+ ]
414
+ );
415
+
416
+ if ( false !== $order ) {
417
+ $purchase_time = $order->get_creation_date();
418
+ }
419
+ }
420
+
421
+ if ( $purchase_time ) {
422
+ $date = \Tribe__Date_Utils::build_date_object( $purchase_time );
423
+
424
+ $date->setTimezone( new \DateTimeZone( 'UTC' ) );
425
+
426
+ $order_creation_timestamp = $date->getTimestamp();
427
+
428
+ /**
429
+ * Filters the amount of time a part of the stock will be reserved by a pending Order.
430
+ *
431
+ * The time applies from the Order creation time.
432
+ * In the unlikely scenario that an Order goes from Completed to Pending then, if the
433
+ * reservation time allows it, a part of the stock will be reserved for it.
434
+ *
435
+ * @since 4.7
436
+ *
437
+ * @param int $pending_stock_reservation_time The amount of seconds, from the Order creation time,
438
+ * part of the stock will be reserved for the Order;
439
+ * defaults to 30 minutes.
440
+ * @param array $attendee An array of data defining the current Attendee
441
+ * @param \Tribe__Tickets__Commerce__PayPal__Order $order The object representing the Order that generated
442
+ * the Attendee
443
+ */
444
+ $pending_stock_reservation_time = (int) apply_filters( 'tec_tickets_commerce_pending_stock_reserve_time', 30 * 60, $attendee, $order );
445
+
446
+ return time() <= ( $order_creation_timestamp + $pending_stock_reservation_time );
447
+ }
448
+
449
+ return Completed::SLUG === $order_status;
450
+ }
451
+
452
+ /**
453
+ * Get attendee data for attendee.
454
+ *
455
+ * @since 5.1.9
456
+ */
457
+ public function get_attendee() {
458
+ /**
459
+ * @todo Determine if this meta piece can be moved into the ET+ codebase.
460
+ */
461
+ $meta = '';
462
+ if ( class_exists( 'Tribe__Tickets_Plus__Meta', false ) ) {
463
+ $meta = get_post_meta( $attendee->ID, \Tribe__Tickets_Plus__Meta::META_KEY, true );
464
+
465
+ // Process Meta to include value, slug, and label
466
+ if ( ! empty( $meta ) ) {
467
+ $meta = tribe( Module::class )->process_attendee_meta( $attendee['product_id'], $meta );
468
+ }
469
+ }
470
+ }
471
+ }
src/Tickets/Commerce/Cart.php ADDED
@@ -0,0 +1,660 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce;
4
+
5
+ use TEC\Tickets\Commerce;
6
+ use TEC\Tickets\Commerce\Utils\Price;
7
+ use \Tribe__Utils__Array as Arr;
8
+
9
+ /**
10
+ * Class Cart
11
+ *
12
+ * @since 5.1.9
13
+ *
14
+ * @package TEC\Tickets\Commerce
15
+ */
16
+ class Cart {
17
+
18
+ /**
19
+ * Which URL param we use to identify a given page as the cart.
20
+ * Keep in mind this is not the only way, please use `is_current_page()` to determine that.
21
+ *
22
+ * @since 5.1.9
23
+ *
24
+ * @var string
25
+ */
26
+ public static $url_query_arg = 'tec-tc-cart';
27
+
28
+ /**
29
+ * Which URL param we use to tell the checkout page to set a cookie, since you cannot set a cookie on a 302
30
+ * redirect.
31
+ *
32
+ * @since 5.1.9
33
+ *
34
+ * @var string
35
+ */
36
+ public static $cookie_query_arg = 'tec-tc-cookie';
37
+
38
+ /**
39
+ * Redirect mode string, which will be used to determine which kind of cart the repository might be.
40
+ *
41
+ * @since 5.1.9
42
+ *
43
+ * @var string
44
+ */
45
+ const REDIRECT_MODE = 'redirect';
46
+
47
+ /**
48
+ * Which URL param we use to identify a given page as the cart.
49
+ * Keep in mind this is not the only way, please use `is_current_page()` to determine that.
50
+ *
51
+ * @since 5.1.9
52
+ *
53
+ * @var string[]
54
+ */
55
+ protected $available_modes = [ self::REDIRECT_MODE ];
56
+
57
+ /**
58
+ * Which cookie we will store the cart hash.
59
+ *
60
+ * @since 5.1.9
61
+ *
62
+ * @var string
63
+ */
64
+ public static $cart_hash_cookie_name = 'tec-tickets-commerce-cart';
65
+
66
+ /**
67
+ * Which invoice number we are using here.
68
+ *
69
+ * @since 5.1.9
70
+ *
71
+ * @var string
72
+ */
73
+ protected $cart_hash;
74
+
75
+ /**
76
+ * From the current active cart repository we fetch it's mode.
77
+ *
78
+ * @since 5.1.9
79
+ *
80
+ * @return string
81
+ */
82
+ public function get_mode() {
83
+ return $this->get_repository()->get_mode();
84
+ }
85
+
86
+ /**
87
+ * Gets the list of available modes we can use for the cart.
88
+ *
89
+ * @since 5.1.9
90
+ *
91
+ * @return string[]
92
+ */
93
+ public function get_available_modes() {
94
+ return $this->available_modes;
95
+ }
96
+
97
+ /**
98
+ * If a given string is a valid and available mode.
99
+ *
100
+ * @since 5.1.9
101
+ *
102
+ * @param string $mode Which mode we are testing.
103
+ *
104
+ * @return bool
105
+ */
106
+ public function is_available_mode( $mode ) {
107
+ return in_array( $mode, $this->get_available_modes(), true );
108
+
109
+ }
110
+
111
+ /**
112
+ * If the current page is the cart page or not.
113
+ *
114
+ * @since 5.1.9
115
+ *
116
+ * @return bool
117
+ */
118
+ public function is_current_page() {
119
+ $cart_mode = tribe_get_request_var( static::$url_query_arg, false );
120
+
121
+ if ( ! $this->is_available_mode( $cart_mode ) ) {
122
+ return false;
123
+ }
124
+
125
+ // When the current cart doesn't use this mode we fail the page check.
126
+ if ( $this->get_mode() !== $cart_mode ) {
127
+ return false;
128
+ }
129
+
130
+ return true;
131
+ }
132
+
133
+ /**
134
+ * Returns the name of the transient used by the cart.
135
+ *
136
+ * @since 5.1.9
137
+ *
138
+ * @param string $id
139
+ *
140
+ * @return string
141
+ */
142
+ public static function get_transient_name( $id ) {
143
+ return Commerce::ABBR . '-cart-' . md5( $id );
144
+ }
145
+
146
+ /**
147
+ * Returns the name of the transient used by the cart for invoice numbers
148
+ *
149
+ * @since 5.1.9
150
+ *
151
+ * @param string $id
152
+ *
153
+ * @return string
154
+ */
155
+ public static function get_invoice_transient_name( $id ) {
156
+ return Commerce::ABBR . '-invoice-' . md5( $id );
157
+ }
158
+
159
+ /**
160
+ * Determine the Current cart Transient Key based on invoice number.
161
+ *
162
+ * @since 5.1.9
163
+ *
164
+ * @return string
165
+ */
166
+ public function get_current_cart_transient() {
167
+ $cart_hash = $this->get_cart_hash();
168
+
169
+ return static::get_transient_name( $cart_hash );
170
+ }
171
+
172
+ /**
173
+ * Determine the Current cart URL.
174
+ *
175
+ * @since 5.1.9
176
+ *
177
+ * @return string
178
+ */
179
+ public function get_url() {
180
+ $url = home_url( '/' );
181
+
182
+ $url = add_query_arg( [ static::$url_query_arg => $this->get_mode() ], $url );
183
+
184
+ /**
185
+ * Allows modifications to the cart url for Tickets Commerce.
186
+ *
187
+ * @since 5.1.9
188
+ *
189
+ * @param string $url URL for the cart.
190
+ */
191
+ return (string) apply_filters( 'tec_tickets_commerce_cart_url', $url );
192
+ }
193
+
194
+ /**
195
+ * Reads the cart hash from the cookies.
196
+ *
197
+ * @since 5.1.9
198
+ *
199
+ * @return string|bool The cart hash or `false` if not found.
200
+ */
201
+ public function get_cart_hash( $generate = false ) {
202
+ $cart_hash_length = 12;
203
+
204
+ $cart_hash = $this->cart_hash;
205
+
206
+ if (
207
+ ! empty( $_COOKIE[ static::$cart_hash_cookie_name ] )
208
+ && strlen( $_COOKIE[ static::$cart_hash_cookie_name ] ) === $cart_hash_length
209
+ ) {
210
+ $cart_hash = $_COOKIE[ static::$cart_hash_cookie_name ];
211
+
212
+ $cart_hash_transient = get_transient( static::get_transient_name( $cart_hash ) );
213
+
214
+ if ( empty( $cart_hash_transient ) ) {
215
+ $cart_hash = false;
216
+ }
217
+ }
218
+
219
+ if ( empty( $cart_hash ) && $generate ) {
220
+ $cart_hash = wp_generate_password( $cart_hash_length, false );
221
+ }
222
+
223
+ /**
224
+ * Filters the cart hash used for the Cart.
225
+ *
226
+ * @since 5.1.9
227
+ *
228
+ * @param string $cart_hash Invoice number.
229
+ */
230
+ $this->cart_hash = apply_filters( 'tec_tickets_commerce_cart_hash', $cart_hash );
231
+
232
+ return $this->cart_hash;
233
+ }
234
+
235
+ /**
236
+ * Clear the cart.
237
+ *
238
+ * @since 5.1.9
239
+ *
240
+ * @return false
241
+ */
242
+ public function clear_cart() {
243
+ $is_empty = empty( $_COOKIE[ static::$cart_hash_cookie_name ] );
244
+ $this->set_cart_hash_cookie( null );
245
+
246
+ if ( $is_empty ) {
247
+ return false;
248
+ }
249
+
250
+ $cart_hash = $_COOKIE[ static::$cart_hash_cookie_name ];
251
+ unset( $_COOKIE[ static::$cart_hash_cookie_name ] );
252
+
253
+ return delete_transient( static::get_transient_name( $cart_hash ) );
254
+ }
255
+
256
+ /**
257
+ * Sets the cart hash cookie or resets the cookie.
258
+ *
259
+ * @since 5.1.9
260
+ *
261
+ * @parem string $value Value used for the cookie or empty to purge the cookie.
262
+ *
263
+ * @return boolean
264
+ */
265
+ public function set_cart_hash_cookie( $value = '' ) {
266
+ if ( headers_sent() ) {
267
+ return false;
268
+ }
269
+
270
+ /**
271
+ * Filters the life span of the Cart Cookie.
272
+ *
273
+ * @since 5.1.9
274
+ *
275
+ * @param int $expires The expiry time, as passed to setcookie().
276
+ */
277
+ $expire = apply_filters( 'tec_tickets_commerce_cart_expiration', time() + 1 * HOUR_IN_SECONDS );
278
+ $referer = wp_get_referer();
279
+
280
+ if ( $referer ) {
281
+ $secure = ( 'https' === parse_url( $referer, PHP_URL_SCHEME ) );
282
+ } else {
283
+ $secure = false;
284
+ }
285
+
286
+ // When null means we are deleting.
287
+ if ( null === $value ) {
288
+ $expire = 1;
289
+ }
290
+
291
+ $is_cookie_set = setcookie( static::$cart_hash_cookie_name, $value, $expire, COOKIEPATH ?: '/', COOKIE_DOMAIN, $secure );
292
+
293
+ // Overwrite local variable so we can use it right away.
294
+ $_COOKIE[ static::$cart_hash_cookie_name ] = $value;
295
+
296
+ return $is_cookie_set;
297
+ }
298
+
299
+ /**
300
+ * Gets the current instance of cart handling that we are using.
301
+ *
302
+ * @since 5.1.9
303
+ *
304
+ * @return Commerce\Cart\Cart_Interface
305
+ */
306
+ public function get_repository() {
307
+ $default_cart = tribe( Cart\Unmanaged_Cart::class );
308
+
309
+ /**
310
+ * Filters the cart repository, by default we use Unmanaged Cart.
311
+ *
312
+ * @since 5.1.9
313
+ *
314
+ * @param Cart\Cart_Interface $cart Instance of the cart repository managing the cart.
315
+ */
316
+ return apply_filters( 'tec_tickets_commerce_cart_repository', $default_cart );
317
+ }
318
+
319
+ /**
320
+ * Get the tickets currently in the cart for a given provider.
321
+ *
322
+ * @since 5.1.9
323
+ *
324
+ * @param bool $full_item_params Determines all the item params, including event_id, sub_total, and obj.
325
+ *
326
+ * @return array List of items.
327
+ */
328
+ public function get_items_in_cart( $full_item_params = false ) {
329
+ $cart = $this->get_repository();
330
+
331
+ $items = $cart->get_items();
332
+
333
+ // When Items is empty in any capacity return an empty array.
334
+ if ( empty( $items ) ) {
335
+ return [];
336
+ }
337
+
338
+ if ( $full_item_params ) {
339
+ $items = array_map( static function ( $item ) {
340
+ $item['obj'] = \Tribe__Tickets__Tickets::load_ticket_object( $item['ticket_id'] );
341
+ $item['event_id'] = $item['obj']->get_event_id();
342
+ $item['sub_total'] = Price::sub_total( $item['obj']->price, $item['quantity'] );
343
+
344
+ return $item;
345
+ }, $items );
346
+ }
347
+
348
+ return $items;
349
+ }
350
+
351
+ /**
352
+ * Handles the process of adding a ticket product to the cart.
353
+ *
354
+ * If the cart contains a line item for the product, this will replace the previous quantity.
355
+ * If the quantity is zero and the cart contains a line item for the product, this will remove it.
356
+ *
357
+ * @since 5.1.9
358
+ *
359
+ * @param int $ticket_id Ticket ID.
360
+ * @param int $quantity Ticket quantity to add.
361
+ * @param array $extra_data Extra data to send to the cart item.
362
+ */
363
+ public function add_ticket( $ticket_id, $quantity = 1, array $extra_data = [] ) {
364
+ $cart = $this->get_repository();
365
+
366
+ // Enforces that the min to add is 1.
367
+ $quantity = max( 1, (int) $quantity );
368
+
369
+ // Add to / update quantity in cart.
370
+ $cart->add_item( $ticket_id, $quantity, $extra_data );
371
+ }
372
+
373
+ /**
374
+ * Handles the process of adding a ticket product to the cart.
375
+ *
376
+ * If the cart contains a line item for the product, this will replace the previous quantity.
377
+ * If the quantity is zero and the cart contains a line item for the product, this will remove it.
378
+ *
379
+ * @since 5.1.9
380
+ *
381
+ * @param int $ticket_id Ticket ID.
382
+ * @param int $quantity Ticket quantity to remove.
383
+ */
384
+ public function remove_ticket( $ticket_id, $quantity = 1 ) {
385
+ $cart = $this->get_repository();
386
+
387
+ // Enforces that the min to remove is 1.
388
+ $quantity = max( 1, (int) $quantity );
389
+
390
+ $cart->remove_item( $ticket_id, $quantity );
391
+ }
392
+
393
+ /**
394
+ * If product cache parameter is found, delete saved products from temporary cart.
395
+ *
396
+ * @filter wp_loaded 0
397
+ *
398
+ * @since 5.1.9
399
+ */
400
+ public function maybe_delete_expired_products() {
401
+ $delete = tribe_get_request_var( 'clear_product_cache', null );
402
+
403
+ if ( empty( $delete ) ) {
404
+ return;
405
+ }
406
+
407
+ $transient_key = $this->get_current_cart_transient();
408
+
409
+ // Bail if we have no data key.
410
+ if ( false === $transient_key ) {
411
+ return;
412
+ }
413
+
414
+ $transient = get_transient( $transient_key );
415
+
416
+ // Bail if we have no data to delete.
417
+ if ( empty( $transient ) ) {
418
+ return;
419
+ }
420
+
421
+ // Bail if ET+ is not in place.
422
+ if ( ! class_exists( 'Tribe__Tickets_Plus__Meta__Storage' ) ) {
423
+ return;
424
+ }
425
+ $storage = new \Tribe__Tickets_Plus__Meta__Storage();
426
+
427
+ foreach ( $transient as $ticket_id => $data ) {
428
+ $storage->delete_cookie( $ticket_id );
429
+ }
430
+ }
431
+
432
+ /**
433
+ * Prepare the data for cart processing.
434
+ *
435
+ * Note that most of the data that is processed here is legacy, so you will see very weird and wonky naming.
436
+ * Make sure when you are making modifications you consider:
437
+ * - Event Tickets without ET+ additional data
438
+ * - Event Ticket Plus IAC
439
+ * - Event Tickets Plus Attendee Registration
440
+ *
441
+ * @since 5.1.9
442
+ *
443
+ * @param array $request_data Request Data to be prepared.
444
+ *
445
+ * @return array
446
+ */
447
+ public function prepare_data( $request_data ) {
448
+ /**
449
+ * Filters the Cart data before sending to the prepare method.
450
+ *
451
+ * @since 5.1.9
452
+ *
453
+ * @param array $request_data The cart data before processing.
454
+ */
455
+ $request_data = apply_filters( 'tec_tickets_commerce_cart_pre_prepare_data', $request_data );
456
+
457
+ if ( empty( $request_data['tribe_tickets_ar_data'] ) ) {
458
+ return [];
459
+ }
460
+
461
+ /** @var \Tribe__Tickets__Tickets_Handler $handler */
462
+ $handler = tribe( 'tickets.handler' );
463
+
464
+ $raw_data = $request_data['tribe_tickets_ar_data'];
465
+
466
+ // Attempt to JSON decode data if needed.
467
+ if ( ! is_array( $raw_data ) ) {
468
+ $raw_data = stripslashes( $raw_data );
469
+ $raw_data = json_decode( $raw_data, true );
470
+ }
471
+
472
+ $raw_data = array_merge( $request_data, $raw_data );
473
+
474
+ $data = [];
475
+ $data['post_id'] = absint( Arr::get( $raw_data, 'tribe_tickets_post_id' ) );
476
+ $data['provider'] = sanitize_text_field( Arr::get( $raw_data, 'tribe_tickets_provider', Module::class ) );
477
+ $data['tickets'] = Arr::get( $raw_data, 'tribe_tickets_tickets' );
478
+ $data['meta'] = Arr::get( $raw_data, 'tribe_tickets_meta', [] );
479
+ $tickets_meta = Arr::get( $raw_data, 'tribe_tickets', [] );
480
+
481
+ $default_ticket = [
482
+ 'ticket_id' => 0,
483
+ 'quantity' => 0,
484
+ 'optout' => false,
485
+ 'iac' => 'none',
486
+ 'extra' => [],
487
+ ];
488
+
489
+ /**
490
+ * @todo Determine if this should be moved into the Ticket Controller.
491
+ */
492
+ $data['tickets'] = array_map( static function ( $ticket ) use ( $default_ticket, $handler, $tickets_meta ) {
493
+ if ( empty( $ticket['quantity'] ) ) {
494
+ return false;
495
+ }
496
+
497
+ $ticket = array_merge( $default_ticket, $ticket );
498
+
499
+ $ticket['quantity'] = (int) $ticket['quantity'];
500
+
501
+ if ( $ticket['quantity'] < 0 ) {
502
+ return false;
503
+ }
504
+
505
+ if ( ! empty( $tickets_meta[ $ticket['ticket_id'] ]['attendees'] ) ) {
506
+ $ticket['extra']['attendees'] = $tickets_meta[ $ticket['ticket_id'] ]['attendees'];
507
+ }
508
+
509
+ $ticket['extra']['optout'] = tribe_is_truthy( $ticket['optout'] );
510
+ unset( $ticket['optout'] );
511
+
512
+ $ticket['extra']['iac'] = sanitize_text_field( $ticket['iac'] );
513
+ unset( $ticket['iac'] );
514
+
515
+ $ticket['obj'] = \Tribe__Tickets__Tickets::load_ticket_object( $ticket['ticket_id'] );
516
+
517
+ if ( ! $handler->is_ticket_readable( $ticket['ticket_id'] ) ) {
518
+ return false;
519
+ }
520
+
521
+ return $ticket;
522
+ }, $data['tickets'] );
523
+
524
+ // Remove empty items.
525
+ $data['tickets'] = array_filter( $data['tickets'] );
526
+
527
+ /**
528
+ * Filters the Meta on the Data before processing.
529
+ *
530
+ * @since 5.1.9
531
+ *
532
+ * @param array $meta Meta information on the cart.
533
+ * @param array $data Data used for the cart.w
534
+ */
535
+ $data['meta'] = apply_filters( 'tec_tickets_commerce_cart_prepare_data_meta', $data['meta'], $data );
536
+
537
+ /**
538
+ * Filters the Cart data before sending to to the Cart Repository.
539
+ *
540
+ * @since 5.1.9
541
+ *
542
+ * @param array $data The cart data after processing.
543
+ */
544
+ return apply_filters( 'tec_tickets_commerce_cart_prepare_data', $data );
545
+ }
546
+
547
+ /**
548
+ * Prepares the data from the Tickets form.
549
+ *
550
+ * @since 5.1.9
551
+ *
552
+ * @return bool
553
+ */
554
+ public function parse_request() {
555
+ // When it's not the current page we just bail.
556
+ if ( ! $this->is_current_page() ) {
557
+ return false;
558
+ }
559
+
560
+ $data = $this->prepare_data( $_POST );
561
+
562
+ /**
563
+ * Hook to inject behavior before cart is processed, if you need to change the data that will be used, you
564
+ * should look into `tec_tickets_commerce_cart_prepare_data`.
565
+ *
566
+ * @since 5.1.9
567
+ *
568
+ * @param array $data Data used to process the cart.
569
+ */
570
+ do_action( 'tec_tickets_commerce_cart_before_process', $data );
571
+
572
+ $processed = $this->process( $data );
573
+
574
+ /**
575
+ * Hook to inject behavior after cart is processed.
576
+ *
577
+ * @since 5.1.9
578
+ *
579
+ * @param array $data Data used to process the cart.
580
+ * @param bool $processed Whether or not we processed the data.
581
+ */
582
+ do_action( 'tec_tickets_commerce_cart_after_process', $data, $processed );
583
+
584
+ if ( static::REDIRECT_MODE === $this->get_mode() ) {
585
+ $redirect_url = tribe( Checkout::class )->get_url();
586
+
587
+ if ( ! $_COOKIE[ $this->get_cart_hash() ] ) {
588
+ $redirect_url = add_query_arg( [ static::$cookie_query_arg => $this->get_cart_hash() ], $redirect_url );
589
+ }
590
+
591
+ /**
592
+ * Which url it redirects after the processing of the cart.
593
+ *
594
+ * @since 5.1.9
595
+ *
596
+ * @param string $redirect_url Which url we will direct after processing the cart. Defaults to Checkout page.
597
+ * @param array $data Data that we just processed on the cart.
598
+ */
599
+ $redirect_url = apply_filters( 'tec_tickets_commerce_cart_to_checkout_redirect_url', $redirect_url, $data );
600
+
601
+ if ( null !== $redirect_url ) {
602
+ wp_safe_redirect( $redirect_url );
603
+ tribe_exit();
604
+ }
605
+ }
606
+
607
+ return true;
608
+ }
609
+
610
+ /**
611
+ * Process a given cart data into this cart instance.
612
+ *
613
+ * @since 5.1.9
614
+ *
615
+ * @param array $data
616
+ *
617
+ * @return array|boolean Boolean true when it was a success or an array of errors.
618
+ */
619
+ public function process( array $data = [] ) {
620
+ if ( empty( $data ) ) {
621
+ return false;
622
+ }
623
+
624
+ /** @var \Tribe__Tickets__REST__V1__Messages $messages */
625
+ $messages = tribe( 'tickets.rest-v1.messages' );
626
+
627
+ // Get the number of available tickets.
628
+ /** @var \Tribe__Tickets__Tickets_Handler $tickets_handler */
629
+ $tickets_handler = tribe( 'tickets.handler' );
630
+
631
+ $errors = [];
632
+
633
+ foreach ( $data['tickets'] as $ticket ) {
634
+ $available = $tickets_handler->get_ticket_max_purchase( $ticket['ticket_id'] );
635
+
636
+ // Bail if ticket does not have enough available capacity.
637
+ if ( ( - 1 !== $available && $available < $ticket['quantity'] ) || ! $ticket['obj']->date_in_range() ) {
638
+ $error_code = 'ticket-capacity-not-available';
639
+
640
+ $errors[] = new \WP_Error( $error_code, sprintf( $messages->get_message( $error_code ), $ticket['obj']->name ), [
641
+ 'ticket' => $ticket,
642
+ 'max_available' => $available,
643
+ ] );
644
+ continue;
645
+ }
646
+
647
+ $this->add_ticket( $ticket['ticket_id'], $ticket['quantity'], $ticket['extra'] );
648
+ }
649
+
650
+ // Saved added items to the cart.
651
+ $this->get_repository()->save();
652
+
653
+ if ( ! empty( $errors ) ) {
654
+ return $errors;
655
+ }
656
+
657
+ return true;
658
+ }
659
+
660
+ }
src/Tickets/Commerce/Cart/Cart_Interface.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Cart;
4
+
5
+ /**
6
+ * Interface Cart_Interface
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets\Commerce\Cart
11
+ */
12
+ interface Cart_Interface {
13
+
14
+ /**
15
+ * Sets the cart id.
16
+ *
17
+ * @since 5.1.9
18
+ *
19
+ * @param string $id
20
+ */
21
+ public function set_id( $id );
22
+
23
+ /**
24
+ * Gets the Cart mode based.
25
+ *
26
+ * @since 5.1.9
27
+ *
28
+ * @return string
29
+ */
30
+ public function get_mode();
31
+
32
+ /**
33
+ * Gets the cart items from the cart.
34
+ *
35
+ * This method should include any persistence by the cart implementation.
36
+ *
37
+ * @since 5.1.9
38
+ *
39
+ * @return array
40
+ */
41
+ public function get_items();
42
+
43
+ /**
44
+ * Saves the cart.
45
+ *
46
+ * This method should include any persistence, request and redirection required
47
+ * by the cart implementation.
48
+ *
49
+ * @since 5.1.9
50
+ */
51
+ public function save();
52
+
53
+ /**
54
+ * Clears the cart of its contents and persists its new state.
55
+ *
56
+ * This method should include any persistence, request and redirection required
57
+ * by the cart implementation.
58
+ */
59
+ public function clear();
60
+
61
+ /**
62
+ * Whether a cart exists meeting the specified criteria.
63
+ *
64
+ * @since 5.1.9
65
+ *
66
+ * @param array $criteria
67
+ */
68
+ public function exists( array $criteria = [] );
69
+
70
+ /**
71
+ * Whether the cart contains items or not.
72
+ *
73
+ * @since 5.1.9
74
+ *
75
+ * @return bool|int The number of products in the cart (regardless of the products quantity) or `false`
76
+ *
77
+ */
78
+ public function has_items();
79
+
80
+ /**
81
+ * Whether an item is in the cart or not.
82
+ *
83
+ * @since 5.1.9
84
+ *
85
+ * @param string $item_id
86
+ *
87
+ * @return bool|int Either the quantity in the cart for the item or `false`.
88
+ */
89
+ public function has_item( $item_id );
90
+
91
+ /**
92
+ * Adds a specified quantity of the item to the cart.
93
+ *
94
+ * @since 5.1.9
95
+ *
96
+ * @param int|string $item_id The item ID.
97
+ * @param int $quantity The quantity to remove.
98
+ * @param array $extra_data Extra data to save to the item.
99
+ */
100
+ public function add_item( $item_id, $quantity, array $extra_data = [] );
101
+
102
+ /**
103
+ * Determines if this instance of the cart has a public page.
104
+ *
105
+ * @since 5.1.9
106
+ *
107
+ * @return bool
108
+ */
109
+ public function has_public_page();
110
+
111
+ /**
112
+ * Removes an item from the cart.
113
+ *
114
+ * @since 5.1.9
115
+ *
116
+ * @param int|string $item_id The item ID.
117
+ * @param null|int $quantity The quantity to remove.
118
+ */
119
+ public function remove_item( $item_id, $quantity = null );
120
+ }
src/Tickets/Commerce/Cart/Unmanaged_Cart.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Cart;
4
+
5
+ use TEC\Tickets\Commerce;
6
+
7
+ /**
8
+ * Class Unmanaged_Cart
9
+ *
10
+ * Models a transitional, not managed, cart implementation; cart management functionality
11
+ * is offloaded to PayPal.
12
+ *
13
+ * @since 5.1.9
14
+ */
15
+ class Unmanaged_Cart implements Cart_Interface {
16
+
17
+ /**
18
+ * @var string The Cart hash for this cart.
19
+ */
20
+ protected $cart_hash;
21
+
22
+ /**
23
+ * @var array|null The list of items, null if not retrieved from transient yet.
24
+ */
25
+ protected $items = null;
26
+
27
+ /**
28
+ * {@inheritDoc}
29
+ */
30
+ public function has_public_page() {
31
+ return false;
32
+ }
33
+
34
+ /**
35
+ * {@inheritDoc}
36
+ */
37
+ public function get_mode() {
38
+ return \TEC\Tickets\Commerce\Cart::REDIRECT_MODE;
39
+ }
40
+
41
+ /**
42
+ * {@inheritdoc}
43
+ */
44
+ public function set_id( $id ) {
45
+ $this->cart_hash = $id;
46
+ }
47
+
48
+ /**
49
+ * {@inheritdoc}
50
+ */
51
+ public function save() {
52
+ $cart_hash = tribe( Commerce\Cart::class )->get_cart_hash( true );
53
+
54
+ if ( false === $cart_hash ) {
55
+ return false;
56
+ }
57
+
58
+ if ( ! $this->has_items() ) {
59
+ $this->clear();
60
+
61
+ return;
62
+ }
63
+
64
+ set_transient( Commerce\Cart::get_transient_name( $cart_hash ), $this->items, DAY_IN_SECONDS );
65
+ tribe( Commerce\Cart::class )->set_cart_hash_cookie( $cart_hash );
66
+ }
67
+
68
+ /**
69
+ * {@inheritdoc}
70
+ */
71
+ public function get_items() {
72
+ if ( null !== $this->items ) {
73
+ return $this->items;
74
+ }
75
+
76
+ if ( ! $this->exists() ) {
77
+ return false;
78
+ }
79
+
80
+ $cart_hash = tribe( Commerce\Cart::class )->get_cart_hash();
81
+
82
+ $items = get_transient( Commerce\Cart::get_transient_name( $cart_hash ) );
83
+
84
+ if ( is_array( $items ) && ! empty( $items ) ) {
85
+ $this->items = $items;
86
+ }
87
+
88
+ return $this->items;
89
+ }
90
+
91
+ /**
92
+ * {@inheritdoc}
93
+ */
94
+ public function clear() {
95
+ $cart_hash = tribe( Commerce\Cart::class )->get_cart_hash();
96
+
97
+ if ( false === $cart_hash ) {
98
+ return false;
99
+ }
100
+
101
+ delete_transient( Commerce\Cart::get_transient_name( $cart_hash ) );
102
+ tribe( Commerce\Cart::class )->set_cart_hash_cookie( $cart_hash );
103
+ }
104
+
105
+ /**
106
+ * {@inheritdoc}
107
+ */
108
+ public function exists( array $criteria = [] ) {
109
+ $cart_hash = tribe( Commerce\Cart::class )->get_cart_hash();
110
+
111
+ if ( false === $cart_hash ) {
112
+ return false;
113
+ }
114
+
115
+ return (bool) get_transient( Commerce\Cart::get_transient_name( $cart_hash ) );
116
+ }
117
+
118
+ /**
119
+ * {@inheritdoc}
120
+ */
121
+ public function has_items() {
122
+ $items = $this->get_items();
123
+
124
+ return count( $items );
125
+ }
126
+
127
+ /**
128
+ * {@inheritdoc}
129
+ */
130
+ public function has_item( $item_id ) {
131
+ $items = $this->get_items();
132
+
133
+ return ! empty( $items[ $item_id ] ) ? (int) $items[ $item_id ]['quantity'] : false;
134
+ }
135
+
136
+ /**
137
+ * {@inheritdoc}
138
+ */
139
+ public function add_item( $item_id, $quantity, array $extra_data = [] ) {
140
+ $current_quantity = $this->has_item( $item_id );
141
+
142
+ $new_quantity = (int) $quantity;
143
+
144
+ if ( 0 < $current_quantity ) {
145
+ $new_quantity += (int) $current_quantity;
146
+ }
147
+
148
+ $new_quantity = max( $new_quantity, 0 );
149
+
150
+ if ( 0 < $new_quantity ) {
151
+ $item['ticket_id'] = $item_id;
152
+ $item['quantity'] = $new_quantity;
153
+
154
+ $item['extra'] = $extra_data;
155
+
156
+ $this->items[ $item_id ] = $item;
157
+ } else {
158
+ $this->remove_item( $item_id );
159
+ }
160
+ }
161
+
162
+ /**
163
+ * {@inheritdoc}
164
+ */
165
+ public function remove_item( $item_id, $quantity = null ) {
166
+ if ( null !== $quantity ) {
167
+ $this->add_item( $item_id, - abs( (int) $quantity ) );
168
+
169
+ return;
170
+ }
171
+
172
+ if ( $this->has_item( $item_id ) ) {
173
+ unset( $this->items[ $item_id ] );
174
+ }
175
+ }
176
+ }
src/Tickets/Commerce/Checkout.php ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce;
4
+
5
+ /**
6
+ * Class Checkout
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets\Commerce
11
+ */
12
+ class Checkout {
13
+ /**
14
+ * Get the Checkout page ID.
15
+ *
16
+ * @since 5.1.9
17
+ *
18
+ *
19
+ * @return int|null
20
+ */
21
+ public function get_page_id() {
22
+ $checkout_page = (int) tribe_get_option( Settings::$option_checkout_page );
23
+
24
+ if ( empty( $checkout_page ) ) {
25
+ return null;
26
+ }
27
+
28
+ /**
29
+ * Allows filtering of the Page ID for the Checkout page.
30
+ *
31
+ * @since 5.1.9
32
+ *
33
+ * @param int|null $checkout_page Which page is used in the settings.
34
+ */
35
+ return apply_filters( 'tec_tickets_commerce_checkout_page_id', $checkout_page );
36
+ }
37
+
38
+ /**
39
+ * Determine the Current checkout URL.
40
+ *
41
+ * @since 5.1.9
42
+ *
43
+ * @return string
44
+ */
45
+ public function get_url() {
46
+ $url = home_url( '/' );
47
+ $checkout_page = $this->get_page_id();
48
+
49
+ if ( is_numeric( $checkout_page ) ) {
50
+ $checkout_page = get_post( $checkout_page );
51
+ }
52
+
53
+ // Only modify the URL in case we have a checkout page setup in the settings.
54
+ if ( $checkout_page instanceof \WP_Post ) {
55
+ $url = get_the_permalink( $checkout_page );
56
+ }
57
+
58
+ /**
59
+ * Allows modifications to the checkout url for Tickets Commerce.
60
+ *
61
+ * @since 5.1.9
62
+ *
63
+ * @param string $url URL for the cart.
64
+ */
65
+ return (string) apply_filters( 'tec_tickets_commerce_checkout_url', $url );
66
+ }
67
+
68
+ /**
69
+ * Determines if the current page is the Checkout page.
70
+ *
71
+ * @since 5.1.9
72
+ *
73
+ *
74
+ * @return bool
75
+ */
76
+ public function is_current_page() {
77
+ if ( is_admin() ) {
78
+ return false;
79
+ }
80
+
81
+ $current_page = get_queried_object_id();
82
+ $is_current_page = $this->get_page_id() === $current_page;
83
+
84
+ /**
85
+ * @todo determine hte usage of tribe_ticket_redirect_to
86
+ * $redirect = tribe_get_request_var( 'tribe_tickets_redirect_to', null );
87
+ */
88
+
89
+ /**
90
+ * Allows modifications to the conditional of if we are in the checkout page.
91
+ *
92
+ * @since 5.1.9
93
+ *
94
+ * @param bool $is_current_page Are we in the current page for checkout.
95
+ */
96
+ return tribe_is_truthy( apply_filters( 'tec_tickets_commerce_checkout_is_current_page', $is_current_page ) );
97
+ }
98
+
99
+ /**
100
+ * If there is any data or request management or parsing that needs to happen on the Checkout page here is where
101
+ * we do it.
102
+ *
103
+ * @since 5.1.9
104
+ */
105
+ public function parse_request() {
106
+ if ( ! $this->is_current_page() ) {
107
+ return;
108
+ }
109
+
110
+ // In case the ID is passed we set the cookie for usage.
111
+ $cookie_param = tribe_get_request_var( Cart::$cookie_query_arg, false );
112
+ if ( $cookie_param ) {
113
+ tribe( Cart::class )->set_cart_hash_cookie( $cookie_param );
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Get the login URL.
119
+ *
120
+ * @since 5.1.9
121
+ *
122
+ * @return string
123
+ */
124
+ public function get_login_url() {
125
+ $login_url = get_site_url( null, 'wp-login.php' );
126
+
127
+ $login_url = add_query_arg( 'redirect_to', $this->get_url(), $login_url );
128
+
129
+ /**
130
+ * Provides an opportunity to modify the login URL used within frontend
131
+ * checkout (typically when they need to login before they can proceed).
132
+ *
133
+ * @since 5.1.9
134
+ *
135
+ * @param string $login_url
136
+ */
137
+ return apply_filters( 'tec_tickets_commerce_checkout_login_url', $login_url );
138
+ }
139
+
140
+ /**
141
+ * Get the registration URL.
142
+ *
143
+ * @since 5.1.9
144
+ *
145
+ * @return string
146
+ */
147
+ public function get_registration_url() {
148
+ $registration_url = wp_registration_url();
149
+
150
+ $registration_url = add_query_arg( 'redirect_to', $this->get_url(), $registration_url );
151
+
152
+ /**
153
+ * Provides an opportunity to modify the registration URL used within frontend
154
+ * checkout (typically when they need to login before they can proceed).
155
+ *
156
+ * @since 5.1.9
157
+ *
158
+ * @param string $login_url
159
+ */
160
+ return apply_filters( 'tec_tickets_commerce_checkout_registration_url', $registration_url );
161
+ }
162
+ }
src/Tickets/Commerce/Communication/Email.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Communications;
4
+
5
+ /**
6
+ * Class Email
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets\Commerce\Communications
11
+ */
12
+ class Email {
13
+ /**
14
+ * Sends ticket email
15
+ *
16
+ * @since 4.7.6 added $post_id parameter
17
+ *
18
+ * @param string $order_id Order post ID
19
+ * @param int $post_id Parent post ID (optional)
20
+ */
21
+ public function send_tickets_email( $order_id, $post_id = null ) {
22
+ $all_attendees = $this->get_attendees_by_order_id( $order_id );
23
+
24
+ $to_send = array();
25
+
26
+ if ( empty( $all_attendees ) ) {
27
+ return;
28
+ }
29
+
30
+ // Look at each attendee and check if a ticket was sent: in each case where a ticket
31
+ // has not yet been sent we should a) send the ticket out by email and b) record the
32
+ // fact it was sent
33
+ foreach ( $all_attendees as $single_attendee ) {
34
+ // Only add those attendees/tickets that haven't already been sent
35
+ if ( ! empty( $single_attendee['ticket_sent'] ) ) {
36
+ continue;
37
+ }
38
+
39
+ $to_send[] = $single_attendee;
40
+ }
41
+
42
+ /**
43
+ * Controls the list of tickets which will be emailed out.
44
+ *
45
+ * @since 4.7
46
+ * @since 4.7.6 added new parameter $post_id
47
+ *
48
+ * @param array $to_send list of tickets to be sent out by email
49
+ * @param array $all_attendees list of all attendees/tickets, including those already sent out
50
+ * @param int $post_id
51
+ * @param string $order_id
52
+ *
53
+ */
54
+ $to_send = (array) apply_filters( 'tribe_tickets_tpp_tickets_to_send', $to_send, $all_attendees, $post_id, $order_id );
55
+
56
+ if ( empty( $to_send ) ) {
57
+ return;
58
+ }
59
+
60
+ $send_args = [
61
+ 'post_id' => $post_id,
62
+ 'order_id' => $order_id,
63
+ 'send_purchaser_all' => true,
64
+ ];
65
+
66
+ // Send the emails.
67
+ $this->send_tickets_email_for_attendees( $to_send, $send_args );
68
+ }
69
+ }
src/Tickets/Commerce/Currency.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce;
4
+
5
+ /**
6
+ * Class Currency
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets\Commerce
11
+ */
12
+ class Currency {
13
+
14
+ }
src/Tickets/Commerce/Editor/Metabox.php ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Editor;
4
+
5
+ use TEC\Tickets\Commerce\Module;
6
+ use Tribe__Tickets__Main as Tickets_Plugin;
7
+
8
+
9
+ /**
10
+ * Class Metabox.
11
+ *
12
+ * @since 5.1.9
13
+ *
14
+ * @package TEC\Tickets\Commerce\Editor
15
+ */
16
+ class Metabox {
17
+
18
+
19
+ /**
20
+ * Add the sku field in the admin's new/edit ticket metabox
21
+ *
22
+ * @since 4.7
23
+ *
24
+ * @param $post_id int id of the event post
25
+ * @param int $ticket_id (null) id of the ticket
26
+ *
27
+ * @return void
28
+ */
29
+ public function do_metabox_sku_options( $post_id, $ticket_id = null ) {
30
+ $sku = '';
31
+
32
+ /** @var \Tribe__Tickets__Tickets_Handler $tickets_handler */
33
+ $tickets_handler = tribe( 'tickets.handler' );
34
+ $provider_obj = tribe( Module::class );
35
+
36
+ $is_correct_provider = $tickets_handler->is_correct_provider( $post_id, $provider_obj );
37
+
38
+ if ( ! empty( $ticket_id ) ) {
39
+ $ticket = tribe( Module::class )->get_ticket( $post_id, $ticket_id );
40
+ $is_correct_provider = $tickets_handler->is_correct_provider( $ticket_id, $provider_obj );
41
+
42
+ if ( ! empty( $ticket ) ) {
43
+ $sku = get_post_meta( $ticket_id, '_sku', true );
44
+ }
45
+ }
46
+
47
+ // Bail when we are not dealing with this provider
48
+ if ( ! $is_correct_provider ) {
49
+ return;
50
+ }
51
+
52
+ $path = Tickets_Plugin::instance()->plugin_path;
53
+
54
+ include $path . 'src/admin-views/commerce/metabox/sku.php';
55
+ }
56
+
57
+ /**
58
+ * Renders the advanced fields in the new/edit ticket form.
59
+ * Using the method, providers can add as many fields as
60
+ * they want, specific to their implementation.
61
+ *
62
+ * @since 5.1.9
63
+ *
64
+ * @param int $post_id
65
+ * @param int $ticket_id
66
+ */
67
+ public function include_metabox_advanced_options( $post_id, $ticket_id ) {
68
+ $provider = __CLASS__;
69
+
70
+ echo '<div id="' . sanitize_html_class( $provider ) . '_advanced" class="tribe-dependent" data-depends="#' . sanitize_html_class( $provider ) . '_radio" data-condition-is-checked>';
71
+
72
+ if ( ! tribe_is_frontend() ) {
73
+ $this->do_metabox_sku_options( $post_id, $ticket_id );
74
+ }
75
+
76
+ /**
77
+ * Allows for the insertion of additional content into the ticket edit form - advanced section
78
+ *
79
+ * @since 4.6
80
+ *
81
+ * @param int Post ID
82
+ * @param string the provider class name
83
+ * @param int $ticket_id The ticket ID.
84
+ */
85
+ do_action( 'tribe_events_tickets_metabox_edit_ajax_advanced', $post_id, $provider, $ticket_id );
86
+
87
+ echo '</div>';
88
+ }
89
+
90
+
91
+ /**
92
+ * Renders the advanced fields in the new/edit ticket form.
93
+ * Using the method, providers can add as many fields as
94
+ * they want, specific to their implementation.
95
+ *
96
+ * @since 4.7
97
+ *
98
+ * @param int $post_id
99
+ * @param int $ticket_id
100
+ *
101
+ * @return mixed
102
+ */
103
+ public function do_metabox_capacity_options( $post_id, $ticket_id ) {
104
+ /** @var \Tribe__Tickets__Tickets_Handler $tickets_handler */
105
+ $tickets_handler = tribe( 'tickets.handler' );
106
+ $provider = tribe( Module::class );
107
+
108
+ $is_correct_provider = $tickets_handler->is_correct_provider( $post_id, $provider );
109
+
110
+ $url = '';
111
+ $stock = '';
112
+ $global_stock_mode = $tickets_handler->get_default_capacity_mode();
113
+ $global_stock_cap = 0;
114
+ $ticket_capacity = null;
115
+ $post_capacity = null;
116
+
117
+ $stock_object = new \Tribe__Tickets__Global_Stock( $post_id );
118
+
119
+ if ( $stock_object->is_enabled() ) {
120
+ $post_capacity = tribe_tickets_get_capacity( $post_id );
121
+ }
122
+
123
+ if ( ! empty( $ticket_id ) ) {
124
+ $ticket = tribe( Module::class )->get_ticket( $post_id, $ticket_id );
125
+ $is_correct_provider = $tickets_handler->is_correct_provider( $ticket_id, $provider );
126
+
127
+ if ( ! empty( $ticket ) ) {
128
+ $stock = $ticket->managing_stock() ? $ticket->stock() : '';
129
+ $ticket_capacity = tribe_tickets_get_capacity( $ticket->ID );
130
+ $global_stock_mode = ( method_exists( $ticket, 'global_stock_mode' ) ) ? $ticket->global_stock_mode() : '';
131
+ $global_stock_cap = ( method_exists( $ticket, 'global_stock_cap' ) ) ? $ticket->global_stock_cap() : 0;
132
+ }
133
+ }
134
+
135
+ // Bail when we are not dealing with this provider
136
+ if ( ! $is_correct_provider ) {
137
+ return;
138
+ }
139
+
140
+ $file = \Tribe__Tickets__Main::instance()->plugin_path . 'src/admin-views/commerce/metabox/capacity.php';
141
+
142
+ /**
143
+ * Filters the absolute path to the file containing the metabox capacity HTML.
144
+ *
145
+ * @since 4.7
146
+ *
147
+ * @param string $file The absolute path to the file containing the metabox capacity HTML
148
+ * @param int|string $ticket_capacity
149
+ * @param int|string $post_capacity
150
+ */
151
+ $file = apply_filters( 'tribe_tickets_tc_metabox_capacity_file', $file, $ticket_capacity, $post_capacity );
152
+
153
+ if ( file_exists( $file ) ) {
154
+ include $file;
155
+ }
156
+ }
157
+ }
src/Tickets/Commerce/Flag_Actions/Decrease_Stock.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Flag_Actions;
4
+
5
+ use TEC\Tickets\Commerce\Order;
6
+ use TEC\Tickets\Commerce\Status\Status_Interface;
7
+
8
+ /**
9
+ * Class Decrease_Stock
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce\Flag_Actions
14
+ */
15
+ class Decrease_Stock extends Flag_Action_Abstract {
16
+ /**
17
+ * {@inheritDoc}
18
+ */
19
+ protected $flags = [
20
+ 'decrease_stock',
21
+ ];
22
+
23
+ /**
24
+ * {@inheritDoc}
25
+ */
26
+ protected $post_types = [
27
+ Order::POSTTYPE
28
+ ];
29
+
30
+ /**
31
+ * {@inheritDoc}
32
+ */
33
+ public function handle( Status_Interface $new_status, $old_status, \WP_Post $post ) {
34
+ $i = true;
35
+ }
36
+ }
src/Tickets/Commerce/Flag_Actions/Flag_Action_Abstract.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Flag_Actions;
4
+
5
+ use TEC\Tickets\Commerce\Status\Status_Interface;
6
+
7
+
8
+ /**
9
+ * Class Flag Action Abstract.
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce\Flag_Actions
14
+ */
15
+ abstract class Flag_Action_Abstract implements Flag_Action_Interface {
16
+ /**
17
+ * When will this particular flag wil be triggered
18
+ *
19
+ * @since 5.1.9
20
+ *
21
+ * @var int
22
+ */
23
+ protected $priority = 10;
24
+
25
+ /**
26
+ * Which flags are associated and will trigger this action.
27
+ *
28
+ * @since 5.1.9
29
+ *
30
+ * @var string[]
31
+ */
32
+ protected $flags = [];
33
+
34
+ /**
35
+ * Which Post Types we check for this flag action.
36
+ *
37
+ * @since 5.1.9
38
+ *
39
+ * @var string[]
40
+ */
41
+ protected $post_types;
42
+
43
+ /**
44
+ * {@inheritDoc}
45
+ */
46
+ public function get_flags() {
47
+ return $this->flags;
48
+ }
49
+
50
+ /**
51
+ * {@inheritDoc}
52
+ */
53
+ public function get_priority() {
54
+ return $this->priority;
55
+ }
56
+
57
+ /**
58
+ * {@inheritDoc}
59
+ */
60
+ public function get_post_types() {
61
+ return $this->post_types;
62
+ }
63
+
64
+ /**
65
+ * {@inheritDoc}
66
+ */
67
+ public function should_trigger( Status_Interface $new_status, $old_status, $post ) {
68
+ if ( ! $this->has_flags( $new_status ) ) {
69
+ return false;
70
+ }
71
+
72
+ if ( ! $this->is_correct_post_type( $post ) ) {
73
+ return false;
74
+ }
75
+
76
+ return true;
77
+ }
78
+
79
+ /**
80
+ * {@inheritDoc}
81
+ */
82
+ public function has_flags( Status_Interface $status ) {
83
+ return $status->has_flags( $this->get_flags() );
84
+ }
85
+
86
+ /**
87
+ * {@inheritDoc}
88
+ */
89
+ public function is_correct_post_type( \WP_Post $post ) {
90
+ return in_array( $post->post_type, $this->get_post_types(), true );
91
+ }
92
+
93
+ /**
94
+ * {@inheritDoc}
95
+ */
96
+ public function maybe_handle( Status_Interface $new_status, $old_status, $post ) {
97
+ if ( ! $this->should_trigger( $new_status, $old_status, $post ) ) {
98
+ return;
99
+ }
100
+ /**
101
+ * @todo For now Flag actions are only for order, so we use `tec_tc_get_order()` but if in the future we add any
102
+ * other post types to the mix we will need to provide a way to pass the post via a formatting method.
103
+ */
104
+ $post = tec_tc_get_order( $post );
105
+
106
+ $this->handle( $new_status, $old_status, $post );
107
+ }
108
+
109
+ /**
110
+ * {@inheritDoc}
111
+ */
112
+ public function hook() {
113
+ foreach ( $this->get_flags() as $flag ) {
114
+ add_action( "tec_tickets_commerce_order_status_flag_{$flag}", [ $this, 'maybe_handle' ], $this->get_priority(), 3 );
115
+ }
116
+ }
117
+
118
+ /**
119
+ * {@inheritDoc}
120
+ */
121
+ abstract public function handle( Status_Interface $new_status, $old_status, \WP_Post $post );
122
+ }
src/Tickets/Commerce/Flag_Actions/Flag_Action_Handler.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Flag_Actions;
4
+
5
+ /**
6
+ * Class Flag_Action_Handler
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets\Commerce\Flag_Actions
11
+ */
12
+ class Flag_Action_Handler extends \tad_DI52_ServiceProvider {
13
+ /**
14
+ * Flag Actions registered.
15
+ *
16
+ * @since 5.1.9
17
+ *
18
+ * @var Flag_Action_Interface[]
19
+ */
20
+ protected $flag_actions = [];
21
+
22
+ /**
23
+ * Which classes we will load for order flag actions by default.
24
+ *
25
+ * @since 5.1.9
26
+ *
27
+ * @var string[]
28
+ */
29
+ protected $default_flag_actions = [
30
+ Generate_Attendees::class,
31
+ Increase_Stock::class,
32
+ Decrease_Stock::class,
33
+ ];
34
+
35
+ /**
36
+ * Gets the flag actions registered.
37
+ *
38
+ * @since 5.1.9
39
+ *
40
+ * @return Flag_Action_Interface[]
41
+ */
42
+ public function get_all() {
43
+ return $this->flag_actions;
44
+ }
45
+
46
+ /**
47
+ * Sets up all the Flag Action instances for the Classes registered in $default_flag_actions.
48
+ *
49
+ * @since 5.1.9
50
+ */
51
+ public function register() {
52
+ foreach ( $this->default_flag_actions as $flag_action_class ) {
53
+ // Spawn the new instance.
54
+ $flag_action = new $flag_action_class;
55
+
56
+ // Register as a singleton for internal ease of use.
57
+ $this->container->singleton( $flag_action_class, $flag_action );
58
+
59
+ // Collect this particular status instance in this class.
60
+ $this->register_flag_action( $flag_action );
61
+ }
62
+
63
+ $this->container->singleton( static::class, $this );
64
+ }
65
+
66
+ /**
67
+ * Register a given flag action into the Handler, and hook the handling to WP.
68
+ *
69
+ * @since 5.1.9
70
+ *
71
+ * @param Flag_Action_Interface $flag_action Which flag action we are registering.
72
+ */
73
+ public function register_flag_action( Flag_Action_Interface $flag_action ) {
74
+ $this->flag_actions[] = $flag_action;
75
+ $flag_action->hook();
76
+ }
77
+ }
src/Tickets/Commerce/Flag_Actions/Flag_Action_Interface.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace TEC\Tickets\Commerce\Flag_Actions;
3
+
4
+ use TEC\Tickets\Commerce\Status\Status_Interface;
5
+
6
+ /**
7
+ * Class Flag Action Interface.
8
+ *
9
+ * @since 5.1.9
10
+ *
11
+ * @package TEC\Tickets\Commerce\Flag_Actions
12
+ */
13
+ interface Flag_Action_Interface {
14
+ /**
15
+ * Gets the flags that we could trigger this flag action for.
16
+ *
17
+ * @since 5.1.9
18
+ *
19
+ * @return string[]
20
+ */
21
+ public function get_flags();
22
+
23
+ /**
24
+ * Gets the post types that we could trigger this flag action for.
25
+ *
26
+ * @since 5.1.9
27
+ *
28
+ * @return string[]
29
+ */
30
+ public function get_post_types();
31
+
32
+ /**
33
+ * Which priority we will hook this particular flag action.
34
+ *
35
+ * @since 5.1.9
36
+ *
37
+ * @return int
38
+ */
39
+ public function get_priority();
40
+
41
+ /**
42
+ * Determines if a transition of status will trigger this flag action.
43
+ *
44
+ * @since 5.1.9
45
+ *
46
+ * @param Status_Interface $new_status New post status.
47
+ * @param Status_Interface|null $old_status Old post status.
48
+ * @param \WP_Post $post Post object.
49
+ *
50
+ * @return bool
51
+ */
52
+ public function should_trigger( Status_Interface $new_status, $old_status, $post );
53
+
54
+ /**
55
+ * Determines if a given status has the correct action flag to trigger.
56
+ *
57
+ * @since 5.1.9
58
+ *
59
+ * @param Status_Interface $status
60
+ *
61
+ * @return bool
62
+ */
63
+ public function has_flags( Status_Interface $status );
64
+
65
+ /**
66
+ * Determines if a given post object is the correct post type to trigger this flag action
67
+ *
68
+ * @since 5.1.9
69
+ *
70
+ * @param \WP_Post $post
71
+ *
72
+ * @return bool
73
+ */
74
+ public function is_correct_post_type( \WP_Post $post );
75
+
76
+ /**
77
+ * Handles the action flag execution.
78
+ *
79
+ * @since 5.1.9
80
+ *
81
+ * @param Status_Interface $new_status New post status.
82
+ * @param Status_Interface|null $old_status Old post status.
83
+ * @param \WP_Post $post Post object.
84
+ */
85
+ public function handle( Status_Interface $new_status, $old_status, \WP_Post $post );
86
+
87
+ /**
88
+ * Triggers the handle method if should_trigger method is true.
89
+ *
90
+ * @since 5.1.9
91
+ *
92
+ * @param Status_Interface $new_status New post status.
93
+ * @param Status_Interface|null $old_status Old post status.
94
+ * @param \WP_Post $post Post object.
95
+ */
96
+ public function maybe_handle( Status_Interface $new_status, $old_status, $post );
97
+
98
+ /**
99
+ * Handles the hooking of a given flag action to the correct actions in WP.
100
+ *
101
+ * @since 5.1.9
102
+ */
103
+ public function hook();
104
+ }
src/Tickets/Commerce/Flag_Actions/Generate_Attendees.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Flag_Actions;
4
+
5
+ use TEC\Tickets\Commerce\Order;
6
+ use TEC\Tickets\Commerce\Status\Status_Interface;
7
+
8
+ /**
9
+ * Class Attendee_Generation
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce\Flag_Actions
14
+ */
15
+ class Generate_Attendees extends Flag_Action_Abstract {
16
+ /**
17
+ * {@inheritDoc}
18
+ */
19
+ protected $flags = [
20
+ 'generate_attendees',
21
+ ];
22
+
23
+ /**
24
+ * {@inheritDoc}
25
+ */
26
+ protected $post_types = [
27
+ Order::POSTTYPE
28
+ ];
29
+
30
+ /**
31
+ * {@inheritDoc}
32
+ */
33
+ public function handle( Status_Interface $new_status, $old_status, \WP_Post $post ) {
34
+ $i = true;
35
+ }
36
+ }
src/Tickets/Commerce/Flag_Actions/Increase_Stock.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Flag_Actions;
4
+
5
+ use TEC\Tickets\Commerce\Order;
6
+ use TEC\Tickets\Commerce\Status\Status_Interface;
7
+
8
+ /**
9
+ * Class Increase_Stock
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce\Flag_Actions
14
+ */
15
+ class Increase_Stock extends Flag_Action_Abstract {
16
+ /**
17
+ * {@inheritDoc}
18
+ */
19
+ protected $flags = [
20
+ 'increase_stock',
21
+ ];
22
+
23
+ /**
24
+ * {@inheritDoc}
25
+ */
26
+ protected $post_types = [
27
+ Order::POSTTYPE
28
+ ];
29
+
30
+ /**
31
+ * {@inheritDoc}
32
+ */
33
+ public function handle( Status_Interface $new_status, $old_status, \WP_Post $post ) {
34
+ $i = true;
35
+ }
36
+ }
src/Tickets/Commerce/Gateways/Abstract_Gateway.php CHANGED
@@ -8,7 +8,7 @@
8
 
9
  namespace TEC\Tickets\Commerce\Gateways;
10
 
11
- use Tribe__Tickets__Commerce__PayPal__Main as PayPal_Main;
12
 
13
  /**
14
  * The gateway related functionality.
@@ -33,15 +33,18 @@ abstract class Abstract_Gateway implements Interface_Gateway {
33
  return static::$key;
34
  }
35
 
 
 
 
 
 
 
 
36
  /**
37
  * @inheritDoc
38
  */
39
  public function register_gateway( array $gateways ) {
40
- $gateways[ static::get_key() ] = [
41
- 'label' => static::get_label(),
42
- 'class' => static::class,
43
- 'object' => $this,
44
- ];
45
 
46
  return $gateways;
47
  }
8
 
9
  namespace TEC\Tickets\Commerce\Gateways;
10
 
11
+ use TEC\Tickets\Commerce;
12
 
13
  /**
14
  * The gateway related functionality.
33
  return static::$key;
34
  }
35
 
36
+ /**
37
+ * @inheritDoc
38
+ */
39
+ public static function get_provider_key() {
40
+ return Commerce::PROVIDER . '-' . static::get_key();
41
+ }
42
+
43
  /**
44
  * @inheritDoc
45
  */
46
  public function register_gateway( array $gateways ) {
47
+ $gateways[ static::get_key() ] = $this;
 
 
 
 
48
 
49
  return $gateways;
50
  }
src/Tickets/Commerce/Gateways/Interface_Gateway.php CHANGED
@@ -15,10 +15,19 @@ interface Interface_Gateway {
15
  *
16
  * @since 5.1.6
17
  *
18
- * @return bool Whether the provider is active.
19
  */
20
  public static function get_key();
21
 
 
 
 
 
 
 
 
 
 
22
  /**
23
  * Get's the label for this Commerce Gateway.
24
  *
@@ -53,7 +62,7 @@ interface Interface_Gateway {
53
  *
54
  * @param array $gateways The list of registered Tickets Commerce gateways.
55
  *
56
- * @return array The list of registered Tickets Commerce gateways.
57
  */
58
  public function register_gateway( array $gateways );
59
  }
15
  *
16
  * @since 5.1.6
17
  *
18
+ * @return string What is the Key used.
19
  */
20
  public static function get_key();
21
 
22
+ /**
23
+ * Get's the provider key for this Commerce Gateway.
24
+ *
25
+ * @since 5.1.9
26
+ *
27
+ * @return string What is the ORM Provider Key used.
28
+ */
29
+ public static function get_provider_key();
30
+
31
  /**
32
  * Get's the label for this Commerce Gateway.
33
  *
62
  *
63
  * @param array $gateways The list of registered Tickets Commerce gateways.
64
  *
65
+ * @return Abstract_Gateway[] The list of registered Tickets Commerce gateways.
66
  */
67
  public function register_gateway( array $gateways );
68
  }
src/Tickets/Commerce/Gateways/Legacy/Gateway.php DELETED
@@ -1,106 +0,0 @@
1
- <?php
2
- /**
3
- *
4
- * @todo This file is not being used currently but we need to remove this before we launch Tickets Commerce.
5
- *
6
- * @since 5.1.6
7
- *
8
- * @package TEC\Tickets\Commerce\Gateways\Legacy
9
- */
10
-
11
- namespace TEC\Tickets\Commerce\Gateways\Legacy;
12
-
13
- use TEC\Tickets\Commerce\Gateways\Abstract_Gateway;
14
- use TEC\Tickets\Commerce\Gateways\Manager;
15
- use Tribe__Tickets__Commerce__PayPal__Main as PayPal_Main;
16
-
17
- /**
18
- * The PayPal Standard (Legacy) specific functionality.
19
- *
20
- * This class will contain everything we can pull out from Tribe__Tickets__Commerce__PayPal__Main that is
21
- * PayPal Standard (Legacy) specific. Anything we can do to split off the logic into this class would be helpful for
22
- * long term maintenance and reducing mess between the various Tickets Commerce gateways developed.
23
- *
24
- * @since 5.1.6
25
- * @package TEC\Tickets\Commerce\Gateways\PayPal_Legacy
26
- */
27
- class Gateway extends Abstract_Gateway {
28
-
29
- /**
30
- * @inheritDoc
31
- */
32
- protected static $key = 'paypal-legacy';
33
-
34
- /**
35
- * @inheritDoc
36
- */
37
- public static function get_label() {
38
- return __( 'PayPal Standard (Legacy)', 'event-tickets' );
39
- }
40
-
41
- /**
42
- * @inheritDoc
43
- */
44
- public static function is_active() {
45
- // If this gateway shouldn't be shown, then don't change the active status.
46
- if ( ! static::should_show() ) {
47
- return false;
48
- }
49
-
50
- /** @var \Tribe__Tickets__Commerce__PayPal__Gateway $gateway */
51
- $gateway = tribe( 'tickets.commerce.paypal.gateway' );
52
-
53
- /** @var \Tribe__Tickets__Commerce__PayPal__Handler__Interface $handler */
54
- $handler = $gateway->build_handler();
55
-
56
- // Only mark as active if config status is complete.
57
- return 'complete' === $handler->get_config_status();
58
- }
59
-
60
- /**
61
- * @inheritDoc
62
- */
63
- public static function should_show() {
64
- /**
65
- * @todo for we just dont show legacy for testing purposes.
66
- */
67
- if ( ! tribe( Manager::class )->should_show_legacy() ) {
68
- return false;
69
- }
70
-
71
- // This site installed Event Tickets 5.2+ so it never should show the old option.
72
- if ( ! tribe_installed_before( 'Tribe__Tickets__Main', '5.2' ) ) {
73
- return false;
74
- }
75
-
76
- // @todo Future: Disable gateway if it does not match the current gateway as the next step down the road.
77
- /*if ( $this->gateway_key !== tribe_get_option( $commerce->option_gateway ) ) {
78
- return false;
79
- }*/
80
-
81
- // Tribe Commerce was previously enabled.
82
- $paypal_enable = tribe_is_truthy( tribe_get_option( 'ticket-paypal-enable' ) );
83
-
84
- // Tribe Commerce PayPal email was previously set.
85
- $paypal_email_is_set = '' !== tribe_get_option( 'ticket-paypal-email' );
86
-
87
- // The gateway should show if it was ever enabled or email was previously set.
88
- if ( $paypal_enable || $paypal_email_is_set ) {
89
- return true;
90
- }
91
-
92
- // Default this gateway to off.
93
- return false;
94
- }
95
-
96
- /**
97
- * @inheritDoc
98
- */
99
- public function get_settings() {
100
- /** @var Settings $settings */
101
- $settings = tribe( Settings::class );
102
-
103
- return $settings->get_settings();
104
- }
105
-
106
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/Legacy/Provider.php DELETED
@@ -1,97 +0,0 @@
1
- <?php
2
- /**
3
- *
4
- * @todo This file is not being used currently but we need to remove this before we launch Tickets Commerce.
5
- *
6
- * @since 5.1.6
7
- *
8
- * @package TEC\Tickets\Commerce\Gateways\Legacy
9
- */
10
-
11
- namespace TEC\Tickets\Commerce\Gateways\Legacy;
12
-
13
- use tad_DI52_ServiceProvider;
14
-
15
- /**
16
- * Service provider for the Tickets Commerce: PayPal Standard (Legacy) gateway.
17
- *
18
- * @since 5.1.6
19
- * @package Tribe\Tickets\Commerce\Tickets_Commerce\Gateways\PayPal_Legacy
20
- */
21
- class Provider extends tad_DI52_ServiceProvider {
22
-
23
- /**
24
- * Register the provider singletons.
25
- *
26
- * @since 5.1.6
27
- */
28
- public function register() {
29
- /**
30
- * Allow filtering whether the PayPal Legacy classes should be registered.
31
- *
32
- * @since 5.1.6
33
- *
34
- * @param bool $should_register Whether the PayPal Legacy classes should be registered.
35
- */
36
- $should_register = apply_filters( 'tribe_tickets_commerce_gateways_paypal_legacy_should_register', true );
37
-
38
- // Check whether we should continue registering the gateway classes.
39
- if ( false === $should_register ) {
40
- return;
41
- }
42
-
43
- $this->container->singleton( Gateway::class );
44
- $this->container->singleton( Settings::class );
45
-
46
- // @todo Determine what is still needed for PayPal Commerce to function.
47
-
48
- tribe_singleton( 'tickets.commerce.paypal.gateway', 'Tribe__Tickets__Commerce__PayPal__Gateway', [ 'build_handler' ] );
49
- tribe_singleton( 'tickets.commerce.paypal.notices', 'Tribe__Tickets__Commerce__PayPal__Notices' );
50
- tribe_singleton( 'tickets.commerce.paypal.endpoints', 'Tribe__Tickets__Commerce__PayPal__Endpoints', [ 'hook' ] );
51
- tribe_singleton( 'tickets.commerce.paypal.endpoints.templates.success', 'Tribe__Tickets__Commerce__PayPal__Endpoints__Success_Template' );
52
- tribe_singleton( 'tickets.commerce.paypal.orders.tabbed-view', 'Tribe__Tickets__Commerce__Orders_Tabbed_View' );
53
- tribe_singleton( 'tickets.commerce.paypal.orders.report', 'Tribe__Tickets__Commerce__PayPal__Orders__Report' );
54
- tribe_singleton( 'tickets.commerce.paypal.orders.sales', 'Tribe__Tickets__Commerce__PayPal__Orders__Sales' );
55
- tribe_singleton( 'tickets.commerce.paypal.screen-options', 'Tribe__Tickets__Commerce__PayPal__Screen_Options', [ 'hook' ] );
56
- tribe_singleton( 'tickets.commerce.paypal.stati', 'Tribe__Tickets__Commerce__PayPal__Stati' );
57
- tribe_singleton( 'tickets.commerce.paypal.currency', 'Tribe__Tickets__Commerce__Currency', [ 'hook' ] );
58
- tribe_singleton( 'tickets.commerce.paypal.links', 'Tribe__Tickets__Commerce__PayPal__Links' );
59
- tribe_singleton( 'tickets.commerce.paypal.oversell.policies', 'Tribe__Tickets__Commerce__PayPal__Oversell__Policies' );
60
- tribe_singleton( 'tickets.commerce.paypal.oversell.request', 'Tribe__Tickets__Commerce__PayPal__Oversell__Request' );
61
- tribe_singleton( 'tickets.commerce.paypal.frontend.tickets-form', 'Tribe__Tickets__Commerce__PayPal__Frontend__Tickets_Form' );
62
- tribe_register( 'tickets.commerce.paypal.cart', 'Tribe__Tickets__Commerce__PayPal__Cart__Unmanaged' );
63
-
64
- tribe()->tag( [
65
- 'tickets.commerce.paypal.shortcodes.tpp-success' => 'Tribe__Tickets__Commerce__PayPal__Shortcodes__Success',
66
- ], 'tpp-shortcodes' );
67
-
68
- $this->hooks();
69
- }
70
-
71
- /**
72
- * Add actions and filters.
73
- *
74
- * @since 5.1.6
75
- */
76
- protected function hooks() {
77
- add_filter( 'tec_tickets_commerce_gateways', [ $this, 'filter_add_gateway' ], 10, 2 );
78
-
79
- add_action( 'init', tribe_callback( 'tickets.commerce.paypal.orders.report', 'hook' ) );
80
-
81
- // @todo The add_shortcode stuff should be in an init action.
82
- /** @var \Tribe__Tickets__Commerce__PayPal__Shortcodes__Interface $shortcode */
83
- foreach ( tribe()->tagged( 'tpp-shortcodes' ) as $shortcode ) {
84
- add_shortcode( $shortcode->tag(), [ $shortcode, 'render' ] );
85
- }
86
-
87
- tribe( 'tickets.commerce.paypal.gateway' );
88
- tribe( 'tickets.commerce.paypal.orders.report' );
89
- tribe( 'tickets.commerce.paypal.screen-options' );
90
- tribe( 'tickets.commerce.paypal.endpoints' );
91
- tribe( 'tickets.commerce.paypal.currency' );
92
- }
93
-
94
- public function filter_add_gateway( array $gateways = [] ) {
95
- return $this->container->make( Gateway::class )->register_gateway( $gateways );
96
- }
97
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/Legacy/Settings.php DELETED
@@ -1,201 +0,0 @@
1
- <?php
2
- /**
3
- *
4
- * @todo This file is not being used currently but we need to remove this before we launch Tickets Commerce.
5
- *
6
- * @since 5.1.6
7
- *
8
- * @package TEC\Tickets\Commerce\Gateways\Legacy
9
- */
10
-
11
- namespace TEC\Tickets\Commerce\Gateways\Legacy;
12
-
13
- use TEC\Tickets\Commerce\Abstract_Settings;
14
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models\MerchantDetail;
15
-
16
- /**
17
- * The PayPal Standard (Legacy) specific settings.
18
- *
19
- * This class will contain all of the settings handling and admin settings config implementation from
20
- * Tribe__Tickets__Commerce__PayPal__Main that is PayPal Standard (Legacy) specific.
21
- *
22
- * @since 5.1.6
23
- * @package Tribe\Tickets\Commerce\Tickets_Commerce\Gateways\PayPal_Legacy
24
- */
25
- class Settings extends Abstract_Settings {
26
-
27
- /**
28
- * The option key for email.
29
- *
30
- * @since 5.1.6
31
- *
32
- * @var string
33
- */
34
- public $option_email = 'ticket-paypal-email';
35
-
36
- /**
37
- * The option key for IPN enabled.
38
- *
39
- * @since 5.1.6
40
- *
41
- * @var string
42
- */
43
- public $option_ipn_enabled = 'ticket-paypal-ipn-enabled';
44
-
45
- /**
46
- * The option key for IPN address set.
47
- *
48
- * @since 5.1.6
49
- *
50
- * @var string
51
- */
52
- public $option_ipn_address_set = 'ticket-paypal-ipn-address-set';
53
-
54
- /**
55
- * The option key for IPN notify URL.
56
- *
57
- * @since 5.1.6
58
- *
59
- * @var string
60
- */
61
- public $option_ipn_notify_url = 'ticket-paypal-notify-url';
62
-
63
- /**
64
- * Get the list of settings for the gateway.
65
- *
66
- * @since 5.1.6
67
- *
68
- * @return array The list of settings for the gateway.
69
- */
70
- public function get_settings() {
71
- $home_url = home_url();
72
-
73
- // The KB article URL will change depending on whether ET+ is active or not.
74
- $paypal_setup_kb_url = class_exists( 'Tribe__Tickets_Plus__Main' ) ? 'https://evnt.is/19yk' : 'https://evnt.is/19yj';
75
- $paypal_setup_kb_link = sprintf(
76
- '<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
77
- esc_url( $paypal_setup_kb_url ),
78
- esc_html__( 'these instructions', 'event-tickets' )
79
- );
80
- $paypal_setup_note = sprintf(
81
- // Translators: %1$s: The word "ticket" in lowercase, %2$s: The "these instructions" link.
82
- esc_html_x( 'Ie Tickets Commerce to sell %1$s, you must configure your PayPal account to communicate with your WordPress site. If you need help getting set up, follow %2$s', 'tickets fields settings PayPal setup', 'event-tickets' ),
83
- esc_html( tribe_get_ticket_label_singular_lowercase( 'tickets_fields_settings_paypal_setup' ) ),
84
- $paypal_setup_kb_link
85
- );
86
-
87
- $ipn_setup_site_link = sprintf(
88
- '<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
89
- esc_url( $home_url ),
90
- esc_html( $home_url )
91
- );
92
- $ipn_setup_site_address = sprintf(
93
- // Translators: %s: The site link.
94
- esc_html__( 'Your site address is: %s', 'event-tickets' ),
95
- $ipn_setup_site_link
96
- );
97
- $ipn_setup_line = sprintf(
98
- '<span class="clear">%s</span><span class="clear">%s</span>',
99
- esc_html__( "Have you entered this site's address in the Notification URL field in IPN Settings?", 'event-tickets' ),
100
- $ipn_setup_site_address
101
- );
102
-
103
- /** @var \Tribe__Tickets__Commerce__PayPal__Handler__IPN $ipn_handler */
104
- $ipn_handler = tribe( 'tickets.commerce.paypal.handler.ipn' );
105
-
106
- $ipn_config_status = sprintf(
107
- '<strong>%1$s <span id="paypal-ipn-config-status" data-status="%2$s">%3$s</span></strong><p class="description"><i>%4$s</i></p>',
108
- esc_html__( 'PayPal configuration status:', 'event-tickets' ),
109
- esc_attr( $ipn_handler->get_config_status( 'slug' ) ),
110
- esc_html( $ipn_handler->get_config_status( 'label' ) ),
111
- esc_html__( 'For help creating and configuring your account, call PayPal at 1-844-720-4038 (USA)', 'event-tickets' )
112
- );
113
-
114
- $settings = [
115
- 'ticket-paypal-configure' => [
116
- 'type' => 'wrapped_html',
117
- 'label' => esc_html__( 'Configure PayPal Legacy:', 'event-tickets' ),
118
- 'html' => '<p>' . $paypal_setup_note . '</p>',
119
- 'validation_type' => 'html',
120
- ],
121
- $this->option_email => [
122
- 'type' => 'email',
123
- 'label' => esc_html__( 'PayPal email to receive payments:', 'event-tickets' ),
124
- 'size' => 'large',
125
- 'default' => '',
126
- 'validation_type' => 'email',
127
- 'class' => 'indent light-bordered checkmark checkmark-right checkmark-hide ipn-required',
128
- ],
129
- $this->option_ipn_enabled => [
130
- 'type' => 'radio',
131
- 'label' => esc_html__( "Have you enabled instant payment notifications (IPN) in your PayPal account's Selling Tools?", 'event-tickets' ),
132
- 'options' => [
133
- 'yes' => __( 'Yes', 'event-tickets' ),
134
- 'no' => __( 'No', 'event-tickets' ),
135
- ],
136
- 'size' => 'large',
137
- 'default' => 'no',
138
- 'validation_type' => 'options',
139
- 'class' => 'indent light-bordered checkmark checkmark-right checkmark-hide ipn-required',
140
- ],
141
- $this->option_ipn_address_set => [
142
- 'type' => 'radio',
143
- 'label' => $ipn_setup_line,
144
- 'options' => [
145
- 'yes' => __( 'Yes', 'event-tickets' ),
146
- 'no' => __( 'No', 'event-tickets' ),
147
- ],
148
- 'size' => 'large',
149
- 'default' => 'no',
150
- 'validation_type' => 'options',
151
- 'class' => 'indent light-bordered checkmark checkmark-right checkmark-hide ipn-required',
152
- ],
153
- 'ticket-paypal-ipn-config-status' => [
154
- 'type' => 'wrapped_html',
155
- 'html' => $ipn_config_status,
156
- 'size' => 'large',
157
- 'default' => 'no',
158
- 'validation_type' => 'html',
159
- 'class' => 'indent light-bordered',
160
- ],
161
- ];
162
-
163
- if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
164
- /** @var \Tribe__Tickets__Commerce__PayPal__Links $paypal_links */
165
- $paypal_links = tribe( 'tickets.commerce.paypal.links' );
166
-
167
- $ipn_notify_note = sprintf(
168
- // Translators: %s: The PayPal notification history link.
169
- esc_html__( 'You can see and manage your IPN Notifications history from the IPN Notifications settings area (%s).', 'event-tickets' ),
170
- // The following string is returned already escaped.
171
- $paypal_links->ipn_notification_history( 'tag' )
172
- );
173
-
174
- $ipn_notify_url_tooltip = sprintf(
175
- // Translators: %s: The PayPal notification settings link.
176
- esc_html__( 'Override the default IPN notify URL with this value. This value must be the same set in PayPal IPN Notifications settings area (%s).', 'event-tickets' ),
177
- // The following string is returned already escaped.
178
- $paypal_links->ipn_notification_settings( 'tag' )
179
- );
180
-
181
- $settings['ticket-paypal-notify-history'] = [
182
- 'type' => 'wrapped_html',
183
- 'html' => '<p>' . $ipn_notify_note . '</p>',
184
- 'size' => 'medium',
185
- 'validation_type' => 'html',
186
- 'class' => 'indent light-bordered',
187
- ];
188
-
189
- $settings[ $this->option_ipn_notify_url ] = [
190
- 'type' => 'text',
191
- 'label' => esc_html__( 'IPN Notify URL', 'event-tickets' ),
192
- 'tooltip' => $ipn_notify_url_tooltip,
193
- 'default' => $home_url,
194
- 'validation_type' => 'html',
195
- ];
196
- }
197
-
198
- return $settings;
199
- }
200
-
201
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/Manager.php CHANGED
@@ -42,7 +42,7 @@ class Manager {
42
  *
43
  * @since 5.1.6
44
  *
45
- * @return array The list of registered Tickets Commerce gateways.
46
  */
47
  public function get_gateways() {
48
  /**
@@ -53,7 +53,7 @@ class Manager {
53
  *
54
  * @since 5.1.6
55
  *
56
- * @param array $gateways The list of registered Tickets Commerce gateways.
57
  */
58
  return (array) apply_filters( 'tec_tickets_commerce_gateways', [] );
59
  }
@@ -66,7 +66,7 @@ class Manager {
66
  * @return string The current Tickets Commerce gateway.
67
  */
68
  public function get_current_gateway() {
69
- $default = Legacy\Gateway::get_key();
70
 
71
  if ( ! $this->should_show_legacy() ) {
72
  $default = PayPal\Gateway::get_key();
@@ -74,4 +74,47 @@ class Manager {
74
 
75
  return (string) tribe_get_option( static::$option_gateway, $default );
76
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  }
42
  *
43
  * @since 5.1.6
44
  *
45
+ * @return Abstract_Gateway[] The list of registered Tickets Commerce gateways.
46
  */
47
  public function get_gateways() {
48
  /**
53
  *
54
  * @since 5.1.6
55
  *
56
+ * @param Abstract_Gateway[] $gateways The list of registered Tickets Commerce gateways.
57
  */
58
  return (array) apply_filters( 'tec_tickets_commerce_gateways', [] );
59
  }
66
  * @return string The current Tickets Commerce gateway.
67
  */
68
  public function get_current_gateway() {
69
+ $default = null;
70
 
71
  if ( ! $this->should_show_legacy() ) {
72
  $default = PayPal\Gateway::get_key();
74
 
75
  return (string) tribe_get_option( static::$option_gateway, $default );
76
  }
77
+
78
+ /**
79
+ * Get the gateway settings from all gateways.
80
+ *
81
+ * @since 5.1.9
82
+ *
83
+ * @return array[]
84
+ */
85
+ public function get_gateway_settings() {
86
+ $gateways = $this->get_gateways();
87
+
88
+ $gateway_setting_groups = [];
89
+
90
+ // Get all of the gateway settings.
91
+ foreach ( $gateways as $gateway_key => $gateway ) {
92
+ if ( ! $gateway::should_show() ) {
93
+ continue;
94
+ }
95
+
96
+ // Get the gateway settings.
97
+ $gateway_settings = $gateway->get_settings();
98
+
99
+ // If there are no gateway settings, don't show this section at all.
100
+ if ( empty( $gateway_settings ) ) {
101
+ continue;
102
+ }
103
+
104
+ $heading = [
105
+ 'tickets-commerce-' . $gateway_key => [
106
+ 'type' => 'wrapped_html',
107
+ 'html' => '<h3 class="event-tickets--admin_settings_subheading">' . $gateway::get_label() . '</h3>',
108
+ 'validation_type' => 'html',
109
+ ],
110
+ ];
111
+
112
+ // Add the gateway label to the start of settings.
113
+ $gateway_setting_groups[] = $heading;
114
+
115
+ $gateway_setting_groups[] = $gateway_settings;
116
+ }
117
+
118
+ return array_merge( ...$gateway_setting_groups );
119
+ }
120
  }
src/Tickets/Commerce/Gateways/PayPal/AjaxRequestHandler.php DELETED
@@ -1,316 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
-
5
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models\MerchantDetail;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\PayPalAuth;
7
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\PayPalOrder;
8
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\RefreshToken;
9
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\MerchantDetails;
10
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\Webhooks;
11
-
12
- // @todo Bring this over.
13
-
14
- /**
15
- * Class AjaxRequestHandler
16
- *
17
- * @package TEC\Tickets\Commerce\Gateways\PayPal
18
- *
19
- * @since 5.1.6
20
- */
21
- class AjaxRequestHandler {
22
-
23
- /**
24
- * @since 5.1.6
25
- *
26
- * @var Webhooks
27
- */
28
- private $webhooksRepository;
29
-
30
- /**
31
- * @since 5.1.6
32
- *
33
- * @var MerchantDetail
34
- */
35
- private $merchantDetails;
36
-
37
- /**
38
- * @since 5.1.6
39
- *
40
- * @var PayPalAuth
41
- */
42
- private $payPalAuth;
43
-
44
- /**
45
- * @since 5.1.6
46
- *
47
- * @var MerchantDetails
48
- */
49
- private $merchantRepository;
50
-
51
- /**
52
- * @since 5.1.6
53
- *
54
- * @var Connect_Client
55
- */
56
- private $refreshToken;
57
-
58
- /**
59
- * @since 5.1.6
60
- *
61
- * @var Settings
62
- */
63
- private $settings;
64
-
65
- /**
66
- * AjaxRequestHandler constructor.
67
- *
68
- * @since 5.1.6
69
- *
70
- * @param Webhooks $webhooksRepository
71
- * @param MerchantDetail $merchantDetails
72
- * @param MerchantDetails $merchantRepository
73
- * @param RefreshToken $refreshToken
74
- * @param Settings $settings
75
- * @param PayPalAuth $payPalAuth
76
- */
77
- public function __construct(
78
- Webhooks $webhooksRepository,
79
- MerchantDetail $merchantDetails,
80
- MerchantDetails $merchantRepository,
81
- RefreshToken $refreshToken,
82
- Settings $settings,
83
- PayPalAuth $payPalAuth
84
- ) {
85
- $this->webhooksRepository = $webhooksRepository;
86
- $this->merchantDetails = $merchantDetails;
87
- $this->merchantRepository = $merchantRepository;
88
- $this->refreshToken = $refreshToken;
89
- $this->settings = $settings;
90
- $this->payPalAuth = $payPalAuth;
91
- }
92
-
93
- /**
94
- * give_paypal_commerce_user_onboarded ajax action handler
95
- *
96
- * @since 5.1.6
97
- */
98
- public function onBoardedUserAjaxRequestHandler() {
99
- $this->validateAdminRequest();
100
-
101
- $partnerLinkInfo = $this->settings->get_partner_link_details();
102
-
103
- $payPalResponse = $this->payPalAuth->getTokenFromAuthorizationCode(
104
- tribe_get_request_var( 'sharedId' ),
105
- tribe_get_request_var( 'authCode' ),
106
- $partnerLinkInfo['nonce']
107
- );
108
-
109
- if ( ! $payPalResponse || array_key_exists( 'error', $payPalResponse ) ) {
110
- wp_send_json_error( __( 'Unexpected response from PayPal when onboarding', 'event-tickets' ) );
111
- }
112
-
113
- $this->settings->update_access_token( $payPalResponse );
114
-
115
- tribe( RefreshToken::class )->registerCronJobToRefreshToken( $payPalResponse['expires_in'] );
116
-
117
- wp_send_json_success( __( 'PayPal account onboarded', 'event-tickets' ) );
118
- }
119
-
120
- /**
121
- * give_paypal_commerce_get_partner_url action handler
122
- *
123
- * @since 5.1.6
124
- */
125
- public function onGetPartnerUrlAjaxRequestHandler() {
126
- $this->validateAdminRequest();
127
-
128
- $country_code = tribe_get_request_var( 'countryCode' );
129
-
130
- /** @var \Tribe__Languages__Locations $locations */
131
- $locations = tribe( 'languages.locations' );
132
- $countries = $locations->get_countries();
133
-
134
- // Check for a valid country.
135
- if ( empty( $country_code ) || ! isset( $countries[ $country_code ] ) ) {
136
- wp_send_json_error( __( 'Must include valid 2-character country code', 'event-tickets' ) );
137
- }
138
-
139
- /** @var Tribe__Settings $settings */
140
- $settings = tribe( 'settings' );
141
-
142
- // Get link to Tickets Tab.
143
- $settings_url = $settings->get_url( [
144
- 'page' => 'tribe-common',
145
- 'tab' => 'event-tickets',
146
- 'tickets-commerce-connected' => '1',
147
- ] );
148
-
149
- // @todo They ultimately need to get here.
150
- // . '#tribe-field-tickets-commerce-paypal-commerce';
151
-
152
- $partner_link_details = $this->payPalAuth->getSellerPartnerLink(
153
- // @todo Replace this URL.
154
- $settings_url,
155
- $country_code
156
- );
157
-
158
- if ( ! $partner_link_details ) {
159
- wp_send_json_error( __( 'Partner details not found', 'event-tickets' ) );
160
- }
161
-
162
- $this->settings->update_account_country( $country_code );
163
- $this->settings->update_partner_link_details( $partner_link_details );
164
-
165
- wp_send_json_success( $partner_link_details );
166
- }
167
-
168
- /**
169
- * give_paypal_commerce_disconnect_account ajax request handler.
170
- *
171
- * @since 5.1.6
172
- */
173
- public function removePayPalAccount() {
174
- $this->validateAdminRequest();
175
-
176
- // Remove the webhook from PayPal if there is one
177
- if ( $webhookConfig = $this->webhooksRepository->getWebhookConfig() ) {
178
- $this->webhooksRepository->deleteWebhook( $this->merchantDetails->accessToken, $webhookConfig->id );
179
- $this->webhooksRepository->deleteWebhookConfig();
180
- }
181
-
182
- $this->merchantRepository->delete();
183
- $this->merchantRepository->deleteAccountErrors();
184
- $this->merchantRepository->deleteClientToken();
185
- $this->refreshToken->deleteRefreshTokenCronJob();
186
-
187
- wp_send_json_success( __( 'PayPal account disconnected', 'event-tickets' ) );
188
- }
189
-
190
- /**
191
- * Create order.
192
- *
193
- * @since 5.1.6
194
- * @todo : handle payment create error on frontend.
195
- *
196
- */
197
- public function createOrder() {
198
- // @todo Set up the order with our own custom code.
199
-
200
- $this->validateFrontendRequest();
201
-
202
- $postData = give_clean( $_POST );
203
- $formId = absint( tribe_get_request_var( 'give-form-id' ) );
204
-
205
- $data = [
206
- 'formId' => $formId,
207
- 'formTitle' => give_payment_gateway_item_title( [ 'post_data' => $postData ], 127 ),
208
- 'paymentAmount' => isset( $postData['give-amount'] ) ? (float) apply_filters( 'give_payment_total', give_maybe_sanitize_amount( $postData['give-amount'], [ 'currency' => give_get_currency( $formId ) ] ) ) : '0.00',
209
- 'payer' => [
210
- 'firstName' => $postData['give_first'],
211
- 'lastName' => $postData['give_last'],
212
- 'email' => $postData['give_email'],
213
- ],
214
- 'application_context' => [
215
- 'shipping_preference' => 'NO_SHIPPING',
216
- ],
217
- ];
218
-
219
- try {
220
- $result = tribe( PayPalOrder::class )->createOrder( $data );
221
-
222
- wp_send_json_success(
223
- [
224
- 'id' => $result,
225
- ]
226
- );
227
- } catch ( \Exception $ex ) {
228
- wp_send_json_error(
229
- [
230
- 'error' => json_decode( $ex->getMessage(), true ),
231
- ]
232
- );
233
- }
234
- }
235
-
236
- /**
237
- * Approve order.
238
- *
239
- * @since 5.1.6
240
- * @todo : handle payment capture error on frontend.
241
- *
242
- */
243
- public function approveOrder() {
244
- $this->validateFrontendRequest();
245
-
246
- $orderId = absint( tribe_get_request_var( 'order' ) );
247
-
248
- // @todo Handle our own order approval process.
249
-
250
- try {
251
- $result = tribe( PayPalOrder::class )->approveOrder( $orderId );
252
-
253
- wp_send_json_success(
254
- [
255
- 'order' => $result,
256
- ]
257
- );
258
- } catch ( \Exception $ex ) {
259
- wp_send_json_error(
260
- [
261
- 'error' => json_decode( $ex->getMessage(), true ),
262
- ]
263
- );
264
- }
265
- }
266
-
267
- /**
268
- * Return on boarding trouble notice.
269
- *
270
- * @since 5.1.6
271
- */
272
- public function onBoardingTroubleNotice() {
273
- $this->validateAdminRequest();
274
-
275
- $actionList = sprintf(
276
- '<ol><li>%1$s</li><li>%2$s</li><li>%3$s %4$s</li></ol>',
277
- esc_html__( 'Make sure to complete the entire PayPal process. Do not close the window you have finished the process.', 'event-tickets' ),
278
- esc_html__( 'The last screen of the PayPal connect process includes a button to be sent back to your site. It is important you click this and do not close the window yourself.', 'event-tickets' ),
279
- esc_html__( 'If you’re still having problems connecting:', 'event-tickets' ),
280
- $this->settings->get_guidance_html()
281
- );
282
-
283
- $standardError = sprintf(
284
- '<div id="give-paypal-onboarding-trouble-notice" class="tribe-common-a11y-hidden"><p class="error-message">%1$s</p><p>%2$s</p></div>',
285
- esc_html__( 'Having trouble connecting to PayPal?', 'event-tickets' ),
286
- $actionList
287
- );
288
-
289
- wp_send_json_success( $standardError );
290
- }
291
-
292
- /**
293
- * Validate admin ajax request.
294
- *
295
- * @since 5.1.6
296
- */
297
- private function validateAdminRequest() {
298
- // @todo Add our own capacity check.
299
- if ( ! current_user_can( 'manage_options' ) ) {
300
- wp_send_json_error( __( 'Access not allowed', 'event-tickets' ), 401 );
301
- }
302
- }
303
-
304
- /**
305
- * Validate frontend ajax request.
306
- *
307
- * @since 5.1.6
308
- */
309
- private function validateFrontendRequest() {
310
- $formId = absint( $_POST['give-form-id'] );
311
-
312
- if ( ! $formId || ! give_verify_payment_form_nonce( give_clean( $_POST['give-form-hash'] ), $formId ) ) {
313
- wp_die();
314
- }
315
- }
316
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/PayPal/Ajax_Request_Handler.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
+
5
+ use TEC\Tickets\Commerce\Gateways\PayPal\Repositories\Order;
6
+ use TEC\Tickets\Commerce\Gateways\PayPal\Repositories\Webhooks;
7
+
8
+ /**
9
+ * Class Ajax_Request_Handler
10
+ *
11
+ * @todo This whole file will stop exsiting once we deprecate all Give's code usage.
12
+ *
13
+ * @since 5.1.6
14
+ * @package TEC\Tickets\Commerce\Gateways\PayPal
15
+ *
16
+ */
17
+ class Ajax_Request_Handler {
18
+
19
+ /**
20
+ * Return on boarding trouble notice.
21
+ *
22
+ * @TODO this method needs to be completely refactored into an admin page action.
23
+ *
24
+ * @since 5.1.6
25
+ */
26
+ public function on_boarding_trouble_notice() {
27
+
28
+ $action_list = sprintf(
29
+ '<ol><li>%1$s</li><li>%2$s</li><li>%3$s %4$s</li></ol>',
30
+ esc_html__( 'Make sure to complete the entire PayPal process. Do not close the window you have finished the process.', 'event-tickets' ),
31
+ esc_html__( 'The last screen of the PayPal connect process includes a button to be sent back to your site. It is important you click this and do not close the window yourself.', 'event-tickets' ),
32
+ esc_html__( 'If you’re still having problems connecting:', 'event-tickets' ),
33
+ $this->settings->get_guidance_html()
34
+ );
35
+
36
+ $standard_error = sprintf(
37
+ '<div id="give-paypal-onboarding-trouble-notice" class="tribe-common-a11y-hidden"><p class="error-message">%1$s</p><p>%2$s</p></div>',
38
+ esc_html__( 'Having trouble connecting to PayPal?', 'event-tickets' ),
39
+ $action_list
40
+ );
41
+
42
+ wp_send_json_success( $standard_error );
43
+ }
44
+ }
src/Tickets/Commerce/Gateways/PayPal/Assets.php CHANGED
@@ -2,17 +2,19 @@
2
  /**
3
  * Handles registering and setup for assets on Ticket Commerce.
4
  *
5
- * @since 5.1.6
6
  *
7
  * @package TEC\Tickets\Commerce\Gateways\PayPal
8
  */
9
 
10
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
11
 
 
 
12
  /**
13
  * Class Assets.
14
  *
15
- * @since 5.1.6
16
  *
17
  * @package TEC\Tickets\Commerce\Gateways\PayPal
18
  */
@@ -24,8 +26,9 @@ class Assets extends \tad_DI52_ServiceProvider {
24
  * @since 5.1.6
25
  */
26
  public function register() {
 
27
  tribe_asset(
28
- \Tribe__Tickets__Main::instance(),
29
  'tribe-tickets-admin-commerce-paypal-commerce-partner-js',
30
  $this->get_partner_js_url(),
31
  [],
@@ -64,6 +67,32 @@ class Assets extends \tad_DI52_ServiceProvider {
64
  ],
65
  ]
66
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
 
69
  /**
@@ -74,12 +103,11 @@ class Assets extends \tad_DI52_ServiceProvider {
74
  * @return string
75
  */
76
  private function get_partner_js_url() {
77
- /** @var PayPalClient $client */
78
- $client = tribe( SDK\PayPalClient::class );
79
 
80
  return sprintf(
81
  '%1$swebapps/merchantboarding/js/lib/lightbox/partner.js',
82
- $client->getHomePageUrl()
83
  );
84
  }
85
  }
2
  /**
3
  * Handles registering and setup for assets on Ticket Commerce.
4
  *
5
+ * @since 5.1.6
6
  *
7
  * @package TEC\Tickets\Commerce\Gateways\PayPal
8
  */
9
 
10
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
11
 
12
+ use TEC\Tickets\Commerce\Gateways\PayPal\REST\Order_Endpoint;
13
+
14
  /**
15
  * Class Assets.
16
  *
17
+ * @since 5.1.6
18
  *
19
  * @package TEC\Tickets\Commerce\Gateways\PayPal
20
  */
26
  * @since 5.1.6
27
  */
28
  public function register() {
29
+ $plugin = \Tribe__Tickets__Main::instance();
30
  tribe_asset(
31
+ $plugin,
32
  'tribe-tickets-admin-commerce-paypal-commerce-partner-js',
33
  $this->get_partner_js_url(),
34
  [],
67
  ],
68
  ]
69
  );
70
+
71
+
72
+ tribe_asset(
73
+ $plugin,
74
+ 'tec-tickets-commerce-gateway-paypal-checkout',
75
+ 'commerce/gateway/paypal/checkout.js',
76
+ [
77
+ 'jquery',
78
+ 'tribe-common',
79
+ ],
80
+ null,
81
+ [
82
+ 'groups' => [
83
+ 'tec-tickets-commerce-gateway-paypal',
84
+ ],
85
+ 'localize' => [
86
+ 'name' => 'tecTicketsCommerceGatewayPayPalCheckout',
87
+ 'data' => static function () {
88
+ return [
89
+ 'orderEndpoint' => tribe( Order_Endpoint::class )->get_route_url(),
90
+ ];
91
+ },
92
+ ],
93
+ ]
94
+ );
95
+
96
  }
97
 
98
  /**
103
  * @return string
104
  */
105
  private function get_partner_js_url() {
106
+ $client = tribe( Client::class );
 
107
 
108
  return sprintf(
109
  '%1$swebapps/merchantboarding/js/lib/lightbox/partner.js',
110
+ $client->get_home_page_url()
111
  );
112
  }
113
  }
src/Tickets/Commerce/Gateways/PayPal/Buttons.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
+
5
+ use Tribe__Utils__Array as Arr;
6
+ use TEC\Tickets\Commerce\Module;
7
+
8
+ /**
9
+ * Class Buttons
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce\Gateways\PayPal
14
+ */
15
+ class Buttons {
16
+
17
+ /**
18
+ * Stores the instance of the template engine that we will use for rendering the elements.
19
+ *
20
+ * @since 5.1.9
21
+ *
22
+ * @var \Tribe__Template
23
+ */
24
+ protected $template;
25
+
26
+ /**
27
+ * Gets the template instance used to setup the rendering of the page.
28
+ *
29
+ * @since 5.1.9
30
+ *
31
+ * @return \Tribe__Template
32
+ */
33
+ public function get_template() {
34
+ if ( empty( $this->template ) ) {
35
+ $this->template = new \Tribe__Template();
36
+ $this->template->set_template_origin( \Tribe__Tickets__Main::instance() );
37
+ $this->template->set_template_folder( 'src/views/v2/commerce/gateway/paypal' );
38
+ $this->template->set_template_context_extract( true );
39
+ $this->template->set_template_folder_lookup( true );
40
+ }
41
+
42
+ return $this->template;
43
+ }
44
+
45
+ public function get_checkout_script() {
46
+ $client = tribe( Client::class );
47
+ $client_token_data = $client->get_client_token();
48
+ $must_login = ! is_user_logged_in() && tribe( Module::class )->login_required();
49
+ $template_vars = [
50
+ 'url' => $client->get_js_sdk_url(),
51
+ 'attribution_id' => Gateway::ATTRIBUTION_ID,
52
+ 'client_token' => Arr::get( $client_token_data, 'client_token' ),
53
+ 'client_token_expires_in' => Arr::get( $client_token_data, 'expires_in' ),
54
+ 'must_login' => $must_login,
55
+ ];
56
+
57
+ tribe_asset_enqueue( 'tec-tickets-commerce-gateway-paypal-checkout' );
58
+
59
+ return $this->get_template()->template( 'checkout-script', $template_vars, false );
60
+ }
61
+ }
src/Tickets/Commerce/Gateways/PayPal/Client.php ADDED
@@ -0,0 +1,498 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
+
5
+ use Tribe__Utils__Array as Arr;
6
+
7
+ /**
8
+ * Class Client
9
+ *
10
+ * @since 5.1.6
11
+ * @package TEC\Tickets\Commerce\Gateways\PayPal
12
+ *
13
+ */
14
+ class Client {
15
+ /**
16
+ * Get environment base URL.
17
+ *
18
+ * @since 5.1.9
19
+ *
20
+ * @return string
21
+ */
22
+ public function get_environment_url() {
23
+ $merchant = tribe( Merchant::class );
24
+
25
+ return $merchant->is_sandbox() ?
26
+ 'https://api.sandbox.paypal.com' :
27
+ 'https://api.paypal.com';
28
+ }
29
+
30
+ /**
31
+ * Safely checks if we have an access token to be used.
32
+ *
33
+ * @since 5.1.9
34
+ *
35
+ * @return string
36
+ */
37
+ public function get_access_token() {
38
+ return tribe( Merchant::class )->get_access_token();
39
+ }
40
+
41
+ /**
42
+ * Get REST API endpoint URL for requests.
43
+ *
44
+ * @since 5.1.9
45
+ *
46
+ *
47
+ * @param string $endpoint The endpoint path.
48
+ * @param array $query_args Query args appended to the URL.
49
+ *
50
+ * @return string The API URL.
51
+ *
52
+ */
53
+ public function get_api_url( $endpoint, array $query_args = [] ) {
54
+ $base_url = $this->get_environment_url();
55
+ $endpoint = ltrim( $endpoint, '/' );
56
+
57
+ return add_query_arg( $query_args, "{$base_url}/{$endpoint}" );
58
+ }
59
+
60
+ /**
61
+ * Fetches the JS SDK url.
62
+ *
63
+ * We use something like: https://www.paypal.com/sdk/js?client-id=sb&locale=en_US&components=buttons
64
+ *
65
+ * @since 5.1.9
66
+ *
67
+ * @param array $query_args Which query args will be added.
68
+ *
69
+ * @return string
70
+ */
71
+ public function get_js_sdk_url( array $query_args = [] ) {
72
+ $url = 'https://www.paypal.com/sdk/js';
73
+ $merchant = tribe( Merchant::class );
74
+ $query_args = array_merge( [
75
+ 'client-id' => $merchant->is_sandbox() ? 'sb' : $merchant->get_client_id(),
76
+ 'merchant-id' => $merchant->get_merchant_id_in_paypal(),
77
+ 'components' => 'buttons,hosted-fields',
78
+ 'intent' => 'capture',
79
+ 'currency' => tribe_get_option( \TEC\Tickets\Commerce\Settings::$option_currency_code, 'USD' ),
80
+ ], $query_args );
81
+ $url = add_query_arg( $query_args, $url );
82
+
83
+ /**
84
+ * Filter the PayPal JS SDK url.
85
+ *
86
+ * @since 5.1.9
87
+ *
88
+ * @param string $url Which URL we are going to use to load the SDK JS.
89
+ * @param array $query_args Which URL args will be added to the JS SDK url.
90
+ */
91
+ return apply_filters( 'tec_tickets_commerce_gateway_paypal_js_sdk_url', $url, $query_args );
92
+ }
93
+
94
+ /**
95
+ * Get PayPal homepage url.
96
+ *
97
+ * @since 5.1.6
98
+ *
99
+ * @return string
100
+ */
101
+ public function get_home_page_url() {
102
+ $subdomain = tribe( Merchant::class )->is_sandbox() ? 'sandbox.' : '';
103
+
104
+ return sprintf(
105
+ 'https://%1$spaypal.com/',
106
+ $subdomain
107
+ );
108
+ }
109
+
110
+ /**
111
+ * Send a GET request to the PayPal API.
112
+ *
113
+ * @since 5.1.9
114
+ *
115
+ * @param string $endpoint
116
+ * @param array $query_args
117
+ * @param array $request_arguments
118
+ *
119
+ * @return array|null
120
+ */
121
+ public function get( $endpoint, array $query_args = [], array $request_arguments = [] ) {
122
+ // If the endpoint passed is a full URL dont try to append anything.
123
+ $url = 0 !== strpos( 'https://', $endpoint )
124
+ ? $this->get_api_url( $endpoint, $query_args )
125
+ : add_query_arg( $query_args, $endpoint );
126
+
127
+ $default_arguments = [
128
+ 'headers' => [
129
+ 'Accept' => 'application/json',
130
+ 'Authorization' => sprintf( 'Bearer %1$s', $this->get_access_token() ),
131
+ 'Content-Type' => 'application/json',
132
+ ]
133
+ ];
134
+ foreach ( $default_arguments as $key => $default_argument ) {
135
+ $request_arguments[ $key ] = array_merge( $default_argument, Arr::get( $request_arguments, $key, [] ) );
136
+ }
137
+ $response = wp_remote_get( $url, $request_arguments );
138
+
139
+ if ( is_wp_error( $response ) ) {
140
+ tribe( 'logger' )->log_error( sprintf(
141
+ '[%s] PayPal GET request error: %s',
142
+ $url,
143
+ $response->get_error_message()
144
+ ), 'tickets-commerce-paypal' );
145
+
146
+ return null;
147
+ }
148
+
149
+ $response_code = wp_remote_retrieve_response_code( $response );
150
+
151
+ // When we receive an error code we return the whole response.
152
+ if ( ! in_array( $response_code, [ 200, 201, 202, 204 ], true ) ) {
153
+ return $response;
154
+ }
155
+
156
+ $response = wp_remote_retrieve_body( $response );
157
+ $response = @json_decode( $response, true );
158
+
159
+ if ( ! is_array( $response ) ) {
160
+ tribe( 'logger' )->log_error( sprintf( '[%s] Unexpected PayPal GET response', $url ), 'tickets-commerce-paypal' );
161
+
162
+ return null;
163
+ }
164
+
165
+ return $response;
166
+ }
167
+
168
+ /**
169
+ * Send a POST request to the PayPal API.
170
+ *
171
+ * @since 5.1.9
172
+ *
173
+ * @param string $endpoint
174
+ * @param array $query_args
175
+ * @param array $request_arguments
176
+ *
177
+ * @return array|null
178
+ */
179
+ public function post( $endpoint, array $query_args = [], array $request_arguments = [] ) {
180
+ // If the endpoint passed is a full URL dont try to append anything.
181
+ $url = 0 !== strpos( 'https://', $endpoint )
182
+ ? $this->get_api_url( $endpoint, $query_args )
183
+ : add_query_arg( $query_args, $endpoint );
184
+
185
+ $default_arguments = [
186
+ 'headers' => [
187
+ 'Accept' => 'application/json',
188
+ 'Authorization' => sprintf( 'Bearer %1$s', $this->get_access_token() ),
189
+ 'Content-Type' => 'application/json',
190
+ ],
191
+ 'body' => [],
192
+ ];
193
+ foreach ( $default_arguments as $key => $default_argument ) {
194
+ $request_arguments[ $key ] = array_merge( $default_argument, Arr::get( $request_arguments, $key, [] ) );
195
+ }
196
+
197
+ $content_type = Arr::get( $request_arguments, [ 'headers', 'Content-Type' ] );
198
+ if ( empty( $content_type ) ) {
199
+ $content_type = Arr::get( $request_arguments, [ 'headers', 'content-type' ] );
200
+ }
201
+
202
+ if (
203
+ ! empty( $request_arguments['body'] )
204
+ && 'application/json' === strtolower( $content_type )
205
+ ) {
206
+ $request_arguments['body'] = wp_json_encode( $request_arguments[ $key ] );
207
+ }
208
+
209
+ $response = wp_remote_post( $url, $request_arguments );
210
+
211
+ if ( is_wp_error( $response ) ) {
212
+ tribe( 'logger' )->log_error( sprintf(
213
+ '[%s] PayPal POST request error: %s',
214
+ $url,
215
+ $response->get_error_message()
216
+ ), 'tickets-commerce-paypal' );
217
+
218
+ return null;
219
+ }
220
+
221
+ $response_code = wp_remote_retrieve_response_code( $response );
222
+
223
+ // When we receive an error code we return the whole response.
224
+ if ( ! in_array( $response_code, [ 200, 201, 202, 204 ], true ) ) {
225
+ return $response;
226
+ }
227
+
228
+ $response = wp_remote_retrieve_body( $response );
229
+ $response = @json_decode( $response, true );
230
+
231
+ if ( ! is_array( $response ) ) {
232
+ tribe( 'logger' )->log_error( sprintf( '[%s] Unexpected PayPal POST response', $url ), 'tickets-commerce-paypal' );
233
+
234
+ return null;
235
+ }
236
+
237
+ return $response;
238
+ }
239
+
240
+ /**
241
+ * Retrieves an Access Token for the Client ID and Secret.
242
+ *
243
+ * @since 5.1.9
244
+ *
245
+ * @param string $client_id The Client ID.
246
+ * @param string $client_secret The Client Secret.
247
+ *
248
+ * @return array|null The token details response or null if there was a problem.
249
+ */
250
+ public function get_access_token_from_client_credentials( $client_id, $client_secret ) {
251
+ $auth = base64_encode( "$client_id:$client_secret" );
252
+ $query_args = [];
253
+
254
+ $args = [
255
+ 'headers' => [
256
+ 'Authorization' => sprintf( 'Basic %1$s', $auth ),
257
+ 'Content-Type' => 'application/x-www-form-urlencoded',
258
+ ],
259
+ 'body' => [
260
+ 'grant_type' => 'client_credentials',
261
+ ],
262
+ ];
263
+
264
+ return $this->post( 'v1/oauth2/token', $query_args, $args );
265
+ }
266
+
267
+ /**
268
+ * Retrieves an Access Token from the authorization code.
269
+ *
270
+ * @since 5.1.9
271
+ *
272
+ * @param string $shared_id Shared ID for merchant.
273
+ * @param string $auth_code Authorization code from on boarding.
274
+ * @param string $nonce Seller nonce from on boarding.
275
+ *
276
+ * @return array|null The token details response or null if there was a problem.
277
+ */
278
+ public function get_access_token_from_authorization_code( $shared_id, $auth_code, $nonce ) {
279
+ $auth = base64_encode( $shared_id );
280
+ $query_args = [];
281
+
282
+ $args = [
283
+ 'headers' => [
284
+ 'Authorization' => sprintf( 'Basic %1$s', $auth ),
285
+ 'Content-Type' => 'application/x-www-form-urlencoded',
286
+ ],
287
+ 'body' => [
288
+ 'grant_type' => 'authorization_code',
289
+ 'code' => $auth_code,
290
+ 'code_verifier' => $nonce,
291
+ ],
292
+ ];
293
+
294
+ return $this->post( 'v1/oauth2/token', $query_args, $args );
295
+ }
296
+
297
+ /**
298
+ * Retrieves a Client Token from the stored Access Token.
299
+ *
300
+ * @link https://developer.paypal.com/docs/business/checkout/advanced-card-payments/
301
+ *
302
+ * @since 5.1.9
303
+ *
304
+ * @return array|null The client token details response or null if there was a problem.
305
+ */
306
+ public function get_client_token() {
307
+ $query_args = [];
308
+ $args = [
309
+ 'headers' => [
310
+ 'Accept' => 'application/json',
311
+ 'Accept-Language' => 'en_US',
312
+ 'Authorization' => sprintf( 'Bearer %1$s', $this->get_access_token() ),
313
+ 'Content-Type' => 'application/json',
314
+ ],
315
+ 'body' => [],
316
+ ];
317
+
318
+ return $this->post( 'v1/identity/generate-token', $query_args, $args );
319
+ }
320
+
321
+ /**
322
+ * Based on a Purchase Unit creates a PayPal order.
323
+ *
324
+ * @link https://developer.paypal.com/docs/api/orders/v2/#orders_create
325
+ * @link https://developer.paypal.com/docs/api/orders/v2/#definition-purchase_unit_request
326
+ *
327
+ * @since 5.1.9
328
+ *
329
+ * @param array<string,mixed>|array<array> $units {
330
+ * Purchase unit used to setup the order in PayPal.
331
+ *
332
+ * @type string $reference_id Reference ID to PayPal.
333
+ * @type string $description Description of this Purchase Unit.
334
+ * @type string $value Value to be payed.
335
+ * @type string $currency Which currency.
336
+ * @type string $merchant_id Merchant ID.
337
+ * @type string $merchant_paypal_id PayPal Merchant ID.
338
+ * @type string $first_name Payee First Name.
339
+ * @type string $last_name Payee Last Name.
340
+ * @type string $email Payee email.
341
+ * @type string $disbursement_mode (optional) By default 'INSTANT'.
342
+ * @type string $payer_id (optional) PayPal Payer ID
343
+ * @type string $tax_id (optional) Tax ID for this purchase Unit.
344
+ * @type string $tax_id_type (optional) Tax ID for this purchase Unit.
345
+ *
346
+ * }
347
+ * @return array|null
348
+ */
349
+ public function create_order( array $units = [] ) {
350
+ $merchant = tribe( Merchant::class );
351
+ $query_args = [];
352
+ $body = [
353
+ 'intent' => 'CAPTURE',
354
+ 'purchase_units' => [],
355
+ 'application_context' => [
356
+ 'shipping_preference' => 'NO_SHIPPING',
357
+ 'user_action' => 'PAY_NOW',
358
+ ],
359
+ ];
360
+
361
+ // Determine if this set of units was just a single unit before looping.
362
+ if ( ! empty( $units['reference_id'] ) ) {
363
+ $units = [ $units ];
364
+ }
365
+
366
+ foreach ( $units as $unit ) {
367
+ /**
368
+ * @link https://developer.paypal.com/docs/api/orders/v2/#definition-payer
369
+ */
370
+ $purchase_unit = [
371
+ 'reference_id' => Arr::get( $unit, 'reference_id' ),
372
+ 'description' => Arr::get( $unit, 'description' ),
373
+ 'amount' => [
374
+ 'value' => Arr::get( $unit, 'value' ),
375
+ 'currency_code' => Arr::get( $unit, 'currency' ),
376
+ ],
377
+ 'payee' => [
378
+ 'merchant_id' => Arr::get( $unit, 'merchant_paypal_id', $merchant->get_merchant_id_in_paypal() ),
379
+ ],
380
+ 'payer' => [
381
+ 'name' => [
382
+ 'given_name' => Arr::get( $unit, 'first_name' ),
383
+ 'surname' => Arr::get( $unit, 'last_name' ),
384
+ ],
385
+ 'email_address' => Arr::get( $unit, 'email' ),
386
+
387
+ ],
388
+ 'payment_instruction' => [
389
+ 'disbursement_mode' => Arr::get( $unit, 'disbursement_mode', 'INSTANT' ),
390
+ ],
391
+ ];
392
+
393
+ /**
394
+ * @todo Need to figure out how to get this email address still.
395
+ */
396
+ if ( ! $merchant->is_sandbox() ) {
397
+ $purchase_unit['payee']['email_address'] = Arr::get( $unit, 'merchant_id', $merchant->get_merchant_id() );
398
+ }
399
+
400
+ if ( ! empty( $unit['tax_id'] ) ) {
401
+ $purchase_unit['payer']['tax_info']['tax_id'] = Arr::get( $unit, 'tax_id' );
402
+ }
403
+
404
+ if ( ! empty( $unit['tax_id_type'] ) ) {
405
+ $purchase_unit['payer']['tax_info']['tax_id_type'] = Arr::get( $unit, 'tax_id_type' );
406
+ }
407
+
408
+ /**
409
+ * @todo We should have some sort of Purchase Unit validation here.
410
+ */
411
+
412
+ $body['purchase_units'][] = $purchase_unit;
413
+ }
414
+
415
+ $args = [
416
+ 'headers' => [
417
+ 'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
418
+ 'Prefer' => 'return=representation',
419
+ ],
420
+ 'body' => $body,
421
+ ];
422
+
423
+ $response = $this->post( '/v2/checkout/orders', $query_args, $args );
424
+
425
+ return $response;
426
+ }
427
+
428
+ /**
429
+ * Captures an order for a given ID in PayPal.
430
+ *
431
+ * @since 5.1.9
432
+ *
433
+ * @param string $order_id
434
+ *
435
+ * @return array|null
436
+ */
437
+ public function capture_order( $order_id ) {
438
+ $query_args = [];
439
+ $body = [];
440
+ $args = [
441
+ 'headers' => [
442
+ 'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
443
+ 'Prefer' => 'return=representation',
444
+ ],
445
+ 'body' => $body,
446
+ ];
447
+
448
+ $capture_id = urlencode( $order_id );
449
+ $url = '/v2/checkout/orders/{order_id}/capture';
450
+ $url = str_replace( '{order_id}', $order_id, $url );
451
+ $response = $this->post( $url, $query_args, $args );
452
+
453
+ return $response;
454
+ }
455
+
456
+ /**
457
+ * Gets the profile information from the customer in PayPal.
458
+ *
459
+ * @link https://developer.paypal.com/docs/api/identity/v1/#userinfo_get
460
+ *
461
+ * @since 5.1.9
462
+ *
463
+ * @return array|null
464
+ */
465
+ public function get_user_info() {
466
+ $query_args = [
467
+ 'schema' => 'paypalv1.1',
468
+ ];
469
+ $body = [];
470
+ $args = [];
471
+
472
+ $url = '/v1/identity/oauth2/userinfo';
473
+ $response = $this->get( $url, $query_args, $args );
474
+
475
+ return $response;
476
+ }
477
+
478
+ public function refund_payment( $capture_id ) {
479
+ $query_args = [];
480
+ $body = [];
481
+ $args = [
482
+ 'headers' => [
483
+ 'PayPal-Partner-Attribution-Id' => Gateway::ATTRIBUTION_ID,
484
+ 'Prefer' => 'return=representation',
485
+ ],
486
+ 'body' => $body,
487
+ ];
488
+
489
+ $capture_id = urlencode( $capture_id );
490
+ $url = '/v2/payments/captures/{capture_id}/refund';
491
+ $url = str_replace( '{capture_id}', $capture_id, $url );
492
+ $response = $this->post( $url, $query_args, $args );
493
+
494
+ return $response;
495
+ }
496
+
497
+
498
+ }
src/Tickets/Commerce/Gateways/PayPal/Connect_Client.php DELETED
@@ -1,35 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
-
5
- /**
6
- * Class Connect_Client
7
- *
8
- * @since 5.1.6
9
- *
10
- * @package TEC\Tickets\Commerce\Gateways\PayPal
11
- */
12
- class Connect_Client {
13
-
14
- /**
15
- * The API URL.
16
- *
17
- * @since 5.1.6
18
- *
19
- * @var string
20
- */
21
- public $api_url = 'https://whodat.theeventscalendar.com/tickets/paypal/connect';
22
-
23
- /**
24
- * Get REST API endpoint URL for requests.
25
- *
26
- * @since 5.1.6
27
- *
28
- * @param string $endpoint The endpoint path.
29
- *
30
- * @return string The API URL.
31
- */
32
- public function get_api_url( $endpoint ) {
33
- return "{$this->api_url}/{$endpoint}";
34
- }
35
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/PayPal/Gateway.php CHANGED
@@ -3,8 +3,6 @@
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
 
5
  use TEC\Tickets\Commerce\Gateways\Abstract_Gateway;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\MerchantDetails;
7
- use Tribe__Tickets__Commerce__PayPal__Main as PayPal_Main;
8
 
9
  /**
10
  * Class Gateway
@@ -16,7 +14,7 @@ class Gateway extends Abstract_Gateway {
16
  /**
17
  * @inheritDoc
18
  */
19
- protected static $key = 'paypal-commerce';
20
 
21
  /**
22
  * PayPal attribution ID for requests.
@@ -27,6 +25,17 @@ class Gateway extends Abstract_Gateway {
27
  */
28
  const ATTRIBUTION_ID = 'TheEventsCalendar_SP_PPCP';
29
 
 
 
 
 
 
 
 
 
 
 
 
30
  /**
31
  * @inheritDoc
32
  */
@@ -43,18 +52,7 @@ class Gateway extends Abstract_Gateway {
43
  return false;
44
  }
45
 
46
- /** @var MerchantDetails $merchantDetails */
47
- $merchantDetails = tribe( MerchantDetails::class );
48
-
49
- // Make sure we have details setup.
50
- $merchantDetails->getDetails();
51
-
52
- // @todo Confirm this is the correct conditional.
53
- if ( $merchantDetails->accountIsConnected() ) {
54
- return true;
55
- }
56
-
57
- return false;
58
  }
59
 
60
  /**
@@ -65,10 +63,7 @@ class Gateway extends Abstract_Gateway {
65
  * @return array The list of settings for the gateway.
66
  */
67
  public function get_settings() {
68
- /** @var Settings $settings */
69
- $settings = tribe( Settings::class );
70
-
71
- return $settings->get_settings();
72
  }
73
 
74
  /**
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
 
5
  use TEC\Tickets\Commerce\Gateways\Abstract_Gateway;
 
 
6
 
7
  /**
8
  * Class Gateway
14
  /**
15
  * @inheritDoc
16
  */
17
+ protected static $key = 'paypal';
18
 
19
  /**
20
  * PayPal attribution ID for requests.
25
  */
26
  const ATTRIBUTION_ID = 'TheEventsCalendar_SP_PPCP';
27
 
28
+ /**
29
+ * PayPal tracking ID version.
30
+ *
31
+ * This shouldn't be updated unless we are modifying something on the PayPal user level.
32
+ *
33
+ * @since 5.1.9
34
+ *
35
+ * @var string
36
+ */
37
+ const VERSION = '1.0.0';
38
+
39
  /**
40
  * @inheritDoc
41
  */
52
  return false;
53
  }
54
 
55
+ return tribe( Merchant::class )->account_is_connected();
 
 
 
 
 
 
 
 
 
 
 
56
  }
57
 
58
  /**
63
  * @return array The list of settings for the gateway.
64
  */
65
  public function get_settings() {
66
+ return tribe( Settings::class )->get_settings();
 
 
 
67
  }
68
 
69
  /**
src/Tickets/Commerce/Gateways/PayPal/Hooks.php CHANGED
@@ -17,6 +17,9 @@
17
 
18
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
19
 
 
 
 
20
  /**
21
  * Class Hooks.
22
  *
@@ -42,60 +45,133 @@ class Hooks extends \tad_DI52_ServiceProvider {
42
  * @since 5.1.6
43
  */
44
  protected function add_actions() {
45
- // Settings page: Connect PayPal.
46
- add_action( 'wp_ajax_tribe_tickets_paypal_commerce_user_on_boarded', [ $this, 'on_boarded_user_ajax_request_handler' ] );
47
- add_action( 'wp_ajax_tribe_tickets_paypal_commerce_get_partner_url', [ $this, 'on_get_partner_url_ajax_request_handler' ] );
48
- add_action( 'wp_ajax_tribe_tickets_paypal_commerce_disconnect_account', [ $this, 'remove_paypal_account' ] );
49
- add_action( 'wp_ajax_tribe_tickets_paypal_commerce_onboarding_trouble_notice', [ $this, 'on_boarding_trouble_notice' ] );
50
- add_action( 'admin_init', [ $this, 'on_boarding_boot' ] );
51
-
52
- // Frontend: PayPal Checkout.
53
- add_action( 'wp_ajax_tribe_tickets_paypal_commerce_create_order', [ $this, 'create_order' ] );
54
- add_action( 'wp_ajax_nopriv_tribe_tickets_paypal_commerce_create_order', [ $this, 'create_order' ] );
55
- add_action( 'wp_ajax_tribe_tickets_paypal_commerce_approve_order', [ $this, 'approve_order' ] );
56
- add_action( 'wp_ajax_nopriv_tribe_tickets_paypal_commerce_approve_order', [ $this, 'approve_order' ] );
57
-
58
  // REST API Endpoint registration.
59
  add_action( 'rest_api_init', [ $this, 'register_endpoints' ] );
 
 
 
 
 
 
60
  }
61
 
62
- /**
63
  * Adds the filters required by each Tickets Commerce component.
64
  *
65
  * @since 5.1.6
66
  */
67
  protected function add_filters() {
68
  add_filter( 'tec_tickets_commerce_gateways', [ $this, 'filter_add_gateway' ], 10, 2 );
 
 
69
  }
70
 
71
- public function on_boarded_user_ajax_request_handler() {
72
- $this->container->make( AjaxRequestHandler::class )->onBoardedUserAjaxRequestHandler();
 
 
 
 
 
 
 
 
 
 
 
 
73
  }
74
 
75
- public function on_get_partner_url_ajax_request_handler() {
76
- $this->container->make( AjaxRequestHandler::class )->onGetPartnerUrlAjaxRequestHandler();
 
 
 
 
 
 
 
 
 
 
 
 
77
  }
78
 
79
- public function remove_paypal_account() {
80
- $this->container->make( AjaxRequestHandler::class )->removePayPalAccount();
 
 
 
 
 
 
 
 
 
 
81
  }
82
 
83
- public function on_boarding_trouble_notice() {
84
- $this->container->make( AjaxRequestHandler::class )->onBoardingTroubleNotice();
 
 
 
 
 
 
 
 
 
 
 
 
85
  }
86
 
87
- public function on_boarding_boot() {
88
- $this->container->make( onBoardingRedirectHandler::class )->boot();
 
 
 
 
 
 
 
89
  }
90
 
91
- public function create_order() {
92
- $this->container->make( AjaxRequestHandler::class )->createOrder();
 
 
 
 
 
 
 
 
 
 
93
  }
94
 
95
- public function approve_order() {
96
- $this->container->make( AjaxRequestHandler::class )->approveOrder();
 
 
 
 
 
 
 
 
 
 
97
  }
98
 
 
 
 
 
 
99
  public function register_endpoints() {
100
  $this->container->make( REST::class )->register_endpoints();
101
  }
@@ -112,4 +188,4 @@ class Hooks extends \tad_DI52_ServiceProvider {
112
  public function filter_add_gateway( array $gateways = [] ) {
113
  return $this->container->make( Gateway::class )->register_gateway( $gateways );
114
  }
115
- }
17
 
18
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
19
 
20
+ use TEC\Tickets\Commerce\Module;
21
+ use TEC\Tickets\Commerce\Shortcodes\Shortcode_Abstract;
22
+
23
  /**
24
  * Class Hooks.
25
  *
45
  * @since 5.1.6
46
  */
47
  protected function add_actions() {
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  // REST API Endpoint registration.
49
  add_action( 'rest_api_init', [ $this, 'register_endpoints' ] );
50
+ add_action( 'tec_tickets_commerce_admin_process_action:paypal-disconnect', [ $this, 'handle_action_disconnect' ] );
51
+ add_action( 'tec_tickets_commerce_admin_process_action:paypal-refresh-access-token', [ $this, 'handle_action_refresh_token' ] );
52
+ add_action( 'tec_tickets_commerce_admin_process_action:paypal-refresh-user-info', [ $this, 'handle_action_refresh_user_info' ] );
53
+
54
+ add_action( 'tribe_template_before_include:tickets/v2/commerce/checkout/header', [ $this, 'include_client_js_sdk_script' ], 15, 3 );
55
+ add_action( 'tribe_template_after_include:tickets/v2/commerce/checkout/footer', [ $this, 'include_payment_buttons' ], 15, 3 );
56
  }
57
 
58
+ /**1
59
  * Adds the filters required by each Tickets Commerce component.
60
  *
61
  * @since 5.1.6
62
  */
63
  protected function add_filters() {
64
  add_filter( 'tec_tickets_commerce_gateways', [ $this, 'filter_add_gateway' ], 10, 2 );
65
+ add_filter( 'tec_tickets_commerce_success_shortcode_checkout_page_paypal_template_vars', [ $this, 'include_checkout_page_vars' ], 10, 2 );
66
+ add_filter( 'tec_tickets_commerce_success_shortcode_success_page_paypal_template_vars', [ $this, 'include_success_page_vars' ], 10, 2 );
67
  }
68
 
69
+ /**
70
+ * Filters the shortcode template vars for the Checkout page template.
71
+ *
72
+ * @since 5.1.9
73
+ *
74
+ * @param array $template_vars
75
+ * @param Shortcode_Abstract $shortcode
76
+ *
77
+ * @return array
78
+ */
79
+ public function include_checkout_page_vars( $template_vars, $shortcode ) {
80
+ $template_vars['merchant'] = tribe( Merchant::class );
81
+
82
+ return $template_vars;
83
  }
84
 
85
+ /**
86
+ * Filters the shortcode template vars for the Checkout page template.
87
+ *
88
+ * @since 5.1.9
89
+ *
90
+ * @param array $template_vars
91
+ * @param Shortcode_Abstract $shortcode
92
+ *
93
+ * @return array
94
+ */
95
+ public function include_success_page_vars( $template_vars, $shortcode ) {
96
+ $template_vars['merchant'] = tribe( Merchant::class );
97
+
98
+ return $template_vars;
99
  }
100
 
101
+ /**
102
+ * Include the Client JS SDK script into checkout.
103
+ *
104
+ * @since 5.1.9
105
+ *
106
+ * @param string $file Which file we are loading.
107
+ * @param string $name Name of file file
108
+ * @param \Tribe__Template $template Which Template object is being used.
109
+ *
110
+ */
111
+ public function include_client_js_sdk_script( $file, $name, $template ) {
112
+ echo tribe( Buttons::class )->get_checkout_script();
113
  }
114
 
115
+ /**
116
+ * Include the Client JS SDK script into checkout.
117
+ *
118
+ * @since 5.1.9
119
+ *
120
+ * @param string $file Which file we are loading.
121
+ * @param string $name Name of file file
122
+ * @param \Tribe__Template $template Which Template object is being used.
123
+ *
124
+ */
125
+ public function include_payment_buttons( $file, $name, $template ) {
126
+ $must_login = ! is_user_logged_in() && tribe( Module::class )->login_required();
127
+
128
+ $template->template( 'gateway/paypal/buttons', [ 'must_login' => $must_login ] );
129
  }
130
 
131
+ /**
132
+ * Handles the disconnecting of the merchant.
133
+ *
134
+ * @todo Display some message when disconnecting.
135
+ * @since 5.1.9
136
+ *
137
+ */
138
+ public function handle_action_disconnect() {
139
+ $this->container->make( Merchant::class )->disconnect();
140
  }
141
 
142
+ /**
143
+ * Handles the refreshing of the token from PayPal for this merchant.
144
+ *
145
+ * @todo Display some message when refreshing token.
146
+ * @since 5.1.9
147
+ *
148
+ */
149
+ public function handle_action_refresh_token() {
150
+ $merchant = $this->container->make( Merchant::class );
151
+ $token_data = $this->container->make( Client::class )->get_access_token_from_client_credentials( $merchant->get_client_id(), $merchant->get_client_secret() );
152
+
153
+ $saved = $merchant->save_access_token_data( $token_data );
154
  }
155
 
156
+ /**
157
+ * Handles the refreshing of the user info from PayPal for this merchant.
158
+ *
159
+ * @todo Display some message when refreshing user info.
160
+ * @since 5.1.9
161
+ *
162
+ */
163
+ public function handle_action_refresh_user_info() {
164
+ $merchant = $this->container->make( Merchant::class );
165
+ $user_info = $this->container->make( Client::class )->get_user_info();
166
+
167
+ $saved = $merchant->save_user_info( $user_info );
168
  }
169
 
170
+ /**
171
+ * Register the Endpoints from Paypal.
172
+ *
173
+ * @since 5.1.9
174
+ */
175
  public function register_endpoints() {
176
  $this->container->make( REST::class )->register_endpoints();
177
  }
188
  public function filter_add_gateway( array $gateways = [] ) {
189
  return $this->container->make( Gateway::class )->register_gateway( $gateways );
190
  }
191
+ }
src/Tickets/Commerce/Gateways/PayPal/Merchant.php ADDED
@@ -0,0 +1,833 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
+
5
+ use Tribe__Utils__Array as Arr;
6
+ use Tribe__Date_Utils as Dates;
7
+ use TEC\Tickets\Commerce\Traits\Has_Mode;
8
+
9
+ /**
10
+ * Class Merchant.
11
+ *
12
+ * @since 5.1.9
13
+ *
14
+ * @package TEC\Tickets\Commerce\Gateways\PayPal
15
+ */
16
+ class Merchant {
17
+ use Has_Mode;
18
+
19
+ /**
20
+ * All account Props we use for the merchant
21
+ *
22
+ * @since 5.1.9
23
+ *
24
+ * @var string[]
25
+ */
26
+ protected $account_props = [
27
+ 'signup_hash',
28
+ 'merchant_id',
29
+ 'merchant_id_in_paypal',
30
+ 'client_id',
31
+ 'client_secret',
32
+ 'account_is_ready',
33
+ 'supports_custom_payments',
34
+ 'account_country',
35
+ 'access_token',
36
+ ];
37
+
38
+ /**
39
+ * Determines if the data needs to be saved to the Database
40
+ *
41
+ * @since 5.1.9
42
+ *
43
+ * @var boolean
44
+ */
45
+ protected $needs_save = false;
46
+
47
+ /**
48
+ * PayPal merchant Id (email address).
49
+ *
50
+ * @since 5.1.9
51
+ *
52
+ * @var null|string
53
+ */
54
+ protected $merchant_id;
55
+
56
+ /**
57
+ * A Hash used during signup that should be associated with the merchant.
58
+ *
59
+ * @since 5.1.9
60
+ *
61
+ * @var null|string
62
+ */
63
+ protected $signup_hash;
64
+
65
+ /**
66
+ * PayPal merchant id.
67
+ *
68
+ * @since 5.1.9
69
+ *
70
+ * @var string
71
+ */
72
+ protected $merchant_id_in_paypal;
73
+
74
+ /**
75
+ * Client id.
76
+ *
77
+ * @since 5.1.9
78
+ *
79
+ * @var string
80
+ */
81
+ protected $client_id;
82
+
83
+ /**
84
+ * Client Secret.
85
+ *
86
+ * @since 5.1.9
87
+ *
88
+ * @var string
89
+ */
90
+ protected $client_secret;
91
+
92
+ /**
93
+ * Client token.
94
+ *
95
+ * @since 5.1.9
96
+ *
97
+ * @var array
98
+ */
99
+ protected $client_token;
100
+
101
+ /**
102
+ * How long till the Client token expires
103
+ *
104
+ * @since 5.1.9
105
+ *
106
+ * @var int
107
+ */
108
+ protected $client_token_expires_in;
109
+
110
+ /**
111
+ * Access token.
112
+ *
113
+ * @since 5.1.9
114
+ *
115
+ * @var string
116
+ */
117
+ protected $access_token;
118
+
119
+ /**
120
+ * Whether or not the connected account is ready to process payments.
121
+ *
122
+ * @since 5.1.9
123
+ *
124
+ * @var bool
125
+ */
126
+ protected $account_is_ready = false;
127
+
128
+ /**
129
+ * Whether or not the account can make custom payments (i.e Advanced Fields & PPCP)
130
+ *
131
+ * @since 5.1.9
132
+ *
133
+ * @var bool
134
+ */
135
+ protected $supports_custom_payments = false;
136
+
137
+ /**
138
+ * PayPal account account country.
139
+ *
140
+ * @since 5.1.9
141
+ *
142
+ * @var string
143
+ */
144
+ protected $account_country;
145
+
146
+ /**
147
+ * Fetches the current signup hash.
148
+ *
149
+ * @since 5.1.9
150
+ *
151
+ * @return string|null
152
+ */
153
+ public function get_signup_hash() {
154
+ return $this->signup_hash;
155
+ }
156
+
157
+ /**
158
+ * Sets the value for signup hash locally, in this instance of the Merchant.
159
+ *
160
+ * @since 5.1.9
161
+ *
162
+ * @param mixed $value Value used for the signup hash.
163
+ * @param boolean $needs_save Determines if the proprieties saved need to save to the DB.
164
+ */
165
+ public function set_signup_hash( $value, $needs_save = true ) {
166
+ $this->set_value( 'signup_hash', $value, $needs_save );
167
+ }
168
+
169
+ /**
170
+ * Fetches the current Merchant ID.
171
+ *
172
+ * @since 5.1.9
173
+ *
174
+ * @return string|null
175
+ */
176
+ public function get_merchant_id() {
177
+ return $this->merchant_id;
178
+ }
179
+
180
+ /**
181
+ * Sets the value for Merchant ID locally, in this instance of the Merchant.
182
+ *
183
+ * @since 5.1.9
184
+ *
185
+ * @param mixed $value Value used for the Merchant ID.
186
+ * @param boolean $needs_save Determines if the proprieties saved need to save to the DB.
187
+ */
188
+ public function set_merchant_id( $value, $needs_save = true ) {
189
+ $this->set_value( 'merchant_id', $value, $needs_save );
190
+ }
191
+
192
+ /**
193
+ * Gets the value stored for the Merchant ID in PayPal.
194
+ *
195
+ * @since 5.1.9
196
+ *
197
+ * @return string
198
+ */
199
+ public function get_merchant_id_in_paypal() {
200
+ return $this->merchant_id_in_paypal;
201
+ }
202
+
203
+ /**
204
+ * Sets the value for Merchant ID in PayPal locally, in this instance of the Merchant.
205
+ *
206
+ * @since 5.1.9
207
+ *
208
+ * @param mixed $value Value used for the Merchant ID in PayPal.
209
+ * @param boolean $needs_save Determines if the proprieties saved need to save to the DB.
210
+ */
211
+ public function set_merchant_id_in_paypal( $value, $needs_save = true ) {
212
+ $this->set_value( 'merchant_id_in_paypal', $value, $needs_save );
213
+ }
214
+
215
+ /**
216
+ * Gets the value stored for the Client ID.
217
+ *
218
+ * @since 5.1.9
219
+ *
220
+ * @return string
221
+ */
222
+ public function get_client_id() {
223
+ return $this->client_id;
224
+ }
225
+
226
+ /**
227
+ * Sets the value for Merchant ID locally, in this instance of the Merchant.
228
+ *
229
+ * @since 5.1.9
230
+ *
231
+ * @param mixed $value Value used for the Merchant ID.
232
+ * @param boolean $needs_save Determines if the proprieties saved need to save to the DB.
233
+ */
234
+ public function set_client_id( $value, $needs_save = true ) {
235
+ $this->client_id = $value;
236
+ }
237
+
238
+ /**
239
+ * Gets the value stored for the Client Secret.
240
+ *
241
+ * @since 5.1.9
242
+ *
243
+ * @return string
244
+ */
245
+ public function get_client_secret() {
246
+ return $this->client_secret;
247
+ }
248
+
249
+ /**
250
+ * Sets the value for Client Secret locally, in this instance of the Merchant.
251
+ *
252
+ * @since 5.1.9
253
+ *
254
+ * @param mixed $value Value used for the Client Secret.
255
+ * @param boolean $needs_save Determines if the proprieties saved need to save to the DB.
256
+ */
257
+ public function set_client_secret( $value, $needs_save = true ) {
258
+ $this->set_value( 'client_secret', $value, $needs_save );
259
+ }
260
+
261
+ /**
262
+ * Gets the value stored for the Access Token.
263
+ *
264
+ * @since 5.1.9
265
+ *
266
+ * @return string
267
+ */
268
+ public function get_access_token() {
269
+ return $this->access_token;
270
+ }
271
+
272
+ /**
273
+ * Sets the value for Access Token locally, in this instance of the Merchant.
274
+ *
275
+ * @since 5.1.9
276
+ *
277
+ * @param mixed $value Value used for the Access Token.
278
+ * @param boolean $needs_save Determines if the proprieties saved need to save to the DB.
279
+ */
280
+ public function set_access_token( $value, $needs_save = true ) {
281
+ $this->set_value( 'access_token', $value, $needs_save );
282
+ }
283
+
284
+ /**
285
+ * Gets the value stored for if the account is ready for usage.
286
+ *
287
+ * @since 5.1.9
288
+ *
289
+ * @return string
290
+ */
291
+ public function get_account_is_ready() {
292
+ return $this->account_is_ready;
293
+ }
294
+
295
+ /**
296
+ * Sets the value for if this account is ready for usage locally, in this instance of the Merchant.
297
+ *
298
+ * @since 5.1.9
299
+ *
300
+ * @param mixed $value Value used for the Account is Ready.
301
+ * @param boolean $needs_save Determines if the proprieties saved need to save to the DB.
302
+ */
303
+ public function set_account_is_ready( $value, $needs_save = true ) {
304
+ $this->set_value( 'account_is_ready', $value, $needs_save );
305
+ }
306
+
307
+ /**
308
+ * Gets the value stored for if this account supports custom payments.
309
+ *
310
+ * @since 5.1.9
311
+ *
312
+ * @return bool
313
+ */
314
+ public function get_supports_custom_payments() {
315
+ return $this->supports_custom_payments;
316
+ }
317
+
318
+ /**
319
+ * Sets the value determining if this supports custom payments locally, in this instance of the Merchant.
320
+ *
321
+ * @since 5.1.9
322
+ *
323
+ * @param mixed $value Value used for the Support for Custom Payments.
324
+ * @param boolean $needs_save Determines if the proprieties saved need to save to the DB.
325
+ */
326
+ public function set_supports_custom_payments( $value, $needs_save = true ) {
327
+ $this->set_value( 'supports_custom_payments', $value, $needs_save );
328
+ }
329
+
330
+ /**
331
+ * Gets the value stored for the Country Code.
332
+ *
333
+ * @since 5.1.9
334
+ *
335
+ * @return string
336
+ */
337
+ public function get_account_country() {
338
+ return $this->account_country;
339
+ }
340
+
341
+ /**
342
+ * Sets the value for Account Country locally, in this instance of the Merchant.
343
+ *
344
+ * @since 5.1.9
345
+ *
346
+ * @param mixed $value Value used for the Account Country.
347
+ * @param boolean $needs_save Determines if the proprieties saved need to save to the DB.
348
+ */
349
+ public function set_account_country( $value, $needs_save = true ) {
350
+ $this->set_value( 'account_country', $value, $needs_save );
351
+ }
352
+
353
+ /**
354
+ * Determines if this instances needs to be saved to the DB.
355
+ *
356
+ * @since 5.1.9
357
+ *
358
+ * @return bool
359
+ */
360
+ public function needs_save() {
361
+ return tribe_is_truthy( $this->needs_save );
362
+ }
363
+
364
+
365
+ /**
366
+ * Returns the options key for the account in the merchant mode.
367
+ *
368
+ * @since 5.1.9
369
+ *
370
+ * @return string
371
+ */
372
+ public function get_account_key() {
373
+ $gateway_key = Gateway::get_key();
374
+ $merchant_mode = $this->get_mode();
375
+
376
+ return "tec_tickets_commerce_{$gateway_key}_{$merchant_mode}_account";
377
+ }
378
+
379
+ /**
380
+ * Returns the data retrieved from the access token refreshing process.
381
+ *
382
+ * @since 5.1.9
383
+ *
384
+ * @return string
385
+ */
386
+ public function get_access_token_data_key() {
387
+ $gateway_key = Gateway::get_key();
388
+ $merchant_mode = $this->get_mode();
389
+
390
+ return "tec_tickets_commerce_{$gateway_key}_{$merchant_mode}_access_token_data";
391
+ }
392
+
393
+ /**
394
+ * Returns the data retrieved from the signup process.
395
+ *
396
+ * Uses normal WP options to be saved, instead of the normal tribe_update_option.
397
+ *
398
+ * @since 5.1.9
399
+ *
400
+ * @return string
401
+ */
402
+ public function get_signup_data_key() {
403
+ $gateway_key = Gateway::get_key();
404
+ $merchant_mode = $this->get_mode();
405
+
406
+ return "tec_tickets_commerce_{$gateway_key}_{$merchant_mode}_signup_data";
407
+ }
408
+
409
+ /**
410
+ * Returns the options key for the account errors in the merchant mode.
411
+ *
412
+ * @since 5.1.9
413
+ *
414
+ * @return string
415
+ */
416
+ public function get_account_errors_key() {
417
+ $gateway_key = Gateway::get_key();
418
+ $merchant_mode = $this->get_mode();
419
+
420
+ return "tec_tickets_commerce_{$gateway_key}_{$merchant_mode}_account_errors";
421
+ }
422
+
423
+ /**
424
+ * Returns the options key for the account account information.
425
+ *
426
+ * @since 5.1.9
427
+ *
428
+ * @return string
429
+ */
430
+ public function get_user_info_key() {
431
+ $gateway_key = Gateway::get_key();
432
+ $merchant_mode = $this->get_mode();
433
+
434
+ return "tec_tickets_commerce_{$gateway_key}_{$merchant_mode}_user_info";
435
+ }
436
+
437
+ /**
438
+ * Handle initial setup for the object singleton.
439
+ *
440
+ * @since 5.1.9
441
+ */
442
+ public function init() {
443
+ $this->set_mode( tribe_tickets_commerce_is_test_mode() ? 'sandbox' : 'live' );
444
+ $this->from_array( $this->get_details_data(), false );
445
+ }
446
+
447
+ /**
448
+ * Return array of merchant details.
449
+ *
450
+ * @since 5.1.9
451
+ *
452
+ * @return array
453
+ */
454
+ public function to_array() {
455
+ return [
456
+ 'signup_hash' => $this->get_signup_hash(),
457
+ 'merchant_id' => $this->get_merchant_id(),
458
+ 'merchant_id_in_paypal' => $this->get_merchant_id_in_paypal(),
459
+ 'client_id' => $this->get_client_id(),
460
+ 'client_secret' => $this->get_client_secret(),
461
+ 'account_is_ready' => $this->get_account_is_ready(),
462
+ 'supports_custom_payments' => $this->get_supports_custom_payments(),
463
+ 'account_country' => $this->get_account_country(),
464
+ 'access_token' => $this->get_access_token(),
465
+ ];
466
+ }
467
+
468
+ /**
469
+ * Make Merchant object from array.
470
+ *
471
+ * @since 5.1.9
472
+ *
473
+ * @param array $data Which values need to .
474
+ * @param boolean $needs_save Determines if the proprieties saved need to save to the DB.
475
+ *
476
+ * @return boolean
477
+ */
478
+ public function from_array( array $data, $needs_save = true ) {
479
+ if ( ! $this->validate( $data ) ) {
480
+ return false;
481
+ }
482
+
483
+ $this->setup_properties( $data, $needs_save );
484
+
485
+ return true;
486
+ }
487
+
488
+ /**
489
+ * Saves a given base value into the class props.
490
+ *
491
+ * @since 5.1.9
492
+ *
493
+ * @param string $key
494
+ * @param mixed $value
495
+ * @param bool $needs_save
496
+ *
497
+ */
498
+ protected function set_value( $key, $value, $needs_save = true ) {
499
+ $this->{$key} = $value;
500
+
501
+ // Determine if we will need to save in the DB.
502
+ if ( $needs_save ) {
503
+ $this->needs_save = true;
504
+ }
505
+ }
506
+
507
+ /**
508
+ * Setup properties from array.
509
+ *
510
+ * @since 5.1.9
511
+ *
512
+ * @param array $data Which values need to be saved.
513
+ * @param boolean $needs_save Determines if the proprieties saved need to save to the DB.
514
+ */
515
+ protected function setup_properties( array $data, $needs_save = true ) {
516
+ if ( array_key_exists( 'signup_hash', $data ) ) {
517
+ $this->set_signup_hash( $data['signup_hash'], $needs_save );
518
+ }
519
+ if ( array_key_exists( 'merchant_id', $data ) ) {
520
+ $this->set_merchant_id( $data['merchant_id'], $needs_save );
521
+ }
522
+ if ( array_key_exists( 'merchant_id_in_paypal', $data ) ) {
523
+ $this->set_merchant_id_in_paypal( $data['merchant_id_in_paypal'], $needs_save );
524
+ }
525
+ if ( array_key_exists( 'client_id', $data ) ) {
526
+ $this->set_client_id( $data['client_id'], $needs_save );
527
+ }
528
+ if ( array_key_exists( 'client_secret', $data ) ) {
529
+ $this->set_client_secret( $data['client_secret'], $needs_save );
530
+ }
531
+ if ( array_key_exists( 'account_is_ready', $data ) ) {
532
+ $this->set_account_is_ready( $data['account_is_ready'], $needs_save );
533
+ }
534
+ if ( array_key_exists( 'supports_custom_payments', $data ) ) {
535
+ $this->set_supports_custom_payments( $data['supports_custom_payments'], $needs_save );
536
+ }
537
+ if ( array_key_exists( 'account_country', $data ) ) {
538
+ $this->set_account_country( $data['account_country'], $needs_save );
539
+ }
540
+ if ( array_key_exists( 'access_token', $data ) ) {
541
+ $this->set_access_token( $data['access_token'], $needs_save );
542
+ }
543
+ }
544
+
545
+ /**
546
+ * Validate merchant details.
547
+ *
548
+ * @since 5.1.6
549
+ *
550
+ * @param array $merchant_details
551
+ */
552
+ public function validate( $merchant_details ) {
553
+ $required = $this->account_props;
554
+
555
+ if ( array_diff( $required, array_keys( $merchant_details ) ) ) {
556
+ return false;
557
+ }
558
+
559
+ return true;
560
+ }
561
+
562
+ /**
563
+ * Save merchant details.
564
+ *
565
+ * @since 5.1.9
566
+ *
567
+ * @return bool
568
+ */
569
+ public function save() {
570
+ if ( false === $this->needs_save() ) {
571
+ return false;
572
+ }
573
+
574
+ $saved = update_option( $this->get_account_key(), $this->to_array() );
575
+
576
+ // If we were able to save, we reset the needs save.
577
+ if ( $saved ) {
578
+ $this->needs_save = false;
579
+ }
580
+
581
+ return $saved;
582
+ }
583
+
584
+ /**
585
+ * Get the merchant details data.
586
+ *
587
+ * @since 5.1.9
588
+ *
589
+ * @return array
590
+ */
591
+ protected function get_details_data() {
592
+ return (array) get_option( $this->get_account_key(), [] );
593
+ }
594
+
595
+ /**
596
+ * Delete merchant account details on the Database.
597
+ *
598
+ * @since 5.1.9
599
+ *
600
+ * @return bool
601
+ */
602
+ public function delete_data() {
603
+ $status = update_option( $this->get_account_key(), null );
604
+
605
+ if ( $status ) {
606
+ $data = array_fill_keys( $this->account_props, null );
607
+ // reset internal values.
608
+ $this->setup_properties( $data, false );
609
+ }
610
+
611
+ return $status;
612
+ }
613
+
614
+ /**
615
+ * Returns the account errors if there are any.
616
+ *
617
+ * @since 5.1.9
618
+ *
619
+ * @return string[]|null
620
+ */
621
+ public function get_account_errors() {
622
+ return get_option( $this->get_account_errors_key(), null );
623
+ }
624
+
625
+ /**
626
+ * Saves the account error message.
627
+ *
628
+ * @since 5.1.9
629
+ *
630
+ * @param string[] $error_message
631
+ *
632
+ * @return bool
633
+ */
634
+ public function save_account_errors( $error_message ) {
635
+ return update_option( $this->get_account_errors_key(), $error_message );
636
+ }
637
+
638
+ /**
639
+ * Deletes the errors for the account.
640
+ *
641
+ * @since 5.1.9
642
+ *
643
+ * @return bool
644
+ */
645
+ public function delete_account_errors() {
646
+ return delete_option( $this->get_account_errors_key() );
647
+ }
648
+
649
+
650
+ /**
651
+ * Saves signup data from the transient into a permanent storage.
652
+ *
653
+ * @since 5.1.9
654
+ *
655
+ * @return array
656
+ */
657
+ public function get_access_token_data() {
658
+ return get_option( $this->get_access_token_data_key(), [] );
659
+ }
660
+
661
+ /**
662
+ * Saves the access token data, and adds some extra information for better usage.
663
+ *
664
+ * @since 5.1.9
665
+ *
666
+ * @param array $token_data
667
+ *
668
+ * @return bool
669
+ */
670
+ public function save_access_token_data( array $token_data ) {
671
+ if ( empty( $token_data['access_token'] ) ) {
672
+ return false;
673
+ }
674
+
675
+ $this->set_access_token( $token_data['access_token'] );
676
+ $this->save();
677
+
678
+ if ( ! empty( $token_data['expires_in'] ) ) {
679
+ $expires_in = Dates::interval( 'PT' . $token_data['expires_in'] . 'S' );
680
+
681
+ // Store date related data in readable formats.
682
+ $token_data['token_retrieval_time'] = Dates::build_date_object( 'now' )->format( Dates::DBDATETIMEFORMAT );
683
+ $token_data['token_expiration_time'] = Dates::build_date_object( 'now' )->add( $expires_in )->format( Dates::DBDATETIMEFORMAT );
684
+ }
685
+
686
+ return update_option( $this->get_access_token_data_key(), $token_data );
687
+ }
688
+
689
+ /**
690
+ * Delete access token data.
691
+ *
692
+ * @since 5.1.9
693
+ *
694
+ * @return bool
695
+ */
696
+ public function delete_access_token_data() {
697
+ return update_option( $this->get_access_token_data_key(), null );
698
+ }
699
+
700
+ /**
701
+ * Saves signup data from the transient into permanent option.
702
+ *
703
+ * @since 5.1.9
704
+ *
705
+ * @param array $signup_data
706
+ *
707
+ * @return bool
708
+ */
709
+ public function save_signup_data( array $signup_data ) {
710
+ return update_option( $this->get_signup_data_key(), $signup_data );
711
+ }
712
+
713
+ /**
714
+ * Saves signup data from the transient into a permanent storage.
715
+ *
716
+ * @since 5.1.9
717
+ *
718
+ * @return array
719
+ */
720
+ public function get_signup_data() {
721
+ return get_option( $this->get_signup_data_key(), [] );
722
+ }
723
+
724
+ /**
725
+ * Deletes signup data from the DB.
726
+ *
727
+ * @since 5.1.9
728
+ *
729
+ * @return bool
730
+ */
731
+ public function delete_signup_data() {
732
+ return delete_option( $this->get_signup_data_key() );
733
+ }
734
+
735
+ /**
736
+ * Saves user info to make sure we have full access later on.
737
+ *
738
+ * @since 5.1.9
739
+ *
740
+ * @param array $user_info User info from the PayPal API.
741
+ *
742
+ * @return bool
743
+ */
744
+ public function save_user_info( array $user_info = [] ) {
745
+ return update_option( $this->get_user_info_key(), $user_info );
746
+ }
747
+
748
+ /**
749
+ * Deletes the user info from the DB.
750
+ *
751
+ * @since 5.1.9
752
+ *
753
+ * @return bool
754
+ */
755
+ public function delete_user_info() {
756
+ return delete_option( $this->get_user_info_key() );
757
+ }
758
+
759
+ /**
760
+ * Saves signup data from the transient into
761
+ *
762
+ * @since 5.1.9
763
+ *
764
+ * @return array
765
+ */
766
+ public function get_user_info() {
767
+ return get_option( $this->get_user_info_key(), [] );
768
+ }
769
+
770
+ /**
771
+ * Returns whether or not the account has been connected
772
+ *
773
+ * @since 5.1.9
774
+ *
775
+ * @return bool
776
+ */
777
+ public function account_is_connected() {
778
+ return tribe_is_truthy( $this->merchant_id_in_paypal );
779
+ }
780
+
781
+ /**
782
+ * Disconnects the merchant completely.
783
+ *
784
+ * @since 5.1.9
785
+ *
786
+ * @return bool
787
+ */
788
+ public function disconnect() {
789
+ $statuses = [
790
+ $this->delete_data(),
791
+ $this->delete_access_token_data(),
792
+ $this->delete_signup_data(),
793
+ $this->delete_user_info(),
794
+ $this->delete_account_errors(),
795
+ ];
796
+
797
+ return in_array( false, $statuses, true );
798
+ }
799
+
800
+ /**
801
+ * Determines if the Merchant is active.
802
+ *
803
+ * @since 5.1.9
804
+ *
805
+ * @return bool
806
+ */
807
+ public function is_active( $recheck = false ) {
808
+ $saved_merchant_id = $this->get_merchant_id_in_paypal();
809
+
810
+ if ( ! $saved_merchant_id ) {
811
+ return false;
812
+ }
813
+
814
+ if ( ! $recheck && true === $this->get_account_is_ready() ) {
815
+ return true;
816
+ }
817
+
818
+ $seller_status = tribe( WhoDat::class )->get_seller_status( $saved_merchant_id );
819
+
820
+ $payments_receivable = Arr::get( $seller_status, 'payments_receivable' );
821
+ $paypal_product_name = Arr::get( $seller_status, [ 'products', 0, 'name' ] );
822
+ $paypal_product_status = Arr::get( $seller_status, [ 'products', 0, 'status' ] );
823
+
824
+ $is_active = ( true === $payments_receivable && 'EXPRESS_CHECKOUT' === $paypal_product_name && 'ACTIVE' === $paypal_product_status );
825
+
826
+ if ( $is_active ) {
827
+ $this->set_account_is_ready( true );
828
+ $this->save();
829
+ }
830
+
831
+ return $is_active;
832
+ }
833
+ }
src/Tickets/Commerce/Gateways/PayPal/{SDK/Models/PayPalOrder.php → Models/PayPal_Order.php} RENAMED
@@ -1,18 +1,18 @@
1
  <?php
2
 
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models;
4
 
5
  use InvalidArgumentException;
6
  use stdClass;
7
 
8
  /**
9
- * Class PayPalOrder
10
  *
11
- * @since 5.1.6
12
- * @package TEC\Tickets\Commerce\Gateways\PayPal
13
  *
14
  */
15
- class PayPalOrder {
16
 
17
  /**
18
  * Order Id.
@@ -48,7 +48,7 @@ class PayPalOrder {
48
  *
49
  * @var string
50
  */
51
- public $createTime;
52
 
53
  /**
54
  * Order update time.
@@ -57,7 +57,7 @@ class PayPalOrder {
57
  *
58
  * @var string
59
  */
60
- public $updateTime;
61
 
62
  /**
63
  * PayPal Order action links.
@@ -84,14 +84,14 @@ class PayPalOrder {
84
  *
85
  * @var stdClass
86
  */
87
- private $purchaseUnit;
88
 
89
  /**
90
  * Payment details for order.
91
  *
92
  * @since 5.1.6
93
  *
94
- * @var PayPalPayment
95
  */
96
  public $payment;
97
 
@@ -102,28 +102,25 @@ class PayPalOrder {
102
  *
103
  * @param $array
104
  *
105
- * @return PayPalOrder
106
  */
107
- public static function fromArray( $array ) {
108
- /* @var PayPalOrder $order */
109
  $order = tribe( __CLASS__ );
110
 
111
  $order->validate( $array );
112
 
113
- // @todo Replace this with a new method somewhere else.
114
- $array = ArrayDataSet::camelCaseKeys( $array );
115
-
116
- foreach ( $array as $itemName => $value ) {
117
- if ( 'purchaseUnits' === $itemName ) {
118
  $value = current( $value );
119
 
120
- $order->purchaseUnit = $value;
121
- $order->payment = PayPalPayment::fromArray( (array) current( $order->purchaseUnit->payments->captures ) );
122
 
123
  continue;
124
  }
125
 
126
- $order->{$itemName} = $value;
127
  }
128
 
129
  return $order;
@@ -134,9 +131,10 @@ class PayPalOrder {
134
  *
135
  * @since 5.1.6
136
  *
 
 
137
  * @param array $array
138
  *
139
- * @throws InvalidArgumentException
140
  */
141
  private function validate( $array ) {
142
  $required = [
1
  <?php
2
 
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal\Models;
4
 
5
  use InvalidArgumentException;
6
  use stdClass;
7
 
8
  /**
9
+ * Class Order
10
  *
11
+ * @since 5.1.6
12
+ * @package TEC\Tickets\Commerce\Gateways\PayPal\Models
13
  *
14
  */
15
+ class PayPal_Order {
16
 
17
  /**
18
  * Order Id.
48
  *
49
  * @var string
50
  */
51
+ public $create_time;
52
 
53
  /**
54
  * Order update time.
57
  *
58
  * @var string
59
  */
60
+ public $update_time;
61
 
62
  /**
63
  * PayPal Order action links.
84
  *
85
  * @var stdClass
86
  */
87
+ private $purchase_unit;
88
 
89
  /**
90
  * Payment details for order.
91
  *
92
  * @since 5.1.6
93
  *
94
+ * @var PayPal_Payment
95
  */
96
  public $payment;
97
 
102
  *
103
  * @param $array
104
  *
105
+ * @return PayPal_Order
106
  */
107
+ public static function from_array( $array ) {
108
+ /* @var PayPal_Order $order */
109
  $order = tribe( __CLASS__ );
110
 
111
  $order->validate( $array );
112
 
113
+ foreach ( $array as $item_name => $value ) {
114
+ if ( 'purchase_units' === $item_name ) {
 
 
 
115
  $value = current( $value );
116
 
117
+ $order->purchase_unit = $value;
118
+ $order->payment = PayPal_Payment::from_array( (array) current( $order->purchase_unit->payments->captures ) );
119
 
120
  continue;
121
  }
122
 
123
+ $order->{$item_name} = $value;
124
  }
125
 
126
  return $order;
131
  *
132
  * @since 5.1.6
133
  *
134
+ * @throws InvalidArgumentException
135
+ *
136
  * @param array $array
137
  *
 
138
  */
139
  private function validate( $array ) {
140
  $required = [
src/Tickets/Commerce/Gateways/PayPal/{SDK/Models/PayPalPayment.php → Models/PayPal_Payment.php} RENAMED
@@ -1,17 +1,17 @@
1
  <?php
2
 
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models;
4
 
5
  use InvalidArgumentException;
6
 
7
  /**
8
- * Class PayPalPayment
9
  *
10
- * @since 5.1.6
11
- * @package TEC\Tickets\Commerce\Gateways\PayPal
12
  *
13
  */
14
- class PayPalPayment {
15
 
16
  /**
17
  * Payment Id.
@@ -47,7 +47,7 @@ class PayPalPayment {
47
  *
48
  * @var string
49
  */
50
- public $createTime;
51
 
52
  /**
53
  * Payment update time.
@@ -56,7 +56,7 @@ class PayPalPayment {
56
  *
57
  * @var string
58
  */
59
- public $updateTime;
60
 
61
  /**
62
  * PayPal Payment action links.
@@ -77,10 +77,10 @@ class PayPalPayment {
77
  *
78
  * @param $array
79
  *
80
- * @return PayPalPayment
81
  */
82
- public static function fromArray( $array ) {
83
- /* @var PayPalPayment $payment */
84
  $payment = tribe( __CLASS__ );
85
 
86
  $payment->validate( $array );
@@ -88,8 +88,8 @@ class PayPalPayment {
88
  // @todo Replace this with a new method somewhere else.
89
  $array = ArrayDataSet::camelCaseKeys( $array );
90
 
91
- foreach ( $array as $itemName => $value ) {
92
- $payment->{$itemName} = $value;
93
  }
94
 
95
  return $payment;
@@ -100,9 +100,10 @@ class PayPalPayment {
100
  *
101
  * @since 5.1.6
102
  *
 
 
103
  * @param array $array
104
  *
105
- * @throws InvalidArgumentException
106
  */
107
  private function validate( $array ) {
108
  $required = [ 'id', 'amount', 'status', 'create_time', 'update_time', 'links' ];
1
  <?php
2
 
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal\Models;
4
 
5
  use InvalidArgumentException;
6
 
7
  /**
8
+ * Class PayPal_Payment
9
  *
10
+ * @since 5.1.6
11
+ * @package TEC\Tickets\Commerce\Gateways\PayPal\Models
12
  *
13
  */
14
+ class PayPal_Payment {
15
 
16
  /**
17
  * Payment Id.
47
  *
48
  * @var string
49
  */
50
+ public $create_time;
51
 
52
  /**
53
  * Payment update time.
56
  *
57
  * @var string
58
  */
59
+ public $update_time;
60
 
61
  /**
62
  * PayPal Payment action links.
77
  *
78
  * @param $array
79
  *
80
+ * @return PayPal_Payment
81
  */
82
+ public static function from_array( $array ) {
83
+ /* @var PayPal_Payment $payment */
84
  $payment = tribe( __CLASS__ );
85
 
86
  $payment->validate( $array );
88
  // @todo Replace this with a new method somewhere else.
89
  $array = ArrayDataSet::camelCaseKeys( $array );
90
 
91
+ foreach ( $array as $item_name => $value ) {
92
+ $payment->{$item_name} = $value;
93
  }
94
 
95
  return $payment;
100
  *
101
  * @since 5.1.6
102
  *
103
+ * @throws InvalidArgumentException
104
+ *
105
  * @param array $array
106
  *
 
107
  */
108
  private function validate( $array ) {
109
  $required = [ 'id', 'amount', 'status', 'create_time', 'update_time', 'links' ];
src/Tickets/Commerce/Gateways/PayPal/Models/Webhook_Config.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal\Models;
4
+
5
+ /**
6
+ * Class Webhook_Config.
7
+ *
8
+ * @since 5.1.6
9
+ *
10
+ * @package TEC\Tickets\Commerce\Gateways\PayPal\Models
11
+ */
12
+ class Webhook_Config {
13
+
14
+ /**
15
+ * @since 5.1.6
16
+ *
17
+ * @var string
18
+ */
19
+ public $id;
20
+
21
+ /**
22
+ * @since 5.1.6
23
+ *
24
+ * @var string
25
+ */
26
+ public $return_url;
27
+
28
+ /**
29
+ * @since 5.1.6
30
+ *
31
+ * @var string[]
32
+ */
33
+ public $events;
34
+
35
+ /**
36
+ * Webhook_Config constructor.
37
+ *
38
+ * @since 5.1.6
39
+ *
40
+ * @param string $id
41
+ * @param string $return_url
42
+ * @param string[] $events
43
+ */
44
+ public function __construct( $id, $return_url, $events ) {
45
+ $this->id = $id;
46
+ $this->return_url = $return_url;
47
+ $this->events = $events;
48
+ }
49
+
50
+ /**
51
+ * Generates an instance from serialized data
52
+ *
53
+ * @since 5.1.6
54
+ *
55
+ * @param array $data
56
+ *
57
+ * @return Webhook_Config
58
+ */
59
+ public static function from_array( array $data ) {
60
+ return new self( $data['id'], $data['return_url'], $data['events'] );
61
+ }
62
+
63
+ /**
64
+ * Generates an array for serialization
65
+ *
66
+ * @since 5.1.6
67
+ *
68
+ * @return array
69
+ */
70
+ public function to_array() {
71
+ return [
72
+ 'id' => $this->id,
73
+ 'return_url' => $this->return_url,
74
+ 'events' => $this->events,
75
+ ];
76
+ }
77
+ }
src/Tickets/Commerce/Gateways/PayPal/On_Boarding_Redirect_Handler.php ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
+
5
+ use Exception;
6
+ use TEC\Tickets\Commerce\Gateways\PayPal\Repositories\Webhooks;
7
+ use Tribe__Settings;
8
+
9
+ /**
10
+ * Class On_Boarding_Redirect_Handler
11
+ *
12
+ * @todo This whole file will stop exsiting once we deprecate all Give's code usage.
13
+ *
14
+ * @since 5.1.6
15
+ * @package TEC\Tickets\Commerce\Gateways\PayPal
16
+ *
17
+ */
18
+ class On_Boarding_Redirect_Handler {
19
+ /**
20
+ * Sets up the webhook for the connected account
21
+ *
22
+ * @since 5.1.6
23
+ */
24
+ private function set_up_webhook() {
25
+ if ( ! is_ssl() ) {
26
+ return;
27
+ }
28
+
29
+ try {
30
+ $webhook_config = $this->webhooks_repository->create_webhook( $this->merchant->get_access_token() );
31
+
32
+ $this->webhooks_repository->save_webhook_config( $webhook_config );
33
+ } catch ( Exception $ex ) {
34
+ tribe( 'logger' )->log_error( $ex->getMessage(), 'tickets-commerce-paypal-commerce' );
35
+
36
+ $errors = [];
37
+
38
+ $errors[] = esc_html__( 'There was a problem with creating webhook on PayPal. A gateway error log also added to get details information about PayPal response.', 'event-tickets' );
39
+
40
+ // Log error messages.
41
+ array_map( static function ( $error_message ) {
42
+ $error_message = is_array( $error_message ) ? $error_message['message'] . ' ' . $error_message['value'] : $error_message;
43
+ tribe( 'logger' )->log_error( $error_message, 'tickets-commerce-paypal-commerce' );
44
+ }, $errors );
45
+
46
+ $this->merchant->save_account_errors( $errors );
47
+ $this->redirect_when_on_boarding_fail();
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Validate rest api credential.
53
+ *
54
+ * @since 5.1.6
55
+ *
56
+ * @param array $array
57
+ *
58
+ */
59
+ private function did_we_get_valid_seller_rest_api_credentials( $array ) {
60
+ $required = [ 'client_id', 'client_secret' ];
61
+ $array = array_filter( $array ); // Remove empty values.
62
+
63
+ $errors = [];
64
+
65
+ if ( array_diff( $required, array_keys( $array ) ) ) {
66
+ $errors[] = [
67
+ 'type' => 'json',
68
+ 'message' => esc_html__( 'PayPal client access token API request response is:', 'event-tickets' ),
69
+ 'value' => wp_json_encode( $this->settings->get_access_token() ),
70
+ ];
71
+
72
+ $errors[] = [
73
+ 'type' => 'json',
74
+ 'message' => esc_html__( 'PayPal client rest API credentials API request response is:', 'event-tickets' ),
75
+ 'value' => wp_json_encode( $array ),
76
+ ];
77
+
78
+ $errors[] = esc_html__( 'There was a problem with PayPal client rest API request and we could not find valid client id and secret.', 'event-tickets' );
79
+
80
+ // Log error messages.
81
+ array_map( static function ( $error_message ) {
82
+ $error_message = is_array( $error_message ) ? $error_message['message'] . ' ' . $error_message['value'] : $error_message;
83
+ tribe( 'logger' )->log_error( $error_message, 'tickets-commerce-paypal-commerce' );
84
+ }, $errors );
85
+
86
+ $this->merchant->save_account_errors( $errors );
87
+ //$this->redirect_when_on_boarding_fail();
88
+ }
89
+ }
90
+
91
+ /**
92
+ * Validate seller on Boarding status.
93
+ *
94
+ * @since 5.1.6
95
+ *
96
+ * @param string $merchant_id
97
+ * @param string $access_token
98
+ * @param bool $uses_custom_payments
99
+ *
100
+ * @return bool|string[]
101
+ */
102
+ private function is_admin_successfully_on_boarded( $merchant_id, $access_token, $uses_custom_payments ) {
103
+ $on_boarded_data = (array) tribe( WhoDat::class )->get_seller_on_boarding_details_from_paypal( $merchant_id, $access_token );
104
+ $on_boarded_data = array_filter( $on_boarded_data ); // Remove empty values.
105
+ $error_messages[] = [
106
+ 'type' => 'json',
107
+ 'message' => esc_html__( 'PayPal merchant status check API request response is:', 'event-tickets' ),
108
+ 'value' => wp_json_encode( $on_boarded_data ),
109
+ ];
110
+
111
+ if ( ! is_ssl() ) {
112
+ $error_messages[] = esc_html__( 'A valid SSL certificate is required to accept payments and set up your PayPal account. Once a
113
+ certificate is installed and the site is using https, please disconnect and reconnect your account.', 'event-tickets' );
114
+ }
115
+
116
+ if ( array_diff( [ 'payments_receivable', 'primary_email_confirmed' ], array_keys( $on_boarded_data ) ) ) {
117
+ $error_messages[] = esc_html__( 'There was a problem with the status check for your account. Please try disconnecting and connecting again. If the problem persists, please contact support.', 'event-tickets' );
118
+
119
+ // Log error messages.
120
+ array_map( static function ( $error_message ) {
121
+ $error_message = is_array( $error_message ) ? $error_message['message'] . ' ' . $error_message['value'] : $error_message;
122
+ tribe( 'logger' )->log_error( $error_message, 'tickets-commerce-paypal-commerce' );
123
+ }, $error_messages );
124
+
125
+ // Return here since the rest of the validations will definitely fail
126
+ return $error_messages;
127
+ }
128
+
129
+ if ( ! $on_boarded_data['payments_receivable'] ) {
130
+ $error_messages[] = esc_html__( 'Set up an account to receive payment from PayPal', 'event-tickets' );
131
+ }
132
+
133
+ if ( ! $on_boarded_data['primary_email_confirmed'] ) {
134
+ $error_messages[] = esc_html__( 'Confirm your primary email address', 'event-tickets' );
135
+ }
136
+
137
+ if ( ! $uses_custom_payments ) {
138
+ return count( $error_messages ) > 1 ? $error_messages : true;
139
+ }
140
+
141
+ if ( array_diff( [ 'products', 'capabilities' ], array_keys( $on_boarded_data ) ) ) {
142
+ $error_messages[] = esc_html__( 'Your account was expected to be able to accept custom payments, but is not. Please make sure your
143
+ account country matches the country setting. If the problem persists, please contact PayPal.', 'event-tickets' );
144
+
145
+ // Return here since the rest of the validations will definitely fail
146
+ return $error_messages;
147
+ }
148
+
149
+ // Grab the PPCP_CUSTOM product from the status data
150
+ $custom_product = current(
151
+ array_filter(
152
+ $on_boarded_data['products'],
153
+ static function ( $product ) {
154
+ return 'PPCP_CUSTOM' === $product['name'];
155
+ }
156
+ )
157
+ );
158
+
159
+ if ( empty( $custom_product ) || $custom_product['vetting_status'] !== 'SUBSCRIBED' ) {
160
+ $error_messages[] = esc_html__( 'Reach out to PayPal to enable PPCP_CUSTOM for your account', 'event-tickets' );
161
+ }
162
+
163
+ // Loop through the capabilities and see if any are not active
164
+ $invalid_capabilities = [];
165
+ foreach ( $on_boarded_data['capabilities'] as $capability ) {
166
+ if ( $capability['status'] !== 'ACTIVE' ) {
167
+ $invalid_capabilities[] = $capability['name'];
168
+ }
169
+ }
170
+
171
+ if ( ! empty( $invalid_capabilities ) ) {
172
+ $error_messages[] = esc_html__( 'Reach out to PayPal to resolve the following capabilities:', 'event-tickets' ) . ' ' . implode( ', ', $invalid_capabilities );
173
+ }
174
+
175
+ // If there were errors then redirect the user with notices
176
+ return count( $error_messages ) > 1 ? $error_messages : true;
177
+ }
178
+
179
+ /**
180
+ * Displays a notice of the site is not using SSL.
181
+ *
182
+ * @since 5.1.6
183
+ */
184
+ private function register_paypal_ssl_notice() {
185
+ if ( ! is_ssl() || ! empty( $this->webhooks_repository->get_webhook_config() ) ) {
186
+ return;
187
+ }
188
+
189
+ /** @var Tribe__Settings $settings */
190
+ $settings = tribe( 'settings' );
191
+
192
+ // Get link to Help page.
193
+ $log_url = $settings->get_url( [
194
+ 'page' => 'tribe-help',
195
+ ] ) . '#tribe-event-log';
196
+
197
+ $log_link = sprintf(
198
+ '<a href="%1$s">%2$s</a>',
199
+ $log_url,
200
+ esc_html__( 'logged data', 'event-tickets' )
201
+ );
202
+
203
+ tribe_error(
204
+ 'paypal-webhook-error',
205
+ sprintf(
206
+ // Translators: %1$s: The logged data link.
207
+ esc_html__( 'There was a problem setting up the webhooks for your PayPal account. Please try disconnecting and reconnecting your PayPal account. If the problem persists, please contact support and provide them with the latest %1$s', 'event-tickets' ),
208
+ $log_link
209
+ ),
210
+ [
211
+ 'type' => 'error',
212
+ ]
213
+ );
214
+ }
215
+ }
src/Tickets/Commerce/Gateways/PayPal/Provider.php CHANGED
@@ -2,8 +2,6 @@
2
 
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
 
5
- use Tribe\Tickets\REST\V1\Endpoints\Commerce\PayPal_Webhook;
6
-
7
  /**
8
  * Service provider for the Tickets Commerce: PayPal Commerce gateway.
9
  *
@@ -25,36 +23,30 @@ class Provider extends \tad_DI52_ServiceProvider {
25
 
26
  // @todo Is this needed?
27
  // $this->container->singleton( PaymentFormElements::class );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
- /*$this->container->singleton( PaymentProcessor::class );;*/
30
- $this->container->singleton( AjaxRequestHandler::class );
31
- $this->container->singleton( onBoardingRedirectHandler::class );
32
- $this->container->singleton( SDK\RefreshToken::class );
33
-
34
- $this->container->singleton( SDK\Repositories\PayPalAuth::class );
35
- $this->container->singleton( SDK\PayPalClient::class );
36
- $this->container->singleton( SDK\Repositories\PayPalOrder::class );
37
-
38
- $this->container->singleton( SDK\Models\MerchantDetail::class, null, [ 'init' ] );
39
- $this->container->singleton( SDK\Repositories\MerchantDetails::class, null, [ 'init' ] );
40
-
41
- $this->container->singleton( Webhooks\WebhookRegister::class );
42
- $this->container->singleton( Webhooks\WebhooksRoute::class );
43
- $this->container->singleton( SDK\Repositories\Webhooks::class, null, [ 'init' ] );
44
-
45
- $this->container->singleton( Webhooks\Listeners\PaymentCaptureCompleted::class );
46
- $this->container->singleton( Webhooks\Listeners\PaymentCaptureDenied::class );
47
- $this->container->singleton( Webhooks\Listeners\PaymentCaptureRefunded::class );
48
- $this->container->singleton( Webhooks\Listeners\PaymentCaptureReversed::class );
49
-
50
- $this->container->singleton( REST::class );
51
- $this->container->singleton( PayPal_Webhook::class, static function() {
52
- return new PayPal_Webhook(
53
- tribe( 'tickets.rest-v1.messages' ),
54
- tribe( 'tickets.rest-v1.repository' ),
55
- tribe( 'tickets.rest-v1.validator' )
56
- );
57
- } );
58
  }
59
 
60
  /**
@@ -88,7 +80,11 @@ class Provider extends \tad_DI52_ServiceProvider {
88
  * @since 5.1.6
89
  */
90
  public function register_endpoints() {
 
 
91
 
 
 
92
  }
93
 
94
  }
2
 
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
 
 
 
5
  /**
6
  * Service provider for the Tickets Commerce: PayPal Commerce gateway.
7
  *
23
 
24
  // @todo Is this needed?
25
  // $this->container->singleton( PaymentFormElements::class );
26
+ // $this->container->singleton( PaymentProcessor::class );
27
+
28
+ $this->container->singleton( Merchant::class, Merchant::class, [ 'init' ] );
29
+
30
+ $this->container->singleton( Ajax_Request_Handler::class );
31
+ $this->container->singleton( On_Boarding_Redirect_Handler::class );
32
+ $this->container->singleton( Refresh_Token::class );
33
+ $this->container->singleton( Client::class );
34
+ $this->container->singleton( Signup::class );
35
+ $this->container->singleton( Status::class );
36
+
37
+ $this->container->singleton( Repositories\Authorization::class );
38
+ $this->container->singleton( Repositories\Order::class );
39
+ $this->container->singleton( Repositories\Webhooks::class );
40
 
41
+ $this->container->singleton( Webhooks\Webhook_Register::class );
42
+ $this->container->singleton( Webhooks\Webhooks_Route::class );
43
+
44
+ $this->container->singleton( Webhooks\Listeners\Payment_Capture_Completed::class );
45
+ $this->container->singleton( Webhooks\Listeners\Payment_Capture_Denied::class );
46
+ $this->container->singleton( Webhooks\Listeners\Payment_Capture_Refunded::class );
47
+ $this->container->singleton( Webhooks\Listeners\Payment_Capture_Reversed::class );
48
+
49
+ $this->register_endpoints();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  }
51
 
52
  /**
80
  * @since 5.1.6
81
  */
82
  public function register_endpoints() {
83
+ $hooks = new REST( $this->container );
84
+ $hooks->register();
85
 
86
+ // Allow Hooks to be removed, by having the them registered to the container
87
+ $this->container->singleton( REST::class, $hooks );
88
  }
89
 
90
  }
src/Tickets/Commerce/Gateways/PayPal/REST.php CHANGED
@@ -2,38 +2,19 @@
2
 
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
 
5
- use Tribe\Tickets\REST\V1\Endpoints\Commerce\PayPal_Webhook;
6
  use WP_REST_Server;
7
 
8
  /**
9
  * Class REST
10
  *
11
- * @since 5.1.6
12
  * @package TEC\Tickets\Commerce\Gateways\PayPal
13
  */
14
- class REST {
15
-
16
- /**
17
- * The REST API namespace to use.
18
- *
19
- * @since 5.1.6
20
- *
21
- * @var string
22
- */
23
- public $namespace = '';
24
-
25
- /**
26
- * The REST API documentation endpoint.
27
- *
28
- * @since 5.1.6
29
- *
30
- * @var \Tribe__Tickets__REST__V1__Endpoints__Swagger_Documentation
31
- */
32
- public $documentation;
33
-
34
- public function __construct() {
35
- $this->namespace = tribe( 'tickets.rest-v1.main' )->get_events_route_namespace();
36
- $this->documentation = tribe( 'tickets.rest-v1.endpoints.documentation' );
37
  }
38
 
39
  /**
@@ -42,20 +23,7 @@ class REST {
42
  * @since 5.1.6
43
  */
44
  public function register_endpoints() {
45
- /** @var PayPal_Webhook $endpoint */
46
- $endpoint = tribe( PayPal_Webhook::class );
47
-
48
- register_rest_route(
49
- $this->namespace,
50
- $endpoint->path,
51
- [
52
- 'methods' => WP_REST_Server::CREATABLE,
53
- 'args' => $endpoint->CREATE_args(),
54
- 'callback' => [ $endpoint, 'create' ],
55
- 'permission_callback' => '__return_true',
56
- ]
57
- );
58
-
59
- $this->documentation->register_documentation_provider( $endpoint->path, $endpoint );
60
  }
61
  }
2
 
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
 
 
5
  use WP_REST_Server;
6
 
7
  /**
8
  * Class REST
9
  *
10
+ * @since 5.1.9
11
  * @package TEC\Tickets\Commerce\Gateways\PayPal
12
  */
13
+ class REST extends \tad_DI52_ServiceProvider {
14
+ public function register() {
15
+ // $this->container->singleton( REST\Webhook_Endpoint::class, [ $this, 'boot_webhook_endpoint' ] );
16
+ $this->container->singleton( REST\On_Boarding_Endpoint::class );
17
+ $this->container->singleton( REST\Order_Endpoint::class );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  }
19
 
20
  /**
23
  * @since 5.1.6
24
  */
25
  public function register_endpoints() {
26
+ $this->container->make( REST\On_Boarding_Endpoint::class )->register();
27
+ $this->container->make( REST\Order_Endpoint::class )->register();
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  }
29
  }
src/Tickets/Commerce/Gateways/PayPal/REST/On_Boarding_Endpoint.php ADDED
@@ -0,0 +1,433 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal\REST;
4
+
5
+ use TEC\Tickets\Commerce\Gateways\PayPal\Client;
6
+ use TEC\Tickets\Commerce\Gateways\PayPal\Merchant;
7
+ use TEC\Tickets\Commerce\Gateways\PayPal\Refresh_Token;
8
+
9
+ use TEC\Tickets\Commerce\Gateways\PayPal\Signup;
10
+ use TEC\Tickets\Commerce\Gateways\PayPal\WhoDat;
11
+ use Tribe__Documentation__Swagger__Provider_Interface;
12
+ use Tribe__Settings;
13
+ use Tribe__Utils__Array as Arr;
14
+
15
+ use WP_Error;
16
+ use WP_REST_Request;
17
+ use WP_REST_Response;
18
+ use WP_REST_Server;
19
+
20
+
21
+ /**
22
+ * Class On_Boarding_Endpoint
23
+ *
24
+ * @since 5.1.9
25
+ *
26
+ * @package TEC\Tickets\Commerce\Gateways\PayPal\REST
27
+ */
28
+ class On_Boarding_Endpoint implements Tribe__Documentation__Swagger__Provider_Interface {
29
+
30
+ /**
31
+ * The REST API endpoint path.
32
+ *
33
+ * @since 5.1.9
34
+ *
35
+ * @var string
36
+ */
37
+ protected $path = '/commerce/paypal/on-boarding';
38
+
39
+ /**
40
+ * Register the actual endpoint on WP Rest API.
41
+ *
42
+ * @since 5.1.9
43
+ */
44
+ public function register() {
45
+ $namespace = tribe( 'tickets.rest-v1.main' )->get_events_route_namespace();
46
+ $documentation = tribe( 'tickets.rest-v1.endpoints.documentation' );
47
+
48
+ register_rest_route(
49
+ $namespace,
50
+ $this->get_endpoint_path(),
51
+ [
52
+ 'methods' => WP_REST_Server::CREATABLE,
53
+ 'args' => $this->fetch_token_args(),
54
+ 'callback' => [ $this, 'handle_fetch_token' ],
55
+ 'permission_callback' => '__return_true',
56
+ ]
57
+ );
58
+
59
+ register_rest_route(
60
+ $namespace,
61
+ $this->get_endpoint_path(),
62
+ [
63
+ 'methods' => WP_REST_Server::READABLE,
64
+ 'args' => $this->signup_redirect_args(),
65
+ 'callback' => [ $this, 'handle_signup_redirect' ],
66
+ 'permission_callback' => '__return_true',
67
+ ]
68
+ );
69
+
70
+ $documentation->register_documentation_provider( $this->get_endpoint_path(), $this );
71
+ }
72
+
73
+ /**
74
+ * Gets the Endpoint path for the on boarding process.
75
+ *
76
+ * @since 5.1.9
77
+ *
78
+ * @return string
79
+ */
80
+ public function get_endpoint_path() {
81
+ return $this->path;
82
+ }
83
+
84
+ /**
85
+ * Get the REST API route URL.
86
+ *
87
+ * @since 5.1.9
88
+ *
89
+ * @return string The REST API route URL.
90
+ */
91
+ public function get_route_url() {
92
+ $namespace = tribe( 'tickets.rest-v1.main' )->get_events_route_namespace();
93
+
94
+ return rest_url( '/' . $namespace . $this->get_endpoint_path(), 'https' );
95
+ }
96
+
97
+ /**
98
+ * Gets the Return URL pointing to this on boarding route.
99
+ *
100
+ * @since 5.1.9
101
+ *
102
+ * @return string
103
+ */
104
+ public function get_return_url( $hash = null ) {
105
+ $arguments = [
106
+ 'hash' => $hash,
107
+ ];
108
+
109
+ return add_query_arg( $arguments, $this->get_route_url() );
110
+ }
111
+
112
+ /**
113
+ * Handles the request that happens in parallel to the User Signup on PayPal but before we redirect the user from
114
+ * the mini browser. So when passing error messages, they need to be registered to be fetched in the FE.
115
+ *
116
+ * @since 5.1.9
117
+ *
118
+ * @param WP_REST_Request $request The request object.
119
+ *
120
+ * @return WP_REST_Response An array containing the data on success or a WP_Error instance on failure.
121
+ */
122
+ public function handle_fetch_token( WP_REST_Request $request ) {
123
+ $response = [
124
+ 'success' => false,
125
+ ];
126
+
127
+ $signup = tribe( Signup::class );
128
+ $client = tribe( Client::class );
129
+ $merchant = tribe( Merchant::class );
130
+
131
+ // Send a request to fetch the access token.
132
+ $paypal_response = $client->get_access_token_from_authorization_code(
133
+ $request->get_param( 'shared_id' ),
134
+ $request->get_param( 'auth_code' ),
135
+ $signup->get_transient_hash()
136
+ );
137
+
138
+ if ( ! $paypal_response || array_key_exists( 'error', $paypal_response ) ) {
139
+ $response['error'] = __( 'Unexpected response from PayPal when on boarding', 'event-tickets' );
140
+
141
+ return new WP_REST_Response( $response );
142
+ }
143
+
144
+ // Save the information on the merchant system.
145
+ $merchant->save_access_token_data( $paypal_response );
146
+
147
+ tribe( Refresh_Token::class )->register_cron_job_to_refresh_token( $paypal_response['expires_in'] );
148
+
149
+ $response['success'] = true;
150
+
151
+ return new WP_REST_Response( $response );
152
+ }
153
+
154
+ /**
155
+ * This request is ran when the user is redirected back from the PayPal miniBrowser, and will not respond with
156
+ * a JSON request, but with a redirect of the user with a success link or error link into the payments tab.
157
+ *
158
+ * @since 5.1.9
159
+ *
160
+ * @param WP_REST_Request $request The request object.
161
+ *
162
+ * @return void This is strictly a redirect response.
163
+ */
164
+ public function handle_signup_redirect( WP_REST_Request $request ) {
165
+ $signup = tribe( Signup::class );
166
+ $existing_hash = $signup->get_transient_hash();
167
+ $request_hash = $request->get_param( 'hash' );
168
+ $return_url = Tribe__Settings::instance()->get_url( [ 'tab' => 'payments', ] );
169
+
170
+ if ( $request_hash !== $existing_hash ) {
171
+ $this->redirect_with( 'invalid-paypal-signup-hash', $return_url );
172
+ }
173
+
174
+ $seller_data = tribe( WhoDat::class )->get_seller_referral_data( $signup->get_referral_data_link() );
175
+ $has_custom_payments = in_array( 'PPCP', Arr::get( $seller_data, [ 'referral_data', 'products' ], [] ), true );
176
+
177
+ $merchant_id = $request->get_param( 'merchantId' );
178
+ $merchant_id_in_paypal = $request->get_param( 'merchantIdInPayPal' );
179
+
180
+ /**
181
+ * @todo Need to figure out where this gets saved in the merchant API.
182
+ */
183
+ $permissions_granted = $request->get_param( 'permissionsGranted' );
184
+ $consent_status = $request->get_param( 'consentStatus' );
185
+ $account_status = $request->get_param( 'accountStatus' );
186
+
187
+ $merchant = tribe( Merchant::class );
188
+
189
+ $merchant->save_signup_data( $seller_data );
190
+
191
+ $merchant->set_signup_hash( $request_hash );
192
+ $merchant->set_merchant_id( $merchant_id );
193
+ $merchant->set_merchant_id_in_paypal( $merchant_id_in_paypal );
194
+
195
+ $access_token = $merchant->get_access_token();
196
+ $credentials = tribe( WhoDat::class )->get_seller_credentials( $access_token );
197
+
198
+ if ( ! isset( $credentials['client_id'], $credentials['client_secret'] ) ) {
199
+ // Save what we have before moving forward.
200
+ $merchant->save();
201
+
202
+ $this->redirect_with( 'invalid-paypal-seller-credentials', $return_url );
203
+ }
204
+
205
+ $merchant->set_client_id( $credentials['client_id'] );
206
+ $merchant->set_client_secret( $credentials['client_secret'] );
207
+ $merchant->set_account_is_ready( true );
208
+ $merchant->set_supports_custom_payments( $has_custom_payments );
209
+ $merchant->save();
210
+
211
+ $client = tribe( Client::class );
212
+
213
+ // Pull Access token data.
214
+ $token_data = $client->get_access_token_from_client_credentials( $credentials['client_id'], $credentials['client_secret'] );
215
+ $merchant->save_access_token_data( $token_data );
216
+
217
+ // Pull user info from PayPal.
218
+ $user_info = $client->get_user_info();
219
+ $merchant->save_user_info( $user_info );
220
+
221
+ /**
222
+ * @todo Need to figure out where this gets saved in the merchant API.
223
+ */
224
+ update_option( 'tickets_commerce_permissions_granted', $permissions_granted );
225
+ update_option( 'tickets_commerce_consent_status', $consent_status );
226
+ update_option( 'tickets_commerce_account_status', $account_status );
227
+
228
+ $this->redirect_with( 'paypal-signup-complete', $return_url );
229
+ }
230
+
231
+ /**
232
+ * Using wp_safe_redirect sends the client back to a given URL after removing the Signup data acquired.
233
+ *
234
+ * @since 5.1.9
235
+ *
236
+ * @param string $status Which status we will add to the URL
237
+ * @param string $url Which URL we are sending the client to.
238
+ * @param array $data Extra that that will be json encoded to the URL.
239
+ *
240
+ */
241
+ protected function redirect_with( $status, $url, array $data = [] ) {
242
+ $signup = tribe( Signup::class );
243
+
244
+ // We always clean signup data before redirect.
245
+ $signup->delete_transient_data();
246
+ $signup->delete_transient_hash();
247
+
248
+ $query_args = [ 'tc-status' => $status ];
249
+
250
+ if ( ! empty( $data ) ) {
251
+ $query_args['tc-data'] = wp_json_encode( $data );
252
+ }
253
+
254
+ // Add an status slug to the URL.
255
+ $url = add_query_arg( $query_args, $url );
256
+
257
+ wp_safe_redirect( $url );
258
+ exit;
259
+ }
260
+
261
+ /**
262
+ * Arguments used for the signup redirect.
263
+ *
264
+ * @since 5.1.9
265
+ *
266
+ * @return array
267
+ */
268
+ public function signup_redirect_args() {
269
+ // Webhooks do not send any arguments, only JSON content.
270
+ return [
271
+ 'hash' => [
272
+ 'description' => 'The nonce validation',
273
+ 'required' => true,
274
+ 'type' => 'string',
275
+ 'validate_callback' => static function ( $value ) {
276
+ if ( ! is_string( $value ) ) {
277
+ return new WP_Error( 'rest_invalid_param', 'The wp_nonce argument must be a string.', [ 'status' => 400 ] );
278
+ }
279
+
280
+ return $value;
281
+ },
282
+ 'sanitize_callback' => [ $this, 'sanitize_callback' ],
283
+ ],
284
+ 'merchantId' => [
285
+ 'description' => 'The merchant ID',
286
+ 'required' => true,
287
+ 'type' => 'string',
288
+ 'validate_callback' => static function ( $value ) {
289
+ if ( ! is_string( $value ) ) {
290
+ return new WP_Error( 'rest_invalid_param', 'The merchantId argument must be a string.', [ 'status' => 400 ] );
291
+ }
292
+
293
+ return $value;
294
+ },
295
+ 'sanitize_callback' => [ $this, 'sanitize_callback' ],
296
+ ],
297
+ 'merchantIdInPayPal' => [
298
+ 'description' => 'The merchant ID in PayPal',
299
+ 'required' => true,
300
+ 'type' => 'string',
301
+ 'validate_callback' => static function ( $value ) {
302
+ if ( ! is_string( $value ) ) {
303
+ return new WP_Error( 'rest_invalid_param', 'The merchantIdInPayPal argument must be a string.', [ 'status' => 400 ] );
304
+ }
305
+
306
+ return $value;
307
+ },
308
+ 'sanitize_callback' => [ $this, 'sanitize_callback' ],
309
+ ],
310
+ 'permissionsGranted' => [
311
+ 'description' => 'The merchant ID in PayPal',
312
+ 'required' => true,
313
+ 'type' => 'string',
314
+ 'validate_callback' => static function ( $value ) {
315
+ if ( ! is_string( $value ) ) {
316
+ return new WP_Error( 'rest_invalid_param', 'The permissionsGranted argument must be a string.', [ 'status' => 400 ] );
317
+ }
318
+
319
+ return $value;
320
+ },
321
+ 'sanitize_callback' => [ $this, 'sanitize_callback' ],
322
+ ],
323
+ 'consentStatus' => [
324
+ 'description' => 'The merchant ID in PayPal',
325
+ 'required' => true,
326
+ 'type' => 'string',
327
+ 'validate_callback' => static function ( $value ) {
328
+ if ( ! is_string( $value ) ) {
329
+ return new WP_Error( 'rest_invalid_param', 'The consentStatus argument must be a string.', [ 'status' => 400 ] );
330
+ }
331
+
332
+ return $value;
333
+ },
334
+ 'sanitize_callback' => [ $this, 'sanitize_callback' ],
335
+ ],
336
+ 'accountStatus' => [
337
+ 'description' => 'The merchant ID in PayPal',
338
+ 'required' => true,
339
+ 'type' => 'string',
340
+ 'validate_callback' => static function ( $value ) {
341
+ if ( ! is_string( $value ) ) {
342
+ return new WP_Error( 'rest_invalid_param', 'The accountStatus argument must be a string.', [ 'status' => 400 ] );
343
+ }
344
+
345
+ return $value;
346
+ },
347
+ 'sanitize_callback' => [ $this, 'sanitize_callback' ],
348
+ ],
349
+ ];
350
+ }
351
+
352
+ /**
353
+ * Arguments used for the fetching of the token request.
354
+ *
355
+ * @since 5.1.9
356
+ *
357
+ * @return array
358
+ */
359
+ public function fetch_token_args() {
360
+ // Webhooks do not send any arguments, only JSON content.
361
+ return [
362
+ 'nonce' => [
363
+ 'description' => 'The nonce validation for WP',
364
+ 'required' => true,
365
+ 'type' => 'string',
366
+ 'validate_callback' => static function ( $value ) {
367
+ if ( ! is_string( $value ) ) {
368
+ return new WP_Error( 'rest_invalid_param', 'The wp_nonce argument must be a string.', [ 'status' => 400 ] );
369
+ }
370
+
371
+ return $value;
372
+ },
373
+ 'sanitize_callback' => [ $this, 'sanitize_callback' ],
374
+ ],
375
+ 'auth_code' => [
376
+ 'description' => 'Authorization Code from PayPal',
377
+ 'required' => true,
378
+ 'type' => 'string',
379
+ 'validate_callback' => static function ( $value ) {
380
+ if ( ! is_string( $value ) ) {
381
+ return new WP_Error( 'rest_invalid_param', 'The merchantId auth_code must be a string.', [ 'status' => 400 ] );
382
+ }
383
+
384
+ return $value;
385
+ },
386
+ 'sanitize_callback' => [ $this, 'sanitize_callback' ],
387
+ ],
388
+ 'shared_id' => [
389
+ 'description' => 'The shared ID from PayPal',
390
+ 'required' => true,
391
+ 'type' => 'string',
392
+ 'validate_callback' => static function ( $value ) {
393
+ if ( ! is_string( $value ) ) {
394
+ return new WP_Error( 'rest_invalid_param', 'The shared_id argument must be a string.', [ 'status' => 400 ] );
395
+ }
396
+
397
+ return $value;
398
+ },
399
+ 'sanitize_callback' => [ $this, 'sanitize_callback' ],
400
+ ],
401
+ ];
402
+ }
403
+
404
+ /**
405
+ * Sanitize a request argument based on details registered to the route.
406
+ *
407
+ * @since 5.1.9
408
+ *
409
+ * @param mixed $value Value of the 'filter' argument.
410
+ *
411
+ * @return string|array
412
+ */
413
+ public function sanitize_callback( $value ) {
414
+ if ( is_array( $value ) ) {
415
+ return array_map( 'sanitize_text_field', $value );
416
+ }
417
+
418
+ return sanitize_text_field( $value );
419
+ }
420
+
421
+ /**
422
+ * {@inheritDoc}
423
+ *
424
+ * @TODO We need to make sure Swagger documentation is present.
425
+ *
426
+ * @since 5.1.9
427
+ *
428
+ * @return array
429
+ */
430
+ public function get_documentation() {
431
+ return [];
432
+ }
433
+ }
src/Tickets/Commerce/Gateways/PayPal/REST/Order_Endpoint.php ADDED
@@ -0,0 +1,278 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal\REST;
4
+
5
+ use tad\WPBrowser\Adapters\WP;
6
+ use TEC\Tickets\Commerce\Cart;
7
+ use TEC\Tickets\Commerce\Gateways\PayPal\Gateway;
8
+ use TEC\Tickets\Commerce\Gateways\PayPal\Status;
9
+ use TEC\Tickets\Commerce\Order;
10
+
11
+ use TEC\Tickets\Commerce\Gateways\PayPal\Client;
12
+ use TEC\Tickets\Commerce\Gateways\PayPal\Merchant;
13
+ use TEC\Tickets\Commerce\Gateways\PayPal\Refresh_Token;
14
+
15
+ use TEC\Tickets\Commerce\Gateways\PayPal\Signup;
16
+ use TEC\Tickets\Commerce\Gateways\PayPal\WhoDat;
17
+
18
+
19
+ use TEC\Tickets\Commerce\Status\Pending;
20
+ use TEC\Tickets\Commerce\Status\Completed;
21
+ use TEC\Tickets\Commerce\Status\Created;
22
+ use TEC\Tickets\Commerce\Success;
23
+ use Tribe__Documentation__Swagger__Provider_Interface;
24
+ use Tribe__Settings;
25
+ use Tribe__Utils__Array as Arr;
26
+
27
+ use WP_Error;
28
+ use WP_REST_Request;
29
+ use WP_REST_Response;
30
+ use WP_REST_Server;
31
+
32
+
33
+ /**
34
+ * Class Order Endpoint.
35
+ *
36
+ * @since 5.1.9
37
+ *
38
+ * @package TEC\Tickets\Commerce\Gateways\PayPal\REST
39
+ */
40
+ class Order_Endpoint implements Tribe__Documentation__Swagger__Provider_Interface {
41
+
42
+ /**
43
+ * The REST API endpoint path.
44
+ *
45
+ * @since 5.1.9
46
+ *
47
+ * @var string
48
+ */
49
+ protected $path = '/commerce/paypal/order';
50
+
51
+ /**
52
+ * Register the actual endpoint on WP Rest API.
53
+ *
54
+ * @since 5.1.9
55
+ */
56
+ public function register() {
57
+ $namespace = tribe( 'tickets.rest-v1.main' )->get_events_route_namespace();
58
+ $documentation = tribe( 'tickets.rest-v1.endpoints.documentation' );
59
+
60
+ register_rest_route(
61
+ $namespace,
62
+ $this->get_endpoint_path(),
63
+ [
64
+ 'methods' => WP_REST_Server::CREATABLE,
65
+ 'args' => $this->create_order_args(),
66
+ 'callback' => [ $this, 'handle_create_order' ],
67
+ 'permission_callback' => '__return_true',
68
+ ]
69
+ );
70
+
71
+ register_rest_route(
72
+ $namespace,
73
+ $this->get_endpoint_path() . '/(?P<order_id>[0-9a-zA-Z]+)',
74
+ [
75
+ 'methods' => WP_REST_Server::CREATABLE,
76
+ 'args' => $this->update_order_args(),
77
+ 'callback' => [ $this, 'handle_update_order' ],
78
+ 'permission_callback' => '__return_true',
79
+ ]
80
+ );
81
+
82
+ $documentation->register_documentation_provider( $this->get_endpoint_path(), $this );
83
+ }
84
+
85
+ /**
86
+ * Gets the Endpoint path for the on boarding process.
87
+ *
88
+ * @since 5.1.9
89
+ *
90
+ * @return string
91
+ */
92
+ public function get_endpoint_path() {
93
+ return $this->path;
94
+ }
95
+
96
+ /**
97
+ * Get the REST API route URL.
98
+ *
99
+ * @since 5.1.9
100
+ *
101
+ * @return string The REST API route URL.
102
+ */
103
+ public function get_route_url() {
104
+ $namespace = tribe( 'tickets.rest-v1.main' )->get_events_route_namespace();
105
+
106
+ return rest_url( '/' . $namespace . $this->get_endpoint_path(), 'https' );
107
+ }
108
+
109
+ /**
110
+ * Handles the request that creates an order with Tickets Commerce and the PayPal gateway.
111
+ *
112
+ * @since 5.1.9
113
+ *
114
+ * @param WP_REST_Request $request The request object.
115
+ *
116
+ * @return WP_Error|WP_REST_Response An array containing the data on success or a WP_Error instance on failure.
117
+ */
118
+ public function handle_create_order( WP_REST_Request $request ) {
119
+ $response = [
120
+ 'success' => false,
121
+ ];
122
+
123
+ $order = tribe( Order::class )->create_from_cart( tribe( Gateway::class ) );
124
+
125
+ $unit = [
126
+ 'reference_id' => $order->ID,
127
+ 'value' => $order->total_value,
128
+ 'currency' => $order->currency,
129
+ 'first_name' => $order->purchaser_first_name,
130
+ 'last_name' => $order->purchaser_last_name,
131
+ 'email' => $order->purchaser_email,
132
+ ];
133
+
134
+ $paypal_order = tribe( Client::class )->create_order( $unit );
135
+
136
+ if ( empty( $paypal_order['id'] ) || empty( $paypal_order['create_time'] ) ) {
137
+ return new WP_Error( 'tec-tc-gateway-paypal-failed-creating-order', null, $order );
138
+ }
139
+
140
+ $updated = tribe( Order::class )->modify_status( $order->ID, Pending::SLUG, [
141
+ 'gateway_payload' => $paypal_order,
142
+ 'gateway_order_id' => $paypal_order['id'],
143
+ ] );
144
+
145
+ if ( is_wp_error( $updated ) ) {
146
+ return $updated;
147
+ }
148
+
149
+ // Respond with the ID for Paypal Usage.
150
+ $response['success'] = true;
151
+ $response['id'] = $paypal_order['id'];
152
+
153
+ return new WP_REST_Response( $response );
154
+ }
155
+
156
+ /**
157
+ * Handles the request that updates an order with Tickets Commerce and the PayPal gateway.
158
+ *
159
+ * @since 5.1.9
160
+ *
161
+ * @param WP_REST_Request $request The request object.
162
+ *
163
+ * @return WP_Error|WP_REST_Response An array containing the data on success or a WP_Error instance on failure.
164
+ */
165
+ public function handle_update_order( WP_REST_Request $request ) {
166
+ $response = [
167
+ 'success' => false,
168
+ ];
169
+
170
+ $paypal_order_id = $request->get_param( 'order_id' );
171
+ $order = tec_tc_orders()->by_args( [
172
+ 'status' => tribe( Pending::class )->get_wp_slug(),
173
+ 'gateway_order_id' => $paypal_order_id,
174
+ ] )->first();
175
+
176
+ if ( ! $order ) {
177
+ return new WP_Error( 'tec-tc-gateway-paypal-nonexistent-order-id', null, $order );
178
+ }
179
+
180
+ $paypal_capture_response = tribe( Client::class )->capture_order( $paypal_order_id );
181
+
182
+ if ( ! $paypal_capture_response ) {
183
+ return new WP_Error( 'tec-tc-gateway-paypal-failed-capture', null, $paypal_capture_response );
184
+ }
185
+
186
+ $paypal_capture_status = Arr::get( $paypal_capture_response, [ 'status' ] );
187
+ $status = tribe( Status::class )->convert_to_commerce_status( $paypal_capture_status );
188
+
189
+ if ( ! $status ) {
190
+ return new WP_Error( 'tec-tc-gateway-paypal-invalid-capture-status', null, $paypal_capture_response );
191
+ }
192
+
193
+ $updated = tribe( Order::class )->modify_status( $order->ID, $status->get_slug(), [
194
+ 'gateway_payload' => $paypal_capture_response,
195
+ ] );
196
+
197
+ if ( is_wp_error( $updated ) ) {
198
+ return $updated;
199
+ }
200
+
201
+ $response['success'] = true;
202
+ $response['status'] = $status->get_slug();
203
+ $response['order_id'] = $order->ID;
204
+
205
+ // When we have success we clear the cart.
206
+ tribe( Cart::class )->clear_cart();
207
+
208
+ $response['redirect_url'] = add_query_arg( [ 'tc-order-id' => $paypal_order_id ], tribe( Success::class )->get_url() );
209
+
210
+ return new WP_REST_Response( $response );
211
+ }
212
+
213
+ /**
214
+ * Arguments used for the signup redirect.
215
+ *
216
+ * @since 5.1.9
217
+ *
218
+ * @return array
219
+ */
220
+ public function create_order_args() {
221
+ return [];
222
+ }
223
+
224
+ /**
225
+ * Arguments used for the signup redirect.
226
+ *
227
+ * @since 5.1.9
228
+ *
229
+ * @return array
230
+ */
231
+ public function update_order_args() {
232
+ return [
233
+ 'order_id' => [
234
+ 'description' => __( 'Order ID in PayPal', 'event-tickets' ),
235
+ 'required' => true,
236
+ 'type' => 'string',
237
+ 'validate_callback' => static function ( $value ) {
238
+ if ( ! is_string( $value ) ) {
239
+ return new WP_Error( 'rest_invalid_param', 'The order ID argument must be a string.', [ 'status' => 400 ] );
240
+ }
241
+
242
+ return $value;
243
+ },
244
+ 'sanitize_callback' => [ $this, 'sanitize_callback' ],
245
+ ],
246
+ ];
247
+ }
248
+
249
+ /**
250
+ * Sanitize a request argument based on details registered to the route.
251
+ *
252
+ * @since 5.1.9
253
+ *
254
+ * @param mixed $value Value of the 'filter' argument.
255
+ *
256
+ * @return string|array
257
+ */
258
+ public function sanitize_callback( $value ) {
259
+ if ( is_array( $value ) ) {
260
+ return array_map( 'sanitize_text_field', $value );
261
+ }
262
+
263
+ return sanitize_text_field( $value );
264
+ }
265
+
266
+ /**
267
+ * {@inheritDoc}
268
+ *
269
+ * @TODO We need to make sure Swagger documentation is present.
270
+ *
271
+ * @since 5.1.9
272
+ *
273
+ * @return array
274
+ */
275
+ public function get_documentation() {
276
+ return [];
277
+ }
278
+ }
src/{Tribe/REST/V1/Endpoints/Commerce/PayPal_Webhook.php → Tickets/Commerce/Gateways/PayPal/REST/Webhook_Endpoint.php} RENAMED
@@ -1,9 +1,10 @@
1
  <?php
2
 
3
- namespace Tribe\Tickets\REST\V1\Endpoints\Commerce;
4
 
5
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\PaymentCaptureCompleted;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\WebhooksRoute;
 
7
  use Tribe__Documentation__Swagger__Provider_Interface;
8
  use Tribe__REST__Endpoints__CREATE_Endpoint_Interface;
9
  use Tribe__Tickets__REST__V1__Endpoints__Base;
@@ -17,7 +18,7 @@ use WP_REST_Response;
17
  * @since 5.1.6
18
  * @package Tribe\Tickets\REST\V1\Endpoints\PayPal_Commerce
19
  */
20
- class PayPal_Webhook
21
  extends Tribe__Tickets__REST__V1__Endpoints__Base
22
  implements Tribe__REST__Endpoints__CREATE_Endpoint_Interface,
23
  Tribe__Documentation__Swagger__Provider_Interface {
@@ -29,7 +30,31 @@ class PayPal_Webhook
29
  *
30
  * @var string
31
  */
32
- public $path = '/paypal-commerce/webhook';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  /**
35
  * {@inheritDoc}
@@ -78,6 +103,8 @@ class PayPal_Webhook
78
  /**
79
  * {@inheritDoc}
80
  *
 
 
81
  * @since 5.1.6
82
  *
83
  * @param WP_REST_Request $request The request object.
@@ -89,8 +116,8 @@ class PayPal_Webhook
89
  $event = $request->get_body();
90
  $headers = $request->get_headers();
91
 
92
- /** @var WebhooksRoute $webhook */
93
- $webhook = tribe( WebhooksRoute::class );
94
 
95
  try {
96
  $processed = $webhook->handle( $event, $headers );
1
  <?php
2
 
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal\REST;
4
 
5
+ use TEC\Tickets\Commerce\Gateways\PayPal\REST;
6
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\Payment_Capture_Completed;
7
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Webhooks_Route;
8
  use Tribe__Documentation__Swagger__Provider_Interface;
9
  use Tribe__REST__Endpoints__CREATE_Endpoint_Interface;
10
  use Tribe__Tickets__REST__V1__Endpoints__Base;
18
  * @since 5.1.6
19
  * @package Tribe\Tickets\REST\V1\Endpoints\PayPal_Commerce
20
  */
21
+ class Webhook_Endpoint
22
  extends Tribe__Tickets__REST__V1__Endpoints__Base
23
  implements Tribe__REST__Endpoints__CREATE_Endpoint_Interface,
24
  Tribe__Documentation__Swagger__Provider_Interface {
30
  *
31
  * @var string
32
  */
33
+ protected $path = '/tickets-commerce/paypal/webhook';
34
+
35
+ /**
36
+ * Gets the Endpoint path for the on boarding process.
37
+ *
38
+ * @since 5.1.9
39
+ *
40
+ * @return string
41
+ */
42
+ public function get_endpoint_path() {
43
+ return $this->path;
44
+ }
45
+
46
+ /**
47
+ * Get the REST API route URL.
48
+ *
49
+ * @since 5.1.9
50
+ *
51
+ * @return string The REST API route URL.
52
+ */
53
+ public function get_route_url() {
54
+ $rest = tribe( REST::class );
55
+
56
+ return rest_url( '/' . $rest->namespace . $this->get_endpoint_path(), 'https' );
57
+ }
58
 
59
  /**
60
  * {@inheritDoc}
103
  /**
104
  * {@inheritDoc}
105
  *
106
+ * @todo WIP -- Still using pieces from Give.
107
+ *
108
  * @since 5.1.6
109
  *
110
  * @param WP_REST_Request $request The request object.
116
  $event = $request->get_body();
117
  $headers = $request->get_headers();
118
 
119
+ /** @var Webhooks_Route $webhook */
120
+ $webhook = tribe( Webhooks_Route::class );
121
 
122
  try {
123
  $processed = $webhook->handle( $event, $headers );
src/Tickets/Commerce/Gateways/PayPal/Refresh_Token.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
+
5
+ use TEC\Tickets\Commerce\Gateways\PayPal\Repositories\Authorization;
6
+
7
+ /**
8
+ * Class Refresh_Token
9
+ *
10
+ * @since 5.1.6
11
+ * @package TEC\Tickets\Commerce\Gateways\PayPal
12
+ */
13
+ class Refresh_Token {
14
+
15
+ /*
16
+ * @since 5.1.6
17
+ *
18
+ * @var Merchant
19
+ */
20
+ private $merchant;
21
+
22
+ /**
23
+ * @since 5.1.6
24
+ *
25
+ * @var Client
26
+ */
27
+ private $client;
28
+
29
+ /**
30
+ * Refresh_Token constructor.
31
+ *
32
+ * @since 5.1.6
33
+ *
34
+ * @param Merchant $merchant
35
+ * @param Client $client
36
+ */
37
+ public function __construct(
38
+ Merchant $merchant = null,
39
+ Client $client = null
40
+ ) {
41
+ $this->merchant = $merchant ?: tribe( Merchant::class );
42
+ $this->client = $client ?: tribe( Client::class );
43
+ }
44
+
45
+ /**
46
+ * Return cron json name which uses to refresh token.
47
+ *
48
+ * @since 5.1.6
49
+ *
50
+ * @return string
51
+ */
52
+ private function get_cron_job_hook_name() {
53
+ return 'tec_tickets_commerce_paypal_refresh_access_token';
54
+ }
55
+
56
+ /**
57
+ * Register cron job to refresh access token.
58
+ * Note: only for internal use.
59
+ *
60
+ * @since 5.1.6
61
+ *
62
+ * @param string $tokenExpires What time the token expires.
63
+ */
64
+ public function register_cron_job_to_refresh_token( $tokenExpires ) {
65
+ // @todo Verify we need this as a cron, do we lose total API access if it expires (no visitors)?
66
+ wp_schedule_single_event(
67
+ // Refresh token before half hours of expires date.
68
+ time() + ( $tokenExpires - 1800 ),
69
+ $this->get_cron_job_hook_name()
70
+ );
71
+ }
72
+
73
+ /**
74
+ * Delete cron job which refresh access token.
75
+ * Note: only for internal use.
76
+ *
77
+ * @since 5.1.6
78
+ */
79
+ public function delete_refresh_token_cron_job() {
80
+ wp_clear_scheduled_hook( $this->get_cron_job_hook_name() );
81
+ }
82
+
83
+ /**
84
+ * Refresh token.
85
+ * Note: only for internal use
86
+ *
87
+ * @since 5.1.6
88
+ */
89
+ public function refresh_token() {
90
+ // Exit if account is not connected.
91
+ if ( ! $this->merchant->account_is_connected() ) {
92
+ return;
93
+ }
94
+
95
+ $token_data = $this->client->get_access_token_from_client_credentials( $this->merchant->get_client_id(), $this->merchant->get_client_secret() );
96
+
97
+ $this->merchant->save_access_token_data( $token_data );
98
+
99
+ $this->register_cron_job_to_refresh_token( $token_data['expires_in'] );
100
+ }
101
+ }
src/Tickets/Commerce/Gateways/PayPal/Repositories/Authorization.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal\Repositories;
4
+
5
+ use TEC\Tickets\Commerce\Gateways\PayPal\WhoDat;
6
+ use TEC\Tickets\Commerce\Gateways\PayPal\Client;
7
+
8
+ /**
9
+ * Class Authorization
10
+ *
11
+ * @since 5.1.6
12
+ * @package TEC\Tickets\Commerce\Gateways\PayPal\Repositories
13
+ */
14
+ class Authorization {
15
+
16
+ /**
17
+ * @since 5.1.6
18
+ *
19
+ * @var Client
20
+ */
21
+ private $paypal_client;
22
+
23
+ /**
24
+ * @since 5.1.6
25
+ *
26
+ * @var WhoDat
27
+ */
28
+ private $connect_client;
29
+
30
+ /**
31
+ * Authorization constructor.
32
+ *
33
+ * @since 5.1.6
34
+ *
35
+ * @param Client $paypal_client
36
+ * @param WhoDat $connect_client
37
+ */
38
+ public function __construct( Client $paypal_client, WhoDat $connect_client ) {
39
+ $this->paypal_client = $paypal_client;
40
+ $this->connect_client = $connect_client;
41
+ }
42
+
43
+ /**
44
+ * Retrieves a token for the Client ID and Secret.
45
+ *
46
+ * @since 5.1.6
47
+ *
48
+ * @param string $client_id The Client ID.
49
+ * @param string $client_secret The Client Secret.
50
+ *
51
+ * @return array|null The token details response or null if there was a problem.
52
+ */
53
+ public function get_token_from_client_credentials( $client_id, $client_secret ) {
54
+ $auth = base64_encode( "$client_id:$client_secret" );
55
+
56
+ $request = wp_remote_post( $this->paypal_client->get_api_url( 'v1/oauth2/token' ), [
57
+ 'headers' => [
58
+ 'Authorization' => sprintf( 'Basic %1$s', $auth ),
59
+ 'Content-Type' => 'application/x-www-form-urlencoded',
60
+ ],
61
+ 'body' => [
62
+ 'grant_type' => 'client_credentials',
63
+ ],
64
+ ] );
65
+
66
+ if ( is_wp_error( $request ) ) {
67
+ tribe( 'logger' )->log_error( sprintf(
68
+ // Translators: %s: The error message.
69
+ __( 'PayPal request error: %s', 'event-tickets' ),
70
+ $request->get_error_message()
71
+ ), 'tickets-commerce-paypal-commerce' );
72
+
73
+ return null;
74
+ }
75
+
76
+ $response = wp_remote_retrieve_body( $request );
77
+ $response = @json_decode( $response, true );
78
+
79
+ if ( ! is_array( $response ) ) {
80
+ tribe( 'logger' )->log_error( __( 'Unexpected PayPal response when getting token from client credentials', 'event-tickets' ), 'tickets-commerce-paypal-commerce' );
81
+
82
+ return null;
83
+ }
84
+
85
+ return $response;
86
+ }
87
+
88
+ }
src/Tickets/Commerce/Gateways/PayPal/Repositories/Order.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal\Repositories;
4
+
5
+ use TEC\Tickets\Commerce\Gateways\PayPal\Client;
6
+
7
+ /**
8
+ * Class Order
9
+ *
10
+ * @since 5.1.6
11
+ * @package TEC\Tickets\Commerce\Gateways\PayPal\Repositories
12
+ *
13
+ */
14
+ class Order {
15
+
16
+ /**
17
+ * @since 5.1.6
18
+ *
19
+ * @var Client
20
+ */
21
+ private $client;
22
+
23
+ /**
24
+ * Order constructor.
25
+ *
26
+ * @since 5.1.6
27
+ *
28
+ * @param Client $client
29
+ */
30
+ public function __construct( Client $client = null ) {
31
+ $this->client = $client ?: tribe( Client::class );
32
+ }
33
+
34
+ /**
35
+ * Approve order.
36
+ *
37
+ * @since 5.1.6
38
+ *
39
+ * @param string|int $order_id Which Order Post Type ID we are going to create a PayPal Order from.
40
+ *
41
+ * @return string
42
+ */
43
+ public function approve( $order_id ) {
44
+ $response = $this->client->capture_order( $order_id );
45
+
46
+ return $response;
47
+ }
48
+
49
+ /**
50
+ * Create order based on Event Ticket Order ID we send the data to Paypal to create the order there.
51
+ *
52
+ * @since 5.1.9
53
+ *
54
+ * @param string|int $order_id Which Order Post Type ID we are going to create a PayPal Order from.
55
+ *
56
+ * @return array
57
+ */
58
+ public function create( $order_id ) {
59
+
60
+ $data = [
61
+
62
+ ];
63
+
64
+ $order_response = $this->client->create_order( $data );
65
+
66
+ return $order_response['id'];
67
+ }
68
+
69
+ /**
70
+ * Refunds a processed payment
71
+ *
72
+ * @since 5.1.6
73
+
74
+ * @param string|int $order_id Which Order Post Type ID we are going to create a PayPal Order from.
75
+ *
76
+ * @return string The id of the refund
77
+ */
78
+ public function refund_payment( $order_id ) {
79
+ $response = $this->client->refund_payment( $order_id );
80
+
81
+ return $response;
82
+ }
83
+ }
src/Tickets/Commerce/Gateways/PayPal/{SDK/Repositories → Repositories}/Webhooks.php RENAMED
@@ -1,36 +1,39 @@
1
  <?php
2
 
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories;
4
 
5
  use Exception;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\DataTransferObjects\PayPalWebhookHeaders;
7
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models\WebhookConfig;
8
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\PayPalClient;
9
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\Traits\HasMode;
10
  use TEC\Tickets\Commerce\Gateways\PayPal\Settings;
11
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\WebhookRegister;
12
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\WebhooksRoute;
13
-
 
 
 
 
 
 
14
  class Webhooks {
15
-
16
- use HasMode;
17
-
18
  /**
19
  * @since 5.1.6
20
  *
21
- * @var WebhooksRoute
22
  */
23
- private $webhookRoute;
24
 
25
  /**
26
- * @var WebhookRegister
27
  */
28
- private $webhooksRegister;
29
 
30
  /**
31
- * @var PayPalClient
32
  */
33
- private $payPalClient;
34
 
35
  /**
36
  * @var Settings
@@ -42,23 +45,14 @@ class Webhooks {
42
  *
43
  * @since 5.1.6
44
  *
45
- * @param PayPalClient $payPalClient
46
- * @param WebhookRegister $webhooksRegister
47
- * @param Settings $settings
48
- */
49
- public function __construct( PayPalClient $payPalClient, WebhookRegister $webhooksRegister, Settings $settings ) {
50
- $this->payPalClient = $payPalClient;
51
- $this->webhooksRegister = $webhooksRegister;
52
- $this->settings = $settings;
53
- }
54
-
55
- /**
56
- * Handle initial setup for the object singleton.
57
- *
58
- * @since 5.1.6
59
  */
60
- public function init() {
61
- $this->setMode( tribe_tickets_commerce_is_test_mode() ? 'sandbox' : 'live' );
 
 
62
  }
63
 
64
  /**
@@ -67,20 +61,20 @@ class Webhooks {
67
  * @see https://developer.paypal.com/docs/api/webhooks/v1/#verify-webhook-signature
68
  * @since 5.1.6
69
  *
70
- * @param string $token
71
- * @param object $event The event to verify
72
- * @param PayPalWebhookHeaders $payPalHeaders
73
  *
74
  * @return bool
75
  */
76
- public function verifyEventSignature( $token, $event, $payPalHeaders ) {
77
  // @todo Move this to the SDK.
78
- $apiUrl = $this->payPalClient->getApiUrl( 'v1/notifications/verify-webhook-signature' );
79
 
80
- $webhookConfig = $this->getWebhookConfig();
81
 
82
  $request = wp_remote_post(
83
- $apiUrl,
84
  [
85
  'headers' => [
86
  'Content-Type' => 'application/json',
@@ -88,12 +82,12 @@ class Webhooks {
88
  ],
89
  'body' => wp_json_encode(
90
  [
91
- 'transmission_id' => $payPalHeaders->transmissionId,
92
- 'transmission_time' => $payPalHeaders->transmissionTime,
93
- 'transmission_sig' => $payPalHeaders->transmissionSig,
94
- 'cert_url' => $payPalHeaders->certUrl,
95
- 'auth_algo' => $payPalHeaders->authAlgo,
96
- 'webhook_id' => $webhookConfig->id,
97
  'webhook_event' => $event,
98
  ]
99
  ),
@@ -102,7 +96,7 @@ class Webhooks {
102
 
103
  if ( is_wp_error( $request ) ) {
104
  tribe( 'logger' )->log_error( sprintf(
105
- // Translators: %s: The error message.
106
  __( 'PayPal request error: %s', 'event-tickets' ),
107
  $request->get_error_message()
108
  ), 'tickets-commerce-paypal-commerce' );
@@ -135,12 +129,12 @@ class Webhooks {
135
  *
136
  * @return object[] The list of PayPal webhooks.
137
  */
138
- public function listWebhooks( $token ) {
139
  // @todo Move this to the SDK.
140
- $apiUrl = $this->payPalClient->getApiUrl( 'v1/notifications/webhooks' );
141
 
142
  $request = wp_remote_get(
143
- $apiUrl,
144
  [
145
  'headers' => [
146
  'Content-Type' => 'application/json',
@@ -151,7 +145,7 @@ class Webhooks {
151
 
152
  if ( is_wp_error( $request ) ) {
153
  tribe( 'logger' )->log_error( sprintf(
154
- // Translators: %s: The error message.
155
  __( 'PayPal request error: %s', 'event-tickets' ),
156
  $request->get_error_message()
157
  ), 'tickets-commerce-paypal-commerce' );
@@ -177,19 +171,19 @@ class Webhooks {
177
  * @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks_get
178
  * @since 5.1.6
179
  *
180
- * @param string $token The PayPal auth token.
181
- * @param string $webhookId The webhook ID.
182
  *
183
  * @throws Exception
184
  *
185
  * @return object The PayPal webhook data.
186
  */
187
- public function getWebhook( $token, $webhookId ) {
188
  // @todo Move this to the SDK.
189
- $apiUrl = $this->payPalClient->getApiUrl( "v1/notifications/webhooks/{$webhookId}" );
190
 
191
  $request = wp_remote_get(
192
- $apiUrl,
193
  [
194
  'headers' => [
195
  'Content-Type' => 'application/json',
@@ -200,7 +194,7 @@ class Webhooks {
200
 
201
  if ( is_wp_error( $request ) ) {
202
  tribe( 'logger' )->log_error( sprintf(
203
- // Translators: %s: The error message.
204
  __( 'PayPal request error: %s', 'event-tickets' ),
205
  $request->get_error_message()
206
  ), 'tickets-commerce-paypal-commerce' );
@@ -234,15 +228,15 @@ class Webhooks {
234
  *
235
  * @param string $token
236
  *
237
- * @return WebhookConfig
238
  * @throws Exception
239
  */
240
- public function createWebhook( $token ) {
241
  // @todo Move this to the SDK.
242
- $apiUrl = $this->payPalClient->getApiUrl( 'v1/notifications/webhooks' );
243
 
244
- $events = $this->webhooksRegister->getRegisteredEvents();
245
- $webhookUrl = tribe( WebhooksRoute::class )->getRouteUrl();
246
 
247
  $request = wp_remote_post(
248
  $apiUrl,
@@ -253,7 +247,7 @@ class Webhooks {
253
  ],
254
  'body' => json_encode(
255
  [
256
- 'url' => $webhookUrl,
257
  'event_types' => array_map(
258
  static function ( $eventType ) {
259
  return [
@@ -269,7 +263,7 @@ class Webhooks {
269
 
270
  if ( is_wp_error( $request ) ) {
271
  tribe( 'logger' )->log_error( sprintf(
272
- // Translators: %s: The error message.
273
  __( 'PayPal request error: %s', 'event-tickets' ),
274
  $request->get_error_message()
275
  ), 'tickets-commerce-paypal-commerce' );
@@ -284,13 +278,13 @@ class Webhooks {
284
  if ( ! empty( $response->name ) ) {
285
  if ( 'WEBHOOK_URL_ALREADY_EXISTS' === $response->name ) {
286
  // The webhook already exists, this is fine!
287
- $webhooks = $this->listWebhooks( $token );
288
 
289
  if ( $webhooks ) {
290
  $webhooks = wp_list_pluck( $webhooks, 'id', 'url' );
291
 
292
- if ( isset( $webhooks[ $webhookUrl ] ) ) {
293
- return new WebhookConfig( $webhooks[ $webhookUrl ], $webhookUrl, $events );
294
  }
295
  }
296
  } elseif ( 'WEBHOOK_NUMBER_LIMIT_EXCEEDED' === $response->name ) {
@@ -304,7 +298,7 @@ class Webhooks {
304
  throw new Exception( 'Failed to create webhook' );
305
  }
306
 
307
- return new WebhookConfig( $response->id, $webhookUrl, $events );
308
  }
309
 
310
  /**
@@ -312,22 +306,23 @@ class Webhooks {
312
  *
313
  * @since 5.1.6
314
  *
315
- * @param string $token
316
- * @param string $webhookId
317
- *
318
  * @throws Exception
319
  *
 
 
 
 
320
  * @return bool
321
  */
322
- public function updateWebhook( $token, $webhookId ) {
323
  // @todo Move this to the SDK.
324
- $apiUrl = $this->payPalClient->getApiUrl( "v1/notifications/webhooks/{$webhookId}" );
325
 
326
- $events = $this->webhooksRegister->getRegisteredEvents();
327
- $webhookUrl = tribe( WebhooksRoute::class )->getRouteUrl();
328
 
329
  $request = wp_remote_request(
330
- $apiUrl,
331
  [
332
  'method' => 'PATCH',
333
  'headers' => [
@@ -339,15 +334,15 @@ class Webhooks {
339
  [
340
  'op' => 'replace',
341
  'path' => '/url',
342
- 'value' => $webhookUrl,
343
  ],
344
  [
345
  'op' => 'replace',
346
  'path' => '/event_types',
347
  'value' => array_map(
348
- static function ( $eventType ) {
349
  return [
350
- 'name' => $eventType,
351
  ];
352
  },
353
  $events
@@ -360,7 +355,7 @@ class Webhooks {
360
 
361
  if ( is_wp_error( $request ) ) {
362
  tribe( 'logger' )->log_error( sprintf(
363
- // Translators: %s: The error message.
364
  __( 'PayPal request error: %s', 'event-tickets' ),
365
  $request->get_error_message()
366
  ), 'tickets-commerce-paypal-commerce' );
@@ -375,11 +370,11 @@ class Webhooks {
375
  if ( ! empty( $response->name ) ) {
376
  if ( 'INVALID_RESOURCE_ID' === $response->name ) {
377
  // The webhook was not found, let's create it.
378
- $webhookConfig = $this->createWebhook( $token );
379
 
380
  tribe( 'logger' )->log_warning( __( 'The PayPal webhook was not able to be updated because it did not exist, attempting to create it now', 'event-tickets' ), 'tickets-commerce-paypal-commerce' );
381
 
382
- if ( $webhookConfig ) {
383
  return true;
384
  }
385
  }
@@ -399,16 +394,16 @@ class Webhooks {
399
  * @since 5.1.6
400
  *
401
  * @param string $token
402
- * @param string $webhookId
403
  *
404
  * @return bool Whether or not the deletion was successful
405
  */
406
- public function deleteWebhook( $token, $webhookId ) {
407
  // @todo Move this to the SDK.
408
- $apiUrl = $this->payPalClient->getApiUrl( "v1/notifications/webhooks/{$webhookId}" );
409
 
410
  $request = wp_remote_request(
411
- $apiUrl,
412
  [
413
  'method' => 'DELETE',
414
  'headers' => [
@@ -428,10 +423,10 @@ class Webhooks {
428
  *
429
  * @since 5.1.6
430
  *
431
- * @param WebhookConfig $config
432
  */
433
- public function saveWebhookConfig( WebhookConfig $config ) {
434
- $this->settings->update_webhook_config( $this->mode, $config );
435
  }
436
 
437
  /**
@@ -439,10 +434,10 @@ class Webhooks {
439
  *
440
  * @since 5.1.6
441
  *
442
- * @return WebhookConfig|null
443
  */
444
- public function getWebhookConfig() {
445
- return $this->settings->get_webhook_config( $this->mode );
446
  }
447
 
448
  /**
@@ -450,7 +445,7 @@ class Webhooks {
450
  *
451
  * @since 5.1.6
452
  */
453
- public function deleteWebhookConfig() {
454
- $this->settings->delete_webhook_config( $this->mode );
455
  }
456
  }
1
  <?php
2
 
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal\Repositories;
4
 
5
  use Exception;
6
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Headers;
7
+ use TEC\Tickets\Commerce\Gateways\PayPal\Models\Webhook_Config;
8
+ use TEC\Tickets\Commerce\Gateways\PayPal\Client;
9
+ use TEC\Tickets\Commerce\Gateways\PayPal\Merchant;
10
  use TEC\Tickets\Commerce\Gateways\PayPal\Settings;
11
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Webhook_Register;
12
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Webhooks_Route;
13
+
14
+ /**
15
+ * Class Webhooks
16
+ *
17
+ * @since 5.1.6
18
+ * @package TEC\Tickets\Commerce\Gateways\PayPal\Repositories
19
+ */
20
  class Webhooks {
 
 
 
21
  /**
22
  * @since 5.1.6
23
  *
24
+ * @var Webhooks_Route
25
  */
26
+ private $webhook_route;
27
 
28
  /**
29
+ * @var Webhook_Register
30
  */
31
+ private $webhooks_register;
32
 
33
  /**
34
+ * @var Client
35
  */
36
+ private $paypal_client;
37
 
38
  /**
39
  * @var Settings
45
  *
46
  * @since 5.1.6
47
  *
48
+ * @param Client $paypal_client
49
+ * @param Webhook_Register $webhooks_register
50
+ * @param Settings $settings
 
 
 
 
 
 
 
 
 
 
 
51
  */
52
+ public function __construct( Client $paypal_client, Webhook_Register $webhooks_register, Settings $settings ) {
53
+ $this->paypal_client = $paypal_client;
54
+ $this->webhooks_register = $webhooks_register;
55
+ $this->settings = $settings;
56
  }
57
 
58
  /**
61
  * @see https://developer.paypal.com/docs/api/webhooks/v1/#verify-webhook-signature
62
  * @since 5.1.6
63
  *
64
+ * @param string $token
65
+ * @param object $event The event to verify
66
+ * @param Headers $paypal_headers
67
  *
68
  * @return bool
69
  */
70
+ public function verify_event_signature( $token, $event, $paypal_headers ) {
71
  // @todo Move this to the SDK.
72
+ $api_url = $this->paypal_client->get_api_url( 'v1/notifications/verify-webhook-signature' );
73
 
74
+ $webhook_config = $this->get_webhook_config();
75
 
76
  $request = wp_remote_post(
77
+ $api_url,
78
  [
79
  'headers' => [
80
  'Content-Type' => 'application/json',
82
  ],
83
  'body' => wp_json_encode(
84
  [
85
+ 'transmission_id' => $paypal_headers->transmission_id,
86
+ 'transmission_time' => $paypal_headers->transmission_time,
87
+ 'transmission_sig' => $paypal_headers->transmission_sig,
88
+ 'cert_url' => $paypal_headers->cert_url,
89
+ 'auth_algo' => $paypal_headers->auth_algo,
90
+ 'webhook_id' => $webhook_config->id,
91
  'webhook_event' => $event,
92
  ]
93
  ),
96
 
97
  if ( is_wp_error( $request ) ) {
98
  tribe( 'logger' )->log_error( sprintf(
99
+ // Translators: %s: The error message.
100
  __( 'PayPal request error: %s', 'event-tickets' ),
101
  $request->get_error_message()
102
  ), 'tickets-commerce-paypal-commerce' );
129
  *
130
  * @return object[] The list of PayPal webhooks.
131
  */
132
+ public function list_webhooks( $token ) {
133
  // @todo Move this to the SDK.
134
+ $api_url = $this->paypal_client->get_api_url( 'v1/notifications/webhooks' );
135
 
136
  $request = wp_remote_get(
137
+ $api_url,
138
  [
139
  'headers' => [
140
  'Content-Type' => 'application/json',
145
 
146
  if ( is_wp_error( $request ) ) {
147
  tribe( 'logger' )->log_error( sprintf(
148
+ // Translators: %s: The error message.
149
  __( 'PayPal request error: %s', 'event-tickets' ),
150
  $request->get_error_message()
151
  ), 'tickets-commerce-paypal-commerce' );
171
  * @see https://developer.paypal.com/docs/api/webhooks/v1/#webhooks_get
172
  * @since 5.1.6
173
  *
174
+ * @param string $token The PayPal auth token.
175
+ * @param string $webhook_id The webhook ID.
176
  *
177
  * @throws Exception
178
  *
179
  * @return object The PayPal webhook data.
180
  */
181
+ public function get_webhook( $token, $webhook_id ) {
182
  // @todo Move this to the SDK.
183
+ $api_url = $this->paypal_client->get_api_url( "v1/notifications/webhooks/{$webhook_id}" );
184
 
185
  $request = wp_remote_get(
186
+ $api_url,
187
  [
188
  'headers' => [
189
  'Content-Type' => 'application/json',
194
 
195
  if ( is_wp_error( $request ) ) {
196
  tribe( 'logger' )->log_error( sprintf(
197
+ // Translators: %s: The error message.
198
  __( 'PayPal request error: %s', 'event-tickets' ),
199
  $request->get_error_message()
200
  ), 'tickets-commerce-paypal-commerce' );
228
  *
229
  * @param string $token
230
  *
231
+ * @return Webhook_Config
232
  * @throws Exception
233
  */
234
+ public function create_webhook( $token ) {
235
  // @todo Move this to the SDK.
236
+ $apiUrl = $this->paypal_client->get_api_url( 'v1/notifications/webhooks' );
237
 
238
+ $events = $this->webhooks_register->get_registered_events();
239
+ $webhook_url = tribe( Webhooks_Route::class )->get_route_url();
240
 
241
  $request = wp_remote_post(
242
  $apiUrl,
247
  ],
248
  'body' => json_encode(
249
  [
250
+ 'url' => $webhook_url,
251
  'event_types' => array_map(
252
  static function ( $eventType ) {
253
  return [
263
 
264
  if ( is_wp_error( $request ) ) {
265
  tribe( 'logger' )->log_error( sprintf(
266
+ // Translators: %s: The error message.
267
  __( 'PayPal request error: %s', 'event-tickets' ),
268
  $request->get_error_message()
269
  ), 'tickets-commerce-paypal-commerce' );
278
  if ( ! empty( $response->name ) ) {
279
  if ( 'WEBHOOK_URL_ALREADY_EXISTS' === $response->name ) {
280
  // The webhook already exists, this is fine!
281
+ $webhooks = $this->list_webhooks( $token );
282
 
283
  if ( $webhooks ) {
284
  $webhooks = wp_list_pluck( $webhooks, 'id', 'url' );
285
 
286
+ if ( isset( $webhooks[ $webhook_url ] ) ) {
287
+ return new Webhook_Config( $webhooks[ $webhook_url ], $webhook_url, $events );
288
  }
289
  }
290
  } elseif ( 'WEBHOOK_NUMBER_LIMIT_EXCEEDED' === $response->name ) {
298
  throw new Exception( 'Failed to create webhook' );
299
  }
300
 
301
+ return new Webhook_Config( $response->id, $webhook_url, $events );
302
  }
303
 
304
  /**
306
  *
307
  * @since 5.1.6
308
  *
 
 
 
309
  * @throws Exception
310
  *
311
+ * @param string $webhook_id
312
+ *
313
+ * @param string $token
314
+ *
315
  * @return bool
316
  */
317
+ public function update_webhook( $token, $webhook_id ) {
318
  // @todo Move this to the SDK.
319
+ $api_url = $this->paypal_client->get_api_url( "v1/notifications/webhooks/{$webhook_id}" );
320
 
321
+ $events = $this->webhooks_register->get_registered_events();
322
+ $webhook_url = tribe( Webhooks_Route::class )->get_route_url();
323
 
324
  $request = wp_remote_request(
325
+ $api_url,
326
  [
327
  'method' => 'PATCH',
328
  'headers' => [
334
  [
335
  'op' => 'replace',
336
  'path' => '/url',
337
+ 'value' => $webhook_url,
338
  ],
339
  [
340
  'op' => 'replace',
341
  'path' => '/event_types',
342
  'value' => array_map(
343
+ static function ( $event_type ) {
344
  return [
345
+ 'name' => $event_type,
346
  ];
347
  },
348
  $events
355
 
356
  if ( is_wp_error( $request ) ) {
357
  tribe( 'logger' )->log_error( sprintf(
358
+ // Translators: %s: The error message.
359
  __( 'PayPal request error: %s', 'event-tickets' ),
360
  $request->get_error_message()
361
  ), 'tickets-commerce-paypal-commerce' );
370
  if ( ! empty( $response->name ) ) {
371
  if ( 'INVALID_RESOURCE_ID' === $response->name ) {
372
  // The webhook was not found, let's create it.
373
+ $webhook_config = $this->create_webhook( $token );
374
 
375
  tribe( 'logger' )->log_warning( __( 'The PayPal webhook was not able to be updated because it did not exist, attempting to create it now', 'event-tickets' ), 'tickets-commerce-paypal-commerce' );
376
 
377
+ if ( $webhook_config ) {
378
  return true;
379
  }
380
  }
394
  * @since 5.1.6
395
  *
396
  * @param string $token
397
+ * @param string $webhook_id
398
  *
399
  * @return bool Whether or not the deletion was successful
400
  */
401
+ public function delete_webhook( $token, $webhook_id ) {
402
  // @todo Move this to the SDK.
403
+ $api_url = $this->paypal_client->get_api_url( "v1/notifications/webhooks/{$webhook_id}" );
404
 
405
  $request = wp_remote_request(
406
+ $api_url,
407
  [
408
  'method' => 'DELETE',
409
  'headers' => [
423
  *
424
  * @since 5.1.6
425
  *
426
+ * @param Webhook_Config $config
427
  */
428
+ public function save_webhook_config( Webhook_Config $config ) {
429
+ $this->settings->update_webhook_config( tribe( Merchant::class )->get_mode(), $config );
430
  }
431
 
432
  /**
434
  *
435
  * @since 5.1.6
436
  *
437
+ * @return Webhook_Config|null
438
  */
439
+ public function get_webhook_config() {
440
+ return $this->settings->get_webhook_config( tribe( Merchant::class )->get_mode() );
441
  }
442
 
443
  /**
445
  *
446
  * @since 5.1.6
447
  */
448
+ public function delete_webhook_config() {
449
+ $this->settings->delete_webhook_config( tribe( Merchant::class )->get_mode() );
450
  }
451
  }
src/Tickets/Commerce/Gateways/PayPal/SDK/Models/MerchantDetail.php DELETED
@@ -1,216 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models;
4
-
5
- use InvalidArgumentException;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\MerchantDetails;
7
-
8
- /**
9
- * Class MerchantDetail
10
- *
11
- * @since 5.1.6
12
- * @package TEC\Tickets\Commerce\Gateways\PayPal
13
- *
14
- */
15
- class MerchantDetail {
16
-
17
- /**
18
- * PayPal merchant Id (email address)
19
- *
20
- * @since 5.1.6
21
- *
22
- * @var null|string
23
- */
24
- public $merchantId = null;
25
-
26
- /**
27
- * PayPal merchant id
28
- *
29
- * @since 5.1.6
30
- *
31
- * @var null|string
32
- */
33
- public $merchantIdInPayPal = null;
34
-
35
- /**
36
- * Client id.
37
- *
38
- * @since 5.1.6
39
- *
40
- * @var null |string
41
- */
42
- public $clientId = null;
43
-
44
- /**
45
- * Client Secret
46
- *
47
- * @since 5.1.6
48
- *
49
- * @var null|string
50
- */
51
- public $clientSecret = null;
52
-
53
- /**
54
- * Access token.
55
- *
56
- * @since 5.1.6
57
- *
58
- * @var null|string
59
- */
60
- public $accessToken = null;
61
-
62
- /**
63
- * Whether or not the connected account is ready to process payments.
64
- *
65
- * @since 5.1.6
66
- *
67
- * @var bool
68
- */
69
- public $accountIsReady = false;
70
-
71
- /**
72
- * Whether or not the account can make custom payments (i.e Advanced Fields & PPCP)
73
- *
74
- * @since 5.1.6
75
- *
76
- * @var bool
77
- */
78
- public $supportsCustomPayments;
79
-
80
- /**
81
- * PayPal account accountCountry.
82
- *
83
- * @since 5.1.6
84
- *
85
- * @var bool
86
- */
87
- public $accountCountry;
88
-
89
- /**
90
- * Access token.
91
- *
92
- * @since 5.1.6
93
- *
94
- * @var array
95
- */
96
- private $tokenDetails = null;
97
-
98
- /**
99
- * Handle initial setup for the object singleton.
100
- *
101
- * @since 5.1.6
102
- */
103
- public function init() {
104
- /** @var MerchantDetails $repository */
105
- $repository = tribe( MerchantDetails::class );
106
-
107
- $merchantDetails = $repository->getDetailsData();
108
-
109
- try {
110
- $this->validate( $merchantDetails );
111
- } catch ( InvalidArgumentException $exception ) {
112
- // Do not continue to set up the properties.
113
- return;
114
- }
115
-
116
- $this->setupProperties( $merchantDetails );
117
- }
118
-
119
- /**
120
- * Return array of merchant details.
121
- *
122
- * @since 5.1.6
123
- *
124
- * @return array
125
- */
126
- public function toArray() {
127
- return [
128
- 'merchantId' => $this->merchantId,
129
- 'merchantIdInPayPal' => $this->merchantIdInPayPal,
130
- 'clientId' => $this->clientId,
131
- 'clientSecret' => $this->clientSecret,
132
- 'token' => $this->tokenDetails,
133
- 'accountIsReady' => $this->accountIsReady,
134
- 'supportsCustomPayments' => $this->supportsCustomPayments,
135
- 'accountCountry' => $this->accountCountry,
136
- ];
137
- }
138
-
139
- /**
140
- * Make MerchantDetail object from array.
141
- *
142
- * @since 5.1.6
143
- *
144
- * @param array $merchantDetails
145
- *
146
- * @return MerchantDetail
147
- */
148
- public static function fromArray( $merchantDetails ) {
149
- $obj = new static();
150
-
151
- if ( ! $merchantDetails ) {
152
- return $obj;
153
- }
154
-
155
- $obj->validate( $merchantDetails );
156
- $obj->setupProperties( $merchantDetails );
157
-
158
- return $obj;
159
- }
160
-
161
- /**
162
- * Setup properties from array.
163
- *
164
- * @since 5.1.6
165
- *
166
- * @param $merchantDetails
167
- *
168
- */
169
- private function setupProperties( $merchantDetails ) {
170
- $this->merchantId = $merchantDetails['merchantId'];
171
- $this->merchantIdInPayPal = $merchantDetails['merchantIdInPayPal'];
172
-
173
- $this->clientId = $merchantDetails['clientId'];
174
- $this->clientSecret = $merchantDetails['clientSecret'];
175
- $this->tokenDetails = $merchantDetails['token'];
176
- $this->accountIsReady = $merchantDetails['accountIsReady'];
177
- $this->supportsCustomPayments = $merchantDetails['supportsCustomPayments'];
178
- $this->accountCountry = $merchantDetails['accountCountry'];
179
- $this->accessToken = $this->tokenDetails['access_token'];
180
- }
181
-
182
- /**
183
- * Validate merchant details.
184
- *
185
- * @since 5.1.6
186
- *
187
- * @param array $merchantDetails
188
- */
189
- private function validate( $merchantDetails ) {
190
- $required = [
191
- 'merchantId',
192
- 'merchantIdInPayPal',
193
- 'clientId',
194
- 'clientSecret',
195
- 'token',
196
- 'accountIsReady',
197
- 'supportsCustomPayments',
198
- 'accountCountry',
199
- ];
200
-
201
- if ( array_diff( $required, array_keys( $merchantDetails ) ) ) {
202
- throw new InvalidArgumentException( esc_html__( 'To create a MerchantDetail object, please provide the following: ' . implode( ', ', $required ), 'event-tickets' ) );
203
- }
204
- }
205
-
206
- /**
207
- * Get refresh token code.
208
- *
209
- * @since 5.1.6
210
- *
211
- * @param array $tokenDetails
212
- */
213
- public function setTokenDetails( $tokenDetails ) {
214
- $this->tokenDetails = array_merge( $this->tokenDetails, $tokenDetails );
215
- }
216
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/PayPal/SDK/Models/WebhookConfig.php DELETED
@@ -1,70 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models;
4
-
5
- class WebhookConfig {
6
-
7
- /**
8
- * @since 5.1.6
9
- *
10
- * @var string
11
- */
12
- public $id;
13
-
14
- /**
15
- * @since 5.1.6
16
- *
17
- * @var string
18
- */
19
- public $returnUrl;
20
-
21
- /**
22
- * @since 5.1.6
23
- *
24
- * @var string[]
25
- */
26
- public $events;
27
-
28
- /**
29
- * WebhookConfig constructor.
30
- *
31
- * @since 5.1.6
32
- *
33
- * @param string $id
34
- * @param string $returnUrl
35
- * @param string[] $events
36
- */
37
- public function __construct( $id, $returnUrl, $events ) {
38
- $this->id = $id;
39
- $this->returnUrl = $returnUrl;
40
- $this->events = $events;
41
- }
42
-
43
- /**
44
- * Generates an instance from serialized data
45
- *
46
- * @since 5.1.6
47
- *
48
- * @param array $data
49
- *
50
- * @return WebhookConfig
51
- */
52
- public static function fromArray( array $data ) {
53
- return new self( $data['id'], $data['returnUrl'], $data['events'] );
54
- }
55
-
56
- /**
57
- * Generates an array for serialization
58
- *
59
- * @since 5.1.6
60
- *
61
- * @return array
62
- */
63
- public function toArray() {
64
- return [
65
- 'id' => $this->id,
66
- 'returnUrl' => $this->returnUrl,
67
- 'events' => $this->events,
68
- ];
69
- }
70
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/PayPal/SDK/PayPalClient.php DELETED
@@ -1,92 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK;
4
-
5
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models\MerchantDetail;
6
- use PayPalCheckoutSdk\Core\PayPalHttpClient;
7
- use PayPalCheckoutSdk\Core\ProductionEnvironment;
8
- use PayPalCheckoutSdk\Core\SandboxEnvironment;
9
-
10
- /**
11
- * Class PayPalClient
12
- *
13
- * @since 5.1.6
14
- * @package TEC\Tickets\Commerce\Gateways\PayPal\SDK
15
- *
16
- */
17
- class PayPalClient {
18
-
19
- /**
20
- * Environment mode.
21
- *
22
- * @since 5.1.6
23
- *
24
- * @var string
25
- */
26
- public $mode = null;
27
-
28
- /**
29
- * PayPalClient constructor.
30
- */
31
- public function __construct() {
32
- $this->mode = tribe_tickets_commerce_is_test_mode() ? 'sandbox' : 'live';
33
- }
34
-
35
- /**
36
- * Get environment.
37
- *
38
- * @since 5.1.6
39
- *
40
- * @return ProductionEnvironment|SandboxEnvironment
41
- */
42
- public function getEnvironment() {
43
- /* @var MerchantDetail $merchant */
44
- $merchant = tribe( MerchantDetail::class );
45
-
46
- return 'sandbox' === $this->mode ?
47
- new SandboxEnvironment( $merchant->clientId, $merchant->clientSecret ) :
48
- new ProductionEnvironment( $merchant->clientId, $merchant->clientSecret );
49
- }
50
-
51
- /**
52
- * Get http client.
53
- *
54
- * @since 5.1.6
55
- *
56
- * @return PayPalHttpClient
57
- */
58
- public function getHttpClient() {
59
- return new PayPalHttpClient( $this->getEnvironment() );
60
- }
61
-
62
- /**
63
- * Get api url.
64
- *
65
- * @since 5.1.6
66
- *
67
- * @param string $endpoint
68
- *
69
- * @return string
70
- */
71
- public function getApiUrl( $endpoint ) {
72
- $baseUrl = $this->getEnvironment()->baseUrl();
73
-
74
- return "{$baseUrl}/$endpoint";
75
- }
76
-
77
- /**
78
- * Get PayPal homepage url.
79
- *
80
- * @since 5.1.6
81
- *
82
- * @return string
83
- */
84
- public function getHomePageUrl() {
85
- $subdomain = 'sandbox' === $this->mode ? 'sandbox.' : '';
86
-
87
- return sprintf(
88
- 'https://%1$spaypal.com/',
89
- $subdomain
90
- );
91
- }
92
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/PayPal/SDK/RefreshToken.php DELETED
@@ -1,113 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK;
4
-
5
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models\MerchantDetail;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\PayPalAuth;
7
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\MerchantDetails;
8
-
9
- /**
10
- * Class RefreshToken
11
- *
12
- * @since 5.1.6
13
- */
14
- class RefreshToken {
15
-
16
- /*
17
- * @since 5.1.6
18
- *
19
- * @var MerchantDetail
20
- */
21
- private $merchantDetail;
22
-
23
- /**
24
- * @since 5.1.6
25
- *
26
- * @var MerchantDetails
27
- */
28
- private $detailsRepository;
29
-
30
- /**
31
- * @since 5.1.6
32
- *
33
- * @var PayPalAuth
34
- */
35
- private $payPalAuth;
36
-
37
- /**
38
- * RefreshToken constructor.
39
- *
40
- * @since 5.1.6
41
- *
42
- * @param MerchantDetails $detailsRepository
43
- * @param PayPalAuth $payPalAuth
44
- * @param MerchantDetail $merchantDetail
45
- */
46
- public function __construct(
47
- MerchantDetails $detailsRepository,
48
- PayPalAuth $payPalAuth,
49
- MerchantDetail $merchantDetail
50
- ) {
51
- $this->detailsRepository = $detailsRepository;
52
- $this->payPalAuth = $payPalAuth;
53
- $this->merchantDetail = $merchantDetail;
54
- }
55
-
56
- /**
57
- * Return cron json name which uses to refresh token.
58
- *
59
- * @since 5.1.6
60
- *
61
- * @return string
62
- */
63
- private function getCronJobHookName() {
64
- return 'tribe_tickets_commerce_paypal_commerce_refresh_token';
65
- }
66
-
67
- /**
68
- * Register cron job to refresh access token.
69
- * Note: only for internal use.
70
- *
71
- * @since 5.1.6
72
- *
73
- * @param string $tokenExpires What time the token expires.
74
- */
75
- public function registerCronJobToRefreshToken( $tokenExpires ) {
76
- // @todo Verify we need this as a cron, do we lose total API access if it expires (no visitors)?
77
- wp_schedule_single_event(
78
- // Refresh token before half hours of expires date.
79
- time() + ( $tokenExpires - 1800 ),
80
- $this->getCronJobHookName()
81
- );
82
- }
83
-
84
- /**
85
- * Delete cron job which refresh access token.
86
- * Note: only for internal use.
87
- *
88
- * @since 5.1.6
89
- */
90
- public function deleteRefreshTokenCronJob() {
91
- wp_clear_scheduled_hook( $this->getCronJobHookName() );
92
- }
93
-
94
- /**
95
- * Refresh token.
96
- * Note: only for internal use
97
- *
98
- * @since 5.1.6
99
- */
100
- public function refreshToken() {
101
- // Exit if account is not connected.
102
- if ( ! $this->detailsRepository->accountIsConnected() ) {
103
- return;
104
- }
105
-
106
- $tokenDetails = $this->payPalAuth->getTokenFromClientCredentials( $this->merchantDetail->clientId, $this->merchantDetail->clientSecret );
107
-
108
- $this->merchantDetail->setTokenDetails( $tokenDetails );
109
- $this->detailsRepository->save( $this->merchantDetail );
110
-
111
- $this->registerCronJobToRefreshToken( $tokenDetails['expires_in'] );
112
- }
113
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/MerchantDetails.php DELETED
@@ -1,213 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories;
4
-
5
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models\MerchantDetail;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\PayPalClient;
7
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\Traits\HasMode;
8
-
9
- /**
10
- * Class MerchantDetails
11
- *
12
- * @since 5.1.6
13
- */
14
- class MerchantDetails {
15
-
16
- use HasMode;
17
-
18
- /**
19
- * Handle initial setup for the object singleton.
20
- *
21
- * @since 5.1.6
22
- */
23
- public function init() {
24
- $this->setMode( tribe_tickets_commerce_is_test_mode() ? 'sandbox' : 'live' );
25
- }
26
-
27
- /**
28
- * Returns whether or not the account has been connected
29
- *
30
- * @since 5.1.6
31
- *
32
- * @return bool
33
- */
34
- public function accountIsConnected() {
35
- /* @var $merchantDetail MerchantDetail */
36
- $merchantDetail = tribe( MerchantDetail::class );
37
-
38
- return (bool) $merchantDetail->merchantIdInPayPal;
39
- }
40
-
41
- /**
42
- * Get the merchant details data.
43
- *
44
- * @since 5.1.6
45
- *
46
- * @return array
47
- */
48
- public function getDetailsData() {
49
- return (array) get_option( $this->getAccountKey(), [] );
50
- }
51
-
52
- /**
53
- * Get merchant details.
54
- *
55
- * @since 5.1.6
56
- *
57
- * @return MerchantDetail
58
- */
59
- public function getDetails() {
60
- return MerchantDetail::fromArray( $this->getDetailsData() );
61
- }
62
-
63
- /**
64
- * Save merchant details.
65
- *
66
- * @since 5.1.6
67
- *
68
- * @param MerchantDetail $merchantDetails
69
- *
70
- * @return bool
71
- */
72
- public function save( MerchantDetail $merchantDetails ) {
73
- return update_option( $this->getAccountKey(), $merchantDetails->toArray() );
74
- }
75
-
76
- /**
77
- * Delete merchant details.
78
- *
79
- * @since 5.1.6
80
- *
81
- * @return bool
82
- */
83
- public function delete() {
84
- return delete_option( $this->getAccountKey() );
85
- }
86
-
87
- /**
88
- * Returns the account errors if there are any
89
- *
90
- * @since 5.1.6
91
- *
92
- * @return string[]|null
93
- */
94
- public function getAccountErrors() {
95
- return get_option( $this->getAccountErrorsKey(), null );
96
- }
97
-
98
- /**
99
- * Saves the account error message
100
- *
101
- * @since 5.1.6
102
- *
103
- * @param string[] $errorMessage
104
- *
105
- * @return bool
106
- */
107
- public function saveAccountErrors( $errorMessage ) {
108
- return update_option( $this->getAccountErrorsKey(), $errorMessage );
109
- }
110
-
111
- /**
112
- * Deletes the errors for the account
113
- *
114
- * @since 5.1.6
115
- *
116
- * @return bool
117
- */
118
- public function deleteAccountErrors() {
119
- return delete_option( $this->getAccountErrorsKey() );
120
- }
121
-
122
- /**
123
- * Deletes the client token for the account
124
- *
125
- * @since 5.1.6
126
- *
127
- * @return bool
128
- */
129
- public function deleteClientToken() {
130
- return delete_transient( $this->getClientTokenKey() );
131
- }
132
-
133
- /**
134
- * Get client token for hosted credit card fields.
135
- *
136
- * @since 5.1.6
137
- *
138
- * @return string
139
- */
140
- public function getClientToken() {
141
- $optionName = $this->getClientTokenKey();
142
-
143
- if ( $optionValue = get_transient( $optionName ) ) {
144
- return $optionValue;
145
- }
146
-
147
- /** @var MerchantDetail $merchant */
148
- $merchant = tribe( MerchantDetail::class );
149
-
150
- $response = wp_remote_retrieve_body(
151
- wp_remote_post(
152
- tribe( PayPalClient::class )->getApiUrl( 'v1/identity/generate-token' ),
153
- [
154
- 'headers' => [
155
- 'Accept' => 'application/json',
156
- 'Accept-Language' => 'en_US',
157
- 'Authorization' => sprintf( 'Bearer %1$s', $merchant->accessToken ),
158
- 'Content-Type' => 'application/json',
159
- ],
160
- ]
161
- )
162
- );
163
-
164
- if ( ! $response ) {
165
- return '';
166
- }
167
-
168
- // @todo Replace this with a new method somewhere else.
169
- $response = ArrayDataSet::camelCaseKeys( json_decode( $response, true ) );
170
-
171
- if ( ! array_key_exists( 'client_token', $response ) ) {
172
- return '';
173
- }
174
-
175
- // Expire token before one minute to prevent unnecessary race condition.
176
- set_transient( $optionName, $response['client_token'], $response['expires_in'] - 60 );
177
-
178
- return $response['clientToken'];
179
- }
180
-
181
- /**
182
- * Returns the options key for the account in the give mode
183
- *
184
- * @since 5.1.6
185
- *
186
- * @return string
187
- */
188
- public function getAccountKey() {
189
- return "tribe_tickets_paypal_commerce_{$this->mode}_account";
190
- }
191
-
192
- /**
193
- * Returns the options key for the account errors in the give mode
194
- *
195
- * @since 5.1.6
196
- *
197
- * @return string
198
- */
199
- private function getAccountErrorsKey() {
200
- return "tribe_tickets_paypal_commerce_{$this->mode}_account_errors";
201
- }
202
-
203
- /**
204
- * Returns the options key for the client token in the give mode
205
- *
206
- * @since 5.1.6
207
- *
208
- * @return string
209
- */
210
- private function getClientTokenKey() {
211
- return "tribe_tickets_paypal_commerce_{$this->mode}_client_token";
212
- }
213
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalAuth.php DELETED
@@ -1,246 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories;
4
-
5
- use TEC\Tickets\Commerce\Gateways\PayPal\Connect_Client;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\PayPalClient;
7
-
8
- class PayPalAuth {
9
-
10
- /**
11
- * @since 5.1.6
12
- *
13
- * @var PayPalClient
14
- */
15
- private $payPalClient;
16
-
17
- /**
18
- * @since 5.1.6
19
- *
20
- * @var Connect_Client
21
- */
22
- private $connectClient;
23
-
24
- /**
25
- * PayPalAuth constructor.
26
- *
27
- * @since 5.1.6
28
- *
29
- * @param PayPalClient $payPalClient
30
- * @param Connect_Client $connectClient
31
- */
32
- public function __construct( PayPalClient $payPalClient, Connect_Client $connectClient ) {
33
- $this->payPalClient = $payPalClient;
34
- $this->connectClient = $connectClient;
35
- }
36
-
37
- /**
38
- * Retrieves a token for the Client ID and Secret.
39
- *
40
- * @since 5.1.6
41
- *
42
- * @param string $client_id The Client ID.
43
- * @param string $client_secret The Client Secret.
44
- *
45
- * @return array|null The token details response or null if there was a problem.
46
- */
47
- public function getTokenFromClientCredentials( $client_id, $client_secret ) {
48
- $auth = base64_encode( "$client_id:$client_secret" );
49
-
50
- $request = wp_remote_post( $this->payPalClient->getApiUrl( 'v1/oauth2/token' ), [
51
- 'headers' => [
52
- 'Authorization' => sprintf( 'Basic %1$s', $auth ),
53
- 'Content-Type' => 'application/x-www-form-urlencoded',
54
- ],
55
- 'body' => [
56
- 'grant_type' => 'client_credentials',
57
- ],
58
- ] );
59
-
60
- if ( is_wp_error( $request ) ) {
61
- tribe( 'logger' )->log_error( sprintf(
62
- // Translators: %s: The error message.
63
- __( 'PayPal request error: %s', 'event-tickets' ),
64
- $request->get_error_message()
65
- ), 'tickets-commerce-paypal-commerce' );
66
-
67
- return null;
68
- }
69
-
70
- $response = wp_remote_retrieve_body( $request );
71
- $response = @json_decode( $response, true );
72
-
73
- if ( ! is_array( $response ) ) {
74
- tribe( 'logger' )->log_error( __( 'Unexpected PayPal response when getting token from client credentials', 'event-tickets' ), 'tickets-commerce-paypal-commerce' );
75
-
76
- return null;
77
- }
78
-
79
- return $response;
80
- }
81
-
82
- /**
83
- * Retrieves a token from the authorization code.
84
- *
85
- * @since 5.1.6
86
- *
87
- * @param string $sharedId Shared ID for merchant.
88
- * @param string $authCode Authorization code from onboarding.
89
- * @param string $nonce Seller nonce from onboarding.
90
- *
91
- * @return array|null The token details response or null if there was a problem.
92
- */
93
- public function getTokenFromAuthorizationCode( $sharedId, $authCode, $nonce ) {
94
- $request = wp_remote_post( $this->payPalClient->getApiUrl( 'v1/oauth2/token' ), [
95
- 'headers' => [
96
- 'Authorization' => sprintf( 'Basic %1$s', base64_encode( $sharedId ) ),
97
- 'Content-Type' => 'application/x-www-form-urlencoded',
98
- ],
99
- 'body' => [
100
- 'grant_type' => 'authorization_code',
101
- 'code' => $authCode,
102
- 'code_verifier' => $nonce,
103
- ],
104
- ] );
105
-
106
- if ( is_wp_error( $request ) ) {
107
- tribe( 'logger' )->log_error( sprintf(
108
- // Translators: %s: The error message.
109
- __( 'PayPal request error: %s', 'event-tickets' ),
110
- $request->get_error_message()
111
- ), 'tickets-commerce-paypal-commerce' );
112
-
113
- return null;
114
- }
115
-
116
- $response = wp_remote_retrieve_body( $request );
117
- $response = @json_decode( $response, true );
118
-
119
- if ( ! is_array( $response ) ) {
120
- tribe( 'logger' )->log_error( __( 'Unexpected PayPal response when getting token from authorization code', 'event-tickets' ), 'tickets-commerce-paypal-commerce' );
121
-
122
- return null;
123
- }
124
-
125
- return $response;
126
- }
127
-
128
- /**
129
- * Retrieves a Partner Link for on-boarding
130
- *
131
- * @param $returnUrl
132
- * @param $country
133
- *
134
- * @return array|null
135
- */
136
- public function getSellerPartnerLink( $returnUrl, $country ) {
137
- $request = wp_remote_post( sprintf( $this->connectClient->get_api_url( 'paypal-commerce/?mode=%1$s&request=partner-link' ), $this->payPalClient->mode ), [
138
- 'body' => [
139
- 'return_url' => $returnUrl,
140
- 'country_code' => $country,
141
- ],
142
- // @todo Remove this when SSL is fixed.
143
- 'sslverify' => false,
144
- ] );
145
-
146
- if ( is_wp_error( $request ) ) {
147
- tribe( 'logger' )->log_error( sprintf(
148
- // Translators: %s: The error message.
149
- __( 'PayPal Commerce Connect request error: %s', 'event-tickets' ),
150
- $request->get_error_message()
151
- ), 'tickets-commerce-paypal-commerce' );
152
-
153
- return null;
154
- }
155
-
156
- $response = wp_remote_retrieve_body( $request );
157
- $response = @json_decode( $response, true );
158
-
159
- if ( ! is_array( $response ) ) {
160
- tribe( 'logger' )->log_error( __( 'Unexpected PayPal Commerce Connect response', 'event-tickets' ), 'tickets-commerce-paypal-commerce' );
161
-
162
- return null;
163
- }
164
-
165
- return $response;
166
- }
167
-
168
- /**
169
- * Get seller on-boarding details from seller.
170
- *
171
- * @since 5.1.6
172
- *
173
- * @param string $accessToken
174
- *
175
- * @param string $merchantId
176
- *
177
- * @return array
178
- */
179
- public function getSellerOnBoardingDetailsFromPayPal( $merchantId, $accessToken ) {
180
- $request = wp_remote_post( $this->connectClient->get_api_url( sprintf( 'paypal-commerce/?mode=%1$s&request=seller-status', $this->payPalClient->mode ) ), [
181
- 'body' => [
182
- 'merchant_id' => $merchantId,
183
- 'token' => $accessToken,
184
- ],
185
- ] );
186
-
187
- if ( is_wp_error( $request ) ) {
188
- tribe( 'logger' )->log_error( sprintf(
189
- // Translators: %s: The error message.
190
- __( 'PayPal Commerce Connect request error: %s', 'event-tickets' ),
191
- $request->get_error_message()
192
- ), 'tickets-commerce-paypal-commerce' );
193
-
194
- return null;
195
- }
196
-
197
- $response = wp_remote_retrieve_body( $request );
198
- $response = @json_decode( $response, true );
199
-
200
- if ( ! is_array( $response ) ) {
201
- tribe( 'logger' )->log_error( __( 'Unexpected PayPal Commerce Connect response', 'event-tickets' ), 'tickets-commerce-paypal-commerce' );
202
-
203
- return null;
204
- }
205
-
206
- return $response;
207
- }
208
-
209
- /**
210
- * Get seller rest API credentials
211
- *
212
- * @since 5.1.6
213
- *
214
- * @param string $accessToken
215
- *
216
- * @return array
217
- */
218
- public function getSellerRestAPICredentials( $accessToken ) {
219
- $request = wp_remote_post( $this->connectClient->get_api_url( sprintf( 'paypal-commerce/?mode=%1$s&request=seller-credentials', $this->payPalClient->mode ) ), [
220
- 'body' => [
221
- 'token' => $accessToken,
222
- ],
223
- ] );
224
-
225
- if ( is_wp_error( $request ) ) {
226
- tribe( 'logger' )->log_error( sprintf(
227
- // Translators: %s: The error message.
228
- __( 'PayPal Commerce Connect request error: %s', 'event-tickets' ),
229
- $request->get_error_message()
230
- ), 'tickets-commerce-paypal-commerce' );
231
-
232
- return null;
233
- }
234
-
235
- $response = wp_remote_retrieve_body( $request );
236
- $response = @json_decode( $response, true );
237
-
238
- if ( ! is_array( $response ) ) {
239
- tribe( 'logger' )->log_error( __( 'Unexpected PayPal Commerce Connect response', 'event-tickets' ), 'tickets-commerce-paypal-commerce' );
240
-
241
- return null;
242
- }
243
-
244
- return $response;
245
- }
246
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/PayPalOrder.php DELETED
@@ -1,175 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories;
4
-
5
- use Exception;
6
- use InvalidArgumentException;
7
-
8
- // @todo Implement PayPal Checkout SDK.
9
- use PayPalCheckoutSdk\Orders\OrdersCaptureRequest;
10
- use PayPalCheckoutSdk\Orders\OrdersCreateRequest;
11
- use PayPalCheckoutSdk\Payments\CapturesRefundRequest;
12
-
13
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models\MerchantDetail;
14
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\PayPalClient;
15
-
16
- /**
17
- * Class PayPalOrder
18
- *
19
- * @since 5.1.6
20
- * @package TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories
21
- *
22
- */
23
- class PayPalOrder {
24
-
25
- /**
26
- * @since 5.1.6
27
- *
28
- * @var PayPalClient
29
- */
30
- private $paypalClient;
31
-
32
- /**
33
- * @since 5.1.6
34
- *
35
- * @var MerchantDetail
36
- */
37
- private $merchantDetails;
38
-
39
- /**
40
- * PayPalOrder constructor.
41
- *
42
- * @since 5.1.6
43
- *
44
- * @param MerchantDetail $merchantDetails
45
- *
46
- * @param PayPalClient $paypalClient
47
- */
48
- public function __construct( PayPalClient $paypalClient, MerchantDetail $merchantDetails ) {
49
- $this->paypalClient = $paypalClient;
50
- $this->merchantDetails = $merchantDetails;
51
- }
52
-
53
- /**
54
- * Approve order.
55
- *
56
- * @since 5.1.6
57
- *
58
- * @param string $orderId
59
- *
60
- * @return string
61
- * @throws Exception
62
- */
63
- public function approveOrder( $orderId ) {
64
- $request = new OrdersCaptureRequest( $orderId );
65
-
66
- try {
67
- return $this->paypalClient->getHttpClient()->execute( $request )->result;
68
- } catch ( Exception $ex ) {
69
- // @todo Log the error.
70
- logError( 'Capture PayPal Commerce payment failure', sprintf( '<strong>Response</strong><pre>%1$s</pre>', print_r( json_decode( $ex->getMessage(), true ), true ) ) );
71
-
72
- throw $ex;
73
- }
74
- }
75
-
76
- /**
77
- * Create order.
78
- *
79
- * @since 5.1.6
80
- *
81
- * @param array $array
82
- *
83
- * @return string
84
- * @throws Exception
85
- */
86
- public function createOrder( $array ) {
87
- $this->validateCreateOrderArguments( $array );
88
-
89
- $request = new OrdersCreateRequest();
90
- // @todo Replace this with our bin code from Gateway::ATTRIBUTION_ID.
91
- $request->payPalPartnerAttributionId( Give( 'PAYPAL_COMMERCE_ATTRIBUTION_ID' ) );
92
- $request->body = [
93
- 'intent' => 'CAPTURE',
94
- 'purchase_units' => [
95
- [
96
- // @todo Replace this.
97
- 'reference_id' => get_post_field( 'post_name', $array['formId'] ),
98
- // @todo Replace this.
99
- 'description' => $array['formTitle'],
100
- 'amount' => [
101
- // @todo Replace this.
102
- 'value' => give_maybe_sanitize_amount( $array['paymentAmount'], [ 'currency' => give_get_currency( $array['formId'] ) ] ),
103
- // @todo Replace this.
104
- 'currency_code' => give_get_currency( $array['formId'] ),
105
- ],
106
- 'payee' => [
107
- 'email_address' => $this->merchantDetails->merchantId,
108
- 'merchant_id' => $this->merchantDetails->merchantIdInPayPal,
109
- ],
110
- 'payer' => [
111
- // @todo Replace these.
112
- 'given_name' => $array['payer']['firstName'],
113
- 'surname' => $array['payer']['lastName'],
114
- 'email_address' => $array['payer']['email'],
115
- ],
116
- 'payment_instruction' => [
117
- 'disbursement_mode' => 'INSTANT',
118
- ],
119
- ],
120
- ],
121
- 'application_context' => [
122
- 'shipping_preference' => 'NO_SHIPPING',
123
- 'user_action' => 'PAY_NOW',
124
- ],
125
- ];
126
-
127
- try {
128
- return $this->paypalClient->getHttpClient()->execute( $request )->result->id;
129
- } catch ( Exception $ex ) {
130
- logError( 'Create PayPal Commerce order failure', sprintf( '<strong>Request</strong><pre>%1$s</pre><br><strong>Response</strong><pre>%2$s</pre>', print_r( $request->body, true ), print_r( json_decode( $ex->getMessage(), true ), true ) ) );
131
-
132
- throw $ex;
133
- }
134
- }
135
-
136
- /**
137
- * Refunds a processed payment
138
- *
139
- * @since 5.1.6
140
- *
141
- * @param $captureId
142
- *
143
- * @return string The id of the refund
144
- * @throws Exception
145
- */
146
- public function refundPayment( $captureId ) {
147
- $refund = new CapturesRefundRequest( $captureId );
148
-
149
- try {
150
- return $this->paypalClient->getHttpClient()->execute( $refund )->result->id;
151
- } catch ( Exception $exception ) {
152
- logError( 'Create PayPal Commerce payment refund failure', sprintf( '<strong>Response</strong><pre>%1$s</pre>', print_r( json_decode( $exception->getMessage(), true ), true ) ) );
153
-
154
- throw $exception;
155
- }
156
- }
157
-
158
- /**
159
- * Validate argument given to create PayPal order.
160
- *
161
- * @since 5.1.6
162
- *
163
- * @param array $array
164
- *
165
- * @throws InvalidArgumentException
166
- */
167
- private function validateCreateOrderArguments( $array ) {
168
- $required = [ 'formId', 'paymentAmount', 'payer' ];
169
- $array = array_filter( $array ); // Remove empty values.
170
-
171
- if ( array_diff( $required, array_keys( $array ) ) ) {
172
- throw new InvalidArgumentException( __( 'To create a paypal order, please provide formId, paymentAmount and payer', 'event-tickets' ) );
173
- }
174
- }
175
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/PayPal/SDK/Repositories/Traits/HasMode.php DELETED
@@ -1,36 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\Traits;
4
-
5
- use InvalidArgumentException;
6
-
7
- trait HasMode {
8
-
9
- /**
10
- * The current working mode: live or sandbox
11
- *
12
- * @since 5.1.6
13
- *
14
- * @var string
15
- */
16
- protected $mode;
17
-
18
- /**
19
- * Sets the mode for the repository for handling operations
20
- *
21
- * @since 5.1.6
22
- *
23
- * @param $mode
24
- *
25
- * @return $this
26
- */
27
- public function setMode( $mode ) {
28
- if ( ! in_array( $mode, [ 'live', 'sandbox' ], true ) ) {
29
- throw new InvalidArgumentException( "Must be either 'live' or 'sandbox', received: $mode" );
30
- }
31
-
32
- $this->mode = $mode;
33
-
34
- return $this;
35
- }
36
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/PayPal/Settings.php CHANGED
@@ -3,9 +3,7 @@
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
 
5
  use TEC\Tickets\Commerce\Abstract_Settings;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models\MerchantDetail;
7
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models\WebhookConfig;
8
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\MerchantDetails;
9
  use Tribe__Languages__Locations;
10
  use Tribe__Tickets__Admin__Views;
11
  use Tribe__Tickets__Main;
@@ -17,74 +15,6 @@ use Tribe__Tickets__Main;
17
  * @package TEC\Tickets\Commerce\Gateways\PayPal
18
  */
19
  class Settings extends Abstract_Settings {
20
-
21
- /**
22
- * The option key for account country.
23
- *
24
- * @since 5.1.6
25
- *
26
- * @var string
27
- */
28
- public $option_account_country = 'tickets-commerce-paypal-commerce-account-country';
29
-
30
- /**
31
- * The option key for access token.
32
- *
33
- * @since 5.1.6
34
- *
35
- * @var string
36
- */
37
- public $option_access_token = 'tickets-commerce-paypal-commerce-access-token';
38
-
39
- /**
40
- * The option key for partner link detail.
41
- *
42
- * @since 5.1.6
43
- *
44
- * @var string
45
- */
46
- public $option_partner_link_detail = 'tickets-commerce-paypal-commerce-partner-link-detail';
47
-
48
- /**
49
- * The option key for webhook config.
50
- *
51
- * @since 5.1.6
52
- *
53
- * @var string
54
- */
55
- public $option_webhook_config = 'tickets-commerce-paypal-commerce-webhook-config';
56
-
57
- /**
58
- * The merchant detail model.
59
- *
60
- * @since 5.1.6
61
- *
62
- * @var MerchantDetail
63
- */
64
- private $merchant_model;
65
-
66
- /**
67
- * The merchant details repository.
68
- *
69
- * @since 5.1.6
70
- *
71
- * @var MerchantDetails
72
- */
73
- private $merchant_repository;
74
-
75
- /**
76
- * Set up the things we need for the settings.
77
- *
78
- * @since 5.1.6
79
- *
80
- * @param MerchantDetail $merchantDetail
81
- * @param MerchantDetails $merchantDetailRepository
82
- */
83
- public function __construct( MerchantDetail $merchantDetail, MerchantDetails $merchantDetailRepository ) {
84
- $this->merchant_model = $merchantDetail;
85
- $this->merchant_repository = $merchantDetailRepository;
86
- }
87
-
88
  /**
89
  * Get the list of settings for the gateway.
90
  *
@@ -110,22 +40,6 @@ class Settings extends Abstract_Settings {
110
  'html' => $this->get_introduction_html(),
111
  'validation_type' => 'html',
112
  ],
113
- $this->option_account_country => [
114
- 'type' => 'dropdown',
115
- 'label' => esc_html__( 'Account Country', 'event-tickets' ),
116
- 'tooltip' => esc_html__( 'This is the country your site operates from.', 'event-tickets' ),
117
- 'size' => 'medium',
118
- 'validation_type' => 'options',
119
- 'options' => $countries,
120
- 'required' => true, // @todo This is not working.
121
- 'can_be_empty' => false, // @todo This is not working.
122
- ],
123
- 'tickets-commerce-paypal-commerce-connect' => [
124
- 'type' => 'wrapped_html',
125
- 'label' => esc_html__( 'PayPal Connection', 'event-tickets' ),
126
- 'html' => $this->get_connect_html(),
127
- 'validation_type' => 'html',
128
- ],
129
  ];
130
  }
131
 
@@ -149,31 +63,6 @@ class Settings extends Abstract_Settings {
149
  return $admin_views->template( 'settings/tickets-commerce/paypal-commerce/introduction', [], false );
150
  }
151
 
152
- /**
153
- * Get the Connect with PayPal HTML.
154
- *
155
- * @since 5.1.6
156
- *
157
- * @return string The Connect with PayPal HTML.
158
- */
159
- public function get_connect_html() {
160
- /** @var Tribe__Tickets__Admin__Views $admin_views */
161
- $admin_views = tribe( 'tickets.admin.views' );
162
-
163
- $account_errors = $this->merchant_repository->getAccountErrors();
164
-
165
- $context = [
166
- 'account_is_connected' => $this->merchant_repository->accountIsConnected(),
167
- 'merchant_id' => $this->merchant_model->merchantId,
168
- 'formatted_errors' => $this->get_formatted_error_html( $account_errors ),
169
- 'guidance_html' => $this->get_guidance_html(),
170
- ];
171
-
172
- $admin_views->add_template_globals( $context );
173
-
174
- return $admin_views->template( 'settings/tickets-commerce/paypal-commerce/connect-with-paypal', [], false );
175
- }
176
-
177
  /**
178
  * Get the guidance HTML.
179
  *
@@ -361,129 +250,4 @@ class Settings extends Abstract_Settings {
361
  public function update_account_country( $country ) {
362
  return tribe_update_option( $this->option_account_country, $country );
363
  }
364
-
365
- /**
366
- * Returns the account access token
367
- *
368
- * @since 5.1.6
369
- *
370
- * @return array|null
371
- */
372
- public function get_access_token() {
373
- $access_token = tribe_get_option( $this->option_access_token );
374
-
375
- if ( ! is_array( $access_token ) ) {
376
- return null;
377
- }
378
-
379
- return $access_token;
380
- }
381
-
382
- /**
383
- * Updates the account access token.
384
- *
385
- * @since 5.1.6
386
- *
387
- * @param array $token The account access token.
388
- *
389
- * @return bool
390
- */
391
- public function update_access_token( $token ) {
392
- return tribe_update_option( $this->option_access_token, (array) $token );
393
- }
394
-
395
- /**
396
- * Deletes the account access token
397
- *
398
- * @since 5.1.6
399
- *
400
- * @return bool
401
- */
402
- public function delete_access_token() {
403
- return tribe_update_option( $this->option_access_token, '' );
404
- }
405
-
406
- /**
407
- * Returns the partner link details
408
- *
409
- * @since 5.1.6
410
- *
411
- * @since 5.1.6
412
- *
413
- * @return string|null
414
- */
415
- public function get_partner_link_details() {
416
- return tribe_get_option( $this->option_partner_link_detail, null );
417
- }
418
-
419
- /**
420
- * Updates the partner link details
421
- *
422
- * @since 5.1.6
423
- *
424
- * @param $linkDetails
425
- *
426
- * @return bool
427
- */
428
- public function update_partner_link_details( $linkDetails ) {
429
- return tribe_update_option( $this->option_partner_link_detail, $linkDetails );
430
- }
431
-
432
- /**
433
- * Deletes the partner link details
434
- *
435
- * @since 5.1.6
436
- *
437
- * @return bool
438
- */
439
- public function delete_partner_link_details() {
440
- return tribe_update_option( $this->option_partner_link_detail, '' );
441
- }
442
-
443
- /**
444
- * Returns the webhook config.
445
- *
446
- * @since 5.1.6
447
- *
448
- * @param string $mode The mode (live/sandbox).
449
- *
450
- * @return WebhookConfig|null
451
- */
452
- public function get_webhook_config( $mode ) {
453
- $config = tribe_get_option( "{$this->option_webhook_config}-{$mode}", null );
454
-
455
- if ( empty( $config ) ) {
456
- return null;
457
- }
458
-
459
- return WebhookConfig::fromArray( $config );
460
- }
461
-
462
- /**
463
- * Updates the webhook config.
464
- *
465
- * @since 5.1.6
466
- *
467
- * @param string $mode The mode (live/sandbox).
468
- * @param WebhookConfig $config The webhook config array.
469
- *
470
- * @return bool
471
- */
472
- public function update_webhook_config( $mode, WebhookConfig $config ) {
473
- return tribe_update_option( "{$this->option_webhook_config}-{$mode}", $config->toArray() );
474
- }
475
-
476
- /**
477
- * Deletes the webhook config.
478
- *
479
- * @since 5.1.6
480
- *
481
- * @param string $mode The mode (live/sandbox).
482
- *
483
- * @return bool
484
- */
485
- public function delete_webhook_config( $mode ) {
486
- return tribe_update_option( "{$this->option_webhook_config}-{$mode}", '' );
487
- }
488
-
489
  }
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
 
5
  use TEC\Tickets\Commerce\Abstract_Settings;
6
+
 
 
7
  use Tribe__Languages__Locations;
8
  use Tribe__Tickets__Admin__Views;
9
  use Tribe__Tickets__Main;
15
  * @package TEC\Tickets\Commerce\Gateways\PayPal
16
  */
17
  class Settings extends Abstract_Settings {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  /**
19
  * Get the list of settings for the gateway.
20
  *
40
  'html' => $this->get_introduction_html(),
41
  'validation_type' => 'html',
42
  ],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  ];
44
  }
45
 
63
  return $admin_views->template( 'settings/tickets-commerce/paypal-commerce/introduction', [], false );
64
  }
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  /**
67
  * Get the guidance HTML.
68
  *
250
  public function update_account_country( $country ) {
251
  return tribe_update_option( $this->option_account_country, $country );
252
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  }
src/Tickets/Commerce/Gateways/PayPal/Signup.php ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
+ use Tribe__Utils__Array as Arr;
5
+
6
+ /**
7
+ * Class Signup
8
+ *
9
+ * @since 5.1.9
10
+ *
11
+ * @package TEC\Tickets\Commerce\Gateways\PayPal
12
+ */
13
+ class Signup {
14
+
15
+ /**
16
+ * Holds the transient key used to store hash passed to PayPal.
17
+ *
18
+ * @since 5.1.9
19
+ *
20
+ * @var string
21
+ */
22
+ public static $signup_hash_meta_key = 'tec_tc_paypal_signup_hash';
23
+
24
+ /**
25
+ * Holds the transient key used to link PayPal to this site.
26
+ *
27
+ * @since 5.1.9
28
+ *
29
+ * @var string
30
+ */
31
+ public static $signup_data_meta_key = 'tec_tc_paypal_signup_data';
32
+
33
+ /**
34
+ * Stores the instance of the template engine that we will use for rendering the page.
35
+ *
36
+ * @since 5.1.9
37
+ *
38
+ * @var \Tribe__Template
39
+ */
40
+ protected $template;
41
+
42
+ /**
43
+ * Gets the template instance used to setup the rendering of the page.
44
+ *
45
+ * @since 5.1.9
46
+ *
47
+ * @return \Tribe__Template
48
+ */
49
+ public function get_template() {
50
+ if ( empty( $this->template ) ) {
51
+ $this->template = new \Tribe__Template();
52
+ $this->template->set_template_origin( \Tribe__Tickets__Main::instance() );
53
+ $this->template->set_template_folder( 'src/admin-views/commerce/gateways/paypal' );
54
+ $this->template->set_template_context_extract( true );
55
+ }
56
+
57
+ return $this->template;
58
+ }
59
+
60
+ /**
61
+ * Gets the saved hash for a given user, empty when non-existent.
62
+ *
63
+ * @since 5.1.9
64
+ *
65
+ * @return string
66
+ */
67
+ public function get_transient_hash() {
68
+ return get_transient( static::$signup_hash_meta_key );
69
+ }
70
+
71
+ /**
72
+ * Gets the saved hash for a given user, empty when non-existent.
73
+ *
74
+ * @since 5.1.9
75
+ *
76
+ * @param string $value Hash for signup.
77
+ *
78
+ * @return bool
79
+ */
80
+ public function update_transient_hash( $value ) {
81
+ return set_transient( static::$signup_hash_meta_key, $value, DAY_IN_SECONDS );
82
+ }
83
+
84
+ /**
85
+ * Delete Hash transient from the DB.
86
+ *
87
+ * @since 5.1.9
88
+ *
89
+ * @return bool
90
+ */
91
+ public function delete_transient_hash() {
92
+ return delete_transient( static::$signup_hash_meta_key );
93
+ }
94
+
95
+ /**
96
+ * Gets the saved hash for a given user, empty when non-existent.
97
+ *
98
+ * @since 5.1.9
99
+ *
100
+ * @return array
101
+ */
102
+ public function get_transient_data() {
103
+ return get_transient( static::$signup_data_meta_key );
104
+ }
105
+
106
+ /**
107
+ * Saves the URL in a transient for later use.
108
+ *
109
+ * @since 5.1.9
110
+ *
111
+ * @param string $value URL for signup.
112
+ *
113
+ * @return bool
114
+ */
115
+ public function update_transient_data( $value ) {
116
+ return set_transient( static::$signup_data_meta_key, $value, DAY_IN_SECONDS );
117
+ }
118
+
119
+ /**
120
+ * Delete url transient from the DB.
121
+ *
122
+ * @since 5.1.9
123
+ *
124
+ * @return bool
125
+ */
126
+ public function delete_transient_data() {
127
+ return delete_transient( static::$signup_data_meta_key );
128
+ }
129
+
130
+ /**
131
+ * Generate a Unique Hash for signup. It will always be 20 characters long.
132
+ *
133
+ * @since 5.1.9
134
+ *
135
+ * @return string
136
+ */
137
+ public function generate_unique_signup_hash() {
138
+ $nonce_key = defined( 'NONCE_KEY' ) ? NONCE_KEY : uniqid( '', true );
139
+ $nonce_salt = defined( 'NONCE_SALT' ) ? NONCE_SALT : uniqid( '', true );
140
+
141
+ $unique = uniqid( '', true );
142
+
143
+ $keys = [ $nonce_key, $nonce_salt, $unique ];
144
+ $keys = array_map( 'md5', $keys );
145
+
146
+ return substr( str_shuffle( implode( '-', $keys ) ), 0, 45 );
147
+ }
148
+
149
+ /**
150
+ * Generates a Tracking it for this website.
151
+ *
152
+ * @since 5.1.9
153
+ *
154
+ * @return string
155
+ */
156
+ public function generate_unique_tracking_id() {
157
+ $id = wp_generate_password( 6, false, false );;
158
+ $url_frags = wp_parse_url( home_url() );
159
+ $url = Arr::get( $url_frags, 'host' ) . Arr::get( $url_frags, 'path' );
160
+ $url = add_query_arg( [
161
+ 'v' => Gateway::VERSION . '-' . $id,
162
+ ], $url );
163
+
164
+ /**
165
+ * Tracking ID sent to PayPal.
166
+ *
167
+ * @since 5.1.9
168
+ *
169
+ * @param string $url Which ID we are using normally a URL, cannot be longer than 127 chars.
170
+ */
171
+ $url = apply_filters( 'tec_tickets_commerce_gateway_paypal_tracking_id', $url );
172
+
173
+ // Always limit it to 127 chars.
174
+ return substr( (string) $url, 0, 127 );
175
+ }
176
+
177
+ /**
178
+ * Request the signup link that redirects the seller to PayPal.
179
+ *
180
+ * @since 5.1.9
181
+ *
182
+ * @return string|false
183
+ */
184
+ public function generate_url() {
185
+ // Fetch the cached value for this user.
186
+ $signup = $this->get_transient_data();
187
+ if ( $signup_url = Arr::get( $signup, [ 'links', 1, 'href' ] ) ) {
188
+ return $signup_url;
189
+ }
190
+
191
+ $hash = $this->generate_unique_signup_hash();
192
+ $this->update_transient_hash( $hash );
193
+
194
+ $signup = tribe( WhoDat::class )->get_seller_signup_data( $hash );
195
+
196
+ if ( ! $signup_url = Arr::get( $signup, [ 'links', 1, 'href' ] ) ) {
197
+ return false;
198
+ }
199
+
200
+ $this->update_transient_data( $signup );
201
+
202
+ return $signup_url;
203
+ }
204
+
205
+ /**
206
+ * From the Transient data store we get the referral data link.
207
+ *
208
+ * @since 5.1.9
209
+ *
210
+ * @return false|string
211
+ */
212
+ public function get_referral_data_link() {
213
+ $links = $this->get_transient_data();
214
+ if ( empty( $links ) ) {
215
+ return false;
216
+ }
217
+
218
+ return Arr::get( $links, [ 'links', 0, 'href' ], false );
219
+ }
220
+
221
+ /**
222
+ * Gets the content for the template used for the sign up link that paypal creates.
223
+ *
224
+ * @since 5.1.9
225
+ *
226
+ * @return false|string
227
+ */
228
+ public function get_link_html() {
229
+ $template_vars = [
230
+ 'url' => $this->generate_url(),
231
+ ];
232
+
233
+ return $this->get_template()->template( 'signup-link', $template_vars, false );
234
+ }
235
+ }
src/Tickets/Commerce/Gateways/PayPal/Status.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
+
5
+ use TEC\Tickets\Commerce\Status as Commerce_Status;
6
+
7
+ /**
8
+ * Class Status
9
+ *
10
+ * @since 5.1.9
11
+ *
12
+ * @package TEC\Tickets\Commerce\Gateways\PayPal
13
+ */
14
+ class Status {
15
+
16
+ /**
17
+ * Order Status in PayPal for created.
18
+ *
19
+ * @since 5.1.9
20
+ *
21
+ * @var string
22
+ */
23
+ CONST CREATED = 'CREATED';
24
+
25
+ /**
26
+ * Order Status in PayPal for saved.
27
+ *
28
+ * @since 5.1.9
29
+ *
30
+ * @var string
31
+ */
32
+ CONST SAVED = 'SAVED';
33
+
34
+ /**
35
+ * Order Status in PayPal for approved.
36
+ *
37
+ * @since 5.1.9
38
+ *
39
+ * @var string
40
+ */
41
+ CONST APPROVED = 'APPROVED';
42
+
43
+ /**
44
+ * Order Status in PayPal for voided.
45
+ *
46
+ * @since 5.1.9
47
+ *
48
+ * @var string
49
+ */
50
+ CONST VOIDED = 'VOIDED';
51
+
52
+ /**
53
+ * Order Status in PayPal for completed.
54
+ *
55
+ * @since 5.1.9
56
+ *
57
+ * @var string
58
+ */
59
+ CONST COMPLETED = 'COMPLETED';
60
+
61
+ /**
62
+ * Order Status in PayPal for payer action required.
63
+ *
64
+ * @since 5.1.9
65
+ *
66
+ * @var string
67
+ */
68
+ CONST PAYER_ACTION_REQUIRED = 'PAYER_ACTION_REQUIRED';
69
+
70
+ /**
71
+ * Default mapping from PayPal Status to Tickets Commerce
72
+ *
73
+ * @since 5.1.9
74
+ *
75
+ * @var array
76
+ */
77
+ protected $default_map = [
78
+ self::CREATED => Commerce_Status\Created::SLUG,
79
+ self::SAVED => Commerce_Status\Pending::SLUG,
80
+ self::APPROVED => Commerce_Status\Approved::SLUG,
81
+ self::VOIDED => Commerce_Status\Voided::SLUG,
82
+ self::COMPLETED => Commerce_Status\Completed::SLUG,
83
+ self::PAYER_ACTION_REQUIRED => Commerce_Status\Action_Required::SLUG,
84
+ ];
85
+
86
+ /**
87
+ * Gets the valid mapping of the statuses.
88
+ *
89
+ * @since 5.1.9
90
+ *
91
+ * @return array
92
+ */
93
+ public function get_valid_statuses() {
94
+ return $this->default_map;
95
+ }
96
+
97
+ /**
98
+ * Checks if a given PayPal status is valid.
99
+ *
100
+ * @since 5.1.9
101
+ *
102
+ * @param string $status Status from PayPal.
103
+ *
104
+ * @return bool
105
+ */
106
+ public function is_valid_status( $status ) {
107
+ $statuses = $this->get_valid_statuses();
108
+ return isset( $statuses[ $status ] );
109
+ }
110
+
111
+ /**
112
+ * Converts a valid PayPal status into a commerce status object.
113
+ *
114
+ * @since 5.1.9
115
+ *
116
+ * @param string $paypal_status A PayPal status string.
117
+ *
118
+ * @return false|Commerce_Status\Status_Interface|null
119
+ */
120
+ public function convert_to_commerce_status( $paypal_status ) {
121
+ if ( ! $this->is_valid_status( $paypal_status ) ) {
122
+ return false;
123
+ }
124
+ $statuses = $this->get_valid_statuses();
125
+
126
+ return tribe( Commerce_Status\Status_Handler::class )->get_by_slug( $statuses[ $paypal_status ] );
127
+ }
128
+ }
src/Tickets/Commerce/Gateways/PayPal/Tickets_Form.php ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
+
5
+ use TEC\Tickets\Commerce\Attendee;
6
+ use TEC\Tickets\Commerce\Module;
7
+
8
+ /**
9
+ * Class Tickets_Form
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce\Gateways\PayPal
14
+ */
15
+ class Tickets_Form {
16
+ protected static $messages = [];
17
+
18
+ /**
19
+ * Gets ticket messages
20
+ *
21
+ * @since 4.7
22
+ *
23
+ * @return array
24
+ */
25
+ public function get_messages() {
26
+ return static::$messages;
27
+ }
28
+
29
+ /**
30
+ * Adds a submission message
31
+ *
32
+ * @since 4.7
33
+ *
34
+ * @param $message
35
+ * @param string $type
36
+ */
37
+ public function add_message( $message, $type = 'update' ) {
38
+ $message = apply_filters( 'tribe_tpp_submission_message', $message, $type );
39
+ static::$messages[] = (object) array( 'message' => $message, 'type' => $type );
40
+ }
41
+
42
+
43
+ /**
44
+ * Filters the post_updated_messages array for attendees
45
+ *
46
+ * @since 4.7
47
+ *
48
+ * @param array $messages Array of update messages
49
+ *
50
+ * @return array
51
+ */
52
+ public function updated_messages( $messages ) {
53
+ $ticket_post = get_post();
54
+
55
+ if ( ! $ticket_post ) {
56
+ return $messages;
57
+ }
58
+
59
+ $post_type = get_post_type( $ticket_post );
60
+
61
+ if ( Attendee::POSTTYPE !== $post_type ) {
62
+ return $messages;
63
+ }
64
+
65
+ $event = tribe( Module::class )->get_event_for_ticket( $ticket_post );
66
+
67
+ $attendees_report_url = add_query_arg(
68
+ array(
69
+ 'post_type' => $event->post_type,
70
+ 'page' => \Tribe__Tickets__Tickets_Handler::$attendees_slug,
71
+ 'event_id' => $event->ID,
72
+ ),
73
+ admin_url( 'edit.php' )
74
+ );
75
+
76
+ $return_link = sprintf(
77
+ esc_html__( 'Return to the %1$sAttendees Report%2$s.', 'event-tickets' ),
78
+ "<a href='" . esc_url( $attendees_report_url ) . "'>",
79
+ '</a>'
80
+ );
81
+
82
+ $messages[ Attendee::POSTTYPE ] = $messages['post'];
83
+ $messages[ Attendee::POSTTYPE ][1] = sprintf(
84
+ esc_html__( 'Post updated. %1$s', 'event-tickets' ),
85
+ $return_link
86
+ );
87
+ $messages[ Attendee::POSTTYPE ][6] = sprintf(
88
+ esc_html__( 'Post published. %1$s', 'event-tickets' ),
89
+ $return_link
90
+ );
91
+ $messages[ Attendee::POSTTYPE ][8] = esc_html__( 'Post submitted.', 'event-tickets' );
92
+ $messages[ Attendee::POSTTYPE ][9] = esc_html__( 'Post scheduled.', 'event-tickets' );
93
+ $messages[ Attendee::POSTTYPE ][10] = esc_html__( 'Post draft updated.', 'event-tickets' );
94
+
95
+ return $messages;
96
+ }
97
+
98
+ /**
99
+ * Whether the form has rendered already or not
100
+ *
101
+ * @var bool
102
+ */
103
+ protected $has_rendered = false;
104
+
105
+ /**
106
+ * Modifies the passed content to inject the front-end tickets form.
107
+ *
108
+ * @todo @juanfra We need to move this to use a whole new set of templates. This is currently still using
109
+ * Tribe Commerce templates and the old system.
110
+ *
111
+ * @since TBR
112
+ *
113
+ * @return void The method will echo in the context of a buffered output.
114
+ *
115
+ * @see Tribe__Tickets__Tickets::front_end_tickets_form_in_content
116
+ */
117
+ public function render() {
118
+ if ( $this->has_rendered || ! tribe( Module::class )->is_active() ) {
119
+ return;
120
+ }
121
+
122
+ $post = get_post();
123
+
124
+ if ( empty( $post ) ) {
125
+ return;
126
+ }
127
+
128
+ // For recurring events (child instances only), default to loading tickets for the parent event
129
+ if ( ! empty( $post->post_parent ) && function_exists( 'tribe_is_recurring_event' ) && tribe_is_recurring_event( $post->ID ) ) {
130
+ $post = get_post( $post->post_parent );
131
+ }
132
+
133
+ $tickets = tribe( Module::class )->get_tickets( $post->ID );
134
+
135
+ foreach ( $tickets as $key => $ticket ) {
136
+ /** @var \Tribe__Tickets__Ticket_Object $ticket */
137
+ if ( ! $ticket->date_in_range() ) {
138
+ unset( $tickets[ $key ] );
139
+ }
140
+ }
141
+
142
+ if ( empty( $tickets ) ) {
143
+ return;
144
+ }
145
+
146
+ $ticket_sent = empty( $_GET['tpp_sent'] ) ? false : true;
147
+
148
+ if ( $ticket_sent ) {
149
+ $this->add_message( esc_html( sprintf( __( 'Your PayPal %1$s has been received! Check your email for your PayPal %1$s confirmation.', 'event-tickets' ), tribe_get_ticket_label_singular( 'ticket_sent' ) ) ), 'success' );
150
+ }
151
+
152
+ $ticket_error = empty( $_GET['tpp_error'] ) ? false : (int) $_GET['tpp_error'];
153
+
154
+ if ( $ticket_error ) {
155
+ $this->add_message( \Tribe__Tickets__Commerce__PayPal__Errors::error_code_to_message( $ticket_error ), 'error' );
156
+ }
157
+
158
+ $ticket_message = empty( $_GET['tpp_message'] ) ? false : (int) $_GET['tpp_message'];
159
+
160
+ if ( $ticket_message ) {
161
+ $this->add_message( \Tribe__Tickets__Commerce__PayPal__Errors::error_code_to_message( $ticket_message ), 'update' );
162
+ }
163
+
164
+ $must_login = ! is_user_logged_in() && tribe( Module::class )->login_required();
165
+
166
+ /**
167
+ * Controls the visibility of the "Log it before purchasing" link below the tickets form
168
+ * for TPP tickets
169
+ *
170
+ * @since 4.9.3
171
+ *
172
+ */
173
+ $display_login_link = apply_filters( 'tribe_tickets_show_login_before_purchasing_link', true );
174
+
175
+ ob_start();
176
+ tribe( Module::class )->getTemplateHierarchy( 'tickets/tpp' );
177
+ $form = ob_get_clean();
178
+
179
+ $currently_available_tickets = array_filter( $tickets, array( $this, 'is_currently_available' ) );
180
+
181
+ if ( count( $currently_available_tickets ) > 0 ) {
182
+ // If we have available tickets there is generally no need to display a 'tickets unavailable' message
183
+ // for this post
184
+ tribe( Module::class )->do_not_show_tickets_unavailable_message();
185
+ } else {
186
+ // Indicate that there are not any tickets, so a 'tickets unavailable' message may be
187
+ // appropriate (depending on whether other ticket providers are active and have a similar
188
+ // result)
189
+ tribe( Module::class )->maybe_show_tickets_unavailable_message( $tickets );
190
+ }
191
+
192
+ // It's only done when it's included
193
+ $this->has_rendered = true;
194
+
195
+ echo $form;
196
+ }
197
+
198
+ /**
199
+ * Sets whether the form rendered already or not.
200
+ *
201
+ * @since 4.7
202
+ *
203
+ * @param bool $has_rendered
204
+ */
205
+ public function has_rendered( $has_rendered ) {
206
+ $this->has_rendered = (bool) $has_rendered;
207
+ }
208
+
209
+ /**
210
+ * A utility method to filter the list of tickets by their currently available status.
211
+ *
212
+ * @since 4.7
213
+ *
214
+ * @param Tribe__Tickets__Ticket_Object $ticket
215
+ *
216
+ * @return bool
217
+ */
218
+ protected function is_currently_available( \Tribe__Tickets__Ticket_Object $ticket ) {
219
+ return $ticket->date_in_range();
220
+ }
221
+ }
src/Tickets/Commerce/Gateways/PayPal/{SDK/DataTransferObjects/PayPalWebhookHeaders.php → Webhooks/Headers.php} RENAMED
@@ -1,47 +1,47 @@
1
  <?php
2
 
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\SDK\DataTransferObjects;
4
 
5
  use Exception;
6
 
7
  /**
8
- * Class PayPalWebhookHeaders.
9
  *
10
- * @since 5.1.6
11
  *
12
- * @package TEC\Tickets\Commerce\Gateways\PayPal\SDK\DataTransferObjects
13
  */
14
- class PayPalWebhookHeaders {
15
 
16
  /**
17
  * @since 5.1.6
18
  * @var string
19
  */
20
- public $transmissionId;
21
 
22
  /**
23
  * @since 5.1.6
24
  * @var string
25
  */
26
- public $transmissionTime;
27
 
28
  /**
29
  * @since 5.1.6
30
  * @var string
31
  */
32
- public $transmissionSig;
33
 
34
  /**
35
  * @since 5.1.6
36
  * @var string
37
  */
38
- public $certUrl;
39
 
40
  /**
41
  * @since 5.1.6
42
  * @var string
43
  */
44
- public $authAlgo;
45
 
46
  /**
47
  * This grabs the headers from the webhook request to be used in the signature verification
@@ -51,23 +51,24 @@ class PayPalWebhookHeaders {
51
  *
52
  * @since 5.1.6
53
  *
 
 
54
  * @param array $headers
55
  *
56
  * @return self
57
- * @throws HttpHeaderException
58
  */
59
- public static function fromHeaders( array $headers ) {
60
- $headerKeys = [
61
- 'transmissionId' => 'Paypal-Transmission-Id',
62
- 'transmissionTime' => 'Paypal-Transmission-Time',
63
- 'transmissionSig' => 'Paypal-Transmission-Sig',
64
- 'certUrl' => 'Paypal-Cert-Url',
65
- 'authAlgo' => 'Paypal-Auth-Algo',
66
  ];
67
 
68
- $payPalHeaders = new self();
69
- $missingKeys = [];
70
- foreach ( $headerKeys as $property => $key ) {
71
  if ( ! isset( $headers[ $key ] ) ) {
72
  $key = str_replace( '-', '_', $key );
73
  $key = strtoupper( $key );
@@ -78,19 +79,19 @@ class PayPalWebhookHeaders {
78
  }
79
 
80
  if ( isset( $headers[ $key ] ) ) {
81
- $payPalHeaders->$property = $headers[ $key ];
82
  } else {
83
- $missingKeys[] = $key;
84
  }
85
  }
86
 
87
- if ( ! empty( $missingKeys ) ) {
88
  tribe( 'logger' )->log_error(
89
  sprintf(
90
- // Translators: %s: The missing keys and header information.
91
  __( 'Missing PayPal webhook header: %s', 'event-tickets' ),
92
  json_encode( [
93
- 'missingKeys' => $missingKeys,
94
  'headers' => $headers,
95
  ] )
96
  ),
@@ -100,6 +101,6 @@ class PayPalWebhookHeaders {
100
  throw new Exception( "Missing PayPal header: $key" );
101
  }
102
 
103
- return $payPalHeaders;
104
  }
105
  }
1
  <?php
2
 
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks;
4
 
5
  use Exception;
6
 
7
  /**
8
+ * Class Headers.
9
  *
10
+ * @since 5.1.6
11
  *
12
+ * @package TEC\Tickets\Commerce\Gateways\PayPal\Webhooks
13
  */
14
+ class Headers {
15
 
16
  /**
17
  * @since 5.1.6
18
  * @var string
19
  */
20
+ public $transmission_id;
21
 
22
  /**
23
  * @since 5.1.6
24
  * @var string
25
  */
26
+ public $transmission_time;
27
 
28
  /**
29
  * @since 5.1.6
30
  * @var string
31
  */
32
+ public $transmission_sig;
33
 
34
  /**
35
  * @since 5.1.6
36
  * @var string
37
  */
38
+ public $cert_url;
39
 
40
  /**
41
  * @since 5.1.6
42
  * @var string
43
  */
44
+ public $auth_algo;
45
 
46
  /**
47
  * This grabs the headers from the webhook request to be used in the signature verification
51
  *
52
  * @since 5.1.6
53
  *
54
+ * @throws \HttpHeaderException
55
+ *
56
  * @param array $headers
57
  *
58
  * @return self
 
59
  */
60
+ public static function from_headers( array $headers ) {
61
+ $header_keys = [
62
+ 'transmission_id' => 'Paypal-Transmission-Id',
63
+ 'transmission_time' => 'Paypal-Transmission-Time',
64
+ 'transmission_sig' => 'Paypal-Transmission-Sig',
65
+ 'cert_url' => 'Paypal-Cert-Url',
66
+ 'auth_algo' => 'Paypal-Auth-Algo',
67
  ];
68
 
69
+ $paypal_headers = new self();
70
+ $missing_keys = [];
71
+ foreach ( $header_keys as $property => $key ) {
72
  if ( ! isset( $headers[ $key ] ) ) {
73
  $key = str_replace( '-', '_', $key );
74
  $key = strtoupper( $key );
79
  }
80
 
81
  if ( isset( $headers[ $key ] ) ) {
82
+ $paypal_headers->{$property} = $headers[ $key ];
83
  } else {
84
+ $missing_keys[] = $key;
85
  }
86
  }
87
 
88
+ if ( ! empty( $missing_keys ) ) {
89
  tribe( 'logger' )->log_error(
90
  sprintf(
91
+ // Translators: %s: The missing keys and header information.
92
  __( 'Missing PayPal webhook header: %s', 'event-tickets' ),
93
  json_encode( [
94
+ 'missing_keys' => $missing_keys,
95
  'headers' => $headers,
96
  ] )
97
  ),
101
  throw new Exception( "Missing PayPal header: $key" );
102
  }
103
 
104
+ return $paypal_headers;
105
  }
106
  }
src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{EventListener.php → Event_Listener.php} RENAMED
@@ -2,7 +2,7 @@
2
 
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners;
4
 
5
- interface EventListener {
6
 
7
  /**
8
  * This processes the PayPal Commerce webhook event passed to it.
@@ -13,5 +13,5 @@ interface EventListener {
13
  *
14
  * @return bool Whether the event was processed successfully.
15
  */
16
- public function processEvent( $event );
17
  }
2
 
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners;
4
 
5
+ interface Event_Listener {
6
 
7
  /**
8
  * This processes the PayPal Commerce webhook event passed to it.
13
  *
14
  * @return bool Whether the event was processed successfully.
15
  */
16
+ public function process_event( $event );
17
  }
src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{PaymentCaptureCompleted.php → Payment_Capture_Completed.php} RENAMED
@@ -9,7 +9,7 @@ namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners;
9
  * @package TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners
10
  *
11
  */
12
- class PaymentCaptureCompleted extends PaymentEventListener {
13
  /**
14
  * The new status to set with successful event.
15
  *
9
  * @package TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners
10
  *
11
  */
12
+ class Payment_Capture_Completed extends Payment_Event_Listener {
13
  /**
14
  * The new status to set with successful event.
15
  *
src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{PaymentCaptureDenied.php → Payment_Capture_Denied.php} RENAMED
@@ -9,7 +9,7 @@ namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners;
9
  * @package TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners
10
  *
11
  */
12
- class PaymentCaptureDenied extends PaymentEventListener {
13
  /**
14
  * The new status to set with successful event.
15
  *
9
  * @package TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners
10
  *
11
  */
12
+ class Payment_Capture_Denied extends Payment_Event_Listener {
13
  /**
14
  * The new status to set with successful event.
15
  *
src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{PaymentCaptureRefunded.php → Payment_Capture_Refunded.php} RENAMED
@@ -9,7 +9,7 @@ namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners;
9
  *
10
  * @since 5.1.6
11
  */
12
- class PaymentCaptureRefunded extends PaymentEventListener {
13
  /**
14
  * The new status to set with successful event.
15
  *
9
  *
10
  * @since 5.1.6
11
  */
12
+ class Payment_Capture_Refunded extends Payment_Event_Listener {
13
  /**
14
  * The new status to set with successful event.
15
  *
src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{PaymentCaptureReversed.php → Payment_Capture_Reversed.php} RENAMED
@@ -9,7 +9,7 @@ namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners;
9
  *
10
  * @since 5.1.6
11
  */
12
- class PaymentCaptureReversed extends PaymentEventListener {
13
  /**
14
  * The new status to set with successful event.
15
  *
9
  *
10
  * @since 5.1.6
11
  */
12
+ class Payment_Capture_Reversed extends Payment_Event_Listener {
13
  /**
14
  * The new status to set with successful event.
15
  *
src/Tickets/Commerce/Gateways/PayPal/Webhooks/Listeners/{PaymentEventListener.php → Payment_Event_Listener.php} RENAMED
@@ -2,9 +2,9 @@
2
 
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners;
4
 
5
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\MerchantDetails;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\Webhooks;
7
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\WebhookRegister;
8
  use WP_Post;
9
 
10
  /**
@@ -14,27 +14,27 @@ use WP_Post;
14
  * @package TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners
15
  *
16
  */
17
- abstract class PaymentEventListener implements EventListener {
18
  /**
19
  * @since 5.1.6
20
  *
21
- * @var MerchantDetails
22
  */
23
- private $merchantRepository;
24
 
25
  /**
26
  * @since 5.1.6
27
  *
28
  * @var Webhooks
29
  */
30
- private $webhookRepository;
31
 
32
  /**
33
  * @since 5.1.6
34
  *
35
- * @var WebhookRegister
36
  */
37
- private $webhookRegister;
38
 
39
  /**
40
  * The new status to set with successful event.
@@ -59,14 +59,14 @@ abstract class PaymentEventListener implements EventListener {
59
  *
60
  * @since 5.1.6
61
  *
62
- * @param MerchantDetails $merchantRepository
63
- * @param WebhookRegister $register
64
- * @param Webhooks $webhookRepository
65
  */
66
- public function __construct( MerchantDetails $merchantRepository, WebhookRegister $register, Webhooks $webhookRepository ) {
67
- $this->merchantRepository = $merchantRepository;
68
- $this->webhookRegister = $register;
69
- $this->webhookRepository = $webhookRepository;
70
  }
71
 
72
  /**
@@ -78,7 +78,7 @@ abstract class PaymentEventListener implements EventListener {
78
  *
79
  * @return bool Whether the event was processed successfully.
80
  */
81
- public function processEvent( $event ) {
82
  // No status set.
83
  if ( ! $this->new_status ) {
84
  return false;
@@ -93,7 +93,7 @@ abstract class PaymentEventListener implements EventListener {
93
  if ( $this->event_type !== $event->event_type ) {
94
  tribe( 'logger' )->log_debug(
95
  sprintf(
96
- // Translators: %s: The PayPal payment event.
97
  __( 'Mismatched event type for webhook event: %s', 'event-tickets' ),
98
  json_encode( $event )
99
  ),
@@ -103,12 +103,12 @@ abstract class PaymentEventListener implements EventListener {
103
  return false;
104
  }
105
 
106
- $paymentId = $this->getParentPaymentIdFromPayment( $event->resource );
107
 
108
- if ( ! $paymentId ) {
109
  tribe( 'logger' )->log_debug(
110
  sprintf(
111
- // Translators: %s: The PayPal payment event.
112
  __( 'Missing PayPal payment for webhook event: %s', 'event-tickets' ),
113
  json_encode( $event )
114
  ),
@@ -118,15 +118,15 @@ abstract class PaymentEventListener implements EventListener {
118
  return false;
119
  }
120
 
121
- $payment = $this->getOrderByPaymentId( $paymentId );
122
 
123
  // If there's no matching payment then it's not tracked by Tickets Commerce.
124
  if ( ! $payment ) {
125
  tribe( 'logger' )->log_debug(
126
  sprintf(
127
- // Translators: %s: The PayPal payment ID.
128
  __( 'Missing order for PayPal payment from webhook: %s', 'event-tickets' ),
129
- $paymentId
130
  ),
131
  'tickets-commerce-paypal-commerce'
132
  );
@@ -149,10 +149,10 @@ abstract class PaymentEventListener implements EventListener {
149
 
150
  tribe( 'logger' )->log_debug(
151
  sprintf(
152
- // Translators: %1$s: The status name; %2$s: The payment information.
153
  __( 'Change %1$s in PayPal from webhook: %2$s', 'event-tickets' ),
154
  $this->new_status,
155
- sprintf( '[Order ID: %s; PayPal Payment ID: %s]', $payment->ID, $paymentId )
156
  ),
157
  'tickets-commerce-paypal-commerce'
158
  );
@@ -163,22 +163,22 @@ abstract class PaymentEventListener implements EventListener {
163
  * @since 5.1.6
164
  *
165
  * @param WP_Post $payment The payment object.
166
- * @param string $paymentId The PayPal payment ID.
167
  * @param object $event The PayPal webhook event.
168
  * @param string $new_status The new order status.
169
  */
170
- do_action( 'tribe_tickets_commerce_gateways_paypal_commerce_webhooks_listeners', $payment, $paymentId, $event, $this->new_status );
171
 
172
  /**
173
  * Allow hooking into the listener status for the new status.
174
  *
175
  * @since 5.1.6
176
  *
177
- * @param WP_Post $payment The payment object.
178
- * @param string $paymentId The PayPal payment ID.
179
- * @param object $event The PayPal webhook event.
180
  */
181
- do_action( "tribe_tickets_commerce_gateways_paypal_commerce_webhooks_listeners_{$this->new_status}", $payment, $paymentId, $event );
182
 
183
  return true;
184
  }
@@ -192,7 +192,7 @@ abstract class PaymentEventListener implements EventListener {
192
  *
193
  * @return \WP_Post|null The matching order or null if not found.
194
  */
195
- public function getOrderByPaymentId( $id ) {
196
  $orm = tribe_tickets_orders( 'tribe-commerce' );
197
 
198
  return $orm->by( 'id', $id )->first();
@@ -207,7 +207,7 @@ abstract class PaymentEventListener implements EventListener {
207
  *
208
  * @return string|false The parent payment ID or false if not found.
209
  */
210
- private function getParentPaymentIdFromPayment( $payment ) {
211
  $link = current( array_filter( $payment->links, static function ( $link ) {
212
  return $link->rel === 'up';
213
  } ) );
@@ -216,19 +216,17 @@ abstract class PaymentEventListener implements EventListener {
216
  return false;
217
  }
218
 
219
- $accountDetails = $this->merchantDetails->getDetails();
220
-
221
  $request = wp_remote_request( $link->href, [
222
  'method' => $link->method,
223
  'headers' => [
224
  'Content-Type' => 'application/json',
225
- 'Authorization' => "Bearer {$accountDetails->accessToken}",
226
  ],
227
  ] );
228
 
229
  if ( is_wp_error( $request ) ) {
230
  tribe( 'logger' )->log_error( sprintf(
231
- // Translators: %s: The error message.
232
  __( 'PayPal capture request error: %s', 'event-tickets' ),
233
  $request->get_error_message()
234
  ), 'tickets-commerce-paypal-commerce' );
2
 
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners;
4
 
5
+ use TEC\Tickets\Commerce\Gateways\PayPal\Merchant;
6
+ use TEC\Tickets\Commerce\Gateways\PayPal\Repositories\Webhooks;
7
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Webhook_Register;
8
  use WP_Post;
9
 
10
  /**
14
  * @package TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners
15
  *
16
  */
17
+ abstract class Payment_Event_Listener implements Event_Listener {
18
  /**
19
  * @since 5.1.6
20
  *
21
+ * @var Merchant
22
  */
23
+ private $merchant;
24
 
25
  /**
26
  * @since 5.1.6
27
  *
28
  * @var Webhooks
29
  */
30
+ private $webhook_repository;
31
 
32
  /**
33
  * @since 5.1.6
34
  *
35
+ * @var Webhook_Register
36
  */
37
+ private $webhook_register;
38
 
39
  /**
40
  * The new status to set with successful event.
59
  *
60
  * @since 5.1.6
61
  *
62
+ * @param Merchant $merchant
63
+ * @param Webhook_Register $register
64
+ * @param Webhooks $webhook_repository
65
  */
66
+ public function __construct( Merchant $merchant, Webhook_Register $register, Webhooks $webhook_repository ) {
67
+ $this->merchant = $merchant;
68
+ $this->webhook_register = $register;
69
+ $this->webhook_repository = $webhook_repository;
70
  }
71
 
72
  /**
78
  *
79
  * @return bool Whether the event was processed successfully.
80
  */
81
+ public function process_event( $event ) {
82
  // No status set.
83
  if ( ! $this->new_status ) {
84
  return false;
93
  if ( $this->event_type !== $event->event_type ) {
94
  tribe( 'logger' )->log_debug(
95
  sprintf(
96
+ // Translators: %s: The PayPal payment event.
97
  __( 'Mismatched event type for webhook event: %s', 'event-tickets' ),
98
  json_encode( $event )
99
  ),
103
  return false;
104
  }
105
 
106
+ $payment_id = $this->get_parent_payment_id_from_payment( $event->resource );
107
 
108
+ if ( ! $payment_id ) {
109
  tribe( 'logger' )->log_debug(
110
  sprintf(
111
+ // Translators: %s: The PayPal payment event.
112
  __( 'Missing PayPal payment for webhook event: %s', 'event-tickets' ),
113
  json_encode( $event )
114
  ),
118
  return false;
119
  }
120
 
121
+ $payment = $this->get_order_by_payment_id( $payment_id );
122
 
123
  // If there's no matching payment then it's not tracked by Tickets Commerce.
124
  if ( ! $payment ) {
125
  tribe( 'logger' )->log_debug(
126
  sprintf(
127
+ // Translators: %s: The PayPal payment ID.
128
  __( 'Missing order for PayPal payment from webhook: %s', 'event-tickets' ),
129
+ $payment_id
130
  ),
131
  'tickets-commerce-paypal-commerce'
132
  );
149
 
150
  tribe( 'logger' )->log_debug(
151
  sprintf(
152
+ // Translators: %1$s: The status name; %2$s: The payment information.
153
  __( 'Change %1$s in PayPal from webhook: %2$s', 'event-tickets' ),
154
  $this->new_status,
155
+ sprintf( '[Order ID: %s; PayPal Payment ID: %s]', $payment->ID, $payment_id )
156
  ),
157
  'tickets-commerce-paypal-commerce'
158
  );
163
  * @since 5.1.6
164
  *
165
  * @param WP_Post $payment The payment object.
166
+ * @param string $payment_id The PayPal payment ID.
167
  * @param object $event The PayPal webhook event.
168
  * @param string $new_status The new order status.
169
  */
170
+ do_action( 'tribe_tickets_commerce_gateways_paypal_commerce_webhooks_listeners', $payment, $payment_id, $event, $this->new_status );
171
 
172
  /**
173
  * Allow hooking into the listener status for the new status.
174
  *
175
  * @since 5.1.6
176
  *
177
+ * @param WP_Post $payment The payment object.
178
+ * @param string $payment_id The PayPal payment ID.
179
+ * @param object $event The PayPal webhook event.
180
  */
181
+ do_action( "tribe_tickets_commerce_gateways_paypal_commerce_webhooks_listeners_{$this->new_status}", $payment, $payment_id, $event );
182
 
183
  return true;
184
  }
192
  *
193
  * @return \WP_Post|null The matching order or null if not found.
194
  */
195
+ public function get_order_by_payment_id( $id ) {
196
  $orm = tribe_tickets_orders( 'tribe-commerce' );
197
 
198
  return $orm->by( 'id', $id )->first();
207
  *
208
  * @return string|false The parent payment ID or false if not found.
209
  */
210
+ private function get_parent_payment_id_from_payment( $payment ) {
211
  $link = current( array_filter( $payment->links, static function ( $link ) {
212
  return $link->rel === 'up';
213
  } ) );
216
  return false;
217
  }
218
 
 
 
219
  $request = wp_remote_request( $link->href, [
220
  'method' => $link->method,
221
  'headers' => [
222
  'Content-Type' => 'application/json',
223
+ 'Authorization' => "Bearer {$this->merchant->get_access_token()}",
224
  ],
225
  ] );
226
 
227
  if ( is_wp_error( $request ) ) {
228
  tribe( 'logger' )->log_error( sprintf(
229
+ // Translators: %s: The error message.
230
  __( 'PayPal capture request error: %s', 'event-tickets' ),
231
  $request->get_error_message()
232
  ), 'tickets-commerce-paypal-commerce' );
src/Tickets/Commerce/Gateways/PayPal/Webhooks/WebhookChecker.php DELETED
@@ -1,104 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks;
4
-
5
- use Exception;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models\MerchantDetail;
7
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\Webhooks;
8
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\WebhooksRoute;
9
-
10
- class WebhookChecker {
11
-
12
- /**
13
- * @since 5.1.6
14
- *
15
- * @var Webhooks
16
- */
17
- private $webhooksRepository;
18
-
19
- /**
20
- * @since 5.1.6
21
- *
22
- * @var WebhooksRoute
23
- */
24
- private $webhooksRoute;
25
-
26
- /**
27
- * @since 5.1.6
28
- *
29
- * @var WebhookRegister
30
- */
31
- private $webhookRegister;
32
-
33
- /**
34
- * @since 5.1.6
35
- *
36
- * @var MerchantDetail
37
- */
38
- private $merchantDetails;
39
-
40
- /**
41
- * WebhookChecker constructor.
42
- *
43
- * @since 5.1.6
44
- *
45
- * @param Webhooks $webhooksRepository
46
- * @param MerchantDetail $merchantDetails
47
- * @param WebhooksRoute $webhooksRoute
48
- * @param WebhookRegister $webhookRegister
49
- */
50
- public function __construct( Webhooks $webhooksRepository, MerchantDetail $merchantDetails, WebhooksRoute $webhooksRoute, WebhookRegister $webhookRegister ) {
51
- $this->webhooksRepository = $webhooksRepository;
52
- $this->merchantDetails = $merchantDetails;
53
- $this->webhooksRoute = $webhooksRoute;
54
- $this->webhookRegister = $webhookRegister;
55
- }
56
-
57
- /**
58
- * Checks whether the webhook configuration has changed. If it has, then update the webhook with PayPal.
59
- *
60
- * @since 5.1.6
61
- */
62
- public function checkWebhookCriteria() {
63
- if ( wp_doing_ajax() || wp_doing_cron() ) {
64
- return;
65
- }
66
-
67
- if ( ! $this->merchantDetails->accessToken ) {
68
- return;
69
- }
70
-
71
- $webhookConfig = $this->webhooksRepository->getWebhookConfig();
72
-
73
- if ( $webhookConfig === null ) {
74
- return;
75
- }
76
-
77
- $webhookUrl = $this->webhooksRoute->getRouteUrl();
78
- $registeredEvents = $this->webhookRegister->getRegisteredEvents();
79
-
80
- $missingEvents = array_merge(
81
- array_diff( $registeredEvents, $webhookConfig->events ),
82
- array_diff( $webhookConfig->events, $registeredEvents )
83
- );
84
- $hasMissingEvents = ! empty( $missingEvents );
85
-
86
- // Update the webhook if the return url or events have changed
87
- if ( $webhookUrl !== $webhookConfig->returnUrl || $hasMissingEvents ) {
88
- try {
89
- $this->webhooksRepository->updateWebhook( $this->merchantDetails->accessToken, $webhookConfig->id );
90
-
91
- $webhookConfig->returnUrl = $webhookUrl;
92
- $webhookConfig->events = $registeredEvents;
93
-
94
- $this->webhooksRepository->saveWebhookConfig( $webhookConfig );
95
- } catch ( Exception $exception ) {
96
- // @todo Replace this with a notice / log.
97
- tribe( 'logger' )->log_error(
98
- __( 'There was a problem updating your PayPal Payments webhook. Please disconnect your account and reconnect it.', 'event-tickets' ),
99
- 'tickets-commerce-paypal-commerce'
100
- );
101
- }
102
- }
103
- }
104
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Gateways/PayPal/Webhooks/Webhook_Checker.php ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks;
4
+
5
+ use Exception;
6
+ use TEC\Tickets\Commerce\Gateways\PayPal\Merchant;
7
+ use TEC\Tickets\Commerce\Gateways\PayPal\Repositories\Webhooks;
8
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Webhooks_Route;
9
+
10
+ class Webhook_Checker {
11
+
12
+ /**
13
+ * @since 5.1.6
14
+ *
15
+ * @var Webhooks
16
+ */
17
+ private $webhooks_repository;
18
+
19
+ /**
20
+ * @since 5.1.6
21
+ *
22
+ * @var Webhooks_Route
23
+ */
24
+ private $webhooks_route;
25
+
26
+ /**
27
+ * @since 5.1.6
28
+ *
29
+ * @var Webhook_Register
30
+ */
31
+ private $webhook_register;
32
+
33
+ /**
34
+ * @since 5.1.6
35
+ *
36
+ * @var Merchant
37
+ */
38
+ private $merchant;
39
+
40
+ /**
41
+ * Webhook_Checker constructor.
42
+ *
43
+ * @since 5.1.6
44
+ *
45
+ * @param Webhooks $webhooks_repository
46
+ * @param Merchant $merchant
47
+ * @param Webhooks_Route $webhooks_route
48
+ * @param Webhook_Register $webhook_register
49
+ */
50
+ public function __construct( Webhooks $webhooks_repository, Merchant $merchant, Webhooks_Route $webhooks_route, Webhook_Register $webhook_register ) {
51
+ $this->webhooks_repository = $webhooks_repository;
52
+ $this->merchant = $merchant;
53
+ $this->webhooks_route = $webhooks_route;
54
+ $this->webhook_register = $webhook_register;
55
+ }
56
+
57
+ /**
58
+ * Checks whether the webhook configuration has changed. If it has, then update the webhook with PayPal.
59
+ *
60
+ * @since 5.1.6
61
+ */
62
+ public function check_webhook_criteria() {
63
+ if ( wp_doing_ajax() || wp_doing_cron() ) {
64
+ return;
65
+ }
66
+
67
+ if ( ! $this->merchant->get_access_token() ) {
68
+ return;
69
+ }
70
+
71
+ $webhook_config = $this->webhooks_repository->get_webhook_config();
72
+
73
+ if ( $webhook_config === null ) {
74
+ return;
75
+ }
76
+
77
+ $webhook_url = $this->webhooks_route->get_route_url();
78
+ $registered_events = $this->webhook_register->get_registered_events();
79
+
80
+ $missing_events = array_merge(
81
+ array_diff( $registered_events, $webhook_config->events ),
82
+ array_diff( $webhook_config->events, $registered_events )
83
+ );
84
+ $has_missing_events = ! empty( $missing_events );
85
+
86
+ // Update the webhook if the return url or events have changed
87
+ if ( $webhook_url !== $webhook_config->return_url || $has_missing_events ) {
88
+ try {
89
+ $this->webhooks_repository->update_webhook( $this->merchant->get_access_token(), $webhook_config->id );
90
+
91
+ $webhook_config->return_url = $webhook_url;
92
+ $webhook_config->events = $registered_events;
93
+
94
+ $this->webhooks_repository->save_webhook_config( $webhook_config );
95
+ } catch ( Exception $exception ) {
96
+ // @todo Replace this with a notice / log.
97
+ tribe( 'logger' )->log_error(
98
+ __( 'There was a problem updating your PayPal Payments webhook. Please disconnect your account and reconnect it.', 'event-tickets' ),
99
+ 'tickets-commerce-paypal-commerce'
100
+ );
101
+ }
102
+ }
103
+ }
104
+ }
src/Tickets/Commerce/Gateways/PayPal/Webhooks/{WebhookRegister.php → Webhook_Register.php} RENAMED
@@ -3,13 +3,13 @@
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks;
4
 
5
  use InvalidArgumentException;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\EventListener;
7
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\PaymentCaptureCompleted;
8
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\PaymentCaptureDenied;
9
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\PaymentCaptureRefunded;
10
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\PaymentCaptureReversed;
11
 
12
- class WebhookRegister {
13
 
14
  /**
15
  * Array of the PayPal webhook event handlers. Add-ons can use the registerEventHandler method
@@ -21,11 +21,11 @@ class WebhookRegister {
21
  *
22
  * @var string[]
23
  */
24
- private $eventHandlers = [
25
- 'PAYMENT.CAPTURE.COMPLETED' => PaymentCaptureCompleted::class,
26
- 'PAYMENT.CAPTURE.DENIED' => PaymentCaptureDenied::class,
27
- 'PAYMENT.CAPTURE.REFUNDED' => PaymentCaptureRefunded::class,
28
- 'PAYMENT.CAPTURE.REVERSED' => PaymentCaptureReversed::class,
29
  ];
30
 
31
  /**
@@ -33,21 +33,21 @@ class WebhookRegister {
33
  *
34
  * @since 5.1.6
35
  *
36
- * @param string $payPalEvent PayPal event to listen for, i.e. CHECKOUT.ORDER.APPROVED
37
- * @param string $eventHandler The FQCN of the event handler
38
  *
39
  * @return $this
40
  */
41
- public function registerEventHandler( $payPalEvent, $eventHandler ) {
42
- if ( isset( $this->eventHandlers[ $payPalEvent ] ) ) {
43
  throw new InvalidArgumentException( 'Cannot register an already registered event' );
44
  }
45
 
46
- if ( ! is_subclass_of( $eventHandler, EventListener::class ) ) {
47
- throw new InvalidArgumentException( 'Listener must be a subclass of ' . EventListener::class );
48
  }
49
 
50
- $this->eventHandlers[ $payPalEvent ] = $eventHandler;
51
 
52
  return $this;
53
  }
@@ -59,9 +59,9 @@ class WebhookRegister {
59
  *
60
  * @param array $handlers = [ 'PAYPAL.EVENT' => EventHandler::class ]
61
  */
62
- public function registerEventHandlers( array $handlers ) {
63
  foreach ( $handlers as $event => $handler ) {
64
- $this->registerEventHandler( $event, $handler );
65
  }
66
  }
67
 
@@ -72,10 +72,10 @@ class WebhookRegister {
72
  *
73
  * @param string $event
74
  *
75
- * @return EventListener
76
  */
77
- public function getEventHandler( $event ) {
78
- return tribe( $this->eventHandlers[ $event ] );
79
  }
80
 
81
  /**
@@ -87,8 +87,8 @@ class WebhookRegister {
87
  *
88
  * @return bool
89
  */
90
- public function hasEventRegistered( $event ) {
91
- return isset( $this->eventHandlers[ $event ] );
92
  }
93
 
94
  /**
@@ -98,7 +98,7 @@ class WebhookRegister {
98
  *
99
  * @return string[]
100
  */
101
- public function getRegisteredEvents() {
102
- return array_keys( $this->eventHandlers );
103
  }
104
  }
3
  namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks;
4
 
5
  use InvalidArgumentException;
6
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\Event_Listener;
7
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\Payment_Capture_Completed;
8
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\Payment_Capture_Denied;
9
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\Payment_Capture_Refunded;
10
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Listeners\Payment_Capture_Reversed;
11
 
12
+ class Webhook_Register {
13
 
14
  /**
15
  * Array of the PayPal webhook event handlers. Add-ons can use the registerEventHandler method
21
  *
22
  * @var string[]
23
  */
24
+ private $event_handlers = [
25
+ 'PAYMENT.CAPTURE.COMPLETED' => Payment_Capture_Completed::class,
26
+ 'PAYMENT.CAPTURE.DENIED' => Payment_Capture_Denied::class,
27
+ 'PAYMENT.CAPTURE.REFUNDED' => Payment_Capture_Refunded::class,
28
+ 'PAYMENT.CAPTURE.REVERSED' => Payment_Capture_Reversed::class,
29
  ];
30
 
31
  /**
33
  *
34
  * @since 5.1.6
35
  *
36
+ * @param string $paypal_event PayPal event to listen for, i.e. CHECKOUT.ORDER.APPROVED
37
+ * @param string $event_handler The FQCN of the event handler
38
  *
39
  * @return $this
40
  */
41
+ public function register_event_handler( $paypal_event, $event_handler ) {
42
+ if ( isset( $this->event_handlers[ $paypal_event ] ) ) {
43
  throw new InvalidArgumentException( 'Cannot register an already registered event' );
44
  }
45
 
46
+ if ( ! is_subclass_of( $event_handler, Event_Listener::class ) ) {
47
+ throw new InvalidArgumentException( 'Listener must be a subclass of ' . Event_Listener::class );
48
  }
49
 
50
+ $this->event_handlers[ $paypal_event ] = $event_handler;
51
 
52
  return $this;
53
  }
59
  *
60
  * @param array $handlers = [ 'PAYPAL.EVENT' => EventHandler::class ]
61
  */
62
+ public function register_event_handlers( array $handlers ) {
63
  foreach ( $handlers as $event => $handler ) {
64
+ $this->register_event_handler( $event, $handler );
65
  }
66
  }
67
 
72
  *
73
  * @param string $event
74
  *
75
+ * @return Event_Listener
76
  */
77
+ public function get_event_handler( $event ) {
78
+ return tribe( $this->event_handlers[ $event ] );
79
  }
80
 
81
  /**
87
  *
88
  * @return bool
89
  */
90
+ public function has_event_registered( $event ) {
91
+ return isset( $this->event_handlers[ $event ] );
92
  }
93
 
94
  /**
98
  *
99
  * @return string[]
100
  */
101
+ public function get_registered_events() {
102
+ return array_keys( $this->event_handlers );
103
  }
104
  }
src/Tickets/Commerce/Gateways/PayPal/Webhooks/{WebhooksRoute.php → Webhooks_Route.php} RENAMED
@@ -4,47 +4,46 @@ namespace TEC\Tickets\Commerce\Gateways\PayPal\Webhooks;
4
 
5
  use Exception;
6
  use TEC\Tickets\Commerce\Gateways\PayPal\REST;
7
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\MerchantDetails;
8
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\Webhooks;
9
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\DataTransferObjects\PayPalWebhookHeaders;
10
- use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\WebhookRegister;
11
- use Tribe\Tickets\REST\V1\Endpoints\Commerce\PayPal_Webhook;
12
 
13
- class WebhooksRoute {
14
  /**
15
  * @since 5.1.6
16
  *
17
- * @var MerchantDetails
18
  */
19
- private $merchantRepository;
20
 
21
  /**
22
  * @since 5.1.6
23
  *
24
  * @var Webhooks
25
  */
26
- private $webhookRepository;
27
 
28
  /**
29
  * @since 5.1.6
30
  *
31
- * @var WebhookRegister
32
  */
33
- private $webhookRegister;
34
 
35
  /**
36
- * WebhooksRoute constructor.
37
  *
38
  * @since 5.1.6
39
  *
40
- * @param MerchantDetails $merchantRepository
41
- * @param WebhookRegister $register
42
- * @param Webhooks $webhookRepository
43
  */
44
- public function __construct( MerchantDetails $merchantRepository, WebhookRegister $register, Webhooks $webhookRepository ) {
45
- $this->merchantRepository = $merchantRepository;
46
- $this->webhookRegister = $register;
47
- $this->webhookRepository = $webhookRepository;
48
  }
49
 
50
  /**
@@ -54,14 +53,12 @@ class WebhooksRoute {
54
  *
55
  * @return string The REST API route URL.
56
  */
57
- public function getRouteUrl() {
58
  /** @var REST $rest */
59
- $rest = tribe( REST::class );
 
60
 
61
- /** @var Webhook $endpoint */
62
- $endpoint = tribe( PayPal_Webhook::class );
63
-
64
- return rest_url( '/' . $rest->namespace . $endpoint->path, 'https' );
65
  }
66
 
67
  /**
@@ -70,20 +67,20 @@ class WebhooksRoute {
70
  *
71
  * @since 5.1.6
72
  *
73
- * @param string|object $event The PayPal payment event object.
 
74
  * @param array $headers The list of HTTP headers for the request.
75
  *
 
 
76
  * @return bool Whether the event was processed.
77
  *
78
- * @throws Exception
79
  */
80
  public function handle( $event, $headers = [] ) {
81
- if ( ! $this->merchantRepository->accountIsConnected() ) {
82
  return false;
83
  }
84
 
85
- $merchantDetails = $this->merchantRepository->getDetails();
86
-
87
  // Try to decode the event.
88
  if ( ! is_object( $event ) ) {
89
  $event = @json_decode( $event );
@@ -95,10 +92,10 @@ class WebhooksRoute {
95
  }
96
 
97
  // If we receive an event that we're not expecting, just ignore it
98
- if ( ! $this->webhookRegister->hasEventRegistered( $event->event_type ) ) {
99
  tribe( 'logger' )->log_debug(
100
  sprintf(
101
- // Translators: %s: The event type.
102
  __( 'PayPal webhook event type not registered or supported: %s', 'event-tickets' ),
103
  $event->event_type
104
  ),
@@ -110,32 +107,32 @@ class WebhooksRoute {
110
 
111
  tribe( 'logger' )->log_debug(
112
  sprintf(
113
- // Translators: %s: The event type.
114
  __( 'Received PayPal webhook event for type: %s', 'event-tickets' ),
115
  $event->event_type
116
  ),
117
  'tickets-commerce-paypal-commerce'
118
  );
119
 
120
- $payPalHeaders = PayPalWebhookHeaders::fromHeaders( $headers );
121
 
122
- if ( ! $this->webhookRepository->verifyEventSignature( $merchantDetails->accessToken, $event, $payPalHeaders ) ) {
123
  tribe( 'logger' )->log_error( __( 'Failed PayPal webhook event verification', 'event-tickets' ), 'tickets-commerce-paypal-commerce' );
124
 
125
  throw new Exception( 'Failed event verification' );
126
  }
127
 
128
  try {
129
- return $this->webhookRegister
130
- ->getEventHandler( $event->event_type )
131
- ->processEvent( $event );
132
  } catch ( Exception $exception ) {
133
- $eventType = empty( $event->event_type ) ? 'Unknown' : $event->event_type;
134
 
135
  tribe( 'logger' )->log_error( sprintf(
136
- // Translators: %s: The event type.
137
  __( 'Error processing webhook: %s', 'event-tickets' ),
138
- $eventType
139
  ), 'tickets-commerce-paypal-commerce' );
140
 
141
  throw $exception;
4
 
5
  use Exception;
6
  use TEC\Tickets\Commerce\Gateways\PayPal\REST;
7
+ use TEC\Tickets\Commerce\Gateways\PayPal\Merchant;
8
+ use TEC\Tickets\Commerce\Gateways\PayPal\Repositories\Webhooks;
9
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Headers;
10
+ use TEC\Tickets\Commerce\Gateways\PayPal\Webhooks\Webhook_Register;
 
11
 
12
+ class Webhooks_Route {
13
  /**
14
  * @since 5.1.6
15
  *
16
+ * @var Merchant
17
  */
18
+ private $merchant;
19
 
20
  /**
21
  * @since 5.1.6
22
  *
23
  * @var Webhooks
24
  */
25
+ private $webhook_repository;
26
 
27
  /**
28
  * @since 5.1.6
29
  *
30
+ * @var Webhook_Register
31
  */
32
+ private $webhook_register;
33
 
34
  /**
35
+ * Webhooks_Route constructor.
36
  *
37
  * @since 5.1.6
38
  *
39
+ * @param Merchant $merchant
40
+ * @param Webhook_Register $register
41
+ * @param Webhooks $webhook_repository
42
  */
43
+ public function __construct( Merchant $merchant, Webhook_Register $register, Webhooks $webhook_repository ) {
44
+ $this->merchant = $merchant;
45
+ $this->webhook_register = $register;
46
+ $this->webhook_repository = $webhook_repository;
47
  }
48
 
49
  /**
53
  *
54
  * @return string The REST API route URL.
55
  */
56
+ public function get_route_url() {
57
  /** @var REST $rest */
58
+ $rest = tribe( REST::class );
59
+ $endpoint = tribe( REST\Webhook::class );
60
 
61
+ return rest_url( '/' . $rest->namespace . $endpoint->get_endpoint_path(), 'https' );
 
 
 
62
  }
63
 
64
  /**
67
  *
68
  * @since 5.1.6
69
  *
70
+ * @throws Exception
71
+ *
72
  * @param array $headers The list of HTTP headers for the request.
73
  *
74
+ * @param string|object $event The PayPal payment event object.
75
+ *
76
  * @return bool Whether the event was processed.
77
  *
 
78
  */
79
  public function handle( $event, $headers = [] ) {
80
+ if ( ! $this->merchant->account_is_connected() ) {
81
  return false;
82
  }
83
 
 
 
84
  // Try to decode the event.
85
  if ( ! is_object( $event ) ) {
86
  $event = @json_decode( $event );
92
  }
93
 
94
  // If we receive an event that we're not expecting, just ignore it
95
+ if ( ! $this->webhook_register->has_event_registered( $event->event_type ) ) {
96
  tribe( 'logger' )->log_debug(
97
  sprintf(
98
+ // Translators: %s: The event type.
99
  __( 'PayPal webhook event type not registered or supported: %s', 'event-tickets' ),
100
  $event->event_type
101
  ),
107
 
108
  tribe( 'logger' )->log_debug(
109
  sprintf(
110
+ // Translators: %s: The event type.
111
  __( 'Received PayPal webhook event for type: %s', 'event-tickets' ),
112
  $event->event_type
113
  ),
114
  'tickets-commerce-paypal-commerce'
115
  );
116
 
117
+ $paypal_headers = Headers::from_headers( $headers );
118
 
119
+ if ( ! $this->webhook_repository->verify_event_signature( $this->merchant->get_access_token(), $event, $paypal_headers ) ) {
120
  tribe( 'logger' )->log_error( __( 'Failed PayPal webhook event verification', 'event-tickets' ), 'tickets-commerce-paypal-commerce' );
121
 
122
  throw new Exception( 'Failed event verification' );
123
  }
124
 
125
  try {
126
+ return $this->webhook_register
127
+ ->get_event_handler( $event->event_type )
128
+ ->process_event( $event );
129
  } catch ( Exception $exception ) {
130
+ $event_type = empty( $event->event_type ) ? 'Unknown' : $event->event_type;
131
 
132
  tribe( 'logger' )->log_error( sprintf(
133
+ // Translators: %s: The event type.
134
  __( 'Error processing webhook: %s', 'event-tickets' ),
135
+ $event_type
136
  ), 'tickets-commerce-paypal-commerce' );
137
 
138
  throw $exception;
src/Tickets/Commerce/Gateways/PayPal/WhoDat.php ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
+
5
+ use TEC\Tickets\Commerce\Gateways\PayPal\REST\On_Boarding_Endpoint;
6
+ use Tribe__Utils__Array as Arr;
7
+
8
+ /**
9
+ * Class Connect_Client
10
+ *
11
+ * @since 5.1.6
12
+ *
13
+ * @package TEC\Tickets\Commerce\Gateways\PayPal
14
+ */
15
+ class WhoDat {
16
+ /**
17
+ * The API URL.
18
+ *
19
+ * @since 5.1.6
20
+ *
21
+ * @var string
22
+ */
23
+ protected $api_url = 'https://whodat.theeventscalendar.com/commerce/v1/paypal';
24
+
25
+ /**
26
+ * Get REST API endpoint URL for requests.
27
+ *
28
+ * @since 5.1.9
29
+ *
30
+ *
31
+ * @param string $endpoint The endpoint path.
32
+ * @param array $query_args Query args appended to the URL.
33
+ *
34
+ * @return string The API URL.
35
+ */
36
+ public function get_api_url( $endpoint, array $query_args = [] ) {
37
+ return add_query_arg( $query_args, "{$this->api_url}/{$endpoint}" );
38
+ }
39
+
40
+ /**
41
+ * Fetch the signup link from PayPal.
42
+ *
43
+ * @since 5.1.9
44
+ *
45
+ * @return array|string
46
+ */
47
+ public function get_seller_signup_data( $hash ) {
48
+ if ( empty( $hash ) ) {
49
+ $hash = tribe( Signup::class )->generate_unique_signup_hash();
50
+ }
51
+
52
+ $return_url = tribe( On_Boarding_Endpoint::class )->get_return_url( $hash );
53
+ $query_args = [
54
+ 'mode' => tribe( Merchant::class )->get_mode(),
55
+ 'nonce' => $hash,
56
+ 'tracking_id' => urlencode( tribe( Signup::class )->generate_unique_tracking_id() ),
57
+ 'return_url' => esc_url( $return_url ),
58
+ ];
59
+
60
+ return $this->get( 'seller/signup', $query_args );
61
+ }
62
+
63
+ /**
64
+ * Fetch the seller referral Data from WhoDat/PayPal.
65
+ *
66
+ * @since 5.1.9
67
+ *
68
+ * @param string $url Which URL WhoDat needs to request.
69
+ *
70
+ * @return array
71
+ */
72
+ public function get_seller_referral_data( $url ) {
73
+ $query_args = [
74
+ 'mode' => tribe( Merchant::class )->get_mode(),
75
+ 'url' => $url
76
+ ];
77
+
78
+ return $this->get( 'seller/referral-data', $query_args );
79
+ }
80
+
81
+ /**
82
+ * Verify if the seller was successfully onboarded.
83
+ *
84
+ * @since 5.1.9
85
+ *
86
+ * @param string $saved_merchant_id The ID we are looking at Paypal with.
87
+ *
88
+ * @return array
89
+ */
90
+ public function get_seller_status( $saved_merchant_id ) {
91
+ $query_args = [
92
+ 'mode' => tribe( Merchant::class )->get_mode(),
93
+ 'merchant_id' => $saved_merchant_id
94
+ ];
95
+
96
+ return $this->post( 'seller/status', $query_args );
97
+ }
98
+
99
+ /**
100
+ * Get seller rest API credentials
101
+ *
102
+ * @since 5.1.9
103
+ *
104
+ * @param string $access_token
105
+ *
106
+ * @return array|null
107
+ */
108
+ public function get_seller_credentials( $access_token ) {
109
+ $query_args = [
110
+ 'mode' => tribe( Merchant::class )->get_mode(),
111
+ 'access_token' => $access_token,
112
+ ];
113
+
114
+ return $this->post( 'seller/credentials', $query_args );
115
+ }
116
+
117
+ /**
118
+ * Send a GET request to WhoDat.
119
+ *
120
+ * @since 5.1.9
121
+ *
122
+ * @param string $endpoint
123
+ * @param array $query_args
124
+ *
125
+ * @return mixed|null
126
+ */
127
+ public function get( $endpoint, array $query_args ) {
128
+ $url = $this->get_api_url( $endpoint, $query_args );
129
+
130
+ $request = wp_remote_get( $url );
131
+
132
+ if ( is_wp_error( $request ) ) {
133
+ $this->log_error( 'WhoDat request error:', $request->get_error_message(), $url );
134
+
135
+ return null;
136
+ }
137
+
138
+ $body = wp_remote_retrieve_body( $request );
139
+ $body = json_decode( $body, true );
140
+
141
+ return $body;
142
+ }
143
+
144
+ /**
145
+ * Send a POST request to WhoDat.
146
+ *
147
+ * @since 5.1.9
148
+ *
149
+ * @param string $endpoint
150
+ * @param array $query_args
151
+ * @param array $request_arguments
152
+ *
153
+ * @return array|null
154
+ */
155
+ public function post( $endpoint, array $query_args = [], array $request_arguments = [] ) {
156
+ $url = $this->get_api_url( $endpoint, $query_args );
157
+
158
+ $default_arguments = [
159
+ 'body' => [],
160
+ ];
161
+ $request_arguments = array_merge_recursive( $default_arguments, $request_arguments );
162
+ $request = wp_remote_post( $url, $request_arguments );
163
+
164
+ if ( is_wp_error( $request ) ) {
165
+ $this->log_error( 'WhoDat request error:', $request->get_error_message(), $url );
166
+
167
+ return null;
168
+ }
169
+
170
+ $body = wp_remote_retrieve_body( $request );
171
+ $body = json_decode( $body, true );
172
+
173
+ if ( ! is_array( $body ) ) {
174
+ $this->log_error( 'WhoDat unexpected response:', $body, $url );
175
+
176
+ return null;
177
+ }
178
+
179
+ return $body;
180
+ }
181
+
182
+ /**
183
+ * Log WhoDat errors.
184
+ *
185
+ * @since 5.1.9
186
+ *
187
+ * @param string $type
188
+ * @param string $message
189
+ * @param string $url
190
+ */
191
+ protected function log_error( $type, $message, $url ) {
192
+ $log = sprintf(
193
+ '[%s] %s %s',
194
+ $url,
195
+ $type,
196
+ $message
197
+ );
198
+ tribe( 'logger' )->log_error( $log, 'whodat-connection' );
199
+ }
200
+ }
src/Tickets/Commerce/Gateways/PayPal/onBoardingRedirectHandler.php DELETED
@@ -1,487 +0,0 @@
1
- <?php
2
-
3
- namespace TEC\Tickets\Commerce\Gateways\PayPal;
4
-
5
- use Exception;
6
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Models\MerchantDetail;
7
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\PayPalAuth;
8
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\MerchantDetails;
9
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\Webhooks;
10
- use Tribe__Settings;
11
-
12
- /**
13
- * Class PayPalOnBoardingRedirectHandler
14
- *
15
- * @since 5.1.6
16
- * @package TEC\Tickets\Commerce\Gateways\PayPal
17
- *
18
- */
19
- class onBoardingRedirectHandler {
20
-
21
- /**
22
- * @since 5.1.6
23
- *
24
- * @var PayPalAuth
25
- */
26
- private $payPalAuth;
27
-
28
- /**
29
- * @since 5.1.6
30
- *
31
- * @var Webhooks
32
- */
33
- private $webhooksRepository;
34
-
35
- /**
36
- * @since 5.1.6
37
- *
38
- * @var MerchantDetails
39
- */
40
- private $merchantRepository;
41
-
42
- /**
43
- * @since 5.1.6
44
- *
45
- * @var Settings
46
- */
47
- private $settings;
48
-
49
- /**
50
- * onBoardingRedirectHandler constructor.
51
- *
52
- * @since 5.1.6
53
- *
54
- * @param Webhooks $webhooks
55
- * @param MerchantDetails $merchantRepository
56
- * @param Settings $settings
57
- * @param PayPalAuth $payPalAuth
58
- */
59
- public function __construct( Webhooks $webhooks, MerchantDetails $merchantRepository, Settings $settings, PayPalAuth $payPalAuth ) {
60
- $this->webhooksRepository = $webhooks;
61
- $this->merchantRepository = $merchantRepository;
62
- $this->settings = $settings;
63
- $this->payPalAuth = $payPalAuth;
64
- }
65
-
66
- /**
67
- * Bootstrap class
68
- *
69
- * @since 5.1.6
70
- */
71
- public function boot() {
72
- if ( $this->isPayPalUserRedirected() ) {
73
- $merchantId = tribe_get_request_var( 'merchantId' );
74
- $merchantIdInPayPal = tribe_get_request_var( 'merchantIdInPayPal' );
75
-
76
- $details = $this->savePayPalMerchantDetails( $merchantId, $merchantIdInPayPal );
77
-
78
- $this->setUpWebhook( $details );
79
- $this->redirectAccountConnected();
80
-
81
- return;
82
- }
83
-
84
- if ( $this->werePayPalAccountDetailsSaved() ) {
85
- $this->registerPayPalSSLNotice();
86
- $this->registerPayPalAccountConnectedNotice();
87
- }
88
-
89
- if ( $this->isStatusRefresh() ) {
90
- $this->refreshAccountStatus();
91
- $this->redirectAccountConnected();
92
-
93
- return;
94
- }
95
- }
96
-
97
- /**
98
- * Save PayPal merchant details
99
- *
100
- * @since 5.1.6
101
- *
102
- * @param string $merchantId The merchant ID.
103
- * @param string $merchantIdInPayPal The merchant ID in PayPal.
104
- *
105
- * @return MerchantDetail
106
- */
107
- private function savePayPalMerchantDetails( $merchantId, $merchantIdInPayPal ) {
108
- $partnerLinkInfo = $this->settings->get_partner_link_details();
109
- $tokenInfo = $this->settings->get_access_token();
110
-
111
- $payPalAccount = [
112
- 'merchantId' => $merchantId,
113
- 'merchantIdInPayPal' => $merchantIdInPayPal,
114
- ];
115
-
116
- $errors = [];
117
-
118
- if ( empty( $payPalAccount['merchantIdInPayPal'] ) ) {
119
- $errors[] = [
120
- 'type' => 'url',
121
- 'message' => esc_html__( 'There was a problem with PayPal return url and we could not find valid merchant ID. Paypal return URL is:', 'event-tickets' ) . "\n",
122
- 'value' => urlencode( $_SERVER['QUERY_STRING'] ),
123
- ];
124
-
125
- // Log error messages.
126
- array_map( static function( $errorMessage ) {
127
- $errorMessage = is_array( $errorMessage ) ? $errorMessage['message'] . ' ' . $errorMessage['value'] : $errorMessage;
128
- tribe( 'logger' )->log_error( $errorMessage, 'tickets-commerce-paypal-commerce' );
129
- }, $errors );
130
-
131
- $this->merchantRepository->saveAccountErrors( $errors );
132
-
133
- $this->redirectWhenOnBoardingFail();
134
- }
135
-
136
- $restApiCredentials = (array) $this->payPalAuth->getSellerRestAPICredentials( $tokenInfo ? $tokenInfo['access_token'] : '' );
137
-
138
- $this->didWeGetValidSellerRestApiCredentials( $restApiCredentials );
139
-
140
- $tokenInfo = $this->payPalAuth->getTokenFromClientCredentials( $restApiCredentials['client_id'], $restApiCredentials['client_secret'] );
141
- //$this->settings->update_access_token( $tokenInfo );
142
-
143
- $payPalAccount['clientId'] = $restApiCredentials['client_id'];
144
- $payPalAccount['clientSecret'] = $restApiCredentials['client_secret'];
145
- $payPalAccount['token'] = $tokenInfo;
146
- $payPalAccount['supportsCustomPayments'] = 'PPCP' === $partnerLinkInfo['product'];
147
- $payPalAccount['accountIsReady'] = true;
148
- $payPalAccount['accountCountry'] = $this->settings->get_account_country();
149
-
150
- $merchantDetails = MerchantDetail::fromArray( $payPalAccount );
151
- $this->merchantRepository->save( $merchantDetails );
152
-
153
- return $merchantDetails;
154
- }
155
-
156
- /**
157
- * Redirects the user to the account connected url
158
- *
159
- * @since 5.1.6
160
- */
161
- private function redirectAccountConnected() {
162
- $this->refreshAccountStatus();
163
-
164
- /** @var Tribe__Settings $settings */
165
- $settings = tribe( 'settings' );
166
-
167
- // Get link to Tickets Tab.
168
- $settings_url = $settings->get_url(
169
- [
170
- 'page' => 'tribe-common',
171
- 'tab' => 'event-tickets',
172
- 'paypal-commerce-account-connected' => '1',
173
- ]
174
- ) . '#tribe-field-tickets-commerce-paypal-commerce';
175
-
176
- wp_redirect( $settings_url );
177
- die();
178
- }
179
-
180
- /**
181
- * Sets up the webhook for the connected account
182
- *
183
- * @since 5.1.6
184
- *
185
- * @param MerchantDetail $merchant_details
186
- */
187
- private function setUpWebhook( MerchantDetail $merchant_details ) {
188
- if ( ! is_ssl() ) {
189
- return;
190
- }
191
-
192
- try {
193
- $webhookConfig = $this->webhooksRepository->createWebhook( $merchant_details->accessToken );
194
-
195
- $this->webhooksRepository->saveWebhookConfig( $webhookConfig );
196
- } catch ( Exception $ex ) {
197
- tribe( 'logger' )->log_error( $ex->getMessage(), 'tickets-commerce-paypal-commerce' );
198
-
199
- $errors = [];
200
-
201
- $errors[] = esc_html__( 'There was a problem with creating webhook on PayPal. A gateway error log also added to get details information about PayPal response.', 'event-tickets' );
202
-
203
- // Log error messages.
204
- array_map( static function( $errorMessage ) {
205
- $errorMessage = is_array( $errorMessage ) ? $errorMessage['message'] . ' ' . $errorMessage['value'] : $errorMessage;
206
- tribe( 'logger' )->log_error( $errorMessage, 'tickets-commerce-paypal-commerce' );
207
- }, $errors );
208
-
209
- $this->merchantRepository->saveAccountErrors( $errors );
210
- $this->redirectWhenOnBoardingFail();
211
- }
212
- }
213
-
214
- /**
215
- * Register notice if account connect success fully.
216
- *
217
- * @since 5.1.6
218
- */
219
- private function registerPayPalAccountConnectedNotice() {
220
- tribe_notice(
221
- 'paypal-commerce-account-connected',
222
- sprintf(
223
- '<p>%s</p>',
224
- esc_html__( 'PayPal Commerce account connected successfully.', 'event-tickets' )
225
- ),
226
- [
227
- 'type' => 'success',
228
- ]
229
- );
230
- }
231
-
232
- /**
233
- * Check whether we are on the settings page.
234
- *
235
- * @since 5.1.6
236
- *
237
- * @return bool Whether we are on the settings page.
238
- */
239
- private function isSettingsPage() {
240
- $page = tribe_get_request_var( 'page' );
241
- $tab = tribe_get_request_var( 'tab' );
242
-
243
- return 'tribe-common' === $page && 'event-tickets' === $tab;
244
- }
245
-
246
- /**
247
- * Returns whether or not the current request is for refreshing the account status
248
- *
249
- * @since 5.1.6
250
- *
251
- * @return bool
252
- */
253
- private function isStatusRefresh() {
254
- return isset( $_GET['paypalStatusCheck'] ) && $this->isSettingsPage();
255
- }
256
-
257
- /**
258
- * Return whether or not PayPal user redirect to setting page after successful onboarding.
259
- *
260
- * @since 5.1.6
261
- *
262
- * @return bool
263
- */
264
- private function isPayPalUserRedirected() {
265
- return isset( $_GET['merchantIdInPayPal'] ) && $this->isSettingsPage();
266
- }
267
-
268
- /**
269
- * Return whether or not PayPal account details were saved.
270
- *
271
- * @since 5.1.6
272
- *
273
- * @return bool
274
- */
275
- private function werePayPalAccountDetailsSaved() {
276
- return isset( $_GET['paypal-commerce-account-connected'] ) && $this->isSettingsPage();
277
- }
278
-
279
- /**
280
- * validate rest api credential.
281
- *
282
- * @since 5.1.6
283
- *
284
- * @param array $array
285
- *
286
- */
287
- private function didWeGetValidSellerRestApiCredentials( $array ) {
288
- $required = [ 'client_id', 'client_secret' ];
289
- $array = array_filter( $array ); // Remove empty values.
290
-
291
- $errors = [];
292
-
293
- if ( array_diff( $required, array_keys( $array ) ) ) {
294
- $errors[] = [
295
- 'type' => 'json',
296
- 'message' => esc_html__( 'PayPal client access token API request response is:', 'event-tickets' ),
297
- 'value' => wp_json_encode( $this->settings->get_access_token() ),
298
- ];
299
-
300
- $errors[] = [
301
- 'type' => 'json',
302
- 'message' => esc_html__( 'PayPal client rest api credentials API request response is:', 'event-tickets' ),
303
- 'value' => wp_json_encode( $array ),
304
- ];
305
-
306
- $errors[] = esc_html__( 'There was a problem with PayPal client rest API request and we could not find valid client id and secret.', 'event-tickets' );
307
-
308
- // Log error messages.
309
- array_map( static function( $errorMessage ) {
310
- $errorMessage = is_array( $errorMessage ) ? $errorMessage['message'] . ' ' . $errorMessage['value'] : $errorMessage;
311
- tribe( 'logger' )->log_error( $errorMessage, 'tickets-commerce-paypal-commerce' );
312
- }, $errors );
313
-
314
- $this->merchantRepository->saveAccountErrors( $errors );
315
- $this->redirectWhenOnBoardingFail();
316
- }
317
- }
318
-
319
- /**
320
- * Handles the request for refreshing the account status
321
- *
322
- * @since 5.1.6
323
- */
324
- private function refreshAccountStatus() {
325
- $merchantDetails = $this->merchantRepository->getDetails();
326
-
327
- $statusErrors = $this->isAdminSuccessfullyOnBoarded( $merchantDetails->merchantIdInPayPal, $merchantDetails->accessToken, $merchantDetails->supportsCustomPayments );
328
- if ( $statusErrors !== true ) {
329
- $merchantDetails->accountIsReady = false;
330
- $this->merchantRepository->saveAccountErrors( $statusErrors );
331
- } else {
332
- $merchantDetails->accountIsReady = true;
333
- $this->merchantRepository->deleteAccountErrors();
334
- }
335
-
336
- $this->merchantRepository->save( $merchantDetails );
337
-
338
- $details = $this->savePayPalMerchantDetails( $merchantDetails->merchantId, $merchantDetails->merchantIdInPayPal );
339
-
340
- $this->setUpWebhook( $details );
341
- }
342
-
343
- /**
344
- * Validate seller on Boarding status
345
- *
346
- * @since 5.1.6
347
- *
348
- * @param string $merchantId
349
- * @param string $accessToken
350
- * @param bool $usesCustomPayments
351
- *
352
- * @return true|string[]
353
- */
354
- private function isAdminSuccessfullyOnBoarded( $merchantId, $accessToken, $usesCustomPayments ) {
355
- $onBoardedData = (array) $this->payPalAuth->getSellerOnBoardingDetailsFromPayPal( $merchantId, $accessToken );
356
- $onBoardedData = array_filter( $onBoardedData ); // Remove empty values.
357
- $errorMessages[] = [
358
- 'type' => 'json',
359
- 'message' => esc_html__( 'PayPal merchant status check API request response is:', 'event-tickets' ),
360
- 'value' => wp_json_encode( $onBoardedData ),
361
- ];
362
-
363
- if ( ! is_ssl() ) {
364
- $errorMessages[] = esc_html__( 'A valid SSL certificate is required to accept payments and set up your PayPal account. Once a
365
- certificate is installed and the site is using https, please disconnect and reconnect your account.', 'event-tickets' );
366
- }
367
-
368
- if ( array_diff( [ 'payments_receivable', 'primary_email_confirmed' ], array_keys( $onBoardedData ) ) ) {
369
- $errorMessages[] = esc_html__( 'There was a problem with the status check for your account. Please try disconnecting and connecting again. If the problem persists, please contact support.', 'event-tickets' );
370
-
371
- // Log error messages.
372
- array_map( static function( $errorMessage ) {
373
- $errorMessage = is_array( $errorMessage ) ? $errorMessage['message'] . ' ' . $errorMessage['value'] : $errorMessage;
374
- tribe( 'logger' )->log_error( $errorMessage, 'tickets-commerce-paypal-commerce' );
375
- }, $errorMessages );
376
-
377
- // Return here since the rest of the validations will definitely fail
378
- return $errorMessages;
379
- }
380
-
381
- if ( ! $onBoardedData['payments_receivable'] ) {
382
- $errorMessages[] = esc_html__( 'Set up an account to receive payment from PayPal', 'event-tickets' );
383
- }
384
-
385
- if ( ! $onBoardedData['primary_email_confirmed'] ) {
386
- $errorMessage[] = esc_html__( 'Confirm your primary email address', 'event-tickets' );
387
- }
388
-
389
- if ( ! $usesCustomPayments ) {
390
- return count( $errorMessages ) > 1 ? $errorMessages : true;
391
- }
392
-
393
- if ( array_diff( [ 'products', 'capabilities' ], array_keys( $onBoardedData ) ) ) {
394
- $errorMessages[] = esc_html__( 'Your account was expected to be able to accept custom payments, but is not. Please make sure your
395
- account country matches the country setting. If the problem persists, please contact PayPal.', 'event-tickets' );
396
-
397
- // Return here since the rest of the validations will definitely fail
398
- return $errorMessages;
399
- }
400
-
401
- // Grab the PPCP_CUSTOM product from the status data
402
- $customProduct = current(
403
- array_filter(
404
- $onBoardedData['products'],
405
- static function ( $product ) {
406
- return 'PPCP_CUSTOM' === $product['name'];
407
- }
408
- )
409
- );
410
-
411
- if ( empty( $customProduct ) || $customProduct['vetting_status'] !== 'SUBSCRIBED' ) {
412
- $errorMessages[] = esc_html__( 'Reach out to PayPal to enable PPCP_CUSTOM for your account', 'event-tickets' );
413
- }
414
-
415
- // Loop through the capabilities and see if any are not active
416
- $invalidCapabilities = [];
417
- foreach ( $onBoardedData['capabilities'] as $capability ) {
418
- if ( $capability['status'] !== 'ACTIVE' ) {
419
- $invalidCapabilities[] = $capability['name'];
420
- }
421
- }
422
-
423
- if ( ! empty( $invalidCapabilities ) ) {
424
- $errorMessages[] = esc_html__( 'Reach out to PayPal to resolve the following capabilities:', 'event-tickets' ) . ' ' . implode( ', ', $invalidCapabilities );
425
- }
426
-
427
- // If there were errors then redirect the user with notices
428
- return count( $errorMessages ) > 1 ? $errorMessages : true;
429
- }
430
-
431
- /**
432
- * Redirect admin to setting section with error.
433
- *
434
- * @since 5.1.6
435
- */
436
- private function redirectWhenOnBoardingFail() {
437
- /** @var Tribe__Settings $settings */
438
- $settings = tribe( 'settings' );
439
-
440
- // Get link to Tickets Tab.
441
- $settings_url = $settings->get_url( [
442
- 'page' => 'tribe-common',
443
- 'tab' => 'event-tickets',
444
- 'paypal-error' => '1',
445
- ] ) . '#tribe-field-tickets-commerce-paypal-commerce';
446
-
447
- wp_redirect( $settings_url );
448
- die();
449
- }
450
-
451
- /**
452
- * Displays a notice of the site is not using SSL
453
- *
454
- * @since 5.1.6
455
- */
456
- private function registerPayPalSSLNotice() {
457
- if ( ! is_ssl() || ! empty( $this->webhooksRepository->getWebhookConfig() ) ) {
458
- return;
459
- }
460
-
461
- /** @var Tribe__Settings $settings */
462
- $settings = tribe( 'settings' );
463
-
464
- // Get link to Help page.
465
- $log_url = $settings->get_url( [
466
- 'page' => 'tribe-help',
467
- ] ) . '#tribe-event-log';
468
-
469
- $logLink = sprintf(
470
- '<a href="%1$s">%2$s</a>',
471
- $log_url,
472
- esc_html__( 'logged data', 'event-tickets' )
473
- );
474
-
475
- tribe_error(
476
- 'paypal-webhook-error',
477
- sprintf(
478
- // Translators: %1$s: The logged data link.
479
- esc_html__( 'There was a problem setting up the webhooks for your PayPal account. Please try disconnecting and reconnecting your PayPal account. If the problem persists, please contact support and provide them with the latest %1$s', 'event-tickets' ),
480
- $logLink
481
- ),
482
- [
483
- 'type' => 'error',
484
- ]
485
- );
486
- }
487
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/Tickets/Commerce/Hooks.php CHANGED
@@ -18,6 +18,7 @@
18
  namespace TEC\Tickets\Commerce;
19
 
20
  use \tad_DI52_ServiceProvider;
 
21
  use Tribe\Tickets\Shortcodes\Tribe_Tickets_Checkout;
22
 
23
  /**
@@ -45,7 +46,31 @@ class Hooks extends tad_DI52_ServiceProvider {
45
  * @since 5.1.6
46
  */
47
  protected function add_actions() {
 
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  }
50
 
51
  /**
@@ -55,9 +80,261 @@ class Hooks extends tad_DI52_ServiceProvider {
55
  */
56
  protected function add_filters() {
57
  add_filter( 'tribe_shortcodes', [ $this, 'filter_register_shortcodes' ] );
58
- add_filter( 'tec_tickets_commerce_settings', [ $this, 'filter_include_commerce_settings' ] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  }
60
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  /**
63
  * Register shortcodes.
@@ -71,20 +348,50 @@ class Hooks extends tad_DI52_ServiceProvider {
71
  * @return array
72
  */
73
  public function filter_register_shortcodes( array $shortcodes ) {
74
- $shortcodes['tribe_tickets_checkout'] = Tribe_Tickets_Checkout::class;
 
75
 
76
  return $shortcodes;
77
  }
78
 
79
-
80
  /**
81
- * Modify the commerce settings completely once we have Tickets Commerce active.
 
82
  *
83
- * @since 5.1.6
84
  *
85
- * @return array
 
 
 
 
 
86
  */
87
- public function filter_include_commerce_settings() {
88
- return $this->container->make( Settings::class )->get_settings();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  }
90
  }
18
  namespace TEC\Tickets\Commerce;
19
 
20
  use \tad_DI52_ServiceProvider;
21
+ use TEC\Tickets\Commerce\Status\Completed;
22
  use Tribe\Tickets\Shortcodes\Tribe_Tickets_Checkout;
23
 
24
  /**
46
  * @since 5.1.6
47
  */
48
  protected function add_actions() {
49
+ add_action( 'tribe_settings_do_tabs', [ $this, 'register_payments_tab' ], 15 );
50
 
51
+ add_action( 'init', [ $this, 'register_post_types' ] );
52
+ add_action( 'init', [ $this, 'register_order_statuses' ], 11 );
53
+ add_action( 'tribe_common_loaded', [ $this, 'load_commerce_module' ] );
54
+
55
+ add_action( 'template_redirect', [ $this, 'do_cart_parse_request' ] );
56
+ add_action( 'template_redirect', [ $this, 'do_checkout_parse_request' ] );
57
+
58
+ add_action( 'event_tickets_attendee_update', [ $this, 'update_attendee_data' ], 10, 3 );
59
+ add_action( 'event_tickets_after_attendees_update', [ $this, 'maybe_send_tickets_after_status_change' ] );
60
+
61
+ add_action( 'wp_loaded', [ $this, 'maybe_delete_expired_products' ], 0 );
62
+ add_action( 'wp_loaded', [ $this, 'maybe_redirect_to_attendees_registration_screen' ], 1 );
63
+
64
+ add_action( 'tribe_events_tickets_metabox_edit_advanced', [ $this, 'include_metabox_advanced_options' ], 10, 2 );
65
+
66
+ add_action( 'tribe_events_tickets_attendees_event_details_top', [ $this, 'setup_attendance_totals' ] );
67
+ add_action( 'trashed_post', [ $this, 'maybe_redirect_to_attendees_report' ] );
68
+ add_action( 'tickets_tpp_ticket_deleted', [ $this, 'update_stock_after_deletion' ], 10, 3 );
69
+
70
+ add_action( 'transition_post_status', [ $this, 'transition_order_post_status_hooks' ], 10, 3 );
71
+
72
+ // This needs to run earlier than our page setup.
73
+ add_action( 'admin_init', [ $this, 'maybe_trigger_process_action' ], 5 );
74
  }
75
 
76
  /**
80
  */
81
  protected function add_filters() {
82
  add_filter( 'tribe_shortcodes', [ $this, 'filter_register_shortcodes' ] );
83
+
84
+ add_filter( 'tribe_attendee_registration_form_classes', [ $this, 'filter_registration_form_class' ] );
85
+ add_filter( 'tribe_attendee_registration_cart_provider', [ $this, 'filter_registration_cart_provider' ], 10, 2 );
86
+
87
+ add_filter( 'tribe_tickets_get_default_module', [ $this, 'filter_de_prioritize_module' ], 5, 2 );
88
+
89
+ add_filter( 'tribe_tickets_checkout_urls', [ $this, 'filter_js_include_checkout_url' ] );
90
+ add_filter( 'tribe_tickets_cart_urls', [ $this, 'filter_js_include_cart_url' ] );
91
+
92
+ add_filter( 'event_tickets_attendees_tc_checkin_stati', [ $this, 'filter_checkin_statuses' ] );
93
+ }
94
+
95
+ /**
96
+ * Initializes the Module Class.
97
+ *
98
+ * @since 5.1.9
99
+ */
100
+ public function load_commerce_module() {
101
+ $this->container->make( Module::class );
102
+ }
103
+
104
+ public function register_payments_tab() {
105
+ $this->container->make( Settings::class )->register_tab();
106
+ }
107
+
108
+ /**
109
+ * Register all Commerce Post Types in WordPress.
110
+ *
111
+ * @since 5.1.9
112
+ */
113
+ public function register_post_types() {
114
+ $this->container->make( Attendee::class )->register_post_type();
115
+ $this->container->make( Order::class )->register_post_type();
116
+ $this->container->make( Ticket::class )->register_post_type();
117
+ }
118
+
119
+ /**
120
+ * Register all Order Statuses with WP.
121
+ *
122
+ * @since 5.1.9
123
+ */
124
+ public function register_order_statuses() {
125
+ $this->container->make( Status\Status_Handler::class )->register_order_statuses();
126
+ }
127
+
128
+ /**
129
+ * Depending on which page, tab and if an action is present we trigger the processing.
130
+ *
131
+ * @since 5.1.9
132
+ */
133
+ public function maybe_trigger_process_action() {
134
+ $page = tribe_get_request_var( 'page' );
135
+ if ( \Tribe__Settings::instance()->adminSlug !== $page ) {
136
+ return;
137
+ }
138
+
139
+ $tab = tribe_get_request_var( 'tab' );
140
+ if ( 'payments' !== $tab ) {
141
+ return;
142
+ }
143
+
144
+ $action = (string) tribe_get_request_var( 'tc-action' );
145
+ if ( empty( $action ) ) {
146
+ return;
147
+ }
148
+
149
+ /**
150
+ * Process Tickets Commerce actions when in the Payments Tab.
151
+ *
152
+ * @since 5.1.9
153
+ *
154
+ * @param string $action Which action we are processing.
155
+ */
156
+ do_action( 'tec_tickets_commerce_admin_process_action', $action );
157
+
158
+ /**
159
+ * Process Tickets Commerce actions when in the Payments Tab.
160
+ *
161
+ * @since 5.1.9
162
+ */
163
+ do_action( "tec_tickets_commerce_admin_process_action:{$action}" );
164
+ }
165
+
166
+ /**
167
+ * Fires when a post is transitioned from one status to another so that we can make another hook that is namespaced.
168
+ *
169
+ * @since 5.1.9
170
+ *
171
+ * @param string $new_status New post status.
172
+ * @param string $old_status Old post status.
173
+ * @param \WP_Post $post Post object.
174
+ */
175
+ public function transition_order_post_status_hooks( $new_status, $old_status, $post ) {
176
+ $this->container->make( Status\Status_Handler::class )->transition_order_post_status_hooks( $new_status, $old_status, $post );
177
+ }
178
+
179
+ /**
180
+ * Filters the array of statuses that will mark an ticket attendee as eligible for check-in.
181
+ *
182
+ * @todo TribeCommerceLegacy: Move this into a Check In Handler class.
183
+ *
184
+ * @since 5.1.9
185
+ *
186
+ * @param array $statuses An array of statuses that should mark an ticket attendee as
187
+ * available for check-in.
188
+ *
189
+ * @return array The original array plus the 'yes' status.
190
+ */
191
+ public function filter_checkin_statuses( array $statuses = [] ) {
192
+ $statuses[] = tribe( Completed::class )->get_wp_slug();
193
+
194
+ return array_unique( $statuses );
195
+ }
196
+
197
+ /**
198
+ * Parse the cart request, and possibly redirect, so it happens on `template_redirect`.
199
+ *
200
+ * @since 5.1.9
201
+ */
202
+ public function do_cart_parse_request() {
203
+ $this->container->make( Cart::class )->parse_request();
204
+ }
205
+
206
+ /**
207
+ * Parse the checkout request.
208
+ *
209
+ * @since 5.1.9
210
+ */
211
+ public function do_checkout_parse_request() {
212
+ $this->container->make( Checkout::class )->parse_request();
213
+ }
214
+
215
+ /**
216
+ * Backwards compatibility to update stock after deletion of Ticket.
217
+ *
218
+ * @todo Determine if this is still required.
219
+ *
220
+ * @since 5.1.9
221
+ *
222
+ * @param int $ticket_id the attendee id being deleted
223
+ * @param int $post_id the post or event id for the attendee
224
+ * @param int $product_id the ticket-product id in Tribe Commerce
225
+ */
226
+ public function update_stock_after_deletion( $ticket_id, $post_id, $product_id ) {
227
+ $this->container->make( Ticket::class )->update_stock_after_deletion( $ticket_id, $post_id, $product_id );
228
+ }
229
+
230
+ /**
231
+ * Sets up the Attendance Totals Class report with the Attendee Screen
232
+ *
233
+ * @since 5.1.9
234
+ */
235
+ public function setup_attendance_totals() {
236
+ $this->container->make( Reports\Attendance_Totals::class )->integrate_with_attendee_screen();
237
+ }
238
+
239
+ /**
240
+ * Redirect the user after deleting trashing an Attendee to the Reports page.
241
+ *
242
+ * @since 5.1.94
243
+ *
244
+ * @param int $post_id WP_Post ID
245
+ */
246
+ public function maybe_redirect_to_attendees_report( $post_id ) {
247
+ $this->container->make( Attendee::class )->maybe_redirect_to_attendees_report( $post_id );
248
+ }
249
+
250
+ /**
251
+ * Includes the metabox advanced options for Tickets Commerce.
252
+ *
253
+ * @since 5.1.9
254
+ *
255
+ * @param int $post_id Which post we are attaching the metabox to.
256
+ * @param null|int $ticket_id Ticket we are rendering the metabox for.
257
+ */
258
+ public function include_metabox_advanced_options( $post_id, $ticket_id = null ) {
259
+ $this->container->make( Editor\Metabox::class )->include_metabox_advanced_options( $post_id, $ticket_id );
260
+ }
261
+
262
+ /**
263
+ * Updates the Attendee metadata after insertion.
264
+ *
265
+ * @since 5.1.9
266
+ *
267
+ * @param array $attendee_data Information that we are trying to save.
268
+ * @param int $attendee_id The attendee ID.
269
+ * @param int $post_id The event/post ID.
270
+ *
271
+ */
272
+ public function update_attendee_data( $attendee_data, $attendee_id, $post_id ) {
273
+ $this->container->make( Attendee::class )->update_attendee_data( $attendee_data, $attendee_id, $post_id );
274
+ }
275
+
276
+ /**
277
+ * Fully here for compatibility initially to reduce complexity on the Module.
278
+ *
279
+ * @since 5.1.9
280
+ *
281
+ * @param int $event_id Which ID we are triggering changes to.
282
+ *
283
+ */
284
+ public function maybe_send_tickets_after_status_change( $event_id ) {
285
+ $this->container->make( Attendee::class )->maybe_send_tickets_after_status_change( $event_id );
286
+ }
287
+
288
+ /**
289
+ * Redirect to the Attendees registration page when trying to add tickets.
290
+ *
291
+ * @todo Needs to move to the Checkout page and out of the module.
292
+ *
293
+ * @since 5.1.9
294
+ */
295
+ public function maybe_redirect_to_attendees_registration_screen() {
296
+ $this->container->make( Module::class )->maybe_redirect_to_attendees_registration_screen();
297
  }
298
 
299
+ /**
300
+ * Delete expired cart items.
301
+ *
302
+ * @todo Needs to move to the Cart page and out of the module.
303
+ *
304
+ * @since 5.1.9
305
+ */
306
+ public function maybe_delete_expired_products() {
307
+ $this->container->make( Cart::class )->maybe_delete_expired_products();
308
+ }
309
+
310
+ /**
311
+ * Add the HTML Classes to the registration form for this module.
312
+ *
313
+ * @todo Determine what this is used for.
314
+ *
315
+ * @since 5.1.9
316
+ *
317
+ * @param $classes
318
+ *
319
+ * @return array
320
+ */
321
+ public function filter_registration_form_class( $classes ) {
322
+ return $this->container->make( Attendee::class )->registration_form_class( $classes );
323
+ }
324
+
325
+ /**
326
+ * Included here for Event Tickets Plus compatibility.
327
+ *
328
+ * @since 5.1.9
329
+ *
330
+ * @param object $provider_obj
331
+ * @param string $provider
332
+ *
333
+ * @return object
334
+ */
335
+ public function filter_registration_cart_provider( $provider_obj, $provider ) {
336
+ return $this->container->make( Attendee::class )->registration_cart_provider( $provider_obj, $provider );
337
+ }
338
 
339
  /**
340
  * Register shortcodes.
348
  * @return array
349
  */
350
  public function filter_register_shortcodes( array $shortcodes ) {
351
+ $shortcodes[ Shortcodes\Checkout_Shortcode::get_wp_slug() ] = Shortcodes\Checkout_Shortcode::class;
352
+ $shortcodes[ Shortcodes\Success_Shortcode::get_wp_slug() ] = Shortcodes\Success_Shortcode::class;
353
 
354
  return $shortcodes;
355
  }
356
 
 
357
  /**
358
+ * If other modules are active, we should de prioritize this one (we want other commerce
359
+ * modules to take priority over this one).
360
  *
361
+ * @todo Determine if this is still needed.
362
  *
363
+ * @since 5.1.9
364
+ *
365
+ * @param string $default_module
366
+ * @param string[] $available_modules
367
+ *
368
+ * @return string
369
  */
370
+ public function filter_de_prioritize_module( $default_module, array $available_modules ) {
371
+ $tribe_commerce_module = get_class( $this );
372
+
373
+ // If this isn't the default (or if there isn't a choice), no need to de prioritize.
374
+ if (
375
+ $default_module !== $tribe_commerce_module
376
+ || count( $available_modules ) < 2
377
+ || reset( $available_modules ) !== $tribe_commerce_module
378
+ ) {
379
+ return $default_module;
380
+ }
381
+
382
+ return next( $available_modules );
383
+ }
384
+
385
+ public function filter_js_include_cart_url( $urls ) {
386
+ $urls[ Module::class ] = tribe( Cart::class )->get_url();
387
+
388
+ return $urls;
389
+ }
390
+
391
+ public function filter_js_include_checkout_url( $urls ) {
392
+ // Note the checkout needs to pass by the cart URL first for AR modal.
393
+ $urls[ Module::class ] = tribe( Cart::class )->get_url();
394
+
395
+ return $urls;
396
  }
397
  }
src/Tickets/Commerce/Models/Attendee_Model.php ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Models an Tickets Commerce Attendee.
4
+ *
5
+ * @since 5.1.9
6
+ *
7
+ * @package TEC\Tickets\Commerce\Models
8
+ */
9
+
10
+ namespace TEC\Tickets\Commerce\Models;
11
+
12
+ use DateInterval;
13
+ use DatePeriod;
14
+ use DateTimeZone;
15
+ use TEC\Tickets\Commerce\Module;
16
+ use Tribe\Models\Post_Types\Base;
17
+ use TEC\Tickets\Commerce\Attendee;
18
+ use Tribe\Utils\Lazy_Collection;
19
+ use Tribe\Utils\Lazy_String;
20
+ use Tribe\Utils\Post_Thumbnail;
21
+ use Tribe__Date_Utils as Dates;
22
+ use Tribe__Utils__Array as Arr;
23
+
24
+ /**
25
+ * Class Attendee.
26
+ *
27
+ * @since 5.1.9
28
+ *
29
+ * @package TEC\Tickets\Commerce\Models
30
+ */
31
+ class Attendee_Model extends Base {
32
+ /**
33
+ * {@inheritDoc}
34
+ */
35
+ protected function build_properties( $filter ) {
36
+ try {
37
+ $cache_this = $this->get_caching_callback( $filter );
38
+
39
+ $post_id = $this->post->ID;
40
+
41
+ $post_meta = get_post_meta( $post_id );
42
+
43
+ $ticket_id = Arr::get( $post_meta, [ Attendee::$ticket_relation_meta_key, 0 ] );
44
+ $order_id = Arr::get( $post_meta, [ Attendee::$order_relation_meta_key, 0 ] );
45
+ $event_id = Arr::get( $post_meta, [ Attendee::$event_relation_meta_key, 0 ] );
46
+ $user_id = Arr::get( $post_meta, [ Attendee::$user_relation_meta_key, 0 ] );
47
+
48
+ $ticket = tec_tc_get_ticket( $ticket_id );
49
+ $order = tec_tc_get_order( $order_id );
50
+
51
+ $is_product_deleted = empty( $ticket ) && ! $ticket instanceof \WP_Post;
52
+
53
+ $checked_in = Arr::get( $post_meta, [ Attendee::$checked_in_meta_key, 0 ] );
54
+ $security = Arr::get( $post_meta, [ Attendee::$security_code_meta_key, 0 ] );
55
+ $opt_out = tribe_is_truthy( Arr::get( $post_meta, [ Attendee::$optout_meta_key, 0 ] ) );
56
+ $status = Arr::get( $post_meta, [ Attendee::$status_meta_key, 0 ] );
57
+ $ticket_sent = (int) Arr::get( $post_meta, [ Attendee::$ticket_sent_meta_key, 0 ] );
58
+ $deleted_ticket_title = Arr::get( $post_meta, [ Attendee::$deleted_ticket_meta_key, 0 ] );
59
+ $first_name = Arr::get( $post_meta, [ Attendee::$first_name_meta_key, 0 ] );
60
+ $last_name = Arr::get( $post_meta, [ Attendee::$last_name_meta_key, 0 ] );
61
+ $full_name = $first_name . ' ' . $last_name;
62
+ $email = Arr::get( $post_meta, [ Attendee::$email_meta_key, 0 ] );
63
+ $is_subscribed = tribe_is_truthy( Arr::get( $post_meta, [ Attendee::$subscribed_meta_key, 0 ] ) );
64
+
65
+ // Tries to determine an Attendee Unique ID.
66
+ $ticket_unique_id = Arr::get( $post_meta, [ '_unique_id', 0 ] );
67
+ $ticket_unique_id = empty( $ticket_unique_id ) ? $post_id : $ticket_unique_id;
68
+
69
+ $ticket_title = ( $is_product_deleted ? $ticket->post_title : $deleted_ticket_title . ' ' . __( '(deleted)', 'event-tickets' ) );
70
+
71
+ $is_purchaser = $email === $order->purchaser_email;
72
+
73
+ $properties = [
74
+ 'optout' => $opt_out,
75
+ 'ticket' => $ticket_title,
76
+ 'attendee_id' => $post_id,
77
+ 'security' => $security,
78
+ 'product_id' => $ticket_id,
79
+ 'check_in' => $checked_in,
80
+ 'order_status' => $status,
81
+ 'user_id' => $user_id,
82
+ 'ticket_sent' => $ticket_sent,
83
+
84
+ // Fields for Email Tickets.
85
+ 'event_id' => $event_id,
86
+ 'ticket_name' => $ticket_title,
87
+ 'holder_name' => $full_name,
88
+ 'holder_email' => $email,
89
+ 'order_id' => $order_id,
90
+ 'ticket_id' => $ticket_unique_id,
91
+ 'qr_ticket_id' => $post_id,
92
+ 'security_code' => $security,
93
+
94
+ // Attendee Meta, should be populated later by ET+
95
+ 'attendee_meta' => [],
96
+
97
+ // Handle initial Attendee flags.
98
+ 'is_subscribed' => $is_subscribed,
99
+ 'is_purchaser' => $is_purchaser,
100
+ ];
101
+ } catch ( \Exception $e ) {
102
+ return [];
103
+ }
104
+
105
+ return $properties;
106
+ }
107
+
108
+ /**
109
+ * {@inheritDoc}
110
+ */
111
+ protected function get_cache_slug() {
112
+ return 'tc_attendees';
113
+ }
114
+ }
src/Tickets/Commerce/Models/Order_Model.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Models an Tickets Commerce Orders.
4
+ *
5
+ * @since 5.1.9
6
+ *
7
+ * @package TEC\Tickets\Commerce\Models
8
+ */
9
+
10
+ namespace TEC\Tickets\Commerce\Models;
11
+
12
+ use TEC\Tickets\Commerce;
13
+ use TEC\Tickets\Commerce\Module;
14
+ use TEC\Tickets\Commerce\Order;
15
+ use Tribe\Models\Post_Types\Base;
16
+ use Tribe\Utils\Lazy_Collection;
17
+ use Tribe\Utils\Lazy_String;
18
+ use Tribe\Utils\Post_Thumbnail;
19
+ use Tribe__Date_Utils as Dates;
20
+ use Tribe__Utils__Array as Arr;
21
+
22
+ /**
23
+ * Class Order.
24
+ *
25
+ * @since 5.1.9
26
+ *
27
+ * @package TEC\Tickets\Commerce\Models
28
+ */
29
+ class Order_Model extends Base {
30
+
31
+ /**
32
+ * {@inheritDoc}
33
+ */
34
+ protected function build_properties( $filter ) {
35
+ try {
36
+ $cache_this = $this->get_caching_callback( $filter );
37
+
38
+ $post_id = $this->post->ID;
39
+
40
+ $post_meta = get_post_meta( $post_id );
41
+
42
+ $cart_items = maybe_unserialize( Arr::get( $post_meta, [ Order::$cart_items_meta_key, 0 ] ) );
43
+ $total_value = Arr::get( $post_meta, [ Order::$total_value_meta_key, 0 ] );
44
+ $currency = Arr::get( $post_meta, [ Order::$currency_meta_key, 0 ], 'USD' );
45
+ $gateway_slug = Arr::get( $post_meta, [ Order::$gateway_meta_key, 0 ] );
46
+ $gateway_order_id = Arr::get( $post_meta, [ Order::$gateway_order_id_meta_key, 0 ] );
47
+ $gateway_payload = $this->get_gateway_payloads( $post_meta );
48
+
49
+ $purchaser_full_name = Arr::get( $post_meta, [ Order::$purchaser_full_name_meta_key, 0 ] );
50
+ $purchaser_first_name = Arr::get( $post_meta, [ Order::$purchaser_first_name_meta_key, 0 ] );
51
+ $purchaser_last_name = Arr::get( $post_meta, [ Order::$purchaser_last_name_meta_key, 0 ] );
52
+ $purchaser_email = Arr::get( $post_meta, [ Order::$purchaser_email_meta_key, 0 ] );
53
+
54
+ $events_in_order = Arr::get( $post_meta, [ Order::$events_in_order_meta_key ] );
55
+ $tickets_in_order = Arr::get( $post_meta, [ Order::$tickets_in_order_meta_key ] );
56
+
57
+ $properties = [
58
+ 'provider' => Module::class,
59
+ 'provider_slug' => Commerce::ABBR,
60
+ 'gateway' => $gateway_slug,
61
+ 'gateway_order_id' => $gateway_order_id,
62
+ 'gateway_payload' => $gateway_payload,
63
+ 'total_value' => $total_value,
64
+ 'currency' => $currency,
65
+ 'purchaser' => [
66
+ 'user_id' => $this->post->post_author,
67
+ 'first_name' => $purchaser_first_name,
68
+ 'last_name' => $purchaser_last_name,
69
+ 'full_name' => $purchaser_full_name,
70
+ 'email' => $purchaser_email,
71
+ ],
72
+ 'cart_items' => $cart_items,
73
+ 'events_in_order' => $events_in_order,
74
+ 'tickets_in_order' => $tickets_in_order,
75
+ ];
76
+ } catch ( \Exception $e ) {
77
+ return [];
78
+ }
79
+
80
+ return $properties;
81
+ }
82
+
83
+ protected function get_gateway_payloads( $post_meta ) {
84
+ $statuses = tribe( Commerce\Status\Status_Handler::class )->get_all();
85
+ $meta = [];
86
+
87
+ foreach ( $statuses as $status ) {
88
+ $status_payloads = Arr::get( $post_meta, [ Order::get_gateway_payload_meta_key( $status ) ], [] );
89
+
90
+ $meta[ $status->get_slug() ] = $status_payloads;
91
+ }
92
+
93
+ return array_filter( $meta );
94
+ }
95
+
96
+ /**
97
+ * {@inheritDoc}
98
+ */
99
+ protected function get_cache_slug() {
100
+ return 'tc_orders';
101
+ }
102
+
103
+ }
src/Tickets/Commerce/Models/Ticket_Model.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Models an Tickets Commerce Ticket.
4
+ *
5
+ * @since 5.1.9
6
+ *
7
+ * @package TEC\Tickets\Commerce\Models
8
+ */
9
+
10
+ namespace TEC\Tickets\Commerce\Models;
11
+
12
+ use DateInterval;
13
+ use DatePeriod;
14
+ use DateTimeZone;
15
+ use Tribe\Models\Post_Types\Base;
16
+ use TEC\Tickets\Commerce\Ticket;
17
+ use Tribe\Utils\Lazy_Collection;
18
+ use Tribe\Utils\Lazy_String;
19
+ use Tribe\Utils\Post_Thumbnail;
20
+ use Tribe__Date_Utils as Dates;
21
+
22
+ /**
23
+ * Class Attendee.
24
+ *
25
+ * @since 5.1.9
26
+ *
27
+ * @package TEC\Tickets\Commerce\Models
28
+ */
29
+ class Ticket_Model extends Base {
30
+ /**
31
+ * {@inheritDoc}
32
+ */
33
+ protected function build_properties( $filter ) {
34
+ try {
35
+ $cache_this = $this->get_caching_callback( $filter );
36
+
37
+ $post_id = $this->post->ID;
38
+
39
+ $post_meta = get_post_meta( $post_id );
40
+
41
+ // $total_value = isset( $post_meta[ Ticket::$total_value_meta_key ][0] ) ? $post_meta[ Ticket::$total_value_meta_key ][0] : null;
42
+
43
+ $properties = [
44
+
45
+ ];
46
+ } catch ( \Exception $e ) {
47
+ return [];
48
+ }
49
+
50
+ return $properties;
51
+ }
52
+
53
+ /**
54
+ * {@inheritDoc}
55
+ */
56
+ protected function get_cache_slug() {
57
+ return 'tc_tickets';
58
+ }
59
+ }
src/Tickets/Commerce/Module.php ADDED
@@ -0,0 +1,615 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce;
4
+
5
+ use TEC\Tickets\Commerce;
6
+ use TEC\Tickets\Commerce\Status\Completed;
7
+
8
+ /**
9
+ * Class Tickets Provider class for Tickets Commerce
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce\Gateways\PayPal
14
+ */
15
+ class Module extends \Tribe__Tickets__Tickets {
16
+
17
+ public function __construct() {
18
+ // This needs to happen before parent construct.
19
+ $this->plugin_name = __( 'Tickets Commerce', 'event-tickets' );
20
+
21
+ parent::__construct();
22
+
23
+ $this->attendee_object = Attendee::POSTTYPE;
24
+
25
+ $this->attendee_ticket_sent = '_tribe_tpp_attendee_ticket_sent';
26
+
27
+ $this->attendee_optout_key = Attendee::$optout_meta_key;
28
+
29
+ $this->attendee_tpp_key = Attendee::$status_meta_key;
30
+
31
+ $this->ticket_object = Ticket::POSTTYPE;
32
+
33
+ $this->event_key = Attendee::$event_relation_meta_key;
34
+
35
+ $this->checkin_key = Attendee::$checked_in_meta_key;
36
+
37
+ $this->order_key = Attendee::$order_relation_meta_key;
38
+
39
+ $this->refund_order_key = '_tribe_tpp_refund_order';
40
+
41
+ $this->security_code = Attendee::$security_code_meta_key;
42
+
43
+ $this->full_name = '_tribe_tpp_full_name';
44
+
45
+ $this->email = Attendee::$purchaser_email_meta_key;
46
+ }
47
+
48
+ /**
49
+ * {@inheritdoc}
50
+ */
51
+ public $orm_provider = \TEC\Tickets\Commerce::PROVIDER;
52
+
53
+ /**
54
+ * Name of the CPT that holds Attendees (tickets holders).
55
+ *
56
+ * @since 5.1.9
57
+ *
58
+ * @var string
59
+ */
60
+ const ATTENDEE_OBJECT = Attendee::POSTTYPE;
61
+
62
+ /**
63
+ * Name of the CPT that holds Orders
64
+ *
65
+ * @since 5.1.9
66
+ *
67
+ * @var string
68
+ */
69
+ const ORDER_OBJECT = Order::POSTTYPE;
70
+
71
+ /**
72
+ * Meta key that relates Attendees and Events.
73
+ *
74
+ * @since 5.1.9
75
+ *
76
+ * @var string
77
+ */
78
+ const ATTENDEE_EVENT_KEY = '_tec_tickets_commerce_event';
79
+
80
+ /**
81
+ * Meta key that relates Attendees and Products.
82
+ *
83
+ * @since 5.1.9
84
+ *
85
+ * @var string
86
+ */
87
+ const ATTENDEE_PRODUCT_KEY = '_tec_tickets_commerce_product';
88
+
89
+ /**
90
+ * Meta key that relates Attendees and Orders.
91
+ *
92
+ * @since 5.1.9
93
+ *
94
+ * @var string
95
+ */
96
+ const ATTENDEE_ORDER_KEY = '_tec_tickets_commerce_order';
97
+
98
+ /**
99
+ * Indicates if a ticket for this attendee was sent out via email.
100
+ *
101
+ * @since 5.1.9
102
+ *
103
+ * @var string
104
+ */
105
+ public $attendee_ticket_sent;
106
+
107
+ /**
108
+ * Meta key that if this attendee wants to show on the attendee list
109
+ *
110
+ * @since 5.1.9
111
+ *
112
+ * @var string
113
+ */
114
+ public $attendee_optout_key;
115
+
116
+ /**
117
+ * Meta key that if this attendee PayPal status
118
+ *
119
+ * @since 5.1.9
120
+ *
121
+ * @var string
122
+ */
123
+ public $attendee_tpp_key;
124
+
125
+ /**
126
+ * Name of the CPT that holds Tickets
127
+ *
128
+ * @since 5.1.9
129
+ *
130
+ * @var string
131
+ */
132
+ public $ticket_object;
133
+
134
+ /**
135
+ * Meta key that relates Products and Events
136
+ *
137
+ * @since 5.1.9
138
+ *
139
+ * @var string
140
+ */
141
+ public $event_key;
142
+
143
+ /**
144
+ * Meta key that stores if an attendee has checked in to an event
145
+ *
146
+ * @since 5.1.9
147
+ *
148
+ * @var string
149
+ */
150
+ public $checkin_key;
151
+
152
+ /**
153
+ * Meta key that ties attendees together by order
154
+ *
155
+ * @since 5.1.9
156
+ *
157
+ * @var string
158
+ */
159
+ public $order_key;
160
+
161
+ /**
162
+ * Meta key that ties attendees together by refunded order
163
+ *
164
+ * @since 5.1.9
165
+ *
166
+ * @var string
167
+ */
168
+ public $refund_order_key;
169
+
170
+ /**
171
+ * Meta key that holds the security code that's printed in the tickets
172
+ *
173
+ * @since 5.1.9
174
+ *
175
+ * @var string
176
+ */
177
+ public $security_code;
178
+
179
+ /**
180
+ * Meta key that holds the full name of the tickets PayPal "buyer"
181
+ *
182
+ * @since 5.1.9
183
+ *
184
+ * @var string
185
+ */
186
+ public $full_name;
187
+
188
+ /**
189
+ * Meta key that holds the email of the tickets PayPal "buyer"
190
+ *
191
+ * @since 5.1.9
192
+ *
193
+ * @var string
194
+ */
195
+ public $email;
196
+
197
+ /**
198
+ * Meta key that holds the name of a ticket to be used in reports if the Product is deleted
199
+ *
200
+ * @since 5.1.9
201
+ *
202
+ * @var string
203
+ */
204
+ public $deleted_product = '_tribe_deleted_product_name';
205
+
206
+ /**
207
+ * A variable holder if PayPal is loaded
208
+ *
209
+ * @since 5.1.9
210
+ *
211
+ * @var boolean
212
+ */
213
+ protected $is_loaded = false;
214
+
215
+ /**
216
+ * This method is required for the module to properly load.
217
+ *
218
+ * @since 5.1.9
219
+
220
+ * @return static
221
+ */
222
+ public static function get_instance() {
223
+ return tribe( static::class );
224
+ }
225
+ /**
226
+ * Registers all actions/filters
227
+ *
228
+ * @since 5.1.9
229
+ */
230
+ public function hooks() {
231
+ // if the hooks have already been bound, don't do it again
232
+ if ( $this->is_loaded ) {
233
+ return false;
234
+ }
235
+
236
+ // add_filter( 'post_updated_messages', [ $this, 'updated_messages' ] );
237
+
238
+ // add_action( 'init', tribe_callback( 'tickets.commerce.paypal.orders.report', 'hook' ) );
239
+ // add_action( 'tribe_tickets_attendees_page_inside', tribe_callback( 'tickets.commerce.paypal.orders.tabbed-view', 'render' ) );
240
+ // add_filter( 'tribe_tickets_stock_message_available_quantity', tribe_callback( 'tickets.commerce.paypal.orders.sales', 'filter_available' ), 10, 4 );
241
+ // add_action( 'admin_init', tribe_callback( 'tickets.commerce.paypal.oversell.request', 'handle' ) );```
242
+ }
243
+
244
+ /**
245
+ * Send tickets email for attendees.
246
+ *
247
+ * @since 5.1.9
248
+ *
249
+ * @param array $attendees List of attendees.
250
+ * @param array $args {
251
+ * The list of arguments to use for sending ticket emails.
252
+ *
253
+ * @type string $subject The email subject.
254
+ * @type string $content The email content.
255
+ * @type string $from_name The name to send tickets from.
256
+ * @type string $from_email The email to send tickets from.
257
+ * @type array|string $headers The list of headers to send.
258
+ * @type array $attachments The list of attachments to send.
259
+ * @type string $provider The provider slug (rsvp, tpp, woo, edd).
260
+ * @type int $post_id The post/event ID to send the emails for.
261
+ * @type string|int $order_id The order ID to send the emails for.
262
+ * }
263
+ *
264
+ * @return int The number of emails sent successfully.
265
+ */
266
+ public function send_tickets_email_for_attendees( $attendees, $args = [] ) {
267
+ $args = array_merge(
268
+ [
269
+ 'subject' => tribe_get_option( Settings::$option_confirmation_email_subject, false ),
270
+ 'from_name' => tribe_get_option( Settings::$option_confirmation_email_sender_name, false ),
271
+ 'from_email' => tribe_get_option( Settings::$option_confirmation_email_sender_email, false ),
272
+ 'provider' => Commerce::ABBR,
273
+ ],
274
+ $args
275
+ );
276
+
277
+ return parent::send_tickets_email_for_attendees( $attendees, $args );
278
+ }
279
+
280
+ /**
281
+ * Shows the tickets form in the front end
282
+ *
283
+ * @since 5.1.9
284
+ *
285
+ * @param $content
286
+ *
287
+ * @return void
288
+ */
289
+ public function front_end_tickets_form( $content ) {
290
+
291
+ $post = $GLOBALS['post'];
292
+ $tickets = $this->get_tickets( $post->ID );
293
+
294
+ foreach ( $tickets as $index => $ticket ) {
295
+ if ( __CLASS__ !== $ticket->provider_class ) {
296
+ unset( $tickets[ $index ] );
297
+ }
298
+ }
299
+
300
+ if ( empty( $tickets ) ) {
301
+ return;
302
+ }
303
+
304
+ tribe( Tickets_View::class )->get_tickets_block( $post->ID );
305
+ }
306
+
307
+ /**
308
+ * Indicates if we currently require users to be logged in before they can obtain
309
+ * tickets.
310
+ *
311
+ * @since 5.1.9
312
+ *
313
+ * @return bool
314
+ */
315
+ public function login_required() {
316
+ $requirements = (array) tribe_get_option( 'ticket-authentication-requirements', array() );
317
+
318
+ return in_array( 'event-tickets_all', $requirements, true );
319
+ }
320
+
321
+ /**
322
+ * Get attendees by id and associated post type
323
+ * or default to using $post_id
324
+ *
325
+ * @since 5.1.9
326
+ *
327
+ * @param $post_id
328
+ * @param null $post_type
329
+ *
330
+ * @return array|mixed
331
+ */
332
+ public function get_attendees_by_id( $post_id, $post_type = null ) {
333
+ if ( ! $post_type ) {
334
+ $post_type = get_post_type( $post_id );
335
+ }
336
+
337
+ switch ( $post_type ) {
338
+ case $this->attendee_object:
339
+ return $this->get_attendees_by_attendee_id( $post_id );
340
+
341
+ break;
342
+ case 'tpp_order_hash':
343
+ return $this->get_attendees_by_order_id( $post_id );
344
+
345
+ break;
346
+ case $this->ticket_object:
347
+ return $this->get_attendees_by_ticket_id( $post_id );
348
+
349
+ break;
350
+ default:
351
+ return $this->get_attendees_by_post_id( $post_id );
352
+
353
+ break;
354
+ }
355
+
356
+ }
357
+
358
+ /**
359
+ * Returns the value of a key defined by the class.
360
+ *
361
+ * @since 5.1.9
362
+ *
363
+ * @param string $key
364
+ *
365
+ * @return string The key value or an empty string if not defined.
366
+ */
367
+ public static function get_key( $key ) {
368
+ $instance = self::get_instance();
369
+ $key = strtolower( $key );
370
+
371
+ $constant_map = [
372
+ 'attendee_event_key' => $instance->attendee_event_key,
373
+ 'attendee_product_key' => $instance->attendee_product_key,
374
+ 'attendee_order_key' => $instance->order_key,
375
+ 'attendee_optout_key' => $instance->attendee_optout_key,
376
+ 'attendee_tpp_key' => $instance->attendee_tpp_key,
377
+ 'event_key' => $instance->get_event_key(),
378
+ 'checkin_key' => $instance->checkin_key,
379
+ 'order_key' => $instance->order_key,
380
+ ];
381
+
382
+ return \Tribe__Utils__Array::get( $constant_map, $key, '' );
383
+ }
384
+
385
+ /**
386
+ * Indicates if global stock support is enabled for this provider.
387
+ *
388
+ * @since 5.1.9
389
+ *
390
+ * @return bool
391
+ */
392
+ public function supports_global_stock() {
393
+ /**
394
+ * Allows the declaration of global stock support for Tribe Commerce tickets
395
+ * to be overridden.
396
+ *
397
+ * @param bool $enable_global_stock_support
398
+ */
399
+ return (bool) apply_filters( 'tec_tickets_commerce_enable_global_stock', true );
400
+ }
401
+
402
+ /**
403
+ * All the methods below here were created merely as a backwards compatibility piece for our old Code that
404
+ * depends so much on the concept of a Main class handling all kinds of integration pieces.
405
+ *
406
+ * ! DO NOT INTRODUCE MORE LOGIC OR COMPLEXITY ON THESE METHODS !
407
+ *
408
+ * The methods are all focused on routing functionality to their correct handlers.
409
+ */
410
+
411
+ /**
412
+ * Get's the product price html
413
+ *
414
+ * @since 5.1.9
415
+ *
416
+ * @param int|object $product
417
+ * @param array|boolean $attendee
418
+ *
419
+ * @return string
420
+ */
421
+ public function get_price_html( $product, $attendee = false ) {
422
+ return tribe( Ticket::class )->get_price_html( $product, $attendee );
423
+ }
424
+
425
+ /**
426
+ * Gets the product price value
427
+ *
428
+ * @since 5.1.9
429
+ *
430
+ * @param int|\WP_Post $product
431
+ *
432
+ * @return string
433
+ */
434
+ public function get_price_value( $product ) {
435
+ return tribe( Ticket::class )->get_price_value( $product );
436
+ }
437
+
438
+ /**
439
+ * Whether a specific attendee is valid toward inventory decrease or not.
440
+ *
441
+ * By default only attendees generated as part of a Completed order will count toward
442
+ * an inventory decrease but, if the option to reserve stock for Pending Orders is activated,
443
+ * then those attendees generated as part of a Pending Order will, for a limited time after the
444
+ * order creation, cause the inventory to be decreased.
445
+ *
446
+ * @since 5.1.9
447
+ *
448
+ * @param array $attendee
449
+ *
450
+ * @return bool
451
+ */
452
+ public function attendee_decreases_inventory( array $attendee ) {
453
+ tribe( Attendee::class )->decreases_inventory( $attendee );
454
+ }
455
+
456
+ /**
457
+ * {@inheritdoc}
458
+ */
459
+ public function get_attendee( $attendee, $post_id = 0 ) {
460
+ return tec_tc_get_attendee( $attendee, ARRAY_A );
461
+ }
462
+
463
+ /**
464
+ * Event Tickets Plus Admin Reports page will use this data from this method.
465
+ *
466
+ * @since 5.1.9
467
+ *
468
+ *
469
+ * @param string|int $order_id
470
+ *
471
+ * @return array
472
+ */
473
+ public function get_order_data( $order_id ) {
474
+ return tec_tc_get_order( $order_id, ARRAY_A );
475
+ }
476
+
477
+ /**
478
+ * Renders the advanced fields in the new/edit ticket form.
479
+ * Using the method, providers can add as many fields as
480
+ * they want, specific to their implementation.
481
+ *
482
+ * @since 5.1.9
483
+ *
484
+ * @param int $post_id
485
+ * @param int $ticket_id
486
+ */
487
+ public function do_metabox_capacity_options( $post_id, $ticket_id ) {
488
+ tribe( Editor\Metabox::class )->do_metabox_capacity_options( $post_id, $ticket_id );
489
+ }
490
+
491
+ /**
492
+ * Maps to the Cart Class method to get the cart.
493
+ *
494
+ * @since 5.1.9
495
+ *
496
+ * @return string
497
+ */
498
+ public function get_cart_url() {
499
+ return tribe( Cart::class )->get_url();
500
+ }
501
+
502
+ /**
503
+ * Generate and store all the attendees information for a new order.
504
+ *
505
+ * @since 5.1.9
506
+ *
507
+ * @param string $payment_status The tickets payment status, defaults to completed.
508
+ * @param bool $redirect Whether the client should be redirected or not.
509
+ */
510
+ public function generate_tickets( $payment_status = 'completed', $redirect = true ) {
511
+ tribe( Order::class )->generate_order( $payment_status, $redirect );
512
+ }
513
+
514
+ /**
515
+ * Gets an individual ticket.
516
+ *
517
+ * @since 5.1.9
518
+ *
519
+ * @param int|\WP_Post $post_id
520
+ * @param int|\WP_Post $ticket_id
521
+ *
522
+ * @return null|\Tribe__Tickets__Ticket_Object
523
+ */
524
+ public function get_ticket( $post_id, $ticket_id ) {
525
+ return tribe( Ticket::class )->get_ticket( $ticket_id );
526
+ }
527
+
528
+ /**
529
+ * Saves a Tickets Commerce ticket.
530
+ *
531
+ * @since 5.1.9
532
+ *
533
+ * @param int $post_id Post ID.
534
+ * @param \Tribe__Tickets__Ticket_Object $ticket Ticket object.
535
+ * @param array $raw_data Ticket data.
536
+ *
537
+ * @return int|false The updated/created ticket post ID or false if no ticket ID.
538
+ */
539
+ public function save_ticket( $post_id, $ticket, $raw_data = [] ) {
540
+ // Run anything we might need on parent method.
541
+ parent::save_ticket( $post_id, $ticket, $raw_data );
542
+
543
+ /**
544
+ * Important, do not add anything above this method.
545
+ * Our goal is to reduce the amount of load on the `Module`, relegate these behaviors to the correct models.
546
+ */
547
+ return tribe( Ticket::class )->save( $post_id, $ticket, $raw_data );
548
+ }
549
+
550
+ /**
551
+ * Deletes a ticket.
552
+ *
553
+ * @since 5.1.9
554
+ *
555
+ * @param $event_id
556
+ * @param $ticket_id
557
+ *
558
+ * @return bool
559
+ */
560
+ public function delete_ticket( $event_id, $ticket_id ) {
561
+ /**
562
+ * Important, do not add anything above this method.
563
+ * Our goal is to reduce the amount of load on the `Module`, relegate these behaviors to the correct models.
564
+ */
565
+ $deleted = tribe( Ticket::class )->delete( $event_id, $ticket_id );
566
+
567
+ if ( ! $deleted ) {
568
+ return $deleted;
569
+ }
570
+
571
+ // Run anything we might need on parent method.
572
+ parent::delete_ticket( $event_id, $ticket_id );
573
+
574
+ return $deleted;
575
+ }
576
+
577
+ /**
578
+ * Return whether we're currently on the checkout page for Tickets Commerce.
579
+ *
580
+ * @since 5.1.9
581
+ *
582
+ * @return bool
583
+ */
584
+ public function is_checkout_page() {
585
+ return tribe( Checkout::class )->is_current_page();
586
+ }
587
+
588
+ /**
589
+ * Links to sales report for all tickets for this event.
590
+ *
591
+ * @since 5.1.9
592
+ *
593
+ * @param int $event_id
594
+ * @param bool $url_only
595
+ *
596
+ * @return string
597
+ */
598
+ public function get_event_reports_link( $event_id, $url_only = false ) {
599
+ return tribe( Commerce\Reports\Event::class )->get_link( $event_id, $url_only );
600
+ }
601
+
602
+ /**
603
+ * Links to the sales report for this product.
604
+ *
605
+ * @since 5.1.9
606
+ *
607
+ * @param $event_id
608
+ * @param $ticket_id
609
+ *
610
+ * @return string
611
+ */
612
+ public function get_ticket_reports_link( $event_id, $ticket_id ) {
613
+ return tribe( Commerce\Reports\Event::class )->get_link( $event_id, $ticket_id );
614
+ }
615
+ }
src/Tickets/Commerce/Order.php ADDED
@@ -0,0 +1,642 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce;
4
+
5
+ use TEC\Tickets\Commerce;
6
+ use TEC\Tickets\Commerce\Utils\Price;
7
+
8
+ /**
9
+ * Class Order
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce
14
+ */
15
+ class Order {
16
+ /**
17
+ * Tickets Commerce Order Post Type slug.
18
+ *
19
+ * @since 5.1.9
20
+ *
21
+ * @var string
22
+ */
23
+ const POSTTYPE = 'tec_tc_order';
24
+
25
+ /**
26
+ * Which meta holds which gateway was used on this order.
27
+ *
28
+ * @since 5.1.9
29
+ *
30
+ * @var string
31
+ */
32
+ public static $gateway_meta_key = '_tec_tc_order_gateway';
33
+
34
+ /**
35
+ * Which meta holds which gateway order id was used on this order.
36
+ *
37
+ * @since 5.1.9
38
+ *
39
+ * @var string
40
+ */
41
+ public static $gateway_order_id_meta_key = '_tec_tc_order_gateway_order_id';
42
+
43
+ /**
44
+ * Normally when dealing with the gateways we have a payload from the original creation of the Order on their side
45
+ * of the API, we should store that whole Payload with this meta key so that this data can be used in the future.
46
+ *
47
+ * @since 5.1.9
48
+ *
49
+ * @var string
50
+ */
51
+ public static $gateway_payload_meta_key = '_tec_tc_order_gateway_payload';
52
+
53
+ /**
54
+ * Which meta holds the cart items used to setup this order.
55
+ *
56
+ * @since 5.1.9
57
+ *
58
+ * @var string
59
+ */
60
+ public static $cart_items_meta_key = '_tec_tc_order_cart_items';
61
+
62
+ /**
63
+ * Which meta holds the tickets in a given order, they are added as individual meta items, allowing them to be
64
+ * selected in a meta query.
65
+ *
66
+ * @since 5.1.9
67
+ *
68
+ * @var string
69
+ */
70
+ public static $tickets_in_order_meta_key = '_tec_tc_order_tickets_in_order';
71
+
72
+ /**
73
+ * Which meta holds the events in a given order, they are added as individual meta items, allowing them to be
74
+ * selected in a meta query.
75
+ *
76
+ * @since 5.1.9
77
+ *
78
+ * @var string
79
+ */
80
+ public static $events_in_order_meta_key = '_tec_tc_order_events_in_order';
81
+
82
+ /**
83
+ * Which meta holds the cart items used to setup this order.
84
+ *
85
+ * @since 5.1.9
86
+ *
87
+ * @var string
88
+ */
89
+ public static $total_value_meta_key = '_tec_tc_order_total_value';
90
+
91
+ /**
92
+ * Which meta holds the cart items used to setup this order.
93
+ *
94
+ * @since 5.1.9
95
+ *
96
+ * @var string
97
+ */
98
+ public static $currency_meta_key = '_tec_tc_order_currency';
99
+
100
+ /**
101
+ * Which meta holds the purchaser full name.
102
+ *
103
+ * @since 5.1.9
104
+ *
105
+ * @var string
106
+ */
107
+ public static $purchaser_full_name_meta_key = '_tec_tc_order_purchaser_full_name';
108
+
109
+ /**
110
+ * Which meta holds the purchaser first name.
111
+ *
112
+ * @since 5.1.9
113
+ *
114
+ * @var string
115
+ */
116
+ public static $purchaser_first_name_meta_key = '_tec_tc_order_purchaser_first_name';
117
+
118
+ /**
119
+ * Which meta holds the purchaser last name.
120
+ *
121
+ * @since 5.1.9
122
+ *
123
+ * @var string
124
+ */
125
+ public static $purchaser_last_name_meta_key = '_tec_tc_order_purchaser_last_name';
126
+
127
+ /**
128
+ * Which meta holds the cart items used to setup this order.
129
+ *
130
+ * @since 5.1.9
131
+ *
132
+ * @var string
133
+ */
134
+ public static $purchaser_email_meta_key = '_tec_tc_order_purchaser_email';
135
+
136
+ /**
137
+ * Register this Class post type into WP.
138
+ *
139
+ * @since 5.1.9
140
+ */
141
+ public function register_post_type() {
142
+ $post_type_args = [
143
+ 'label' => __( 'Orders', 'event-tickets' ),
144
+ 'public' => false,
145
+ 'show_ui' => false,
146
+ 'show_in_menu' => false,
147
+ 'query_var' => false,
148
+ 'rewrite' => false,
149
+ 'capability_type' => 'post',
150
+ 'has_archive' => false,
151
+ 'hierarchical' => false,
152
+ ];
153
+
154
+ /**
155
+ * Filter the arguments that craft the order post type.
156
+ *
157
+ * @see register_post_type
158
+ *
159
+ * @since 5.1.9
160
+ *
161
+ * @param array $post_type_args Post type arguments, passed to register_post_type()
162
+ */
163
+ $post_type_args = apply_filters( 'tec_tickets_commerce_order_post_type_args', $post_type_args );
164
+
165
+ register_post_type( static::POSTTYPE, $post_type_args );
166
+ }
167
+
168
+ /**
169
+ * Gets the meta Key for a given Order Status gateway_payload.
170
+ *
171
+ * @since 5.1.9
172
+ *
173
+ * @param Status\Status_Interface $status
174
+ *
175
+ * @return string
176
+ */
177
+ public static function get_gateway_payload_meta_key( Commerce\Status\Status_Interface $status ) {
178
+ return static::$gateway_payload_meta_key . '_' . $status->get_slug();
179
+ }
180
+
181
+ /**
182
+ * Modify the status of a given order based on Slug.
183
+ *
184
+ * @since 5.1.9
185
+ *
186
+ * @throws \Tribe__Repository__Usage_Error
187
+ *
188
+ * @param int $order_id Which order ID will be updated.
189
+ * @param string $status_slug Which Order Status we are modifying to.
190
+ * @param array $extra_args Extra repository arguments.
191
+ *
192
+ * @return bool|\WP_Error
193
+ */
194
+ public function modify_status( $order_id, $status_slug, array $extra_args = [] ) {
195
+ $status = tribe( Commerce\Status\Status_Handler::class )->get_by_slug( $status_slug );
196
+
197
+ if ( ! $status ) {
198
+ return false;
199
+ }
200
+
201
+ $can_apply = $status->can_apply_to( $order_id );
202
+ if ( ! $can_apply ) {
203
+ return $can_apply;
204
+ }
205
+
206
+ $args = array_merge( $extra_args, [ 'status' => $status->get_wp_slug() ] );
207
+
208
+ $updated = tec_tc_orders()->by_args( [
209
+ 'status' => 'any',
210
+ 'id' => $order_id,
211
+ ] )->set_args( $args )->save();
212
+
213
+ return (bool) $updated;
214
+ }
215
+
216
+ /**
217
+ * @todo WIP
218
+ *
219
+ * @since 5.1.9
220
+ *
221
+ * @throws \Tribe__Repository__Usage_Error
222
+ *
223
+ * @return false|\WP_Post
224
+ */
225
+ public function create_from_cart( Commerce\Gateways\Interface_Gateway $gateway, $purchaser = null ) {
226
+ $cart = tribe( Cart::class );
227
+
228
+ $items = $cart->get_items_in_cart();
229
+ $items = array_map( static function ( $item ) {
230
+ $ticket = \Tribe__Tickets__Tickets::load_ticket_object( $item['ticket_id'] );
231
+ $item['sub_total'] = Price::sub_total( $ticket->price, $item['quantity'] );
232
+
233
+ return $item;
234
+ }, $items );
235
+ $sub_totals = array_filter( wp_list_pluck( $items, 'sub_total' ) );
236
+ $total = Price::total( $sub_totals );
237
+
238
+ $order_args = [
239
+ 'title' => $this->generate_order_title( $items, $cart->get_cart_hash() ),
240
+ 'total_value' => $total,
241
+ 'cart_items' => $items,
242
+ 'gateway' => $gateway::get_key(),
243
+ ];
244
+
245
+ // When purchaser data-set is not passed we pull from the current user.
246
+ if ( empty( $purchaser ) && is_user_logged_in() && $user = wp_get_current_user() ) {
247
+ $order_args['author'] = $user->ID;
248
+ $order_args['purchaser_full_name'] = $user->first_name . ' ' . $user->last_name;
249
+ $order_args['purchaser_first_name'] = $user->first_name;
250
+ $order_args['purchaser_last_name'] = $user->last_name;
251
+ $order_args['purchaser_email'] = $user->user_email;
252
+ }
253
+
254
+ $order = tec_tc_orders()->set_args( $order_args )->create();
255
+
256
+ // We were unable to create the order bail from here.
257
+ if ( ! $order ) {
258
+ return false;
259
+ }
260
+
261
+ return $order;
262
+ }
263
+
264
+ /**
265
+ * Generates a title based on Cart Hash, items in the cart.
266
+ *
267
+ * @since 5.1.9
268
+ *
269
+ * @param array $items List of events form
270
+ *
271
+ * @return string
272
+ */
273
+ public function generate_order_title( $items, $hash = null ) {
274
+ $title = [ 'TEC-TC' ];
275
+ if ( $hash ) {
276
+ $title[] = $hash;
277
+ }
278
+ $title[] = 'T';
279
+
280
+ $tickets = array_filter( wp_list_pluck( $items, 'ticket_id' ) );
281
+ $title = array_merge( $title, $tickets );
282
+
283
+ return implode( '-', $title );
284
+ }
285
+
286
+ /**
287
+ * Redirects to the source post after a recoverable (logic) error.
288
+ *
289
+ * @todo Determine if redirecting should be something relegated to some other method, and here we just actually
290
+ * generate the order/Attendees.
291
+ *
292
+ * @see \Tribe__Tickets__Commerce__PayPal__Errors for error codes translations.
293
+ * @since 5.1.9
294
+ *
295
+ * @param bool $redirect Whether to really redirect or not.
296
+ * @param int $post_id A post ID
297
+ *
298
+ * @param int $error_code The current error code
299
+ *
300
+ */
301
+ protected function redirect_after_error( $error_code, $redirect, $post_id ) {
302
+ $url = add_query_arg( 'tpp_error', $error_code, get_permalink( $post_id ) );
303
+ if ( $redirect ) {
304
+ wp_redirect( esc_url_raw( $url ) );
305
+ }
306
+ tribe_exit();
307
+ }
308
+
309
+ /**
310
+ * Generate and store all the attendees information for a new order.
311
+ *
312
+ * @since 5.1.9
313
+ *
314
+ * @param string $payment_status The tickets payment status, defaults to completed.
315
+ * @param bool $redirect Whether the client should be redirected or not.
316
+ *
317
+ */
318
+ public function generate_order( $payment_status = 'completed', $redirect = true ) {
319
+ /*
320
+ * This method might run during a POST (IPN) PayPal request hence the
321
+ * purchasing user ID, if any, will be stored in a custom PayPal var.
322
+ * Let's fallback on the current user ID for GET requests (PDT); it will be always `0`
323
+ * during a PayPal POST (IPN) request.
324
+ */
325
+ $attendee_user_id = ! isset( $custom['user_id'] ) ? get_current_user_id() : absint( $custom['user_id'] );
326
+
327
+ $attendee_full_name = empty( $transaction_data['first_name'] ) && empty( $transaction_data['last_name'] )
328
+ ? ''
329
+ : sanitize_text_field( "{$transaction_data['first_name']} {$transaction_data['last_name']}" );
330
+
331
+ $attendee_email = empty( $transaction_data['payer_email'] ) ? null : sanitize_email( $transaction_data['payer_email'] );
332
+ $attendee_email = is_email( $attendee_email ) ? $attendee_email : null;
333
+
334
+ if ( ! empty( $attendee_user_id ) ) {
335
+ $attendee = get_user_by( 'id', $attendee_user_id );
336
+
337
+ // Check if the user was found.
338
+ if ( $attendee ) {
339
+ // Check if the user has an email address.
340
+ if ( $attendee->user_email ) {
341
+ $attendee_email = $attendee->user_email;
342
+ }
343
+
344
+ $user_full_name = trim( "{$attendee->first_name} {$attendee->last_name}" );
345
+
346
+ // Check if the user has first/last name.
347
+ if ( ! empty( $user_full_name ) ) {
348
+ $attendee_full_name = $user_full_name;
349
+ }
350
+ }
351
+ }
352
+
353
+ /**
354
+ * This is an array of tickets IDs for which the user decided to opt-out.
355
+ *
356
+ * @see \Tribe__Tickets_Plus__Commerce__PayPal__Attendees::register_optout_choice()
357
+ */
358
+ $attendee_optouts = \Tribe__Utils__Array::get( $custom, 'oo', [] );
359
+
360
+ if ( ! $attendee_email || ! $attendee_full_name ) {
361
+ $this->redirect_after_error( 101, $redirect, $post_id );
362
+
363
+ return;
364
+ }
365
+
366
+ // Iterate over each product
367
+ foreach ( (array) $transaction_data['items'] as $item ) {
368
+ $order_attendee_id = 0;
369
+
370
+ if ( empty( $item['ticket'] ) ) {
371
+ continue;
372
+ }
373
+
374
+ /** @var \Tribe__Tickets__Ticket_Object $ticket_type */
375
+ $ticket_type = $item['ticket'];
376
+ $product_id = $ticket_type->ID;
377
+
378
+ // Get the event this tickets is for
379
+ $post = $ticket_type->get_event();
380
+
381
+ if ( empty( $post ) ) {
382
+ continue;
383
+ }
384
+
385
+ $post_id = $post->ID;
386
+
387
+ // if there were no PayPal tickets for the product added to the cart, continue
388
+ if ( empty( $item['quantity'] ) ) {
389
+ continue;
390
+ }
391
+
392
+ // get the PayPal status `decrease_stock_by` value
393
+ $status_stock_size = 1;
394
+
395
+ $ticket_qty = (int) $item['quantity'];
396
+
397
+ // to avoid tickets from not being created on a status stock size of 0
398
+ // let's take the status stock size into account and create a number of tickets
399
+ // at least equal to the number of tickets the user requested
400
+ $ticket_qty = $status_stock_size < 1 ? $ticket_qty : $status_stock_size * $ticket_qty;
401
+
402
+ $qty = max( $ticket_qty, 0 );
403
+
404
+ // Throw an error if Qty is bigger then Remaining
405
+ if ( $payment_status === tribe( Commerce\Status\Completed::class )->get_wp_slug() && $ticket_type->managing_stock() ) {
406
+ add_action( 'tec_tickets_commerce_pending_stock_ignore', '__return_true' );
407
+ $inventory = (int) $ticket_type->inventory();
408
+ remove_action( 'tec_tickets_commerce_pending_stock_ignore', '__return_true' );
409
+
410
+ $inventory_is_not_unlimited = - 1 !== $inventory;
411
+
412
+ if ( $inventory_is_not_unlimited && $qty > $inventory ) {
413
+ if ( ! $order->was_pending() ) {
414
+ $this->redirect_after_error( 102, $redirect, $post_id );
415
+
416
+ return;
417
+ }
418
+
419
+ /** @var \Tribe__Tickets__Commerce__PayPal__Oversell__Policies $oversell_policies */
420
+ $oversell_policies = tribe( 'tickets.commerce.paypal.oversell.policies' );
421
+ $oversell_policy = $oversell_policies->for_post_ticket_order( $post_id, $ticket_type->ID, $order_id );
422
+
423
+ $qty = $oversell_policy->modify_quantity( $qty, $inventory );
424
+
425
+ if ( ! $oversell_policy->allows_overselling() ) {
426
+ $oversold_attendees = tribe( Module::class )->get_attendees_by_order_id( $order_id );
427
+ $oversell_policy->handle_oversold_attendees( $oversold_attendees );
428
+ $this->redirect_after_error( 102, $redirect, $post_id );
429
+
430
+ return;
431
+ }
432
+ }
433
+ }
434
+
435
+ if ( $qty === 0 ) {
436
+ $this->redirect_after_error( 103, $redirect, $post_id );
437
+
438
+ return;
439
+ }
440
+
441
+ $has_tickets = true;
442
+
443
+ /**
444
+ * PayPal specific action fired just before a PayPal-driven attendee ticket for an event is generated
445
+ *
446
+ * @since 4.7
447
+ *
448
+ * @param int $post_id ID of event
449
+ * @param string $ticket_type Ticket Type object for the product
450
+ * @param array $data Parsed PayPal transaction data
451
+ */
452
+ do_action( 'tribe_tickets_tpp_before_attendee_ticket_creation', $post_id, $ticket_type, $transaction_data );
453
+
454
+ $existing_attendees = tribe( Module::class )->get_attendees_by_order_id( $order_id );
455
+
456
+ $has_generated_new_tickets = false;
457
+
458
+ /** @var \Tribe__Tickets__Commerce__Currency $currency */
459
+ $currency = tribe( 'tickets.commerce.currency' );
460
+ $currency_symbol = $currency->get_currency_symbol( $product_id, true );
461
+
462
+ // Iterate over all the amount of tickets purchased (for this product)
463
+ for ( $i = 0; $i < $qty; $i ++ ) {
464
+ $attendee_id = null;
465
+ $updating_attendee = false;
466
+
467
+ /**
468
+ * Allow filtering the individual attendee name used when creating a new attendee.
469
+ *
470
+ * @since 5.0.3
471
+ *
472
+ * @param string $individual_attendee_name The attendee full name.
473
+ * @param int|null $attendee_number The attendee number index value from the order, starting with zero.
474
+ * @param int $order_id The order ID.
475
+ * @param int $ticket_id The ticket ID.
476
+ * @param int $post_id The ID of the post associated to the ticket.
477
+ * @param \Tribe__Tickets__Tickets $provider The current ticket provider object.
478
+ */
479
+ $individual_attendee_name = apply_filters( 'tribe_tickets_attendee_create_individual_name', $attendee_full_name, $i, $order_id, $product_id, $post_id, $this );
480
+
481
+ /**
482
+ * Allow filtering the individual attendee email used when creating a new attendee.
483
+ *
484
+ * @since 5.0.3
485
+ *
486
+ * @param string $individual_attendee_email The attendee email.
487
+ * @param int|null $attendee_number The attendee number index value from the order, starting with zero.
488
+ * @param int $order_id The order ID.
489
+ * @param int $ticket_id The ticket ID.
490
+ * @param int $post_id The ID of the post associated to the ticket.
491
+ * @param \Tribe__Tickets__Tickets $provider The current ticket provider object.
492
+ */
493
+ $individual_attendee_email = apply_filters( 'tribe_tickets_attendee_create_individual_email', $attendee_email, $i, $order_id, $product_id, $post_id, $this );
494
+
495
+ // check if we already have an attendee or not
496
+ $post_title = $individual_attendee_name . ' | ' . ( $i + 1 );
497
+ $criteria = [ 'post_title' => $post_title, 'product_id' => $product_id, 'event_id' => $post_id ];
498
+ $existing_attendee = wp_list_filter( $existing_attendees, $criteria );
499
+
500
+ if ( ! empty( $existing_attendee ) ) {
501
+ $existing_attendee = reset( $existing_attendee );
502
+ $updating_attendee = true;
503
+ $attendee_id = $existing_attendee['attendee_id'];
504
+ $attendee = [];
505
+ } else {
506
+ $attendee = [
507
+ 'post_title' => $post_title,
508
+ ];
509
+
510
+ // since we are creating at least one
511
+ $has_generated_new_tickets = true;
512
+ }
513
+
514
+ $attendee_order_status = trim( strtolower( $payment_status ) );
515
+
516
+ $repository = tribe_attendees( $this->orm_provider );
517
+
518
+ $data = $attendee;
519
+
520
+ $data['order_attendee_id'] = $order_attendee_id;
521
+ $data['attendee_status'] = $attendee_order_status;
522
+
523
+ if ( Order_Statuses::$refunded === $payment_status ) {
524
+ $refund_order_id = \Tribe__Utils__Array::get( $transaction_data, 'txn_id', '' );
525
+
526
+ $data['refund_order_id'] = $refund_order_id;
527
+ }
528
+
529
+ if ( ! $updating_attendee ) {
530
+ $optout = \Tribe__Utils__Array::get( $attendee_optouts, 'ticket_' . $product_id, false );
531
+ $optout = filter_var( $optout, FILTER_VALIDATE_BOOLEAN );
532
+ $optout = $optout ? 'yes' : 'no';
533
+
534
+ $data['ticket_id'] = $product_id;
535
+ $data['post_id'] = $post_id;
536
+ $data['order_id'] = $order_id;
537
+ $data['optout'] = $optout;
538
+ $data['full_name'] = $individual_attendee_name;
539
+ $data['email'] = $individual_attendee_email;
540
+ $data['price_paid'] = get_post_meta( $product_id, '_price', true );
541
+ $data['price_currency'] = $currency_symbol;
542
+
543
+ if ( 0 < $attendee_user_id ) {
544
+ $data['user_id'] = $attendee_user_id;
545
+ }
546
+
547
+ $attendee_object = tribe( Module::class )->create_attendee( $ticket_type, $data );
548
+ $attendee_id = $attendee_object->ID;
549
+
550
+ } else {
551
+ // Update attendee.
552
+ tribe( Module::class )->update_attendee( $attendee_id, $data );
553
+ }
554
+
555
+ $order->add_attendee( $attendee_id );
556
+
557
+ $order_attendee_id ++;
558
+
559
+ if ( ! empty( $existing_attendee ) ) {
560
+ $existing_attendees = wp_list_filter( $existing_attendees, array( 'attendee_id' => $existing_attendee['attendee_id'] ), 'NOT' );
561
+ }
562
+ }
563
+
564
+ if ( ! ( empty( $existing_attendees ) || empty( $oversell_policy ) ) ) {
565
+ // an oversell policy applied: what to do with existing oversold attendees?
566
+ $oversell_policy->handle_oversold_attendees( $existing_attendees );
567
+ }
568
+
569
+ if ( $has_generated_new_tickets ) {
570
+ /**
571
+ * Action fired when a PayPal has had attendee tickets generated for it.
572
+ *
573
+ * @since 4.7
574
+ *
575
+ * @param int $product_id PayPal ticket post ID
576
+ * @param string $order_id ID of the PayPal order
577
+ * @param int $qty Quantity ordered
578
+ */
579
+ do_action( 'event_tickets_tpp_tickets_generated_for_product', $product_id, $order_id, $qty );
580
+ }
581
+
582
+ /**
583
+ * Action fired when a PayPal has had attendee tickets updated for it.
584
+ *
585
+ * This will fire even when tickets are initially created; if you need to hook on the
586
+ * creation process only use the 'event_tickets_tpp_tickets_generated_for_product' action.
587
+ *
588
+ * @since 4.7
589
+ *
590
+ * @param int $product_id PayPal ticket post ID
591
+ * @param string $order_id ID of the PayPal order
592
+ * @param int $qty Quantity ordered
593
+ */
594
+ do_action( 'event_tickets_tpp_tickets_generated_for_product', $product_id, $order_id, $qty );
595
+
596
+ // After Adding the Values we Update the Transient
597
+ \Tribe__Post_Transient::instance()->delete( $post_id, \Tribe__Tickets__Tickets::ATTENDEES_CACHE );
598
+ }
599
+
600
+ $order->update();
601
+
602
+ /**
603
+ * Fires when an PayPal attendee tickets have been generated.
604
+ *
605
+ * @since 4.7
606
+ *
607
+ * @param string $order_id ID of the PayPal order
608
+ * @param int $post_id ID of the post the order was placed for
609
+ */
610
+ do_action( 'event_tickets_tpp_tickets_generated', $order_id, $post_id );
611
+
612
+ /**
613
+ * Filters whether a confirmation email should be sent or not for PayPal tickets.
614
+ *
615
+ * This applies to attendance and non attendance emails.
616
+ *
617
+ * @since 4.7
618
+ *
619
+ * @param bool $send_mail Defaults to `true`.
620
+ */
621
+ $send_mail = apply_filters( 'tribe_tickets_tpp_send_mail', true );
622
+
623
+ if (
624
+ $send_mail
625
+ && $has_tickets
626
+ && $attendee_order_status === Order_Statuses::$completed
627
+ ) {
628
+ $this->send_tickets_email( $order_id, $post_id );
629
+ }
630
+
631
+ // Redirect to the same page to prevent double purchase on refresh
632
+ if ( ! empty( $post_id ) ) {
633
+ /** @var \Tribe__Tickets__Commerce__PayPal__Endpoints $endpoints */
634
+ $endpoints = tribe( 'tickets.commerce.paypal.endpoints' );
635
+ $url = $endpoints->success_url( $order_id, $post_id );
636
+ if ( $redirect ) {
637
+ wp_redirect( esc_url_raw( $url ) );
638
+ }
639
+ tribe_exit();
640
+ }
641
+ }
642
+ }
src/Tickets/Commerce/Provider.php CHANGED
@@ -10,7 +10,8 @@ namespace TEC\Tickets\Commerce;
10
 
11
  use tad_DI52_ServiceProvider;
12
  use TEC\Tickets\Commerce\Gateways;
13
- use Tribe__Tickets__Main;
 
14
 
15
  /**
16
  * Service provider for the Tickets Commerce.
@@ -35,6 +36,8 @@ class Provider extends tad_DI52_ServiceProvider {
35
  $this->register_hooks();
36
  $this->register_assets();
37
 
 
 
38
  $this->register_legacy_compat();
39
 
40
  // Register the SP on the container.
@@ -44,9 +47,28 @@ class Provider extends tad_DI52_ServiceProvider {
44
  // Register all singleton classes.
45
  $this->container->singleton( Gateways\Manager::class, Gateways\Manager::class );
46
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  // Load any external SPs we might need.
48
  $this->container->register( Gateways\PayPal\Provider::class );
49
- // $this->container->register( Gateways\Legacy\Provider::class );
50
  }
51
 
52
  /**
@@ -61,6 +83,20 @@ class Provider extends tad_DI52_ServiceProvider {
61
  $this->container->singleton( Assets::class, $assets );
62
  }
63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  /**
65
  * Registers the provider handling all the 1st level filters and actions for Tickets Commerce.
66
  *
@@ -72,7 +108,7 @@ class Provider extends tad_DI52_ServiceProvider {
72
 
73
  // Allow Hooks to be removed, by having the them registered to the container
74
  $this->container->singleton( Hooks::class, $hooks );
75
- $this->container->singleton( 'tickets.hooks', $hooks );
76
  }
77
 
78
  /**
@@ -85,6 +121,6 @@ class Provider extends tad_DI52_ServiceProvider {
85
  $v1_compat->register();
86
 
87
  $this->container->singleton( Legacy_Compat::class, $v1_compat );
88
- $this->container->singleton( 'tickets.legacy-compat', $v1_compat );
89
  }
90
  }
10
 
11
  use tad_DI52_ServiceProvider;
12
  use TEC\Tickets\Commerce\Gateways;
13
+ use \Tribe__Tickets__Main as Tickets_Plugin;
14
+
15
 
16
  /**
17
  * Service provider for the Tickets Commerce.
36
  $this->register_hooks();
37
  $this->register_assets();
38
 
39
+ $this->load_functions();
40
+
41
  $this->register_legacy_compat();
42
 
43
  // Register the SP on the container.
47
  // Register all singleton classes.
48
  $this->container->singleton( Gateways\Manager::class, Gateways\Manager::class );
49
 
50
+ $this->container->singleton( Reports\Attendance_Totals::class );
51
+ $this->container->singleton( Reports\Event::class );
52
+ $this->container->singleton( Reports\Ticket::class );
53
+
54
+ $this->container->singleton( Editor\Metabox::class );
55
+
56
+ $this->container->singleton( Module::class );
57
+ $this->container->singleton( Attendee::class );
58
+ $this->container->singleton( Order::class );
59
+ $this->container->singleton( Ticket::class );
60
+ $this->container->singleton( Cart::class );
61
+ $this->container->singleton( Cart\Unmanaged_Cart::class );
62
+
63
+ $this->container->singleton( Checkout::class );
64
+ $this->container->singleton( Settings::class );
65
+ $this->container->singleton( Tickets_View::class );
66
+
67
+ $this->container->register( Status\Status_Handler::class );
68
+ $this->container->register( Flag_Actions\Flag_Action_Handler::class );
69
+
70
  // Load any external SPs we might need.
71
  $this->container->register( Gateways\PayPal\Provider::class );
 
72
  }
73
 
74
  /**
83
  $this->container->singleton( Assets::class, $assets );
84
  }
85
 
86
+ /**
87
+ * Include All function files.
88
+ *
89
+ * @since 5.1.9
90
+ */
91
+ protected function load_functions() {
92
+ $path = Tickets_Plugin::instance()->plugin_path;
93
+
94
+ require_once $path . 'src/functions/commerce/orm.php';
95
+ require_once $path . 'src/functions/commerce/orders.php';
96
+ require_once $path . 'src/functions/commerce/attendees.php';
97
+ require_once $path . 'src/functions/commerce/tickets.php';
98
+ }
99
+
100
  /**
101
  * Registers the provider handling all the 1st level filters and actions for Tickets Commerce.
102
  *
108
 
109
  // Allow Hooks to be removed, by having the them registered to the container
110
  $this->container->singleton( Hooks::class, $hooks );
111
+ $this->container->singleton( 'tickets.commerce.hooks', $hooks );
112
  }
113
 
114
  /**
121
  $v1_compat->register();
122
 
123
  $this->container->singleton( Legacy_Compat::class, $v1_compat );
124
+ $this->container->singleton( 'tickets.commerce.legacy-compat', $v1_compat );
125
  }
126
  }
src/Tickets/Commerce/Reports/Attendance_Totals.php ADDED
@@ -0,0 +1,237 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Reports;
4
+
5
+ /**
6
+ * Calculates Ticket Commerce attendance totals for a specified event (ie, how many
7
+ * are going, not going, etc).
8
+ *
9
+ * Also has the capability to print this information as HTML, intended for
10
+ * use in the attendee summary screen.
11
+ *
12
+ * Note that the totals are calculated upon instantiation, effectively making
13
+ * the object a snapshot in time. Therefore if the status of PayPal Tickets is modified
14
+ * or if PayPal Tickets are added/deleted later in the request, it would be necessary
15
+ * to obtain a new object of this type to get accurate results.
16
+ *
17
+ * @since 5.1.9
18
+ *
19
+ * @package TEC\Tickets\Commerce\Reports
20
+ */
21
+ class Attendance_Totals extends \Tribe__Tickets__Abstract_Attendance_Totals {
22
+ protected $total_paid = 0;
23
+ protected $total_pending = 0;
24
+ protected $total_cancelled = 0;
25
+ protected $total_refunded = 0;
26
+
27
+
28
+ /**
29
+ * {@inheritDoc}
30
+ *
31
+ * @since 4.7
32
+ */
33
+ protected function calculate_totals() {
34
+ $tickets = \Tribe__Tickets__Tickets::get_event_tickets( $this->event_id );
35
+
36
+ foreach ( $tickets as $ticket ) {
37
+ /** @var \Tribe__Tickets__Ticket_Object $ticket */
38
+ if ( ! $this->should_count( $ticket ) ) {
39
+ continue;
40
+ }
41
+
42
+ $this->total_paid += $ticket->qty_sold();
43
+ $this->total_pending += $ticket->qty_pending();
44
+ $this->total_cancelled += $ticket->qty_cancelled();
45
+ $this->total_refunded += $ticket->qty_refunded();
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Indicates if the ticket should be factored into our sales counts.
51
+ *
52
+ * @since 4.7
53
+ *
54
+ * @param \Tribe__Tickets__Ticket_Object $ticket
55
+ *
56
+ * @return bool
57
+ */
58
+ protected function should_count( \Tribe__Tickets__Ticket_Object $ticket ) {
59
+ $should_count = 'Tribe__Tickets__RSVP' !== $ticket->provider_class;
60
+
61
+ /**
62
+ * Determine if the provided ticket object should be used when building
63
+ * sales counts.
64
+ *
65
+ * By default, tickets belonging to the Tribe__Tickets__RSVP provider
66
+ * are not to be counted.
67
+ *
68
+ * @since 4.7
69
+ *
70
+ * @param bool $should_count
71
+ * @param \Tribe__Tickets__Ticket_Object $ticket
72
+ */
73
+ return (bool) apply_filters( 'tribe_tickets_should_use_ticket_in_sales_counts', $should_count, $ticket );
74
+ }
75
+
76
+ /**
77
+ * Prints an HTML (unordered) list of attendance totals.
78
+ *
79
+ * @since 4.7
80
+ * @since 4.10.9 Use customizable ticket name functions.
81
+ */
82
+ public function print_totals() {
83
+ $args = [
84
+ 'total_sold_label' => esc_html( sprintf( _x( 'Total %s:', 'attendee summary', 'event-tickets' ), tribe_get_ticket_label_plural( 'total_sold_label' ) ) ),
85
+ 'total_complete_label' => _x( 'Complete:', 'attendee summary', 'event-tickets' ),
86
+ 'total_cancelled_label' => _x( 'Cancelled:', 'attendee summary', 'event-tickets' ),
87
+ 'total_sold' => $this->get_total_sold(),
88
+ 'total_complete' => $this->get_total_complete(),
89
+ 'total_cancelled' => $this->get_total_cancelled(),
90
+ 'total_refunded' => $this->get_total_refunded(),
91
+ 'total_sold_tooltip' => $this->get_total_sold_tooltip(),
92
+ 'total_completed_tooltip' => $this->get_total_completed_tooltip(),
93
+ 'total_cancelled_tooltip' => $this->get_total_cancelled_tooltip(),
94
+ 'total_refunded_tooltip' => $this->get_total_refunded_tooltip(),
95
+ ];
96
+
97
+ tribe( 'tickets.admin.views' )->template( 'attendees-totals-list', $args, true );
98
+ }
99
+
100
+ /**
101
+ * Avoid rendering the total if ET+ is active as this is added by Tribe__Tickets_Plus__Commerce__Attendance_Totals
102
+ * otherwise go with regular flow provided by the parent.
103
+ *
104
+ * @since 4.7.1
105
+ */
106
+ public function integrate_with_attendee_screen() {
107
+ if ( class_exists( 'Tribe__Tickets_Plus__Commerce__Attendance_Totals' ) ) {
108
+ return;
109
+ }
110
+
111
+ parent::integrate_with_attendee_screen();
112
+ }
113
+
114
+ /**
115
+ * The total number of tickets sold for this event.
116
+ *
117
+ * @since 4.7
118
+ *
119
+ * @return int
120
+ */
121
+ public function get_total_sold() {
122
+ $total_sold = $this->get_total_paid() + $this->get_total_pending();
123
+
124
+ /**
125
+ * Returns the total tickets sold for an event.
126
+ *
127
+ * @since 4.7
128
+ *
129
+ * @param int $total_sold Total number of tickets sold.
130
+ * @param int $original_total_sold Original total number of tickets sold.
131
+ * @param int $event_id Event ID.
132
+ */
133
+ return (int) apply_filters( 'tribe_tickets_get_total_sold', $total_sold, $total_sold, $this->event_id );
134
+ }
135
+
136
+ /**
137
+ * The total number of tickets pending further action for this event.
138
+ *
139
+ * @since 4.7
140
+ *
141
+ * @return int
142
+ */
143
+ public function get_total_pending() {
144
+ /**
145
+ * Returns the total tickets pending further action for an event.
146
+ *
147
+ * @since 4.7
148
+ *
149
+ * @param int $total_pending Total number of tickets pending.
150
+ * @param int $original_total_pending Original total number of tickets pending.
151
+ * @param int $event_id Event ID.
152
+ */
153
+ return (int) apply_filters( 'tribe_tickets_get_total_pending', $this->total_pending, $this->total_pending, $this->event_id );
154
+ }
155
+
156
+ /**
157
+ * The total number of tickets sold and paid for, minus cancelled and refunded, for this event.
158
+ *
159
+ * @since 4.7
160
+ *
161
+ * @return int
162
+ */
163
+ public function get_total_complete() {
164
+ $total_complete = $this->get_total_paid() - $this->get_total_cancelled() - $this->get_total_refunded();
165
+
166
+ /**
167
+ * Returns the total tickets completed for an event.
168
+ *
169
+ * @since 4.10.8
170
+ *
171
+ * @param int $total_complete Total number of tickets completed.
172
+ * @param int $original_total_complete Original total number of tickets completed.
173
+ * @param int $event_id Event ID.
174
+ */
175
+ return (int) apply_filters( 'tribe_tickets_get_total_complete', $total_complete, $total_complete, $this->event_id );
176
+ }
177
+
178
+ /**
179
+ * The total number of tickets sold and paid for, for this event.
180
+ *
181
+ * @since 4.6
182
+ *
183
+ * @return int
184
+ */
185
+ public function get_total_paid() {
186
+ /**
187
+ * Returns the total tickets sold and paid for, for an event.
188
+ *
189
+ * @since 4.7
190
+ *
191
+ * @param int $total_paid Total number of tickets paid.
192
+ * @param int $original_total_paid Original total number of tickets paid.
193
+ * @param int $event_id Event ID.
194
+ */
195
+ return (int) apply_filters( 'tribe_tickets_get_total_paid', $this->total_paid, $this->total_paid, $this->event_id );
196
+ }
197
+
198
+ /**
199
+ * The total number of tickets sold then cancelled, for this event.
200
+ *
201
+ * @since 4.10.5
202
+ *
203
+ * @return int
204
+ */
205
+ public function get_total_cancelled() {
206
+ /**
207
+ * Returns the total tickets cancelled, for an event.
208
+ *
209
+ * @since 4.10.5
210
+ *
211
+ * @param int $total_cancelled Total number of tickets cancelled.
212
+ * @param int $original_total_cancelled Original total number of tickets cancelled.
213
+ * @param int $event_id Event ID.
214
+ */
215
+ return (int) apply_filters( 'tribe_tickets_plus_get_total_cancelled', $this->total_cancelled, $this->total_cancelled, $this->event_id );
216
+ }
217
+
218
+ /**
219
+ * The total number of tickets sold then refunded, for this event.
220
+ *
221
+ * @since 4.10.8
222
+ *
223
+ * @return int Total number of tickets refunded.
224
+ */
225
+ public function get_total_refunded() {
226
+ /**
227
+ * Returns the total tickets refunded, for an event.
228
+ *
229
+ * @since 4.10.8
230
+ *
231
+ * @param int $total_refunded Total number of tickets refunded.
232
+ * @param int $original_total_refunded Original total number of tickets refunded.
233
+ * @param int $event_id Event ID.
234
+ */
235
+ return (int) apply_filters( 'tribe_tickets_get_total_refunded', $this->total_refunded, $this->total_refunded, $this->event_id );
236
+ }
237
+ }
src/Tickets/Commerce/Reports/Event.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Reports;
4
+
5
+ use TEC\Tickets\Commerce\Module;
6
+
7
+ /**
8
+ * Class Event Report management.
9
+ *
10
+ * @since 5.1.9
11
+ *
12
+ * @package TEC\Tickets\Commerce\Reports
13
+ */
14
+ class Event {
15
+
16
+
17
+ /**
18
+ * Links to sales report for all tickets for this event.
19
+ *
20
+ * @since 5.1.9
21
+ *
22
+ * @param int $event_id
23
+ * @param bool $url_only
24
+ *
25
+ * @return string
26
+ */
27
+ public function get_link( $event_id, $url_only = false ) {
28
+ $ticket_ids = (array) tribe( Module::class )->get_tickets_ids( $event_id );
29
+ if ( empty( $ticket_ids ) ) {
30
+ return '';
31
+ }
32
+
33
+ $query = array(
34
+ 'page' => 'tpp-orders',
35
+ 'post_id' => $event_id,
36
+ );
37
+
38
+ $report_url = add_query_arg( $query, admin_url( 'admin.php' ) );
39
+
40
+ /**
41
+ * Filter the PayPal Ticket Orders (Sales) Report URL
42
+ *
43
+ * @var string $report_url Report URL
44
+ * @var int $event_id The post ID
45
+ * @var array $ticket_ids An array of ticket IDs
46
+ *
47
+ * @return string
48
+ */
49
+ $report_url = apply_filters( 'tribe_tickets_paypal_report_url', $report_url, $event_id, $ticket_ids );
50
+
51
+ return $url_only
52
+ ? $report_url
53
+ : '<small> <a href="' . esc_url( $report_url ) . '">' . esc_html__( 'Sales report', 'event-tickets' ) . '</a> </small>';
54
+ }
55
+ }
src/Tickets/Commerce/Reports/Ticket.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Reports;
4
+
5
+ /**
6
+ * Class Ticket Report management.
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets\Commerce\Reports
11
+ */
12
+ class Ticket {
13
+
14
+
15
+ /**
16
+ * Links to the sales report for this product.
17
+ *
18
+ * @since 5.1.9
19
+ *
20
+ * @param $event_id
21
+ * @param $ticket_id
22
+ *
23
+ * @return string
24
+ */
25
+ public function get_link( $event_id, $ticket_id ) {
26
+ if ( empty( $ticket_id ) ) {
27
+ return '';
28
+ }
29
+
30
+ $query = array(
31
+ 'page' => 'tpp-orders',
32
+ 'product_ids' => $ticket_id,
33
+ 'post_id' => $event_id,
34
+ );
35
+
36
+ $report_url = add_query_arg( $query, admin_url( 'admin.php' ) );
37
+
38
+ return '<span><a href="' . esc_url( $report_url ) . '">' . esc_html__( 'Report', 'event-tickets' ) . '</a></span>';
39
+ }
40
+ }
src/Tickets/Commerce/Repositories/Attendees_Repository.php ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Repositories;
4
+
5
+
6
+ use TEC\Tickets\Commerce;
7
+ use TEC\Tickets\Commerce\Module;
8
+ use \Tribe__Repository;
9
+ use TEC\Tickets\Commerce\Attendee;
10
+ use Tribe__Repository__Usage_Error as Usage_Error;
11
+
12
+ use Tribe__Utils__Array as Arr;
13
+ use Tribe__Date_Utils as Dates;
14
+
15
+ /**
16
+ * Class Attendees Repository.
17
+ *
18
+ * @since 5.1.9
19
+ *
20
+ * @package TEC\Tickets\Commerce\Repositories
21
+ */
22
+ class Attendees_Repository extends Tribe__Repository {
23
+ /**
24
+ * The unique fragment that will be used to identify this repository filters.
25
+ *
26
+ * @since 5.1.9
27
+ *
28
+ * @var string
29
+ */
30
+ protected $filter_name = 'tc_attendees';
31
+
32
+ /**
33
+ * Key name to use when limiting lists of keys.
34
+ *
35
+ * @since 5.1.9
36
+ *
37
+ * @var string
38
+ */
39
+ protected $key_name = \TEC\Tickets\Commerce::ABBR;
40
+
41
+ /**
42
+ * {@inheritdoc}
43
+ */
44
+ public function __construct() {
45
+ parent::__construct();
46
+
47
+ // Set the order post type.
48
+ $this->default_args['post_type'] = Attendee::POSTTYPE;
49
+ $this->default_args['post_status'] = 'publish';
50
+ $this->create_args['post_status'] = 'publish';
51
+ $this->create_args['post_type'] = Attendee::POSTTYPE;
52
+
53
+ // Add event specific aliases.
54
+ $this->update_fields_aliases = array_merge(
55
+ $this->update_fields_aliases,
56
+ [
57
+ 'order_id' => 'post_parent',
58
+ 'ticket_id' => Attendee::$ticket_relation_meta_key,
59
+ 'event_id' => Attendee::$event_relation_meta_key,
60
+ 'security_code' => Attendee::$security_code_meta_key,
61
+ 'opt_out' => Attendee::$optout_meta_key,
62
+ 'checked_in' => Attendee::$checked_in_meta_key,
63
+ 'first_name' => Attendee::$first_name_meta_key,
64
+ 'last_name' => Attendee::$last_name_meta_key,
65
+ 'email' => Attendee::$email_meta_key,
66
+ 'is_deleted_ticket' => Attendee::$deleted_ticket_meta_key,
67
+ 'ticket_sent' => Attendee::$ticket_sent_meta_key,
68
+ 'is_subscribed' => Attendee::$subscribed_meta_key,
69
+ ]
70
+ );
71
+ }
72
+
73
+ /**
74
+ * {@inheritDoc}
75
+ */
76
+ protected function format_item( $id ) {
77
+ $formatted = null === $this->formatter
78
+ ? tec_tc_get_attendee( $id )
79
+ : $this->formatter->format_item( $id );
80
+
81
+ /**
82
+ * Filters a single formatted attendee result.
83
+ *
84
+ * @since 5.1.9
85
+ *
86
+ * @param mixed|\WP_Post $formatted The formatted event result, usually a post object.
87
+ * @param int $id The formatted post ID.
88
+ * @param \Tribe__Repository__Interface $this The current repository object.
89
+ */
90
+ $formatted = apply_filters( 'tec_tickets_commerce_repository_attendee_format', $formatted, $id, $this );
91
+
92
+ return $formatted;
93
+ }
94
+
95
+ /**
96
+ * {@inheritdoc}
97
+ */
98
+ public function filter_postarr_for_create( array $postarr ) {
99
+ if ( isset( $postarr['meta_input'] ) ) {
100
+ $postarr = $this->filter_meta_input( $postarr );
101
+ }
102
+
103
+ return parent::filter_postarr_for_create( $postarr );
104
+ }
105
+
106
+ /**
107
+ * {@inheritdoc}
108
+ */
109
+ public function filter_postarr_for_update( array $postarr, $post_id ) {
110
+ if ( isset( $postarr['meta_input'] ) ) {
111
+ $postarr = $this->filter_meta_input( $postarr, $post_id );
112
+ }
113
+
114
+ return parent::filter_postarr_for_update( $postarr, $post_id );
115
+ }
116
+
117
+ /**
118
+ * Filters and updates the order meta to make sure it makes sense.
119
+ *
120
+ * @since 5.1.9
121
+ *
122
+ * @param array $postarr The update post array, passed entirely for context purposes.
123
+ * @param int $post_id The ID of the event that's being updated.
124
+ *
125
+ * @return array The filtered postarr array.
126
+ */
127
+ protected function filter_meta_input( array $postarr, $post_id = null ) {
128
+ // if ( ! empty( $postarr['meta_input']['purchaser'] ) ) {
129
+ // $postarr = $this->filter_purchaser_input( $postarr, $post_id );
130
+ // }
131
+
132
+ return $postarr;
133
+ }
134
+ }
src/Tickets/Commerce/Repositories/Order_Repository.php ADDED
@@ -0,0 +1,486 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Repositories;
4
+
5
+ use TEC\Tickets\Commerce;
6
+ use TEC\Tickets\Commerce\Module;
7
+ use \Tribe__Repository;
8
+ use TEC\Tickets\Commerce\Order;
9
+ use Tribe__Repository__Usage_Error as Usage_Error;
10
+
11
+ use Tribe__Utils__Array as Arr;
12
+ use Tribe__Date_Utils as Dates;
13
+
14
+ /**
15
+ * Class Order
16
+ *
17
+ * @since 5.1.9
18
+ */
19
+ class Order_Repository extends Tribe__Repository {
20
+ /**
21
+ * The unique fragment that will be used to identify this repository filters.
22
+ *
23
+ * @since 5.1.9
24
+ *
25
+ * @var string
26
+ */
27
+ protected $filter_name = 'tc_orders';
28
+
29
+ /**
30
+ * Key name to use when limiting lists of keys.
31
+ *
32
+ * @since 5.1.9
33
+ *
34
+ * @var string
35
+ */
36
+ protected $key_name = \TEC\Tickets\Commerce::ABBR;
37
+
38
+ /**
39
+ * {@inheritdoc}
40
+ */
41
+ public function __construct() {
42
+ parent::__construct();
43
+
44
+ $insert_status = tribe( Commerce\Status\Status_Handler::class )->get_insert_status();
45
+
46
+ // Set the order post type.
47
+ $this->default_args['post_type'] = Order::POSTTYPE;
48
+ $this->default_args['post_status'] = $insert_status->get_wp_slug();
49
+ $this->create_args['post_status'] = $insert_status->get_wp_slug();
50
+ $this->create_args['post_type'] = Order::POSTTYPE;
51
+ $this->create_args['currency'] = tribe_get_option( Commerce\Settings::$option_currency_code, 'USD' );
52
+
53
+ // Add event specific aliases.
54
+ $this->update_fields_aliases = array_merge(
55
+ $this->update_fields_aliases,
56
+ [
57
+ 'gateway' => Order::$gateway_meta_key,
58
+ 'gateway_order_id' => Order::$gateway_order_id_meta_key,
59
+ 'cart_items' => Order::$cart_items_meta_key,
60
+ 'total_value' => Order::$total_value_meta_key,
61
+ 'currency' => Order::$currency_meta_key,
62
+ 'purchaser_full_name' => Order::$purchaser_full_name_meta_key,
63
+ 'purchaser_first_name' => Order::$purchaser_first_name_meta_key,
64
+ 'purchaser_last_name' => Order::$purchaser_last_name_meta_key,
65
+ 'purchaser_email' => Order::$purchaser_email_meta_key,
66
+ ]
67
+ );
68
+
69
+ $this->schema = array_merge(
70
+ $this->schema,
71
+ [
72
+ 'tickets' => [ $this, 'filter_by_tickets' ],
73
+ 'tickets_not' => [ $this, 'filter_by_tickets_not' ],
74
+ 'events' => [ $this, 'filter_by_events' ],
75
+ 'events_not' => [ $this, 'filter_by_events_not' ],
76
+ ]
77
+ );
78
+
79
+ $this->add_simple_meta_schema_entry( 'gateway', Order::$gateway_meta_key, 'meta_equals' );
80
+ $this->add_simple_meta_schema_entry( 'gateway_order_id', Order::$gateway_order_id_meta_key, 'meta_equals' );
81
+ $this->add_simple_meta_schema_entry( 'currency', Order::$currency_meta_key, 'meta_equals' );
82
+ $this->add_simple_meta_schema_entry( 'purchaser_full_name', Order::$purchaser_full_name_meta_key, 'meta_equals' );
83
+ $this->add_simple_meta_schema_entry( 'purchaser_first_name', Order::$purchaser_first_name_meta_key, 'meta_equals' );
84
+ $this->add_simple_meta_schema_entry( 'purchaser_last_name', Order::$purchaser_last_name_meta_key, 'meta_equals' );
85
+ $this->add_simple_meta_schema_entry( 'purchaser_email', Order::$purchaser_email_meta_key, 'meta_equals' );
86
+ }
87
+
88
+ /**
89
+ * {@inheritDoc}
90
+ */
91
+ protected function format_item( $id ) {
92
+ $formatted = null === $this->formatter
93
+ ? tec_tc_get_order( $id )
94
+ : $this->formatter->format_item( $id );
95
+
96
+ /**
97
+ * Filters a single formatted order result.
98
+ *
99
+ * @since 5.1.9
100
+ *
101
+ * @param mixed|\WP_Post $formatted The formatted event result, usually a post object.
102
+ * @param int $id The formatted post ID.
103
+ * @param \Tribe__Repository__Interface $this The current repository object.
104
+ */
105
+ $formatted = apply_filters( 'tec_tickets_commerce_repository_order_format', $formatted, $id, $this );
106
+
107
+ return $formatted;
108
+ }
109
+
110
+ /**
111
+ * {@inheritdoc}
112
+ */
113
+ public function filter_postarr_for_create( array $postarr ) {
114
+ if ( isset( $postarr['meta_input'] ) ) {
115
+ $postarr = $this->filter_meta_input( $postarr );
116
+ }
117
+
118
+ if ( ! empty( $postarr['gateway_payload'] ) ) {
119
+ $payload = $postarr['gateway_payload'];
120
+ unset( $postarr['gateway_payload'] );
121
+
122
+ $status = tribe( Commerce\Status\Status_Handler::class )->get_by_wp_slug( $this->create_args['post_status'] );
123
+
124
+ if ( $status ) {
125
+ $postarr['meta_input'][ Order::get_gateway_payload_meta_key( $status ) ] = $payload;
126
+ }
127
+ }
128
+
129
+ return parent::filter_postarr_for_create( $postarr );
130
+ }
131
+
132
+ /**
133
+ * {@inheritdoc}
134
+ */
135
+ public function filter_postarr_for_update( array $postarr, $post_id ) {
136
+ if ( isset( $postarr['meta_input'] ) ) {
137
+ $postarr = $this->filter_meta_input( $postarr, $post_id );
138
+ }
139
+
140
+ if ( ! empty( $postarr['tickets_in_order'] ) ) {
141
+ $tickets = array_filter( array_unique( (array) $postarr['tickets_in_order'] ) );
142
+ unset( $postarr['tickets_in_order'] );
143
+
144
+ // Delete all of the previous ones when updating.
145
+ delete_post_meta( $post_id, Order::$tickets_in_order_meta_key );
146
+
147
+ foreach ( $tickets as $ticket_id ) {
148
+ add_post_meta( $post_id, Order::$tickets_in_order_meta_key, $ticket_id );
149
+ }
150
+ }
151
+
152
+ if ( ! empty( $postarr['events_in_order'] ) ) {
153
+ $events = array_filter( array_unique( (array) $postarr['events_in_order'] ) );
154
+ unset( $postarr['events_in_order'] );
155
+
156
+ // Delete all of the previous ones when updating.
157
+ delete_post_meta( $post_id, Order::$events_in_order_meta_key );
158
+
159
+ foreach ( $events as $event_id ) {
160
+ add_post_meta( $post_id, Order::$events_in_order_meta_key, $event_id );
161
+ }
162
+ }
163
+
164
+ if ( ! empty( $postarr['meta_input']['gateway_payload'] ) ) {
165
+ $payload = $postarr['meta_input']['gateway_payload'];
166
+ unset( $postarr['meta_input']['gateway_payload'] );
167
+
168
+ $status = tribe( Commerce\Status\Status_Handler::class )->get_by_wp_slug( $postarr['post_status'] );
169
+
170
+ if ( $status ) {
171
+ add_post_meta( $post_id, Order::get_gateway_payload_meta_key( $status ), $payload );
172
+ }
173
+ }
174
+
175
+ return parent::filter_postarr_for_update( $postarr, $post_id );
176
+ }
177
+
178
+ /**
179
+ * {@inheritDoc}
180
+ */
181
+ protected function get_create_callback( array $postarr ) {
182
+ $callback = parent::get_create_callback( $postarr );
183
+
184
+ // only modify if the filters didn't change anything.
185
+ if ( 'wp_insert_post' === $callback ) {
186
+ $callback = [ $this, 'create_order_with_meta' ];
187
+ }
188
+
189
+ return $callback;
190
+ }
191
+
192
+ /**
193
+ * When creating an order via the repository there are two meta elements that need to be added using
194
+ * `add_post_meta` with the $unique param set to false.
195
+ *
196
+ * So we hijack the default create callback for this repository to allow for that behavior to exist.
197
+ *
198
+ * @since 5.1.9
199
+ *
200
+ * @param array $postarr The post array that will be used for the creation.
201
+ *
202
+ * @return int The Post ID.
203
+ */
204
+ protected function create_order_with_meta( array $postarr ) {
205
+ $callback = parent::get_create_callback( $postarr );
206
+
207
+ $tickets = [];
208
+ if ( ! empty( $postarr['meta_input']['tickets_in_order'] ) ) {
209
+ $tickets = array_filter( array_unique( (array) $postarr['meta_input']['tickets_in_order'] ) );
210
+ unset( $postarr['meta_input']['tickets_in_order'] );
211
+ }
212
+
213
+ $events = [];
214
+ if ( ! empty( $postarr['meta_input']['events_in_order'] ) ) {
215
+ $events = array_filter( array_unique( (array) $postarr['meta_input']['events_in_order'] ) );
216
+ unset( $postarr['meta_input']['events_in_order'] );
217
+ }
218
+
219
+ $created = call_user_func( $callback, $postarr );
220
+
221
+ // Dont add in case we are dealing with a failed insertion.
222
+ if ( ! is_wp_error( $created ) ) {
223
+ foreach ( $events as $event_id ) {
224
+ add_post_meta( $created, Order::$events_in_order_meta_key, $event_id );
225
+ }
226
+
227
+ foreach ( $tickets as $ticket_id ) {
228
+ add_post_meta( $created, Order::$tickets_in_order_meta_key, $ticket_id );
229
+ }
230
+ }
231
+
232
+ return $created;
233
+ }
234
+
235
+ /**
236
+ * Filters the tickets data from the input so we can properly save the cart items.
237
+ *
238
+ * @since 5.1.9
239
+ *
240
+ * @param array $postarr Data set that needs filtering.
241
+ * @param null|int $post_id When we are dealing with an Update we have an ID here.
242
+ *
243
+ * @return array
244
+ */
245
+ protected function filter_gateway_payload( $postarr, $post_id = null ) {
246
+ $meta = Arr::get( $postarr, 'meta_input', [] );
247
+ $items = Arr::get( $meta, 'gateway_payload', [] );
248
+
249
+ if ( ! empty( $items ) ) {
250
+ $statuses = tribe( Commerce\Status\Status_Handler::class )->get_all();
251
+
252
+ }
253
+
254
+ return $postarr;
255
+ }
256
+
257
+ /**
258
+ * Filters the tickets data from the input so we can properly save the cart items.
259
+ *
260
+ * @since 5.1.9
261
+ *
262
+ * @param array $postarr Data set that needs filtering.
263
+ * @param null|int $post_id When we are dealing with an Update we have an ID here.
264
+ *
265
+ * @return array
266
+ */
267
+ protected function filter_cart_items_input( $postarr, $post_id = null ) {
268
+ $meta = Arr::get( $postarr, 'meta_input', [] );
269
+ $items = Arr::get( $meta, Order::$cart_items_meta_key, [] );
270
+
271
+ if ( ! empty( $items ) ) {
272
+ $ticket_ids = array_unique( array_filter( array_values( wp_list_pluck( $items, 'ticket_id' ) ) ) );
273
+ $event_objects = array_map( [ tribe( Module::class ), 'get_event_for_ticket' ], $ticket_ids );
274
+ $event_ids = array_unique( array_filter( array_values( wp_list_pluck( $event_objects, 'ID' ) ) ) );
275
+
276
+ // These will be remove right before actually creating the order.
277
+ $postarr['meta_input']['tickets_in_order'] = $ticket_ids;
278
+ $postarr['meta_input']['events_in_order'] = $event_ids;
279
+ }
280
+
281
+ return $postarr;
282
+ }
283
+
284
+ /**
285
+ * Filters the Purchaser data from the input so we can properly save the data.
286
+ *
287
+ * @since 5.1.9
288
+ *
289
+ * @param array $postarr Data set that needs filtering.
290
+ * @param null|int $post_id When we are dealing with an Update we have an ID here.
291
+ *
292
+ * @return array
293
+ */
294
+ protected function filter_purchaser_input( $postarr, $post_id = null ) {
295
+ $meta = Arr::get( $postarr, 'meta_input', [] );
296
+ $purchaser = Arr::get( $meta, 'purchaser', [] );
297
+
298
+ if ( is_numeric( $purchaser ) && $user = get_userdata( $purchaser ) ) {
299
+ $full_name = $user->display_name;
300
+ $first_name = $user->first_name;
301
+ $last_name = $user->last_name;
302
+ $email = $user->user_email;
303
+ } else {
304
+ $full_name = Arr::get( $purchaser, 'full_name' );
305
+ $first_name = Arr::get( $purchaser, 'first_name' );
306
+ $last_name = Arr::get( $purchaser, 'last_name' );
307
+ $email = Arr::get( $purchaser, 'email' );
308
+ }
309
+
310
+ // Maybe set the first / last name.
311
+ if ( empty( $first_name ) || empty( $last_name ) ) {
312
+ $first_name = $full_name;
313
+ $last_name = '';
314
+
315
+ // Get first name and last name.
316
+ if ( false !== strpos( $full_name, ' ' ) ) {
317
+ $name_parts = explode( ' ', $full_name );
318
+
319
+ // First name is first text.
320
+ $first_name = array_shift( $name_parts );
321
+
322
+ // Last name is everything the first text.
323
+ $last_name = implode( ' ', $name_parts );
324
+ }
325
+ }
326
+
327
+ $postarr['meta_input'][ Order::$purchaser_email_meta_key ] = $email;
328
+ $postarr['meta_input'][ Order::$purchaser_full_name_meta_key ] = $full_name;
329
+ $postarr['meta_input'][ Order::$purchaser_first_name_meta_key ] = $first_name;
330
+ $postarr['meta_input'][ Order::$purchaser_last_name_meta_key ] = $last_name;
331
+
332
+ unset( $postarr['meta_input']['purchaser'] );
333
+
334
+ return $postarr;
335
+ }
336
+
337
+ /**
338
+ * Filters and updates the order meta to make sure it makes sense.
339
+ *
340
+ * @since 5.1.9
341
+ *
342
+ * @param array $postarr The update post array, passed entirely for context purposes.
343
+ * @param int $post_id The ID of the event that's being updated.
344
+ *
345
+ * @return array The filtered postarr array.
346
+ */
347
+ protected function filter_meta_input( array $postarr, $post_id = null ) {
348
+ if ( ! empty( $postarr['meta_input']['purchaser'] ) ) {
349
+ $postarr = $this->filter_purchaser_input( $postarr, $post_id );
350
+ }
351
+
352
+ if ( ! empty( $postarr['meta_input']['gateway_payload'] ) ) {
353
+ $postarr = $this->filter_gateway_payload( $postarr, $post_id );
354
+ }
355
+
356
+ if ( ! empty( $postarr['meta_input'][ Order::$cart_items_meta_key ] ) ) {
357
+ $postarr = $this->filter_cart_items_input( $postarr, $post_id );
358
+ }
359
+
360
+ return $postarr;
361
+ }
362
+
363
+ /**
364
+ * Cleans up a list of Post IDs into an usable array for DB query.
365
+ *
366
+ * @since 5.1.9
367
+ *
368
+ * @param int|\WP_Post|int[]|\WP_Post[] $posts Which posts we are filtering by.
369
+ *
370
+ * @return array
371
+ */
372
+ protected function clean_post_ids( $posts ) {
373
+ return array_unique( array_filter( array_map( static function ( $post ) {
374
+ if ( is_numeric( $post ) ) {
375
+ return $post;
376
+ }
377
+
378
+ if ( $post instanceof \WP_Post ) {
379
+ return $post->ID;
380
+ }
381
+
382
+ return null;
383
+ }, (array) $posts ) ) );
384
+ }
385
+
386
+ /**
387
+ * Filters order by whether or not it contains a given ticket/s.
388
+ *
389
+ * @since 5.1.9
390
+ *
391
+ * @param int|\WP_Post|int[]|\WP_Post[] $tickets Which tickets we are filtering by.
392
+ *
393
+ * @return null
394
+ */
395
+ public function filter_by_tickets( $tickets = null ) {
396
+ if ( empty( $tickets ) ) {
397
+ return null;
398
+ }
399
+
400
+ $tickets = $this->clean_post_ids( $tickets );
401
+
402
+ if ( empty( $tickets ) ) {
403
+ return null;
404
+ }
405
+
406
+ $this->by( 'meta_in', Order::$tickets_in_order_meta_key, $tickets );
407
+
408
+ return null;
409
+ }
410
+
411
+ /**
412
+ * Filters order by whether or not it contains a given ticket/s.
413
+ *
414
+ * @since 5.1.9
415
+ *
416
+ * @param int|\WP_Post|int[]|\WP_Post[] $tickets Which tickets we are filtering by.
417
+ *
418
+ * @return null
419
+ */
420
+ public function filter_by_tickets_not( $tickets = null ) {
421
+ if ( empty( $tickets ) ) {
422
+ return null;
423
+ }
424
+
425
+ $tickets = $this->clean_post_ids( $tickets );
426
+
427
+ if ( empty( $tickets ) ) {
428
+ return null;
429
+ }
430
+
431
+ $this->by( 'meta_not_in', Order::$tickets_in_order_meta_key, $tickets );
432
+
433
+ return null;
434
+ }
435
+
436
+ /**
437
+ * Filters order by whether or not it contains a given ticket/s.
438
+ *
439
+ * @since 5.1.9
440
+ *
441
+ * @param int|\WP_Post|int[]|\WP_Post[] $events Which events we are filtering by.
442
+ *
443
+ * @return null
444
+ */
445
+ public function filter_by_events( $events = null ) {
446
+ if ( empty( $events ) ) {
447
+ return null;
448
+ }
449
+
450
+ $events = $this->clean_post_ids( $events );
451
+
452
+ if ( empty( $events ) ) {
453
+ return null;
454
+ }
455
+
456
+ $this->by( 'meta_in', Order::$events_in_order_meta_key, $events );
457
+
458
+ return null;
459
+ }
460
+
461
+ /**
462
+ * Filters order by whether or not it contains a given event/s.
463
+ *
464
+ * @since 5.1.9
465
+ *
466
+ * @param int|\WP_Post|int[]|\WP_Post[] $events Which events we are filtering by.
467
+ *
468
+ * @return null
469
+ */
470
+ public function filter_by_events_not( $events = null ) {
471
+ if ( empty( $events ) ) {
472
+ return null;
473
+ }
474
+
475
+ $events = $this->clean_post_ids( $events );
476
+
477
+ if ( empty( $events ) ) {
478
+ return null;
479
+ }
480
+
481
+ $this->by( 'meta_not_in', Order::$events_in_order_meta_key, $events );
482
+
483
+ return null;
484
+ }
485
+
486
+ }
src/Tickets/Commerce/Repositories/Tickets_Repository.php ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Repositories;
4
+
5
+ use TEC\Tickets\Commerce;
6
+ use TEC\Tickets\Commerce\Module;
7
+ use \Tribe__Repository;
8
+ use TEC\Tickets\Commerce\Ticket;
9
+ use Tribe__Repository__Usage_Error as Usage_Error;
10
+
11
+ use Tribe__Utils__Array as Arr;
12
+ use Tribe__Date_Utils as Dates;
13
+
14
+ /**
15
+ * Class Tickets Repository.
16
+ *
17
+ * @since 5.1.9
18
+ *
19
+ * @package TEC\Tickets\Commerce\Repositories
20
+ */
21
+ class Tickets_Repository extends Tribe__Repository {
22
+ /**
23
+ * The unique fragment that will be used to identify this repository filters.
24
+ *
25
+ * @since 5.1.9
26
+ *
27
+ * @var string
28
+ */
29
+ protected $filter_name = 'tc_tickets';
30
+
31
+ /**
32
+ * Key name to use when limiting lists of keys.
33
+ *
34
+ * @since 5.1.9
35
+ *
36
+ * @var string
37
+ */
38
+ protected $key_name = \TEC\Tickets\Commerce::ABBR;
39
+
40
+ /**
41
+ * {@inheritdoc}
42
+ */
43
+ public function __construct() {
44
+ parent::__construct();
45
+
46
+ // Set the order post type.
47
+ $this->default_args['post_type'] = Ticket::POSTTYPE;
48
+ $this->default_args['post_status'] = 'publish';
49
+ $this->create_args['post_status'] = 'publish';
50
+ $this->create_args['post_type'] = Ticket::POSTTYPE;
51
+
52
+ // Add event specific aliases.
53
+ $this->update_fields_aliases = array_merge(
54
+ $this->update_fields_aliases,
55
+ [
56
+ 'event' => Ticket::$event_relation_meta_key,
57
+ 'show_description' => Ticket::$show_description_meta_key,
58
+ 'price' => Ticket::$price_meta_key,
59
+ ]
60
+ );
61
+ }
62
+
63
+ /**
64
+ * {@inheritDoc}
65
+ */
66
+ protected function format_item( $id ) {
67
+ $formatted = null === $this->formatter
68
+ ? tec_tc_get_ticket( $id )
69
+ : $this->formatter->format_item( $id );
70
+
71
+ /**
72
+ * Filters a single formatted ticket result.
73
+ *
74
+ * @since 5.1.9
75
+ *
76
+ * @param mixed|\WP_Post $formatted The formatted event result, usually a post object.
77
+ * @param int $id The formatted post ID.
78
+ * @param \Tribe__Repository__Interface $this The current repository object.
79
+ */
80
+ $formatted = apply_filters( 'tec_tickets_commerce_repository_ticket_format', $formatted, $id, $this );
81
+
82
+ return $formatted;
83
+ }
84
+
85
+ /**
86
+ * {@inheritdoc}
87
+ */
88
+ public function filter_postarr_for_create( array $postarr ) {
89
+ if ( isset( $postarr['meta_input'] ) ) {
90
+ $postarr = $this->filter_meta_input( $postarr );
91
+ }
92
+
93
+ return parent::filter_postarr_for_create( $postarr );
94
+ }
95
+
96
+ /**
97
+ * {@inheritdoc}
98
+ */
99
+ public function filter_postarr_for_update( array $postarr, $post_id ) {
100
+ if ( isset( $postarr['meta_input'] ) ) {
101
+ $postarr = $this->filter_meta_input( $postarr, $post_id );
102
+ }
103
+
104
+ return parent::filter_postarr_for_update( $postarr, $post_id );
105
+ }
106
+
107
+ /**
108
+ * Filters and updates the order meta to make sure it makes sense.
109
+ *
110
+ * @since 5.1.9
111
+ *
112
+ * @param array $postarr The update post array, passed entirely for context purposes.
113
+ * @param int $post_id The ID of the event that's being updated.
114
+ *
115
+ * @return array The filtered postarr array.
116
+ */
117
+ protected function filter_meta_input( array $postarr, $post_id = null ) {
118
+ // if ( ! empty( $postarr['meta_input']['purchaser'] ) ) {
119
+ // $postarr = $this->filter_purchaser_input( $postarr, $post_id );
120
+ // }
121
+
122
+ return $postarr;
123
+ }
124
+ }
src/Tickets/Commerce/Settings.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /**
3
  *
4
- * @since 5.1.6
5
  *
6
  * @package TEC\Tickets\Commerce
7
  */
@@ -30,7 +30,7 @@ class Settings extends Abstract_Settings {
30
  *
31
  * @var string
32
  */
33
- public $option_enable = 'tickets-commerce-enable';
34
 
35
  /**
36
  * The option key for sandbox.
@@ -39,7 +39,7 @@ class Settings extends Abstract_Settings {
39
  *
40
  * @var string
41
  */
42
- public $option_sandbox = 'ticket-paypal-sandbox';
43
 
44
  /**
45
  * The option key for currency code.
@@ -48,7 +48,7 @@ class Settings extends Abstract_Settings {
48
  *
49
  * @var string
50
  */
51
- public $option_currency_code = 'ticket-paypal-currency-code';
52
 
53
  /**
54
  * The option key for stock handling.
@@ -57,7 +57,7 @@ class Settings extends Abstract_Settings {
57
  *
58
  * @var string
59
  */
60
- public $option_stock_handling = 'ticket-paypal-stock-handling';
61
 
62
  /**
63
  * The option key for success page.
@@ -66,7 +66,7 @@ class Settings extends Abstract_Settings {
66
  *
67
  * @var string
68
  */
69
- public $option_success_page = 'ticket-paypal-success-page';
70
 
71
  /**
72
  * The option key for checkout page.
@@ -75,7 +75,7 @@ class Settings extends Abstract_Settings {
75
  *
76
  * @var string
77
  */
78
- public $option_checkout_page = 'tickets-commerce-checkout-page';
79
 
80
  /**
81
  * The option key for confirmation email sender email.
@@ -84,7 +84,7 @@ class Settings extends Abstract_Settings {
84
  *
85
  * @var string
86
  */
87
- public $option_confirmation_email_sender_email = 'ticket-paypal-confirmation-email-sender-email';
88
 
89
  /**
90
  * The option key for confirmation email sender name.
@@ -93,7 +93,7 @@ class Settings extends Abstract_Settings {
93
  *
94
  * @var string
95
  */
96
- public $option_confirmation_email_sender_name = 'ticket-paypal-confirmation-email-sender-name';
97
 
98
  /**
99
  * The option key for confirmation email subject.
@@ -102,16 +102,33 @@ class Settings extends Abstract_Settings {
102
  *
103
  * @var string
104
  */
105
- public $option_confirmation_email_subject = 'ticket-paypal-confirmation-email-subject';
106
 
107
  /**
108
- * Get the list of settings for Tickets Commerce.
109
  *
110
- * @since 5.1.6
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  *
112
- * @return array The list of settings for Tickets Commerce.
 
 
 
113
  */
114
- public function get_settings() {
 
115
  $plus_link = sprintf(
116
  '<a href="https://evnt.is/19zl" target="_blank" rel="noopener noreferrer">%s</a>',
117
  esc_html__( 'Event Tickets Plus', 'event-tickets' )
@@ -121,13 +138,51 @@ class Settings extends Abstract_Settings {
121
  esc_html__( 'Check it out!', 'event-tickets' )
122
  );
123
  $plus_message = sprintf(
124
- // Translators: %1$s: The Event Tickets Plus link, %2$s: The word "ticket" in lowercase, %3$s: The "Check it out!" link.
125
  esc_html_x( 'Tickets Commerce is a light implementation of a commerce gateway using PayPal and simplified stock handling. If you need more advanced features, take a look at %1$s. In addition to integrating with your favorite ecommerce provider, Event Tickets Plus includes options to collect custom information for attendees, check users in via QR codes, and share stock between %2$s. %3$s', 'about Tickets Commerce', 'event-tickets' ),
126
  $plus_link,
127
  esc_html( tribe_get_ticket_label_singular_lowercase( 'tickets_fields_settings_about_tribe_commerce' ) ),
128
  $plus_link_2
129
  );
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  // @todo Replace this with a better and more performant REST API based solution.
132
  $page_args = [
133
  'post_status' => 'publish',
@@ -143,8 +198,8 @@ class Settings extends Abstract_Settings {
143
  // Add an initial empty selection to the start.
144
  $pages = [ 0 => __( '-- No page set --', 'event-tickets' ) ] + $pages;
145
 
146
- $tpp_success_shortcode = 'tribe-tpp-success';
147
- $tickets_commerce_checkout_shortcode = 'tribe_tickets_checkout';
148
 
149
  /** @var \Tribe__Tickets__Commerce__Currency $commerce_currency */
150
  $commerce_currency = tribe( 'tickets.commerce.currency' );
@@ -153,40 +208,15 @@ class Settings extends Abstract_Settings {
153
 
154
  $current_user = get_user_by( 'id', get_current_user_id() );
155
 
156
- // @todo Fill this out and make it check if PayPal Legacy was previously active.
157
- $is_tickets_commerce_enabled = false;
158
-
159
- $top_level_settings = [
160
- 'tickets-commerce-heading' => [
161
- 'type' => 'html',
162
- 'html' => '<h3>' . __( 'Tickets Commerce', 'event-tickets' ) . '</h3>',
163
- ],
164
- 'tickets-commerce-et-plus-header' => [
165
- 'type' => 'html',
166
- 'html' => '<p>' . $plus_message . '</p>',
167
- ],
168
- $this->option_enable => [
169
- 'type' => 'checkbox_bool',
170
- 'label' => esc_html__( 'Enable Tickets Commerce', 'event-tickets' ),
171
- 'tooltip' => esc_html__( 'Check this box if you wish to turn on Tickets Commerce functionality.', 'event-tickets' ),
172
- 'size' => 'medium',
173
- 'default' => $is_tickets_commerce_enabled,
174
- 'validation_type' => 'boolean',
175
- 'attributes' => [
176
- 'id' => $this->option_enable . '-input',
177
- ],
178
- ],
179
- ];
180
-
181
  $settings = [
182
- $this->option_sandbox => [
183
  'type' => 'checkbox_bool',
184
  'label' => esc_html__( 'Enable Test Mode', 'event-tickets' ),
185
  'tooltip' => esc_html__( 'Enables Test mode for testing payments. Any payments made will be done on "sandbox" accounts.', 'event-tickets' ),
186
  'default' => false,
187
  'validation_type' => 'boolean',
188
  ],
189
- $this->option_currency_code => [
190
  'type' => 'dropdown',
191
  'label' => esc_html__( 'Currency Code', 'event-tickets' ),
192
  'tooltip' => esc_html__( 'The currency that will be used for Tickets Commerce transactions.', 'event-tickets' ),
@@ -194,12 +224,12 @@ class Settings extends Abstract_Settings {
194
  'validation_type' => 'options',
195
  'options' => $paypal_currency_code_options,
196
  ],
197
- $this->option_stock_handling => [
198
  'type' => 'radio',
199
  'label' => esc_html__( 'Stock Handling', 'event-tickets' ),
200
  'tooltip' => esc_html(
201
  sprintf(
202
- // Translators: %s: The word "ticket" in lowercase.
203
  _x( 'When a customer purchases a %s, the payment gateway might flag the order as Pending. The order will be Complete once payment is confirmed by the payment gateway.', 'tickets fields settings paypal stock handling', 'event-tickets' ),
204
  tribe_get_ticket_label_singular_lowercase( 'tickets_fields_settings_paypal_stock_handling' )
205
  )
@@ -208,26 +238,26 @@ class Settings extends Abstract_Settings {
208
  'validation_type' => 'options',
209
  'options' => [
210
  'on-pending' => sprintf(
211
- // Translators: %s: The word "ticket" in lowercase.
212
  esc_html__( 'Decrease available %s stock as soon as a Pending order is created.', 'event-tickets' ),
213
  tribe_get_ticket_label_singular_lowercase( 'stock_handling' )
214
  ),
215
  'on-complete' => sprintf(
216
- // Translators: %s: The word "ticket" in lowercase.
217
  esc_html__( 'Only decrease available %s stock if an order is confirmed as Completed by the payment gateway.', 'event-tickets' ),
218
  tribe_get_ticket_label_singular_lowercase( 'stock_handling' )
219
  ),
220
  ],
221
  'tooltip_first' => true,
222
  ],
223
- $this->option_checkout_page => [
224
  'type' => 'dropdown',
225
  'label' => esc_html__( 'Checkout page', 'event-tickets' ),
226
  'tooltip' => esc_html(
227
  sprintf(
228
- // Translators: %s: The [shortcode] for the success page.
229
  __( 'This is the page where customers go to complete their purchase. Use the %s shortcode to display the checkout experience in the page content.', 'event-tickets' ),
230
- "[$tickets_commerce_checkout_shortcode]"
231
  )
232
  ),
233
  'size' => 'medium',
@@ -235,14 +265,14 @@ class Settings extends Abstract_Settings {
235
  'options' => $pages,
236
  'required' => true,
237
  ],
238
- $this->option_success_page => [
239
  'type' => 'dropdown',
240
  'label' => esc_html__( 'Success page', 'event-tickets' ),
241
  'tooltip' => esc_html(
242
  sprintf(
243
- // Translators: %s: The [shortcode] for the success page.
244
  __( 'After a successful order, users will be redirected to this page. Use the %s shortcode to display the order confirmation to the user in the page content.', 'event-tickets' ),
245
- "[$tpp_success_shortcode]"
246
  )
247
  ),
248
  'size' => 'medium',
@@ -250,12 +280,12 @@ class Settings extends Abstract_Settings {
250
  'options' => $pages,
251
  'required' => true,
252
  ],
253
- $this->option_confirmation_email_sender_email => [
254
  'type' => 'email',
255
  'label' => esc_html__( 'Confirmation email sender address', 'event-tickets' ),
256
  'tooltip' => esc_html(
257
  sprintf(
258
- // Translators: %s: The word "tickets" in lowercase.
259
  _x( 'Email address that %s customers will receive confirmation from. Leave empty to use the default WordPress site email address.', 'tickets fields settings confirmation email', 'event-tickets' ),
260
  tribe_get_ticket_label_plural_lowercase( 'tickets_fields_settings_paypal_confirmation_email' )
261
  )
@@ -265,12 +295,12 @@ class Settings extends Abstract_Settings {
265
  'validation_type' => 'email',
266
  'can_be_empty' => true,
267
  ],
268
- $this->option_confirmation_email_sender_name => [
269
  'type' => 'text',
270
  'label' => esc_html__( 'Confirmation email sender name', 'event-tickets' ),
271
  'tooltip' => esc_html(
272
  sprintf(
273
- // Translators: %s: The word "ticket" in lowercase.
274
  _x( 'Sender name of the confirmation email sent to customers when confirming a %s purchase.', 'tickets fields settings paypal email sender', 'event-tickets' ),
275
  tribe_get_ticket_label_singular_lowercase( 'tickets_fields_settings_paypal_email_sender' )
276
  )
@@ -280,12 +310,12 @@ class Settings extends Abstract_Settings {
280
  'validation_callback' => 'is_string',
281
  'validation_type' => 'textarea',
282
  ],
283
- $this->option_confirmation_email_subject => [
284
  'type' => 'text',
285
  'label' => esc_html__( 'Confirmation email subject', 'event-tickets' ),
286
  'tooltip' => esc_html(
287
  sprintf(
288
- // Translators: %s: The word "ticket" in lowercase.
289
  _x( 'Subject of the confirmation email sent to customers when confirming a %s purchase.', 'tickets fields settings paypal email subject', 'event-tickets' ),
290
  tribe_get_ticket_label_singular_lowercase( 'tickets_fields_settings_paypal_email_subject' )
291
  )
@@ -293,7 +323,7 @@ class Settings extends Abstract_Settings {
293
  'size' => 'large',
294
  'default' => esc_html(
295
  sprintf(
296
- // Translators: %s: The word "tickets" in lowercase.
297
  _x( 'You have %s!', 'tickets fields settings paypal email subject', 'event-tickets' ),
298
  tribe_get_ticket_label_plural_lowercase( 'tickets_fields_settings_paypal_email_subject' )
299
  )
@@ -303,48 +333,7 @@ class Settings extends Abstract_Settings {
303
  ],
304
  ];
305
 
306
- /** @var Manager $manager */
307
- $manager = tribe( Manager::class );
308
-
309
- $gateways = $manager->get_gateways();
310
-
311
- $gateway_setting_groups = [];
312
-
313
- // Get all of the gateway settings.
314
- foreach ( $gateways as $gateway ) {
315
- /** @var Abstract_Gateway $gateway_object */
316
- $gateway_object = $gateway['object'];
317
-
318
- if ( ! $gateway_object::should_show() ) {
319
- continue;
320
- }
321
-
322
- // Get the gateway settings.
323
- $gateway_settings = $gateway_object->get_settings();
324
-
325
- // If there are no gateway settings, don't show this section at all.
326
- if ( empty( $gateway_settings ) ) {
327
- continue;
328
- }
329
-
330
- $heading = [
331
- 'tickets-commerce-' . $gateway_object::get_key() => [
332
- 'type' => 'wrapped_html',
333
- 'html' => '<h3 class="event-tickets--admin_settings_subheading">' . $gateway['label'] . '</h3>',
334
- 'validation_type' => 'html',
335
- ],
336
- ];
337
-
338
- // Add the gateway label to the start of settings.
339
- $gateway_setting_groups[] = $heading;
340
-
341
- $gateway_setting_groups[] = $gateway_settings;
342
- }
343
-
344
- if ( ! empty( $gateway_setting_groups ) ) {
345
- // Add the gateway setting groups.
346
- $settings = array_merge( $settings, array_merge( ...$gateway_setting_groups ) );
347
- }
348
 
349
  /**
350
  * Allow filtering the list of Tickets Commerce settings.
@@ -355,10 +344,22 @@ class Settings extends Abstract_Settings {
355
  */
356
  $settings = apply_filters( 'tribe_tickets_commerce_settings', $settings );
357
 
358
- // Handle setting up dependencies for all of the fields.
359
- $validate_if = new Tribe__Field_Conditional( $this->option_enable, 'tribe_is_truthy' );
 
 
 
 
 
 
 
 
 
 
 
 
360
  $fieldset_attributes = [
361
- 'data-depends' => '#' . $this->option_enable . '-input',
362
  'data-condition-is-checked' => '',
363
  ];
364
 
@@ -378,9 +379,7 @@ class Settings extends Abstract_Settings {
378
  $commerce_field['validate_if'] = $validate_if;
379
  }
380
 
381
- unset( $commerce_field );
382
-
383
- return array_merge( $top_level_settings, $settings );
384
  }
385
 
386
  }
1
  <?php
2
  /**
3
  *
4
+ * @since 5.1.6
5
  *
6
  * @package TEC\Tickets\Commerce
7
  */
30
  *
31
  * @var string
32
  */
33
+ public static $option_enable = 'tickets-commerce-enable';
34
 
35
  /**
36
  * The option key for sandbox.
39
  *
40
  * @var string
41
  */
42
+ public static $option_sandbox = 'tickets-commerce-sandbox';
43
 
44
  /**
45
  * The option key for currency code.
48
  *
49
  * @var string
50
  */
51
+ public static $option_currency_code = 'tickets-commerce-currency-code';
52
 
53
  /**
54
  * The option key for stock handling.
57
  *
58
  * @var string
59
  */
60
+ public static $option_stock_handling = 'tickets-commerce-stock-handling';
61
 
62
  /**
63
  * The option key for success page.
66
  *
67
  * @var string
68
  */
69
+ public static $option_success_page = 'tickets-commerce-success-page';
70
 
71
  /**
72
  * The option key for checkout page.
75
  *
76
  * @var string
77
  */
78
+ public static $option_checkout_page = 'tickets-commerce-checkout-page';
79
 
80
  /**
81
  * The option key for confirmation email sender email.
84
  *
85
  * @var string
86
  */
87
+ public static $option_confirmation_email_sender_email = 'tickets-commerce-confirmation-email-sender-email';
88
 
89
  /**
90
  * The option key for confirmation email sender name.
93
  *
94
  * @var string
95
  */
96
+ public static $option_confirmation_email_sender_name = 'tickets-commerce-confirmation-email-sender-name';
97
 
98
  /**
99
  * The option key for confirmation email subject.
102
  *
103
  * @var string
104
  */
105
+ public static $option_confirmation_email_subject = 'tickets-commerce-confirmation-email-subject';
106
 
107
  /**
108
+ * Create the Tickets Commerce Payments Settings Tab.
109
  *
110
+ * @since 5.1.9
111
+ */
112
+ public function register_tab() {
113
+ $tab_settings = [
114
+ 'priority' => 25,
115
+ 'fields' => $this->get_settings(),
116
+ 'show_save' => false,
117
+ ];
118
+
119
+ new \Tribe__Settings_Tab( 'payments', esc_html__( 'Payments', 'event-tickets' ), $tab_settings );
120
+ }
121
+
122
+ /**
123
+ * Gets the top level settings for Tickets Commerce.
124
  *
125
+ * @since 5.1.9
126
+ *
127
+ *
128
+ * @return array[]
129
  */
130
+ public function get_top_level_settings() {
131
+
132
  $plus_link = sprintf(
133
  '<a href="https://evnt.is/19zl" target="_blank" rel="noopener noreferrer">%s</a>',
134
  esc_html__( 'Event Tickets Plus', 'event-tickets' )
138
  esc_html__( 'Check it out!', 'event-tickets' )
139
  );
140
  $plus_message = sprintf(
141
+ // Translators: %1$s: The Event Tickets Plus link, %2$s: The word "ticket" in lowercase, %3$s: The "Check it out!" link.
142
  esc_html_x( 'Tickets Commerce is a light implementation of a commerce gateway using PayPal and simplified stock handling. If you need more advanced features, take a look at %1$s. In addition to integrating with your favorite ecommerce provider, Event Tickets Plus includes options to collect custom information for attendees, check users in via QR codes, and share stock between %2$s. %3$s', 'about Tickets Commerce', 'event-tickets' ),
143
  $plus_link,
144
  esc_html( tribe_get_ticket_label_singular_lowercase( 'tickets_fields_settings_about_tribe_commerce' ) ),
145
  $plus_link_2
146
  );
147
 
148
+ // @todo Fill this out and make it check if PayPal Legacy was previously active.
149
+ $is_tickets_commerce_enabled = tec_tickets_commerce_is_enabled();
150
+
151
+ $top_level_settings = [
152
+ 'tickets-commerce-header' => [
153
+ 'type' => 'html',
154
+ 'html' => '<div class="tec-tickets-commerce-toggle"><label class="tec-tickets-commerce-switch"><input type="checkbox" name="' . static::$option_enable . '" value="' . $is_tickets_commerce_enabled . '" ' . checked( $is_tickets_commerce_enabled, true, false ) . ' id="tickets-commerce-enable-input" class="tribe-dependency tribe-dependency-verified"><span class="tec-tickets-commerce-slider round"></span></label><h2>' . esc_html__( 'Enable Tickets Commerce', 'event-tickets' ) . '</h2></div>',
155
+ ],
156
+ 'tickets-commerce-description' => [
157
+ 'type' => 'html',
158
+ 'html' => '<div class="tec-tickets-commerce-description">' . $plus_message . '</div>',
159
+ ],
160
+ static::$option_enable => [
161
+ 'type' => 'hidden',
162
+ 'validation_type' => 'boolean',
163
+ ],
164
+ ];
165
+
166
+ /**
167
+ * Hook to modify the top level settings for Tickets Commerce.
168
+ *
169
+ * @since 5.1.9
170
+ *
171
+ * @param array[] $top_level_settings Top level settings.
172
+ */
173
+ return apply_filters( 'tec_tickets_commerce_settings_top_level', $top_level_settings );
174
+ }
175
+
176
+ /**
177
+ * Get the list of settings for Tickets Commerce.
178
+ *
179
+ * @since 5.1.6
180
+ *
181
+ * @return array The list of settings for Tickets Commerce.
182
+ */
183
+ public function get_settings() {
184
+ $gateways_manager = tribe( Manager::class );
185
+
186
  // @todo Replace this with a better and more performant REST API based solution.
187
  $page_args = [
188
  'post_status' => 'publish',
198
  // Add an initial empty selection to the start.
199
  $pages = [ 0 => __( '-- No page set --', 'event-tickets' ) ] + $pages;
200
 
201
+ $success_shortcode = Shortcodes\Success_Shortcode::get_wp_slug();
202
+ $checkout_shortcode = Shortcodes\Checkout_Shortcode::get_wp_slug();
203
 
204
  /** @var \Tribe__Tickets__Commerce__Currency $commerce_currency */
205
  $commerce_currency = tribe( 'tickets.commerce.currency' );
208
 
209
  $current_user = get_user_by( 'id', get_current_user_id() );
210
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
211
  $settings = [
212
+ static::$option_sandbox => [
213
  'type' => 'checkbox_bool',
214
  'label' => esc_html__( 'Enable Test Mode', 'event-tickets' ),
215
  'tooltip' => esc_html__( 'Enables Test mode for testing payments. Any payments made will be done on "sandbox" accounts.', 'event-tickets' ),
216
  'default' => false,
217
  'validation_type' => 'boolean',
218
  ],
219
+ static::$option_currency_code => [
220
  'type' => 'dropdown',
221
  'label' => esc_html__( 'Currency Code', 'event-tickets' ),
222
  'tooltip' => esc_html__( 'The currency that will be used for Tickets Commerce transactions.', 'event-tickets' ),
224
  'validation_type' => 'options',
225
  'options' => $paypal_currency_code_options,
226
  ],
227
+ static::$option_stock_handling => [
228
  'type' => 'radio',
229
  'label' => esc_html__( 'Stock Handling', 'event-tickets' ),
230
  'tooltip' => esc_html(
231
  sprintf(
232
+ // Translators: %s: The word "ticket" in lowercase.
233
  _x( 'When a customer purchases a %s, the payment gateway might flag the order as Pending. The order will be Complete once payment is confirmed by the payment gateway.', 'tickets fields settings paypal stock handling', 'event-tickets' ),
234
  tribe_get_ticket_label_singular_lowercase( 'tickets_fields_settings_paypal_stock_handling' )
235
  )
238
  'validation_type' => 'options',
239
  'options' => [
240
  'on-pending' => sprintf(
241
+ // Translators: %s: The word "ticket" in lowercase.
242
  esc_html__( 'Decrease available %s stock as soon as a Pending order is created.', 'event-tickets' ),
243
  tribe_get_ticket_label_singular_lowercase( 'stock_handling' )
244
  ),
245
  'on-complete' => sprintf(
246
+ // Translators: %s: The word "ticket" in lowercase.
247
  esc_html__( 'Only decrease available %s stock if an order is confirmed as Completed by the payment gateway.', 'event-tickets' ),
248
  tribe_get_ticket_label_singular_lowercase( 'stock_handling' )
249
  ),
250
  ],
251
  'tooltip_first' => true,
252
  ],
253
+ static::$option_checkout_page => [
254
  'type' => 'dropdown',
255
  'label' => esc_html__( 'Checkout page', 'event-tickets' ),
256
  'tooltip' => esc_html(
257
  sprintf(
258
+ // Translators: %s: The [shortcode] for the success page.
259
  __( 'This is the page where customers go to complete their purchase. Use the %s shortcode to display the checkout experience in the page content.', 'event-tickets' ),
260
+ "[$checkout_shortcode]"
261
  )
262
  ),
263
  'size' => 'medium',
265
  'options' => $pages,
266
  'required' => true,
267
  ],
268
+ static::$option_success_page => [
269
  'type' => 'dropdown',
270
  'label' => esc_html__( 'Success page', 'event-tickets' ),
271
  'tooltip' => esc_html(
272
  sprintf(
273
+ // Translators: %s: The [shortcode] for the success page.
274
  __( 'After a successful order, users will be redirected to this page. Use the %s shortcode to display the order confirmation to the user in the page content.', 'event-tickets' ),
275
+ "[$success_shortcode]"
276
  )
277
  ),
278
  'size' => 'medium',
280
  'options' => $pages,
281
  'required' => true,
282
  ],
283
+ static::$option_confirmation_email_sender_email => [
284
  'type' => 'email',
285
  'label' => esc_html__( 'Confirmation email sender address', 'event-tickets' ),
286
  'tooltip' => esc_html(
287
  sprintf(
288
+ // Translators: %s: The word "tickets" in lowercase.
289
  _x( 'Email address that %s customers will receive confirmation from. Leave empty to use the default WordPress site email address.', 'tickets fields settings confirmation email', 'event-tickets' ),
290
  tribe_get_ticket_label_plural_lowercase( 'tickets_fields_settings_paypal_confirmation_email' )
291
  )
295
  'validation_type' => 'email',
296
  'can_be_empty' => true,
297
  ],
298
+ static::$option_confirmation_email_sender_name => [
299
  'type' => 'text',
300
  'label' => esc_html__( 'Confirmation email sender name', 'event-tickets' ),
301
  'tooltip' => esc_html(
302
  sprintf(
303
+ // Translators: %s: The word "ticket" in lowercase.
304
  _x( 'Sender name of the confirmation email sent to customers when confirming a %s purchase.', 'tickets fields settings paypal email sender', 'event-tickets' ),
305
  tribe_get_ticket_label_singular_lowercase( 'tickets_fields_settings_paypal_email_sender' )
306
  )
310
  'validation_callback' => 'is_string',
311
  'validation_type' => 'textarea',
312
  ],
313
+ static::$option_confirmation_email_subject => [
314
  'type' => 'text',
315
  'label' => esc_html__( 'Confirmation email subject', 'event-tickets' ),
316
  'tooltip' => esc_html(
317
  sprintf(
318
+ // Translators: %s: The word "ticket" in lowercase.
319
  _x( 'Subject of the confirmation email sent to customers when confirming a %s purchase.', 'tickets fields settings paypal email subject', 'event-tickets' ),
320
  tribe_get_ticket_label_singular_lowercase( 'tickets_fields_settings_paypal_email_subject' )
321
  )
323
  'size' => 'large',
324
  'default' => esc_html(
325
  sprintf(
326
+ // Translators: %s: The word "tickets" in lowercase.
327
  _x( 'You have %s!', 'tickets fields settings paypal email subject', 'event-tickets' ),
328
  tribe_get_ticket_label_plural_lowercase( 'tickets_fields_settings_paypal_email_subject' )
329
  )
333
  ],
334
  ];
335
 
336
+ $settings = array_merge( $gateways_manager->get_gateway_settings(), $settings );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337
 
338
  /**
339
  * Allow filtering the list of Tickets Commerce settings.
344
  */
345
  $settings = apply_filters( 'tribe_tickets_commerce_settings', $settings );
346
 
347
+ return array_merge( $this->get_top_level_settings(), $settings );
348
+ }
349
+
350
+ /**
351
+ * Handle setting up dependencies for all of the fields.
352
+ *
353
+ * @since 5.1.9
354
+ *
355
+ * @param array[] $settings Which settings we are applying conditioanls to.
356
+ *
357
+ * @return array[]
358
+ */
359
+ public function apply_commerce_enabled_conditional( $settings ) {
360
+ $validate_if = new Tribe__Field_Conditional( static::$option_enable, 'tribe_is_truthy' );
361
  $fieldset_attributes = [
362
+ 'data-depends' => '#' . static::$option_enable . '-input',
363
  'data-condition-is-checked' => '',
364
  ];
365
 
379
  $commerce_field['validate_if'] = $validate_if;
380
  }
381
 
382
+ return $settings;
 
 
383
  }
384
 
385
  }
src/Tickets/Commerce/Shortcodes/Checkout_Shortcode.php ADDED
@@ -0,0 +1,84 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Shortcode [tec_tickets_checkout].
4
+ *
5
+ * @since 5.1.9
6
+ * @package TEC\Tickets\Commerce
7
+ */
8
+
9
+ namespace TEC\Tickets\Commerce\Shortcodes;
10
+
11
+ use TEC\Tickets\Commerce\Checkout;
12
+ use TEC\Tickets\Commerce\Cart;
13
+ use TEC\Tickets\Commerce\Module;
14
+ use TEC\Tickets\Commerce\Order;
15
+ use TEC\Tickets\Commerce\Status\Completed;
16
+ use TEC\Tickets\Commerce\Status\Created;
17
+ use TEC\Tickets\Commerce\Gateways\PayPal\Merchant;
18
+ use TEC\Tickets\Commerce\Gateways\PayPal\Settings;
19
+ use Tribe__Tickets__Editor__Template;
20
+ use TEC\Tickets\Commerce\Utils\Price;
21
+
22
+ /**
23
+ * Class for Shortcode Tribe_Tickets_Checkout.
24
+ *
25
+ * @since 5.1.9
26
+ * @package Tribe\Tickets\Shortcodes
27
+ */
28
+ class Checkout_Shortcode extends Shortcode_Abstract {
29
+
30
+ /**
31
+ * Id of the current shortcode for filtering purposes.
32
+ *
33
+ * @since 5.1.9
34
+ *
35
+ * @var string
36
+ */
37
+ public static $shortcode_id = 'checkout';
38
+
39
+ /**
40
+ * {@inheritDoc}
41
+ */
42
+ public function setup_template_vars() {
43
+ $items = tribe( Cart::class )->get_items_in_cart( true );
44
+ $sections = array_unique( array_filter( wp_list_pluck( $items, 'event_id' ) ) );
45
+ $sub_totals = array_filter( wp_list_pluck( $items, 'sub_total' ) );
46
+
47
+ $args = [
48
+ 'provider_id' => Module::class,
49
+ 'provider' => tribe( Module::class ),
50
+ 'items' => $items,
51
+ 'sections' => $sections,
52
+ 'total_value' => tribe_format_currency( Price::total( $sub_totals ) ),
53
+ 'must_login' => ! is_user_logged_in() && tribe( Module::class )->login_required(),
54
+ 'login_url' => tribe( Checkout::class )->get_login_url(),
55
+ 'registration_url' => tribe( Checkout::class )->get_registration_url(),
56
+ ];
57
+
58
+ $this->template_vars = $args;
59
+ }
60
+
61
+ /**
62
+ * {@inheritDoc}
63
+ */
64
+ public function get_html() {
65
+ $context = tribe_context();
66
+
67
+ if ( is_admin() && ! $context->doing_ajax() ) {
68
+ return '';
69
+ }
70
+
71
+ $args = $this->get_template_vars();
72
+
73
+ // Add the rendering attributes into global context.
74
+ $this->get_template()->add_template_globals( $args );
75
+
76
+ $html = $this->get_template()->template( 'checkout', $args, false );
77
+
78
+ // Enqueue assets.
79
+ tribe_asset_enqueue_group( 'tribe-tickets-commerce-checkout' );
80
+
81
+ return $html;
82
+ }
83
+
84
+ }
src/Tickets/Commerce/Shortcodes/Shortcode_Abstract.php ADDED
@@ -0,0 +1,151 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Shortcodes;
4
+
5
+ use TEC\Tickets\Commerce\Gateways\Manager;
6
+ use Tribe\Shortcode\Shortcode_Abstract as Common_Shortcode_Abstract;
7
+
8
+ /**
9
+ * Class Shortcode_Abstract
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce\Shortcodes
14
+ */
15
+ abstract class Shortcode_Abstract extends Common_Shortcode_Abstract {
16
+ /**
17
+ * Configures this instance of the shortcode.
18
+ *
19
+ * @since 5.1.9
20
+ */
21
+ public function __construct() {
22
+ $this->slug = static::get_wp_slug();
23
+ }
24
+
25
+ /**
26
+ * The Shortcode Slug inside of WordPress.
27
+ *
28
+ * @since 5.1.9
29
+ *
30
+ * @return string
31
+ */
32
+ public static function get_wp_slug() {
33
+ return 'tec_tickets_' . static::$shortcode_id;
34
+ }
35
+
36
+ /**
37
+ * Set of template variable used to generate this shortcode.
38
+ *
39
+ * @since 5.1.9
40
+ *
41
+ * @var array
42
+ */
43
+ protected $template_vars = [];
44
+
45
+ /**
46
+ * Stores the instance of the template engine that we will use for rendering the page.
47
+ *
48
+ * @since 5.1.9
49
+ *
50
+ * @var \Tribe__Template
51
+ */
52
+ protected $template;
53
+
54
+ /**
55
+ * Gets the template instance used to setup the rendering of the page.
56
+ *
57
+ * @since 5.1.9
58
+ *
59
+ * @return \Tribe__Template
60
+ */
61
+ public function get_template() {
62
+ if ( empty( $this->template ) ) {
63
+ $this->template = new \Tribe__Template();
64
+ $this->template->set_template_origin( \Tribe__Tickets__Main::instance() );
65
+ $this->template->set_template_folder( 'src/views/v2/commerce' );
66
+ $this->template->set_template_context_extract( true );
67
+ $this->template->set_template_folder_lookup( true );
68
+ }
69
+
70
+ return $this->template;
71
+ }
72
+
73
+ /**
74
+ * Method used to save the template vars for this instance of shortcode.
75
+ *
76
+ * @since 5.1.9
77
+ *
78
+ * @return void
79
+ */
80
+ abstract public function setup_template_vars();
81
+
82
+ /**
83
+ * Gets the current active gateway slug.
84
+ *
85
+ * @since 5.1.9
86
+ *
87
+ * @return string
88
+ */
89
+ public function get_gateway_slug() {
90
+ return (string) tribe( Manager::class )->get_current_gateway();
91
+ }
92
+
93
+ /**
94
+ * Calls the template vars setup and returns after filtering.
95
+ *
96
+ * @since 5.1.9
97
+ *
98
+ * @return array
99
+ */
100
+ public function get_template_vars() {
101
+ $this->setup_template_vars();
102
+
103
+ return (array) $this->filter_template_vars( $this->template_vars );
104
+ }
105
+
106
+ /**
107
+ * Enables filtering of the template variables.
108
+ *
109
+ * @since 5.1.9
110
+ *
111
+ * @param array $template_vars Which set of variables we are passing to the filters.
112
+ *
113
+ * @return array
114
+ */
115
+ public function filter_template_vars( array $template_vars = [] ) {
116
+ /**
117
+ * Applies a filter to template vars for this shortcode.
118
+ *
119
+ * @since 5.1.9
120
+ *
121
+ * @param array $template_vars Current set of callbacks for arguments.
122
+ * @param static $instance Which instance of shortcode we are dealing with.
123
+ */
124
+ $template_vars = apply_filters( 'tec_tickets_commerce_shortcode_page_template_vars', $template_vars, $this );
125
+
126
+ $shortcode_id = static::$shortcode_id;
127
+
128
+ /**
129
+ * Applies a filter to template vars for this shortcode, using ID.
130
+ *
131
+ * @since 5.1.9
132
+ *
133
+ * @param array $template_vars Current set of callbacks for arguments.
134
+ * @param static $instance Which instance of shortcode we are dealing with.
135
+ */
136
+ $template_vars = apply_filters( "tec_tickets_commerce_shortcode_{$shortcode_id}_page_template_vars", $template_vars, $this );
137
+
138
+ $gateway = $this->get_gateway_slug();
139
+
140
+ /**
141
+ * Applies a filter to template vars for this shortcode, using ID and gateway.
142
+ *
143
+ * @since 5.1.9
144
+ *
145
+ * @param array $template_vars Current set of callbacks for arguments.
146
+ * @param static $instance Which instance of shortcode we are dealing with.
147
+ */
148
+ return (array) apply_filters( "tec_tickets_commerce_success_shortcode_{$shortcode_id}_page_{$gateway}_template_vars", $template_vars, $this );
149
+ }
150
+
151
+ }
src/Tickets/Commerce/Shortcodes/Success_Shortcode.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Shortcode [tec_tickets_success].
4
+ *
5
+ * @since 5.1.9
6
+ * @package TEC\Tickets\Commerce
7
+ */
8
+
9
+ namespace TEC\Tickets\Commerce\Shortcodes;
10
+
11
+ use TEC\Tickets\Commerce\Module;
12
+ use TEC\Tickets\Commerce\Status\Completed;
13
+ use TEC\Tickets\Commerce\Success;
14
+
15
+ /**
16
+ * Class for Shortcode Tribe_Tickets_Checkout.
17
+ *
18
+ * @since 5.1.9
19
+ * @package Tribe\Tickets\Shortcodes
20
+ */
21
+ class Success_Shortcode extends Shortcode_Abstract {
22
+
23
+ /**
24
+ * Id of the current shortcode for filtering purposes.
25
+ *
26
+ * @since 5.1.9
27
+ *
28
+ * @var string
29
+ */
30
+ public static $shortcode_id = 'success';
31
+
32
+ /**
33
+ * {@inheritDoc}
34
+ */
35
+ public function setup_template_vars() {
36
+ $order_id = tribe_get_request_var( Success::$order_id_query_arg );
37
+ $order = tec_tc_orders()->by_args( [
38
+ 'status' => 'any',
39
+ 'gateway_order_id' => $order_id,
40
+ ] )->first();
41
+
42
+ $args = [
43
+ 'provider_id' => Module::class,
44
+ 'provider' => tribe( Module::class ),
45
+ 'order_id' => $order_id,
46
+ 'order' => $order,
47
+ ];
48
+
49
+ $this->template_vars = $args;
50
+ }
51
+
52
+ /**
53
+ * {@inheritDoc}
54
+ */
55
+ public function get_html() {
56
+ $context = tribe_context();
57
+
58
+ if ( is_admin() && ! $context->doing_ajax() ) {
59
+ return '';
60
+ }
61
+
62
+ $args = $this->get_template_vars();
63
+
64
+ // Add the rendering attributes into global context.
65
+ $this->get_template()->add_template_globals( $args );
66
+
67
+ $html = $this->get_template()->template( 'success', $args, false );
68
+
69
+ // Enqueue assets.
70
+ tribe_asset_enqueue_group( 'tec-tickets-commerce-success' );
71
+
72
+ return $html;
73
+ }
74
+
75
+ }
src/Tickets/Commerce/Status/Action_Required.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ /**
6
+ * Class Pending.
7
+ *
8
+ * This is a payment that has begun, but is not complete. An example of this is someone who has filled out the checkout
9
+ * form and then gone to Gateway for payment. We have the record of sale, but they haven't completed their payment yet.
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce\Status
14
+ */
15
+ class Action_Required extends Status_Abstract {
16
+ /**
17
+ * Slug for this Status.
18
+ *
19
+ * @since 5.1.9
20
+ *
21
+ * @var string
22
+ */
23
+ const SLUG = 'action-required';
24
+
25
+ /**
26
+ * {@inheritdoc}
27
+ */
28
+ public function get_name() {
29
+ return __( 'Action Required', 'event-tickets' );
30
+ }
31
+
32
+ /**
33
+ * {@inheritdoc}
34
+ */
35
+ protected $flags = [
36
+ 'incomplete',
37
+ 'trigger_option',
38
+ 'attendee_generation',
39
+ 'stock_reduced',
40
+ 'count_attendee',
41
+ 'count_incomplete',
42
+ 'count_sales',
43
+ ];
44
+
45
+ /**
46
+ * {@inheritdoc}
47
+ */
48
+ protected $wp_arguments = [
49
+ 'public' => true,
50
+ 'exclude_from_search' => false,
51
+ 'show_in_admin_all_list' => true,
52
+ 'show_in_admin_status_list' => true,
53
+ ];
54
+ }
src/Tickets/Commerce/Status/Approved.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ /**
6
+ * Class Pending.
7
+ *
8
+ * This is a payment that has begun, but is not complete. An example of this is someone who has filled out the checkout
9
+ * form and then gone to Gateway for payment. We have the record of sale, but they haven't completed their payment yet.
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce\Status
14
+ */
15
+ class Approved extends Status_Abstract {
16
+ /**
17
+ * Slug for this Status.
18
+ *
19
+ * @since 5.1.9
20
+ *
21
+ * @var string
22
+ */
23
+ const SLUG = 'approved';
24
+
25
+ /**
26
+ * {@inheritdoc}
27
+ */
28
+ public function get_name() {
29
+ return __( 'Approved', 'event-tickets' );
30
+ }
31
+
32
+ /**
33
+ * {@inheritdoc}
34
+ */
35
+ protected $flags = [
36
+ 'incomplete',
37
+ 'trigger_option',
38
+ 'attendee_generation',
39
+ 'stock_reduced',
40
+ 'count_attendee',
41
+ 'count_incomplete',
42
+ 'count_sales',
43
+ ];
44
+
45
+ /**
46
+ * {@inheritdoc}
47
+ */
48
+ protected $wp_arguments = [
49
+ 'public' => true,
50
+ 'exclude_from_search' => false,
51
+ 'show_in_admin_all_list' => true,
52
+ 'show_in_admin_status_list' => true,
53
+ ];
54
+ }
src/Tickets/Commerce/Status/Completed.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace TEC\Tickets\Commerce\Status;
3
+
4
+ /**
5
+ * Class Denied.
6
+ *
7
+ * This is the status we use to mark a given order as paid and delivered in our Tickets Commerce system.
8
+ *
9
+ * @since 5.1.9
10
+ *
11
+ * @package TEC\Tickets\Commerce\Status
12
+ */
13
+ class Completed extends Status_Abstract {
14
+ /**
15
+ * Slug for this Status.
16
+ *
17
+ * @since 5.1.9
18
+ *
19
+ * @var string
20
+ */
21
+ const SLUG = 'completed';
22
+
23
+ /**
24
+ * {@inheritdoc}
25
+ */
26
+ public function get_name() {
27
+ return __( 'Completed', 'event-tickets' );
28
+ }
29
+
30
+ /**
31
+ * {@inheritdoc}
32
+ */
33
+ protected $flags = [
34
+ 'complete',
35
+ 'trigger_option',
36
+ 'attendee_generation',
37
+ 'attendee_dispatch',
38
+ 'stock_reduced',
39
+ 'count_attendee',
40
+ 'count_completed',
41
+ 'count_sales',
42
+ ];
43
+
44
+ /**
45
+ * {@inheritdoc}
46
+ */
47
+ protected $wp_arguments = [
48
+ 'public' => true,
49
+ 'exclude_from_search' => false,
50
+ 'show_in_admin_all_list' => true,
51
+ 'show_in_admin_status_list' => true,
52
+ ];
53
+
54
+ }
src/Tickets/Commerce/Status/Created.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace TEC\Tickets\Commerce\Status;
3
+
4
+ /**
5
+ * Class Created.
6
+ *
7
+ * This is the first Status any order will have.
8
+ *
9
+ * Used for handling the Orders that were Created in the Tickets Commerce System but never got to Pending.
10
+ * Normally the change to Pending will depend on the Gateway.
11
+ *
12
+ * @since 5.1.9
13
+ *
14
+ * @package TEC\Tickets\Commerce\Status
15
+ */
16
+ class Created extends Status_Abstract {
17
+ /**
18
+ * Slug for this Status.
19
+ *
20
+ * @since 5.1.9
21
+ *
22
+ * @var string
23
+ */
24
+ const SLUG = 'created';
25
+
26
+ /**
27
+ * {@inheritdoc}
28
+ */
29
+ public function get_name() {
30
+ return __( 'Created', 'event-tickets' );
31
+ }
32
+
33
+ /**
34
+ * {@inheritdoc}
35
+ */
36
+ protected $flags = [
37
+ 'incomplete',
38
+ 'trigger_option',
39
+ ];
40
+
41
+ /**
42
+ * {@inheritdoc}
43
+ */
44
+ protected $wp_arguments = [
45
+ 'public' => true,
46
+ 'exclude_from_search' => false,
47
+ 'show_in_admin_all_list' => true,
48
+ 'show_in_admin_status_list' => true,
49
+ ];
50
+ }
src/Tickets/Commerce/Status/Denied.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ /**
6
+ * Class Denied.
7
+ *
8
+ * Used for handling Orders where the payment process failed, whether it be a credit card rejection or some other error.
9
+ *
10
+ * @since 5.1.9
11
+ *
12
+ * @package TEC\Tickets\Commerce\Status
13
+ */
14
+ class Denied extends Status_Abstract {
15
+ /**
16
+ * Slug for this Status.
17
+ *
18
+ * @since 5.1.9
19
+ *
20
+ * @var string
21
+ */
22
+ const SLUG = 'denied';
23
+
24
+ /**
25
+ * {@inheritdoc}
26
+ */
27
+ public function get_name() {
28
+ return __( 'Denied', 'event-tickets' );
29
+ }
30
+
31
+ /**
32
+ * {@inheritdoc}
33
+ */
34
+ protected $flags = [
35
+ 'incomplete',
36
+ 'warning',
37
+ 'count_canceled',
38
+ ];
39
+
40
+ /**
41
+ * {@inheritdoc}
42
+ */
43
+ protected $wp_arguments = [
44
+ 'public' => true,
45
+ 'exclude_from_search' => false,
46
+ 'show_in_admin_all_list' => true,
47
+ 'show_in_admin_status_list' => true,
48
+ ];
49
+ }
src/Tickets/Commerce/Status/Not_Completed.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ /**
6
+ * Class Denied.
7
+ *
8
+ * Used for handling Orders where Pending payment but never completed it, becoming Abandoned after a week..
9
+ *
10
+ * @since 5.1.9
11
+ *
12
+ * @package TEC\Tickets\Commerce\Status
13
+ */
14
+ class Not_Completed extends Status_Abstract {
15
+ /**
16
+ * Slug for this Status.
17
+ *
18
+ * @since 5.1.9
19
+ *
20
+ * @var string
21
+ */
22
+ const SLUG = 'not-completed';
23
+
24
+ /**
25
+ * {@inheritdoc}
26
+ */
27
+ public function get_name() {
28
+ return __( 'Not Completed', 'event-tickets' );
29
+ }
30
+
31
+ /**
32
+ * {@inheritdoc}
33
+ */
34
+ protected $flags = [
35
+ 'incomplete',
36
+ 'warning',
37
+ 'revert_stock',
38
+ 'archive_attendee'
39
+ ];
40
+
41
+ /**
42
+ * {@inheritdoc}
43
+ */
44
+ protected $wp_arguments = [
45
+ 'public' => true,
46
+ 'exclude_from_search' => false,
47
+ 'show_in_admin_all_list' => true,
48
+ 'show_in_admin_status_list' => true,
49
+ ];
50
+ }
src/Tickets/Commerce/Status/Pending.php ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ use TEC\Tickets\Commerce\Module;
6
+ use TEC\Tickets\Commerce\Ticket;
7
+ use WP_Error;
8
+
9
+ /**
10
+ * Class Pending.
11
+ *
12
+ * This is a payment that has begun, but is not complete. An example of this is someone who has filled out the checkout
13
+ * form and then gone to Gateway for payment. We have the record of sale, but they haven't completed their payment yet.
14
+ *
15
+ * @since 5.1.9
16
+ *
17
+ * @package TEC\Tickets\Commerce\Status
18
+ */
19
+ class Pending extends Status_Abstract {
20
+ /**
21
+ * Slug for this Status.
22
+ *
23
+ * @since 5.1.9
24
+ *
25
+ * @var string
26
+ */
27
+ const SLUG = 'pending';
28
+
29
+ /**
30
+ * {@inheritdoc}
31
+ */
32
+ public function get_name() {
33
+ return __( 'Pending', 'event-tickets' );
34
+ }
35
+
36
+ /**
37
+ * {@inheritdoc}
38
+ */
39
+ protected $flags = [
40
+ 'generate_attendees',
41
+ 'reduce_stock',
42
+ 'count_attendee',
43
+ 'count_incomplete',
44
+ 'count_sales',
45
+ ];
46
+
47
+ /**
48
+ * {@inheritdoc}
49
+ */
50
+ protected $wp_arguments = [
51
+ 'public' => true,
52
+ 'exclude_from_search' => false,
53
+ 'show_in_admin_all_list' => true,
54
+ 'show_in_admin_status_list' => true,
55
+ ];
56
+
57
+ /**
58
+ * {@inheritdoc}
59
+ */
60
+ public function can_apply_to( $order ) {
61
+ $status = parent::can_apply_to( $order );
62
+
63
+ // If the parent status or abstract has an error already we dont even run.
64
+ if ( is_wp_error( $status ) ) {
65
+ return $status;
66
+ }
67
+
68
+ $order = tec_tc_get_order( $order );
69
+
70
+ // Since there are no cart items we can do anything.
71
+ if ( empty( $order->cart_items ) || ! is_array( $order->cart_items ) ) {
72
+ return true;
73
+ }
74
+
75
+ foreach ( $order->cart_items as $item ) {
76
+ // Skip if we dont have a ticket id.
77
+ if ( empty( $item['ticket_id'] ) ) {
78
+ continue;
79
+ }
80
+
81
+ // If item quantity is empty, continue
82
+ if ( empty( $item['quantity'] ) ) {
83
+ continue;
84
+ }
85
+
86
+ /** @var \Tribe__Tickets__Ticket_Object $ticket_type */
87
+ $ticket = tribe( Ticket::class )->get_ticket( $item['ticket_id'] );
88
+
89
+ if ( null === $ticket ) {
90
+ return new WP_Error(
91
+ 'tec-tc-invalid-ticket-id',
92
+ sprintf( __( 'This order contained an invalid Ticket (ID: %1$d)', 'event-tickets' ), $item['ticket_id'] ),
93
+ [
94
+ 'ticket' => $item['ticket_id'],
95
+ 'order' => $order,
96
+ 'new_status' => $this
97
+ ]
98
+ );
99
+ }
100
+
101
+ // Get the event this tickets is for
102
+ $post = $ticket->get_event();
103
+
104
+ if ( empty( $post ) ) {
105
+ return new WP_Error(
106
+ 'tec-tc-invalid-event-id',
107
+ sprintf( __( 'This order contained a Ticket with an invalid Event (Event ID: %1$d)', 'event-tickets' ), $item['ticket_id'] ),
108
+ [
109
+ 'ticket' => $item['ticket_id'],
110
+ 'order' => $order,
111
+ 'new_status' => $this
112
+ ]
113
+ );
114
+ }
115
+
116
+ $qty = max( (int) $item['quantity'], 0 );
117
+
118
+ if ( $qty === 0 ) {
119
+ return new WP_Error(
120
+ 'tec-tc-cannot-purchase-zero',
121
+ sprintf( __( 'Cannot purchase zero of "%1$s"', 'event-tickets' ), $ticket->name ),
122
+ [
123
+ 'ticket' => $item['ticket_id'],
124
+ 'order' => $order,
125
+ 'new_status' => $this
126
+ ]
127
+ );
128
+ }
129
+
130
+ // Throw an error if Qty is bigger then Remaining
131
+ if ( $ticket->managing_stock() ) {
132
+ $inventory = (int) $ticket->inventory();
133
+ $inventory_is_not_unlimited = - 1 !== $inventory;
134
+
135
+ if ( $inventory_is_not_unlimited && $qty > $inventory ) {
136
+ return new WP_Error(
137
+ 'tec-tc-ticket-insufficient-stock',
138
+ sprintf( __( 'Insufficient stock for "%1$s"', 'event-tickets' ), $ticket->name ),
139
+ [
140
+ 'ticket' => $item['ticket_id'],
141
+ 'order' => $order,
142
+ 'new_status' => $this
143
+ ]
144
+ );
145
+ }
146
+ }
147
+
148
+ /**
149
+ * @todo Determine if we need to check for the sale date.
150
+ */
151
+ }
152
+
153
+ return true;
154
+ }
155
+ }
src/Tickets/Commerce/Status/Refunded.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ /**
6
+ * Class Refunded.
7
+ *
8
+ *
9
+ * @since 5.1.9
10
+ *
11
+ * @package TEC\Tickets\Commerce\Status
12
+ */
13
+ class Refunded extends Status_Abstract {
14
+ /**
15
+ * Slug for this Status.
16
+ *
17
+ * @since 5.1.9
18
+ *
19
+ * @var string
20
+ */
21
+ const SLUG = 'refunded';
22
+
23
+ /**
24
+ * {@inheritdoc}
25
+ */
26
+ public function get_name() {
27
+ return __( 'Refunded', 'event-tickets' );
28
+ }
29
+
30
+ /**
31
+ * {@inheritdoc}
32
+ */
33
+ protected $flags = [
34
+ 'warning',
35
+ 'count_refunded',
36
+ ];
37
+
38
+ /**
39
+ * {@inheritdoc}
40
+ */
41
+ protected $wp_arguments = [
42
+ 'public' => true,
43
+ 'exclude_from_search' => false,
44
+ 'show_in_admin_all_list' => true,
45
+ 'show_in_admin_status_list' => true,
46
+ ];
47
+ }
src/Tickets/Commerce/Status/Reversed.php ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ /**
6
+ * Class Refunded.
7
+ *
8
+ *
9
+ * @since 5.1.9
10
+ *
11
+ * @package TEC\Tickets\Commerce\Status
12
+ */
13
+ class Reversed extends Status_Abstract {
14
+ /**
15
+ * Slug for this Status.
16
+ *
17
+ * @since 5.1.9
18
+ *
19
+ * @var string
20
+ */
21
+ const SLUG = 'reversed';
22
+
23
+ /**
24
+ * {@inheritdoc}
25
+ */
26
+ public function get_name() {
27
+ return __( 'Reversed', 'event-tickets' );
28
+ }
29
+
30
+ /**
31
+ * {@inheritdoc}
32
+ */
33
+ protected $flags = [
34
+ 'warning',
35
+ 'count_refunded',
36
+ ];
37
+
38
+ /**
39
+ * {@inheritdoc}
40
+ */
41
+ protected $wp_arguments = [
42
+ 'public' => true,
43
+ 'exclude_from_search' => false,
44
+ 'show_in_admin_all_list' => true,
45
+ 'show_in_admin_status_list' => true,
46
+ ];
47
+ }
src/Tickets/Commerce/Status/Status_Abstract.php ADDED
@@ -0,0 +1,184 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ use TEC\Tickets\Commerce;
6
+
7
+ /**
8
+ * Class Status_Abstract
9
+ *
10
+ * @since 5.1.9
11
+ *
12
+ * @package TEC\Tickets\Commerce\Status
13
+ */
14
+ abstract class Status_Abstract implements Status_Interface {
15
+
16
+ /**
17
+ * Flags associated with this status, important to remember that the Flag Actions will be triggered in the order
18
+ * that these flags are returned.
19
+ *
20
+ * @see static::filter_get_flags
21
+ *
22
+ * List of pre-existing flags from TPP/Tribe Commerce:
23
+ *
24
+ * - incomplete
25
+ * - warning
26
+ * - attendee_generation
27
+ * - attendee_dispatch
28
+ * - stock_reduced
29
+ * - count_attendee
30
+ * - count_sales
31
+ * - count_completed
32
+ * - count_canceled
33
+ * - count_incomplete
34
+ * - count_refunded
35
+ * - count_not_going
36
+ *
37
+ * @since 5.1.9
38
+ *
39
+ * @var string[]
40
+ */
41
+ protected $flags = [];
42
+
43
+ /**
44
+ * Which arguments will be used to register this Status with WordPress.
45
+ *
46
+ * @since 5.1.9
47
+ *
48
+ * @var array
49
+ */
50
+ protected $wp_arguments = [
51
+
52
+ ];
53
+
54
+ /**
55
+ * {@inheritdoc}
56
+ */
57
+ public function get_slug() {
58
+ return static::SLUG;
59
+ }
60
+
61
+ /**
62
+ * {@inheritdoc}
63
+ */
64
+ public function get_wp_slug() {
65
+ return 'tec-' . Commerce::ABBR . '-' . static::SLUG;
66
+ }
67
+
68
+ /**
69
+ * {@inheritdoc}
70
+ */
71
+ public function get_flags() {
72
+ return $this->filter_get_flags( $this->flags );
73
+ }
74
+
75
+ /**
76
+ * {@inheritdoc}
77
+ */
78
+ public function filter_get_flags( $flags ) {
79
+ /**
80
+ * Allows filtering of which flags are associated with this Status.
81
+ *
82
+ * @since 5.1.9
83
+ *
84
+ * @param string[] $flags Set of flags we will use.
85
+ * @param static $status Which status these flags are associated with.
86
+ */
87
+ $flags = apply_filters( 'tec_tickets_commerce_order_status_get_flags', $flags, $this );
88
+
89
+ /**
90
+ * Allows filtering of which flags are associated with this Status.
91
+ *
92
+ * @since 5.1.9
93
+ *
94
+ * @param string[] $flags Set of flags we will use.
95
+ * @param static $status Which status these flags are associated with.
96
+ */
97
+ return apply_filters( "tec_tickets_commerce_order_status_{$this->get_slug()}_get_flags", $flags, $this );
98
+ }
99
+
100
+ /**
101
+ * {@inheritdoc}
102
+ */
103
+ public function has_flags( $flags, $operator = 'AND' ) {
104
+ $intersection = array_intersect( (array) $flags, $this->get_flags() );
105
+
106
+ if ( 'AND' === strtoupper( $operator ) ) {
107
+ return count( $flags ) === count( $intersection );
108
+ }
109
+
110
+ return 0 < count( $intersection );
111
+ }
112
+
113
+ /**
114
+ * When trying to get a param that doesnt exist we test if it's a flag.
115
+ *
116
+ * @since 5.1.9
117
+ *
118
+ * @param string $name Which flag to check.
119
+ *
120
+ * @return bool
121
+ */
122
+ public function __get( $name ) {
123
+ return $this->has_flags( $name );
124
+ }
125
+
126
+ /**
127
+ * {@inheritdoc}
128
+ */
129
+ public function can_apply_to( $order ) {
130
+ return true;
131
+ }
132
+
133
+ /**
134
+ * {@inheritdoc}
135
+ */
136
+ public function get_wp_arguments() {
137
+ $this->setup_wp_arguments();
138
+
139
+ $defaults = [
140
+
141
+ ];
142
+ $arguments = array_merge( $defaults, $this->wp_arguments );
143
+
144
+ return $this->filter_wp_arguments( $arguments );
145
+ }
146
+
147
+ /**
148
+ * {@inheritdoc}
149
+ */
150
+ public function filter_wp_arguments( array $arguments = [] ) {
151
+ /**
152
+ * Allows filtering of which arguments are associated with this Status registering in WP.
153
+ *
154
+ * @since 5.1.9
155
+ *
156
+ * @param array $arguments Which arguments we are passing.
157
+ * @param static $status Which status these arguments are associated with.
158
+ */
159
+ $arguments = apply_filters( 'tec_tickets_commerce_order_status_get_wp_arguments', $arguments, $this );
160
+
161
+ /**
162
+ * Allows filtering of which arguments are associated with this Status registering in WP.
163
+ *
164
+ * @since 5.1.9
165
+ *
166
+ * @param array $arguments Which arguments we are passing.
167
+ * @param static $status Which status these arguments are associated with.
168
+ */
169
+ return apply_filters( "tec_tickets_commerce_order_status_{$this->get_slug()}_get_wp_arguments", $arguments, $this );
170
+
171
+ }
172
+
173
+ /**
174
+ * Allows the configuration of the wp arguments before getting it, specifically used for dynamic arguments like
175
+ * the ones that will require a translation.
176
+ *
177
+ * @since 5.1.9
178
+ *
179
+ */
180
+ protected function setup_wp_arguments() {
181
+ $this->wp_arguments['label'] = $this->get_name();
182
+ $this->wp_arguments['label_count'] = _n_noop( $this->get_name() . ' <span class="count">(%s)</span>', $this->get_name() . ' <span class="count">(%s)</span>', 'event-tickets' );
183
+ }
184
+ }
src/Tickets/Commerce/Status/Status_Handler.php ADDED
@@ -0,0 +1,347 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ use TEC\Tickets\Commerce\Order;
6
+
7
+ /**
8
+ * Class Status_Handler
9
+ *
10
+ * @since 5.1.9
11
+ *
12
+ * @package TEC\Tickets\Commerce\Status
13
+ */
14
+ class Status_Handler extends \tad_DI52_ServiceProvider {
15
+ /**
16
+ * Statuses registered.
17
+ *
18
+ * @since 5.1.9
19
+ *
20
+ * @var Status_Interface[]
21
+ */
22
+ protected $statuses = [];
23
+
24
+ /**
25
+ * Which classes we will load for order statuses by default.
26
+ *
27
+ * @since 5.1.9
28
+ *
29
+ * @var string[]
30
+ */
31
+ protected $default_statuses = [
32
+ Created::class,
33
+ Completed::class,
34
+ Denied::class,
35
+ Not_Completed::class,
36
+ Pending::class,
37
+ Refunded::class,
38
+ Reversed::class,
39
+ Undefined::class,
40
+ Voided::class,
41
+ ];
42
+
43
+ /**
44
+ * Which status every order will be created with.
45
+ *
46
+ * @since 5.1.9
47
+ *
48
+ * @var string
49
+ */
50
+ protected $insert_status = Created::class;
51
+
52
+ /**
53
+ * Sets up all the Status instances for the Classes registered in $default_statuses.
54
+ *
55
+ * @since 5.1.9
56
+ */
57
+ public function register() {
58
+ foreach ( $this->default_statuses as $status_class ) {
59
+ // Spawn the new instance.
60
+ $status = new $status_class;
61
+
62
+ // Register as a singleton for internal ease of use.
63
+ $this->container->singleton( $status_class, $status );
64
+
65
+ // Collect this particular status instance in this class.
66
+ $this->register_status( $status );
67
+ }
68
+
69
+ $this->container->singleton( static::class, $this );
70
+ }
71
+
72
+ /**
73
+ * Which status an order will be created with.
74
+ *
75
+ * @since 5.1.9
76
+ *
77
+ * @return Status_Interface
78
+ */
79
+ public function get_insert_status() {
80
+ return $this->container->make( $this->insert_status );
81
+ }
82
+
83
+ /**
84
+ * Gets the statuses registered.
85
+ *
86
+ * @since 5.1.9
87
+ *
88
+ * @return Status_Interface[]
89
+ */
90
+ public function get_all() {
91
+ return $this->statuses;
92
+ }
93
+
94
+ /**
95
+ * Fetches the first status registered with a given slug.
96
+ *
97
+ * @since 5.1.9
98
+ *
99
+ * @param string $slug
100
+ *
101
+ * @return Status_Interface|null
102
+ */
103
+ public function get_by_slug( $slug ) {
104
+ foreach ( $this->get_all() as $status ) {
105
+ if ( $status->get_slug() === $slug ) {
106
+ return $status;
107
+ }
108
+ }
109
+
110
+ return null;
111
+ }
112
+
113
+ /**
114
+ * Fetches the first status registered with a given wp slug.
115
+ *
116
+ * @since 5.1.9
117
+ *
118
+ * @param string $slug
119
+ *
120
+ * @return Status_Interface
121
+ */
122
+ public function get_by_wp_slug( $slug ) {
123
+ foreach ( $this->get_all() as $status ) {
124
+ if ( $status->get_wp_slug() === $slug ) {
125
+ return $status;
126
+ }
127
+ }
128
+
129
+ return null;
130
+ }
131
+
132
+ /**
133
+ * Fetches the status registered with a given class.
134
+ *
135
+ * @since 5.1.9
136
+ *
137
+ * @param string $class_name
138
+ *
139
+ * @return Status_Interface
140
+ */
141
+ public function get_by_class( $class_name ) {
142
+ foreach ( $this->get_all() as $status ) {
143
+ $status_class = get_class( $status );
144
+
145
+ if ( $status_class === $class_name ) {
146
+ return $status;
147
+ }
148
+ }
149
+
150
+ return null;
151
+ }
152
+
153
+ /**
154
+ * Using `wp_list_filter` fetches which Statuses match the flags and operator passed.
155
+ *
156
+ * @since 5.1.9
157
+ *
158
+ * @param string|array $flags
159
+ * @param string $operator
160
+ *
161
+ * @return Status_Interface[]
162
+ */
163
+ public function get_by_flags( $flags, $operator = 'AND' ) {
164
+ $statuses = wp_list_filter( $this->get_all(), (array) $flags, $operator );
165
+
166
+ return $statuses;
167
+ }
168
+
169
+ /**
170
+ * Register a given status into the Handler.
171
+ *
172
+ * @since 5.1.9
173
+ *
174
+ * @param Status_Interface $status Which status we are registering.
175
+ */
176
+ public function register_status( Status_Interface $status ) {
177
+ $this->statuses[] = $status;
178
+ }
179
+
180
+ /**
181
+ * Registers the post statuses with WordPress.
182
+ *
183
+ * @since 5.1.9
184
+ */
185
+ public function register_order_statuses() {
186
+
187
+ $statuses = $this->get_all();
188
+
189
+ foreach ( $statuses as $status ) {
190
+ register_post_status(
191
+ $status->get_wp_slug(),
192
+ $status->get_wp_arguments()
193
+ );
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Fires when a post is transitioned from one status to another so that we can make another hook that is namespaced.
199
+ *
200
+ * @since 5.1.9
201
+ *
202
+ * @param string $new_status New post status.
203
+ * @param string $old_status Old post status.
204
+ * @param \WP_Post $post Post object.
205
+ */
206
+ public function transition_order_post_status_hooks( $new_status, $old_status, $post ) {
207
+ if ( Order::POSTTYPE !== $post->post_type ) {
208
+ return;
209
+ }
210
+
211
+ $new_status = $this->get_by_wp_slug( $new_status );
212
+ $old_status = $this->get_by_wp_slug( $old_status );
213
+
214
+ if ( ! isset( $new_status ) ) {
215
+ return;
216
+ }
217
+
218
+ /**
219
+ * Fires when a post is transitioned from one status to another.
220
+ *
221
+ * @since 5.1.9
222
+ *
223
+ * @param Status_Interface $new_status New post status.
224
+ * @param Status_Interface|null $old_status Old post status.
225
+ * @param \WP_Post $post Post object.
226
+ */
227
+ do_action( 'tec_tickets_commerce_order_status_transition', $new_status, $old_status, $post );
228
+
229
+ if ( $old_status ) {
230
+ /**
231
+ * Fires when a post is transitioned from one status to another.
232
+ *
233
+ * The dynamic portions of the hook name, `$new_status` and `$old_status`,
234
+ * refer to the old and new post statuses, respectively.
235
+ *
236
+ * @since 5.1.9
237
+ *
238
+ * @param Status_Interface $new_status New post status.
239
+ * @param Status_Interface|null $old_status Old post status.
240
+ * @param \WP_Post $post Post object.
241
+ */
242
+ do_action( "tec_tickets_commerce_order_status_{$old_status->get_slug()}_to_{$new_status->get_slug()}", $new_status, $old_status, $post );
243
+ }
244
+
245
+ /**
246
+ * Fires when a post is transitioned from one status to another.
247
+ *
248
+ * The dynamic portions of the hook name, `$new_status`, refer to the new post status.
249
+ *
250
+ * @since 5.1.9
251
+ *
252
+ * @param Status_Interface $new_status New post status.
253
+ * @param Status_Interface|null $old_status Old post status.
254
+ * @param \WP_Post $post Post object.
255
+ */
256
+ do_action( "tec_tickets_commerce_order_status_{$new_status->get_slug()}", $new_status, $old_status, $post );
257
+
258
+ $this->trigger_status_hooks_by_flags( $new_status, $old_status, $post );
259
+ }
260
+
261
+ /**
262
+ * When a given order is transitioned from a status to another we will pull all it's flags and trigger a couple of
263
+ * extra hooks so that all the required actions can be triggered, examples:
264
+ * - Generating Attendees
265
+ * - Re-stocking ticket/event
266
+ * - Throwing a warning
267
+ * - Handling Email communication
268
+ *
269
+ * @since 5.1.9
270
+ *
271
+ * @param Status_Interface $new_status New post status.
272
+ * @param Status_Interface|null $old_status Old post status.
273
+ * @param \WP_Post $post Post object.
274
+ */
275
+ public function trigger_status_hooks_by_flags( Status_Interface $new_status, $old_status, $post ) {
276
+ $flags = $new_status->get_flags();
277
+
278
+ foreach ( $flags as $flag ) {
279
+ /**
280
+ * Fires when a post is transitioned from one status to another and contains a given flag.
281
+ *
282
+ * The dynamic portions of the hook name, `$flag`, refer to a given flag that this new status contains.
283
+ *
284
+ * @since 5.1.9
285
+ *
286
+ * @param Status_Interface $new_status New post status.
287
+ * @param Status_Interface|null $old_status Old post status.
288
+ * @param \WP_Post $post Post object.
289
+ */
290
+ do_action( "tec_tickets_commerce_order_status_flag_{$flag}", $new_status, $old_status, $post );
291
+
292
+ /**
293
+ * Fires when a post is transitioned from one status to another and contains a given flag.
294
+ *
295
+ * The dynamic portions of the hook name, `$new_status` and `$flag`, refer to the new post status and a
296
+ * given flag that this new status contains.
297
+ *
298
+ * @since 5.1.9
299
+ *
300
+ * @param Status_Interface $new_status New post status.
301
+ * @param Status_Interface|null $old_status Old post status.
302
+ * @param \WP_Post $post Post object.
303
+ */
304
+ do_action( "tec_tickets_commerce_order_status_{$new_status->get_slug()}_flag_{$flag}", $new_status, $old_status, $post );
305
+ }
306
+ }
307
+
308
+ /**
309
+ * Whether an order status will mark a transaction as completed one way or another.
310
+ *
311
+ * A transaction might be completed because it successfully completed, because it
312
+ * was refunded or denied.
313
+ *
314
+ * @since 5.1.9
315
+ *
316
+ * @param string $payment_status
317
+ *
318
+ * @return bool
319
+ */
320
+ public function is_complete_transaction_status( $payment_status ) {
321
+ $statuses = $this->get_by_flags( [ 'count_completed', 'count_refunded' ], 'OR' );
322
+ $statuses = array_map( static function ( $status ) {
323
+ return $status->get_slug();
324
+ }, $statuses );
325
+
326
+ return in_array( $payment_status, $statuses, true );
327
+
328
+ }
329
+
330
+ /**
331
+ * Whether an order status will mark a transaction as generating revenue or not.
332
+ *
333
+ * @since 5.1.9
334
+ *
335
+ * @param string $payment_status
336
+ *
337
+ * @return bool
338
+ */
339
+ public function is_revenue_generating_status( $payment_status ) {
340
+ $statuses = $this->get_by_flags( 'count_completed' );
341
+ $statuses = array_map( static function ( $status ) {
342
+ return $status->get_slug();
343
+ }, $statuses );
344
+
345
+ return in_array( $payment_status, $statuses, true );
346
+ }
347
+ }
src/Tickets/Commerce/Status/Status_Interface.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ /**
6
+ * Class Status_Interface
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets\Commerce\Status
11
+ */
12
+ interface Status_Interface {
13
+ /**
14
+ * Gets the slug of this status in WordPress
15
+ *
16
+ * @since 5.1.9
17
+ *
18
+ * @return string
19
+ */
20
+ public function get_wp_slug();
21
+
22
+ /**
23
+ * Filters and returns the flags for the get_flags method.
24
+ *
25
+ * @since 5.1.9
26
+ *
27
+ * @param string[] $flags Which flags will be filtered.
28
+ *
29
+ * @return string[]
30
+ */
31
+ public function filter_get_flags( $flags );
32
+
33
+ /**
34
+ * Gets the name of this status.
35
+ *
36
+ * @since 5.1.9
37
+ *
38
+ * @return string
39
+ */
40
+ public function get_name();
41
+
42
+ /**
43
+ * Gets the constant slug of this status.
44
+ *
45
+ * @since 5.1.9
46
+ *
47
+ * @return string
48
+ */
49
+ public function get_slug();
50
+
51
+ /**
52
+ * Gets the flags associated with this status.
53
+ *
54
+ * @since 5.1.9
55
+ *
56
+ * @return array
57
+ */
58
+ public function get_flags();
59
+
60
+ /**
61
+ * Determines if this Status has a set of flags.
62
+ *
63
+ * @since 5.1.9
64
+ *
65
+ * @param array|string $flags Which flags we are testing.
66
+ * @param string $operator Operator for the test.
67
+ *
68
+ * @return bool
69
+ */
70
+ public function has_flags( $flags, $operator = 'AND' );
71
+
72
+
73
+ /**
74
+ * Determines if a given order can be modified to this status.
75
+ *
76
+ * @since 5.1.9
77
+ *
78
+ * @param int|\WP_Post $order Which order we are testing against.
79
+ *
80
+ * @return boolean|\WP_Error
81
+ */
82
+ public function can_apply_to( $order );
83
+
84
+ /**
85
+ * Filters the WP arguments used to register the status.
86
+ *
87
+ * @since 5.1.9
88
+ *
89
+ * @param array $arguments Which arguments we are passing.
90
+ *
91
+ * @return array
92
+ */
93
+ public function filter_wp_arguments( array $arguments = [] );
94
+
95
+ /**
96
+ * Fetches the WordPress arguments required to register this Status.
97
+ *
98
+ * @since 5.1.9
99
+ *
100
+ * @return array
101
+ */
102
+ public function get_wp_arguments();
103
+ }
src/Tickets/Commerce/Status/Undefined.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ /**
6
+ * Class Undefined.
7
+ *
8
+ * Orders that landed on Undefined are just broken in some way that we cannot define.
9
+ *
10
+ * @since 5.1.9
11
+ *
12
+ * @package TEC\Tickets\Commerce\Status
13
+ */
14
+ class Undefined extends Status_Abstract {
15
+ /**
16
+ * Slug for this Status.
17
+ *
18
+ * @since 5.1.9
19
+ *
20
+ * @var string
21
+ */
22
+ const SLUG = 'undefined';
23
+
24
+ /**
25
+ * {@inheritdoc}
26
+ */
27
+ public function get_name() {
28
+ return __( 'Undefined', 'event-tickets' );
29
+ }
30
+
31
+ /**
32
+ * {@inheritdoc}
33
+ */
34
+ protected $flags = [
35
+ 'count_incomplete',
36
+ 'incomplete',
37
+ 'warning',
38
+ ];
39
+
40
+ /**
41
+ * {@inheritdoc}
42
+ */
43
+ protected $wp_arguments = [
44
+ 'public' => true,
45
+ 'exclude_from_search' => false,
46
+ 'show_in_admin_all_list' => true,
47
+ 'show_in_admin_status_list' => true,
48
+ ];
49
+ }
src/Tickets/Commerce/Status/Voided.php ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Status;
4
+
5
+ /**
6
+ * Class Voided.
7
+ *
8
+ * Normally when an Order is Voided means the the Authorization for payment failed. Which means this order needs to be
9
+ * ignored and refunded, since it's a status that cannot be reversed into complete or anything else.
10
+ *
11
+ * @since 5.1.9
12
+ *
13
+ * @package TEC\Tickets\Commerce\Status
14
+ */
15
+ class Voided extends Status_Abstract {
16
+ /**
17
+ * Slug for this Status.
18
+ *
19
+ * @since 5.1.9
20
+ *
21
+ * @var string
22
+ */
23
+ const SLUG = 'voided';
24
+
25
+ /**
26
+ * {@inheritdoc}
27
+ */
28
+ public function get_name() {
29
+ return __( 'Voided', 'event-tickets' );
30
+ }
31
+
32
+ /**
33
+ * {@inheritdoc}
34
+ */
35
+ protected $flags = [
36
+ 'count_refunded',
37
+ 'warning',
38
+ ];
39
+
40
+ /**
41
+ * {@inheritdoc}
42
+ */
43
+ protected $wp_arguments = [
44
+ 'public' => true,
45
+ 'exclude_from_search' => false,
46
+ 'show_in_admin_all_list' => true,
47
+ 'show_in_admin_status_list' => true,
48
+ ];
49
+ }
50
+
src/Tickets/Commerce/Success.php ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce;
4
+
5
+ /**
6
+ * Class Success
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets\Commerce
11
+ */
12
+ class Success {
13
+ /**
14
+ * Param we use to store the order ID.
15
+ *
16
+ * @since 5.1.9
17
+ *
18
+ * @var string
19
+ */
20
+ public static $order_id_query_arg = 'tc-order-id';
21
+
22
+ /**
23
+ * Get the Success page ID.
24
+ *
25
+ * @since 5.1.9
26
+ *
27
+ *
28
+ * @return int|null
29
+ */
30
+ public function get_page_id() {
31
+ $success_page = (int) tribe_get_option( Settings::$option_success_page );
32
+
33
+ if ( empty( $success_page ) ) {
34
+ return null;
35
+ }
36
+
37
+ /**
38
+ * Allows filtering of the Page ID for the Success page.
39
+ *
40
+ * @since 5.1.9
41
+ *
42
+ * @param int|null $success_page Which page is used in the settings.
43
+ */
44
+ return apply_filters( 'tec_tickets_commerce_success_page_id', $success_page );
45
+ }
46
+
47
+ /**
48
+ * Determine the Current success URL.
49
+ *
50
+ * @since 5.1.9
51
+ *
52
+ * @return string
53
+ */
54
+ public function get_url() {
55
+ $url = home_url( '/' );
56
+ $success_page = $this->get_page_id();
57
+
58
+ if ( is_numeric( $success_page ) ) {
59
+ $success_page = get_post( $success_page );
60
+ }
61
+
62
+ // Only modify the URL in case we have a success page setup in the settings.
63
+ if ( $success_page instanceof \WP_Post ) {
64
+ $url = get_the_permalink( $success_page );
65
+ }
66
+
67
+ /**
68
+ * Allows modifications to the success url for Tickets Commerce.
69
+ *
70
+ * @since 5.1.9
71
+ *
72
+ * @param string $url URL for the cart.
73
+ */
74
+ return (string) apply_filters( 'tec_tickets_commerce_success_url', $url );
75
+ }
76
+
77
+ /**
78
+ * Determines if the current page is the success page.
79
+ *
80
+ * @since 5.1.9
81
+ *
82
+ *
83
+ * @return bool
84
+ */
85
+ public function is_current_page() {
86
+ if ( is_admin() ) {
87
+ return false;
88
+ }
89
+
90
+ $current_page = get_queried_object_id();
91
+ $is_current_page = $this->get_page_id() === $current_page;
92
+
93
+ /**
94
+ * @todo determine hte usage of tribe_ticket_redirect_to
95
+ * $redirect = tribe_get_request_var( 'tribe_tickets_redirect_to', null );
96
+ */
97
+
98
+ /**
99
+ * Allows modifications to the conditional of if we are in the success page.
100
+ *
101
+ * @since 5.1.9
102
+ *
103
+ * @param bool $is_current_page Are we in the current page for checkout.
104
+ */
105
+ return tribe_is_truthy( apply_filters( 'tec_tickets_commerce_success_is_current_page', $is_current_page ) );
106
+ }
107
+
108
+ /**
109
+ * If there is any data or request management or parsing that needs to happen on the success page here is where
110
+ * we do it.
111
+ *
112
+ * @since 5.1.9
113
+ */
114
+ public function parse_request() {
115
+ if ( ! $this->is_current_page() ) {
116
+ return;
117
+ }
118
+
119
+ // In case the ID is passed we set the cookie for usage.
120
+ $cookie_param = tribe_get_request_var( Cart::$cookie_query_arg, false );
121
+ if ( $cookie_param ) {
122
+ tribe( Cart::class )->set_cart_hash_cookie( $cookie_param );
123
+ }
124
+ }
125
+ }
src/Tickets/Commerce/Ticket.php ADDED
@@ -0,0 +1,768 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce;
4
+
5
+ use TEC\Tickets\Commerce\Status\Denied;
6
+ use TEC\Tickets\Commerce\Status\Pending;
7
+ use TEC\Tickets\Event;
8
+
9
+ use Tribe__Utils__Array as Arr;
10
+ use Tribe__Tickets__Global_Stock as Event_Stock;
11
+
12
+ /**
13
+ * Class Ticket.
14
+ *
15
+ * @since 5.1.9
16
+ *
17
+ * @package TEC\Tickets\Commerce
18
+ */
19
+ class Ticket {
20
+ /**
21
+ * Tickets Commerce Ticket Post Type slug.
22
+ *
23
+ * @since 5.1.9
24
+ *
25
+ * @var string
26
+ */
27
+ const POSTTYPE = 'tec_tc_ticket';
28
+
29
+ /**
30
+ * Which meta holds the Relation ship between an ticket and which event it's registered to.
31
+ *
32
+ * @since 5.1.9
33
+ *
34
+ * @var string
35
+ */
36
+ public static $event_relation_meta_key = '_tec_tickets_commerce_event';
37
+
38
+ /**
39
+ * Which meta holds the data for showing the ticket description.
40
+ *
41
+ * @since 5.1.9
42
+ *
43
+ * @var string
44
+ */
45
+ public static $show_description_meta_key = '_tribe_ticket_show_description';
46
+
47
+ /**
48
+ * Which meta holds the data for the ticket sku.
49
+ *
50
+ * @since 5.1.9
51
+ *
52
+ * @var string
53
+ */
54
+ public static $sku_meta_key = '_sku';
55
+
56
+ /**
57
+ * Which meta holds the data for the ticket price.
58
+ *
59
+ * @since 5.1.9
60
+ *
61
+ * @var string
62
+ */
63
+ public static $price_meta_key = '_price';
64
+
65
+ /**
66
+ * Which meta holds the data for the ticket stock mode.
67
+ *
68
+ * @since 5.1.9
69
+ *
70
+ * @var string
71
+ */
72
+ public static $stock_mode_meta_key = Event_Stock::TICKET_STOCK_MODE;
73
+
74
+ /**
75
+ * Which meta holds the data for the ticket stock.
76
+ *
77
+ * @since 5.1.9
78
+ *
79
+ * @var string
80
+ */
81
+ public static $stock_meta_key = '_stock';
82
+
83
+ /**
84
+ * Which meta holds the data for the ticket stock status.
85
+ *
86
+ * @since 5.1.9
87
+ *
88
+ * @var string
89
+ */
90
+ public static $stock_status_meta_key = '_stock_status';
91
+
92
+ /**
93
+ * Which meta holds the data for the ticket allows backorders.
94
+ *
95
+ * @since 5.1.9
96
+ *
97
+ * @var string
98
+ */
99
+ public static $allow_backorders_meta_key = '_backorders';
100
+
101
+ /**
102
+ * Which meta holds the data for the ticket is managing stock.
103
+ *
104
+ * @since 5.1.9
105
+ *
106
+ * @var string
107
+ */
108
+ public static $should_manage_stock_meta_key = '_manage_stock';
109
+
110
+ /**
111
+ * Register this Class post type into WP.
112
+ *
113
+ * @since 5.1.9
114
+ */
115
+ public function register_post_type() {
116
+
117
+ $post_type_args = [
118
+ 'label' => __( 'Tickets', 'event-tickets' ),
119
+ 'labels' => [
120
+ 'name' => __( 'Tickets Commerce Tickets', 'event-tickets' ),
121
+ 'singular_name' => __( 'Tickets Commerce Ticket', 'event-tickets' ),
122
+ ],
123
+ 'public' => false,
124
+ 'show_ui' => false,
125
+ 'show_in_menu' => false,
126
+ 'query_var' => false,
127
+ 'rewrite' => false,
128
+ 'capability_type' => 'post',
129
+ 'has_archive' => false,
130
+ 'hierarchical' => false,
131
+ ];
132
+
133
+ /**
134
+ * Filter the arguments that craft the ticket post type.
135
+ *
136
+ * @see register_post_type
137
+ *
138
+ * @since 5.1.9
139
+ *
140
+ * @param array $post_type_args Post type arguments, passed to register_post_type()
141
+ */
142
+ $post_type_args = apply_filters( 'tec_tickets_commerce_ticket_post_type_args', $post_type_args );
143
+
144
+ register_post_type( static::POSTTYPE, $post_type_args );
145
+ }
146
+
147
+ /**
148
+ * Gets an individual ticket.
149
+ *
150
+ * @todo TribeCommerceLegacy: This method needs to make use of the Ticket Model.
151
+ *
152
+ * @since 5.1.9
153
+ *
154
+ * @param int|\WP_Post $ticket_id
155
+ *
156
+ * @return null|\Tribe__Tickets__Ticket_Object
157
+ */
158
+ public function get_ticket( $ticket_id ) {
159
+ $product = get_post( $ticket_id );
160
+
161
+ if ( ! $product ) {
162
+ return null;
163
+ }
164
+
165
+ $event_id = get_post_meta( $ticket_id, static::$event_relation_meta_key, true );
166
+
167
+ $return = new \Tribe__Tickets__Ticket_Object();
168
+
169
+ $qty_sold = get_post_meta( $ticket_id, 'total_sales', true );
170
+
171
+ $return->description = $product->post_excerpt;
172
+ $return->ID = $ticket_id;
173
+ $return->name = $product->post_title;
174
+ $return->menu_order = $product->menu_order;
175
+ $return->post_type = $product->post_type;
176
+ $return->price = get_post_meta( $ticket_id, '_price', true );
177
+ $return->provider_class = Module::class;
178
+ $return->admin_link = '';
179
+ $return->show_description = $return->show_description();
180
+ $return->start_date = get_post_meta( $ticket_id, '_ticket_start_date', true );
181
+ $return->end_date = get_post_meta( $ticket_id, '_ticket_end_date', true );
182
+ $return->start_time = get_post_meta( $ticket_id, '_ticket_start_time', true );
183
+ $return->end_time = get_post_meta( $ticket_id, '_ticket_end_time', true );
184
+ $return->sku = get_post_meta( $ticket_id, '_sku', true );
185
+
186
+ // If the quantity sold wasn't set, default to zero
187
+ $qty_sold = $qty_sold ? $qty_sold : 0;
188
+
189
+ // Ticket stock is a simple reflection of remaining inventory for this item...
190
+ $stock = (int) get_post_meta( $ticket_id, '_stock', true );
191
+
192
+ // If we don't have a stock value, then stock should be considered 'unlimited'
193
+ if ( null === $stock ) {
194
+ $stock = - 1;
195
+ }
196
+
197
+ $return->manage_stock( 'yes' === get_post_meta( $ticket_id, '_manage_stock', true ) );
198
+ $return->stock( $stock );
199
+ $return->global_stock_mode( get_post_meta( $ticket_id, \Tribe__Tickets__Global_Stock::TICKET_STOCK_MODE, true ) );
200
+ $capped = get_post_meta( $ticket_id, \Tribe__Tickets__Global_Stock::TICKET_STOCK_CAP, true );
201
+
202
+ if ( '' !== $capped ) {
203
+ $return->global_stock_cap( $capped );
204
+ }
205
+
206
+ $qty_cancelled = $this->get_cancelled( $ticket_id );
207
+
208
+ // Manually add cancelled to sold so that we can remove it correctly later when calculating.
209
+ $return->qty_sold( $qty_sold + $qty_cancelled );
210
+
211
+ $return->qty_cancelled( $qty_cancelled );
212
+
213
+ $pending = $this->get_qty_pending( $ticket_id );
214
+
215
+ $return->qty_pending( $pending );
216
+
217
+ /**
218
+ * Use this Filter to change any information you want about this ticket
219
+ *
220
+ * @since 5.1.9
221
+ *
222
+ * @param object $ticket
223
+ * @param int $post_id
224
+ * @param int $ticket_id
225
+ */
226
+ $return = apply_filters( 'tec_tickets_commerce_get_ticket_legacy', $return, $event_id, $ticket_id );
227
+
228
+ return $return;
229
+ }
230
+
231
+ /**
232
+ * Returns the total number of cancelled tickets.
233
+ *
234
+ * @todo TribeCommerceLegacy: Move this method into the another place.
235
+ *
236
+ * @since 5.1.9
237
+ *
238
+ * @param int $ticket_id The ticket post ID.
239
+ *
240
+ * @return int
241
+ */
242
+ protected function get_cancelled( $ticket_id ) {
243
+ $denied_orders = \Tribe__Tickets__Commerce__PayPal__Order::find_by( array(
244
+ 'ticket_id' => $ticket_id,
245
+ 'post_status' => Denied::SLUG,
246
+ 'posts_per_page' => - 1,
247
+ ), [
248
+ 'items',
249
+ ] );
250
+
251
+ $denied = 0;
252
+ foreach ( $denied_orders as $denied_order ) {
253
+ $denied += $denied_order->get_item_quantity( $ticket_id );
254
+ }
255
+
256
+ return max( 0, $denied );
257
+ }
258
+
259
+ /**
260
+ * Returns the number of pending attendees by ticket.
261
+ *
262
+ * @todo TribeCommerceLegacy: Move this method into the another place.
263
+ *
264
+ * @since 5.1.9
265
+ *
266
+ * @param int $ticket_id The ticket post ID
267
+ * @param bool $refresh Whether to try and use the cached value or not.
268
+ *
269
+ * @return int
270
+ */
271
+ public function get_qty_pending( $ticket_id, $refresh = false ) {
272
+ static $pending_attendees_by_ticket = [];
273
+
274
+ if ( $refresh || empty( $pending_attendees_by_ticket[ $ticket_id ] ) ) {
275
+ $pending_query = new \WP_Query( [
276
+ 'fields' => 'ids',
277
+ 'per_page' => 1,
278
+ 'post_type' => Attendee::POSTTYPE,
279
+ 'meta_query' => [
280
+ [
281
+ 'key' => Attendee::$event_relation_meta_key,
282
+ 'value' => $ticket_id,
283
+ ],
284
+ 'relation' => 'AND',
285
+ [
286
+ 'key' => Attendee::$status_meta_key,
287
+ 'value' => tribe( Pending::class )->get_wp_slug(),
288
+ ],
289
+ ],
290
+ ] );
291
+
292
+ $pending_attendees_by_ticket[ $ticket_id ] = $pending_query->found_posts;
293
+ }
294
+
295
+ return $pending_attendees_by_ticket[ $ticket_id ];
296
+ }
297
+
298
+ /**
299
+ * Legacy method ported from Tribe Commerce (TPP), we are specifically avoiding refactoring anything on the first
300
+ * stage of Tickets Commerce
301
+ *
302
+ * @todo TribeCommerceLegacy: This method needs to be split into `create` and `update`
303
+ *
304
+ * @since 5.1.9
305
+ *
306
+ * @param $post_id
307
+ * @param $ticket
308
+ * @param array $raw_data
309
+ *
310
+ * @return false|int|\WP_Error
311
+ */
312
+ public function save( $post_id, $ticket, $raw_data = [] ) {
313
+ $save_type = 'update';
314
+
315
+ if ( empty( $ticket->ID ) ) {
316
+ $save_type = 'create';
317
+
318
+ /* Create main product post */
319
+ $args = array(
320
+ 'post_status' => 'publish',
321
+ 'post_type' => static::POSTTYPE,
322
+ 'post_author' => get_current_user_id(),
323
+ 'post_excerpt' => $ticket->description,
324
+ 'post_title' => $ticket->name,
325
+ 'menu_order' => tribe_get_request_var( 'menu_order', - 1 ),
326
+ );
327
+
328
+ $ticket->ID = wp_insert_post( $args );
329
+
330
+ // Relate event <---> ticket
331
+ add_post_meta( $ticket->ID, static::$event_relation_meta_key, $post_id );
332
+
333
+ } else {
334
+ $args = array(
335
+ 'ID' => $ticket->ID,
336
+ 'post_excerpt' => $ticket->description,
337
+ 'post_title' => $ticket->name,
338
+ 'menu_order' => $ticket->menu_order,
339
+ );
340
+
341
+ $ticket->ID = wp_update_post( $args );
342
+ }
343
+
344
+ if ( ! $ticket->ID ) {
345
+ return false;
346
+ }
347
+
348
+ /** @var \Tribe__Tickets__Tickets_Handler $tickets_handler */
349
+ $tickets_handler = tribe( 'tickets.handler' );
350
+
351
+ // Updates if we should show Description.
352
+ $ticket->show_description = isset( $ticket->show_description ) && tribe_is_truthy( $ticket->show_description ) ? 'yes' : 'no';
353
+ update_post_meta( $ticket->ID, $tickets_handler->key_show_description, $ticket->show_description );
354
+
355
+ // let's make sure float price values are formatted to "0.xyz"
356
+ if ( is_numeric( $ticket->price ) ) {
357
+ $ticket->price = (string) (int) $ticket->price === $ticket->price
358
+ ? (int) $ticket->price
359
+ : (float) $ticket->price;
360
+ }
361
+
362
+ update_post_meta( $ticket->ID, '_price', $ticket->price );
363
+
364
+ $ticket_data = \Tribe__Utils__Array::get( $raw_data, 'tribe-ticket', array() );
365
+ tribe( Module::class )->update_capacity( $ticket, $ticket_data, $save_type );
366
+
367
+ foreach ( [ 'start_date', 'start_time', 'end_date', 'end_time' ] as $time_key ) {
368
+ if ( isset( $ticket->{$time_key} ) ) {
369
+ update_post_meta( $ticket->ID, "_ticket_{$time_key}", $ticket->{$time_key} );
370
+ } else {
371
+ delete_post_meta( $ticket->ID, "_ticket_{$time_key}" );
372
+ }
373
+ }
374
+
375
+ /**
376
+ * Toggle filter to allow skipping the automatic SKU generation.
377
+ *
378
+ * @param bool $should_default_ticket_sku
379
+ */
380
+ $should_default_ticket_sku = apply_filters( 'tribe_tickets_should_default_ticket_sku', true );
381
+ if ( $should_default_ticket_sku ) {
382
+ // make sure the SKU is set to the correct value
383
+ if ( ! empty( $raw_data['ticket_sku'] ) ) {
384
+ $sku = $raw_data['ticket_sku'];
385
+ } else {
386
+ $post_author = get_post( $ticket->ID )->post_author;
387
+ $str = $raw_data['ticket_name'];
388
+ $str = tribe_strtoupper( $str );
389
+ $sku = "{$ticket->ID}-{$post_author}-" . str_replace( ' ', '-', $str );
390
+ $raw_data['ticket_sku'] = $sku;
391
+ }
392
+ update_post_meta( $ticket->ID, '_sku', $sku );
393
+ }
394
+
395
+ // Fetches all Ticket Form data
396
+ $data = \Tribe__Utils__Array::get( $raw_data, 'tribe-ticket', array() );
397
+
398
+ // Fetch the Global stock Instance for this Event
399
+ $event_stock = new \Tribe__Tickets__Global_Stock( $post_id );
400
+
401
+ // Only need to do this if we haven't already set one - they shouldn't be able to edit it from here otherwise
402
+ if ( ! $event_stock->is_enabled() ) {
403
+ if ( isset( $data['event_capacity'] ) ) {
404
+ $data['event_capacity'] = trim( filter_var( $data['event_capacity'], FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH ) );
405
+
406
+ // If empty we need to modify to -1
407
+ if ( '' === $data['event_capacity'] ) {
408
+ $data['event_capacity'] = - 1;
409
+ }
410
+
411
+ // Makes sure it's an Int after this point
412
+ $data['event_capacity'] = (int) $data['event_capacity'];
413
+
414
+ $tickets_handler->remove_hooks();
415
+
416
+ // We need to update event post meta - if we've set a global stock
417
+ $event_stock->enable();
418
+ $event_stock->set_stock_level( $data['event_capacity'], true );
419
+
420
+ // Update Event capacity
421
+ update_post_meta( $post_id, $tickets_handler->key_capacity, $data['event_capacity'] );
422
+ update_post_meta( $post_id, $event_stock::GLOBAL_STOCK_ENABLED, 1 );
423
+
424
+ $tickets_handler->add_hooks();
425
+ }
426
+ } else {
427
+ // If the Global Stock is configured we pull it from the Event
428
+ $global_capacity = (int) tribe_tickets_get_capacity( $post_id );
429
+ $data['event_capacity'] = (int) \Tribe__Utils__Array::get( 'event_capacity', $data, 0 );
430
+
431
+ if ( ! empty( $data['event_capacity'] ) && $data['event_capacity'] !== $global_capacity ) {
432
+ // Update stock level with $data['event_capacity'].
433
+ $event_stock->set_stock_level( $data['event_capacity'], true );
434
+ } else {
435
+ // Set $data['event_capacity'] with what we know.
436
+ $data['event_capacity'] = $global_capacity;
437
+ }
438
+ }
439
+
440
+ // Default Capacity will be 0
441
+ $default_capacity = 0;
442
+ $is_capacity_passed = true;
443
+
444
+ // If we have Event Global stock we fetch that Stock
445
+ if ( $event_stock->is_enabled() ) {
446
+ $default_capacity = $data['event_capacity'];
447
+ }
448
+
449
+ // Fetch capacity field, if we don't have it use default (defined above)
450
+ $data['capacity'] = trim( \Tribe__Utils__Array::get( $data, 'capacity', $default_capacity ) );
451
+
452
+ // If empty we need to modify to the default
453
+ if ( '' !== $data['capacity'] ) {
454
+ // Makes sure it's an Int after this point
455
+ $data['capacity'] = (int) $data['capacity'];
456
+
457
+ // The only available value lower than zero is -1 which is unlimited
458
+ if ( 0 > $data['capacity'] ) {
459
+ $data['capacity'] = - 1;
460
+ }
461
+
462
+ $default_capacity = $data['capacity'];
463
+ }
464
+
465
+ // Fetch the stock if defined, otherwise use Capacity field
466
+ $data['stock'] = trim( \Tribe__Utils__Array::get( $data, 'stock', $default_capacity ) );
467
+
468
+ // If empty we need to modify to what every capacity was
469
+ if ( '' === $data['stock'] ) {
470
+ $data['stock'] = $default_capacity;
471
+ }
472
+
473
+ // Makes sure it's an Int after this point
474
+ $data['stock'] = (int) $data['stock'];
475
+
476
+ // The only available value lower than zero is -1 which is unlimited.
477
+ if ( 0 > $data['stock'] ) {
478
+ $data['stock'] = - 1;
479
+ }
480
+
481
+ $mode = isset( $data['mode'] ) ? $data['mode'] : 'own';
482
+
483
+ if ( '' !== $mode ) {
484
+ if ( 'update' === $save_type ) {
485
+ $totals = $tickets_handler->get_ticket_totals( $ticket->ID );
486
+ $data['stock'] -= $totals['pending'] + $totals['sold'];
487
+ }
488
+
489
+ // In here is safe to check because we don't have unlimited = -1
490
+ $status = ( 0 < $data['stock'] ) ? 'instock' : 'outofstock';
491
+
492
+ update_post_meta( $ticket->ID, \Tribe__Tickets__Global_Stock::TICKET_STOCK_MODE, $mode );
493
+ update_post_meta( $ticket->ID, '_stock', $data['stock'] );
494
+ update_post_meta( $ticket->ID, '_stock_status', $status );
495
+ update_post_meta( $ticket->ID, '_backorders', 'no' );
496
+ update_post_meta( $ticket->ID, '_manage_stock', 'yes' );
497
+
498
+ // Prevent Ticket Capacity from going higher then Event Capacity
499
+ if (
500
+ $event_stock->is_enabled()
501
+ && \Tribe__Tickets__Global_Stock::OWN_STOCK_MODE !== $mode
502
+ && (
503
+ '' === $data['capacity']
504
+ || $data['event_capacity'] < $data['capacity']
505
+ )
506
+ ) {
507
+ $data['capacity'] = $data['event_capacity'];
508
+ }
509
+ } else {
510
+ // Unlimited Tickets
511
+ // Besides setting _manage_stock to "no" we should remove the associated stock fields if set previously
512
+ update_post_meta( $ticket->ID, '_manage_stock', 'no' );
513
+ delete_post_meta( $ticket->ID, '_stock_status' );
514
+ delete_post_meta( $ticket->ID, '_stock' );
515
+ delete_post_meta( $ticket->ID, \Tribe__Tickets__Global_Stock::TICKET_STOCK_CAP );
516
+ delete_post_meta( $ticket->ID, \Tribe__Tickets__Global_Stock::TICKET_STOCK_MODE );
517
+
518
+ // Set Capacity -1 when we don't have a stock mode, which means unlimited
519
+ $data['capacity'] = - 1;
520
+ }
521
+
522
+ if ( '' !== $data['capacity'] ) {
523
+ // Update Ticket capacity
524
+ update_post_meta( $ticket->ID, $tickets_handler->key_capacity, $data['capacity'] );
525
+ }
526
+
527
+ /**
528
+ * Generic action fired after saving a ticket (by type)
529
+ *
530
+ * @since 5.1.9
531
+ *
532
+ * @param int $post_id Post ID of post the ticket is tied to
533
+ * @param \Tribe__Tickets__Ticket_Object $ticket Ticket that was just saved
534
+ * @param array $raw_data Ticket data
535
+ * @param string $class Commerce engine class
536
+ */
537
+ do_action( "tec_tickets_commerce_after_{$save_type}_ticket", $post_id, $ticket, $raw_data, static::class );
538
+
539
+ /**
540
+ * Generic action fired after saving a ticket
541
+ *
542
+ * @since 4.7
543
+ *
544
+ * @param int $post_id Post ID of post the ticket is tied to
545
+ * @param \Tribe__Tickets__Ticket_Object $ticket Ticket that was just saved
546
+ * @param array $raw_data Ticket data
547
+ * @param string $class Commerce engine class
548
+ */
549
+ do_action( 'tec_tickets_commerce_after_save_ticket', $post_id, $ticket, $raw_data, static::class );
550
+
551
+ return $ticket->ID;
552
+ }
553
+
554
+ /**
555
+ * Deletes a given ticket.
556
+ *
557
+ * @todo TribeCommerceLegacy: This method needs to be refactored to Tickets Commerce standards.
558
+ *
559
+ * @since 5.1.9
560
+ *
561
+ * @param $event_id
562
+ * @param $ticket_id
563
+ *
564
+ * @return bool
565
+ */
566
+ public function delete( $event_id, $ticket_id ) {
567
+ // Ensure we know the event and product IDs (the event ID may not have been passed in)
568
+ if ( empty( $event_id ) ) {
569
+ $event_id = get_post_meta( $ticket_id, Attendee::$event_relation_meta_key, true );
570
+ }
571
+
572
+ // Additional check (in case we were passed an invalid ticket ID and still can't determine the event)
573
+ if ( empty( $event_id ) ) {
574
+ return false;
575
+ }
576
+
577
+ $product_id = get_post_meta( $ticket_id, Attendee::$event_relation_meta_key, true );
578
+
579
+ // @todo: should deleting an attendee replenish a ticket stock?
580
+
581
+ // Store name so we can still show it in the attendee list
582
+ $attendees = tribe( Module::class )->get_attendees_by_id( $event_id );
583
+ $post_to_delete = get_post( $ticket_id );
584
+
585
+ foreach ( (array) $attendees as $attendee ) {
586
+ if ( $attendee['product_id'] == $ticket_id ) {
587
+ update_post_meta( $attendee['attendee_id'], Attendee::$deleted_ticket_meta_key, esc_html( $post_to_delete->post_title ) );
588
+ }
589
+ }
590
+
591
+ // Try to kill the actual ticket/attendee post
592
+ $delete = wp_delete_post( $ticket_id, true );
593
+ if ( is_wp_error( $delete ) || ! isset( $delete->ID ) ) {
594
+ return false;
595
+ }
596
+
597
+ \Tribe__Tickets__Attendance::instance( $event_id )->increment_deleted_attendees_count();
598
+ do_action( 'tec_tickets_commerce_ticket_deleted', $ticket_id, $event_id, $product_id );
599
+ \Tribe__Post_Transient::instance()->delete( $event_id, \Tribe__Tickets__Tickets::ATTENDEES_CACHE );
600
+
601
+ return true;
602
+ }
603
+
604
+ /**
605
+ * Update Stock and Global Stock when deleting an Attendee
606
+ *
607
+ * @todo TribeCommerceLegacy: This should be moved into using a Flag Action.
608
+ *
609
+ * @since 5.1.9
610
+ *
611
+ * @param int $ticket_id the attendee id being deleted
612
+ * @param int $post_id the post or event id for the attendee
613
+ * @param int $product_id the ticket-product id in Tribe Commerce
614
+ */
615
+ public function update_stock_after_deletion( $ticket_id, $post_id, $product_id ) {
616
+
617
+ $global_stock = new \Tribe__Tickets__Global_Stock( $post_id );
618
+ $shared_capacity = false;
619
+ if ( $global_stock->is_enabled() ) {
620
+ $shared_capacity = true;
621
+ }
622
+
623
+ tribe( Module::class )->decrease_ticket_sales_by( $product_id, 1, $shared_capacity, $global_stock );
624
+ }
625
+
626
+ /**
627
+ * Update Global Stock.
628
+ *
629
+ * @todo TribeCommerceLegacy: Not sure where this method fits, might just need to integrate it it into the
630
+ * create/update methods and delete this.
631
+ *
632
+ * @since 5.1.9
633
+ *
634
+ * @param \Tribe__Tickets__Global_Stock $global_stock The global stock object.
635
+ * @param int $qty The quantity to modify stock.
636
+ * @param bool $increase Whether to increase stock, default is false.
637
+ */
638
+ public function update_global_stock( $global_stock, $qty = 1, $increase = false ) {
639
+ $level = $global_stock->get_stock_level();
640
+
641
+ if ( $increase ) {
642
+ $new_level = (int) $level + (int) $qty;
643
+ } else {
644
+ $new_level = (int) $level - (int) $qty;
645
+ }
646
+
647
+ $global_stock->set_stock_level( $new_level );
648
+ }
649
+
650
+ /**
651
+ * Increase the sales for a ticket by a specific quantity.
652
+ *
653
+ * @todo TribeCommerceLegacy: This should be moved into using a Flag Action.
654
+ *
655
+ * @since 5.1.9
656
+ *
657
+ * @param int $ticket_id The ticket post ID.
658
+ * @param int $quantity The quantity to increase the ticket sales by.
659
+ * @param bool $shared_capacity Whether the ticket is using shared capacity.
660
+ * @param \Tribe__Tickets__Global_Stock|null $global_stock The stock object or null.
661
+ *
662
+ * @return int The new sales amount.
663
+ */
664
+ public function increase_ticket_sales_by( $ticket_id, $quantity = 1, $shared_capacity = false, $global_stock = null ) {
665
+ // Adjust sales.
666
+ $sales = (int) get_post_meta( $ticket_id, 'total_sales', true ) + $quantity;
667
+
668
+ update_post_meta( $ticket_id, 'total_sales', $sales );
669
+
670
+ if ( $shared_capacity && $global_stock instanceof \Tribe__Tickets__Global_Stock ) {
671
+ $this->update_global_stock( $global_stock, $quantity );
672
+ }
673
+
674
+ return $sales;
675
+ }
676
+
677
+ /**
678
+ * Decrease the sales for a ticket by a specific quantity.
679
+ *
680
+ * @todo TribeCommerceLegacy: This should be moved into using a Flag Action.
681
+ *
682
+ * @since 5.1.9
683
+ *
684
+ * @param int $ticket_id The ticket post ID.
685
+ * @param int $quantity The quantity to increase the ticket sales by.
686
+ * @param bool $shared_capacity Whether the ticket is using shared capacity.
687
+ * @param \Tribe__Tickets__Global_Stock|null $global_stock The stock object or null.
688
+ *
689
+ * @return int The new sales amount.
690
+ */
691
+ public function decrease_ticket_sales_by( $ticket_id, $quantity = 1, $shared_capacity = false, $global_stock = null ) {
692
+ // Adjust sales.
693
+ $sales = (int) get_post_meta( $ticket_id, 'total_sales', true ) - $quantity;
694
+
695
+ // Prevent negatives.
696
+ $sales = max( $sales, 0 );
697
+
698
+ update_post_meta( $ticket_id, 'total_sales', $sales );
699
+
700
+ if ( $shared_capacity && $global_stock instanceof \Tribe__Tickets__Global_Stock ) {
701
+ $this->update_global_stock( $global_stock, $quantity, true );
702
+ }
703
+
704
+ return $sales;
705
+ }
706
+
707
+ /**
708
+ * Gets the product price value.
709
+ *
710
+ * @todo TribeCommerceLegacy: This should not be used, the model should be used.
711
+ *
712
+ * @since 5.1.9
713
+ *
714
+ * @param int|\WP_Post $product
715
+ *
716
+ * @return string
717
+ */
718
+ public function get_price_value( $product ) {
719
+ $product = get_post( $product );
720
+
721
+ if ( ! $product instanceof \WP_Post ) {
722
+ return false;
723
+ }
724
+
725
+ return get_post_meta( $product->ID, static::$price_meta_key, true );
726
+ }
727
+
728
+ /**
729
+ * Get's the product price html
730
+ *
731
+ * @todo TribeCommerceLegacy: This should not be used, the model and a template should be used.
732
+ *
733
+ * @since 5.1.9
734
+ *
735
+ * @param int|object $product
736
+ * @param array|boolean $attendee
737
+ *
738
+ * @return string
739
+ */
740
+ public function get_price_html( $product, $attendee = false ) {
741
+ $product_id = $product;
742
+
743
+ if ( $product instanceof \WP_Post ) {
744
+ $product_id = $product->ID;
745
+ } elseif ( is_numeric( $product_id ) ) {
746
+ $product = get_post( $product_id );
747
+ } else {
748
+ return '';
749
+ }
750
+
751
+ $price = $this->get_price_value( $product );
752
+ $price = tribe( 'tickets.commerce.paypal.currency' )->format_currency( $price, $product_id );
753
+
754
+ $price_html = '<span class="tribe-tickets-price-amount amount">' . esc_html( $price ) . '</span>';
755
+
756
+ /**
757
+ * Allow filtering of the Price HTML
758
+ *
759
+ * @since 5.1.9
760
+ *
761
+ * @param string $price_html
762
+ * @param mixed $product
763
+ * @param mixed $attendee
764
+ *
765
+ */
766
+ return apply_filters( 'tec_tickets_commerce_ticket_price_html', $price_html, $product, $attendee );
767
+ }
768
+ }
src/Tickets/Commerce/Tickets_View.php ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce;
4
+
5
+ /**
6
+ * Class Tickets_View
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets\Commerce
11
+ */
12
+ class Tickets_View extends \Tribe__Tickets__Tickets_View {
13
+ /**
14
+ * Groups PayPal ticket attendees by purchaser name/email
15
+ *
16
+ * @since 5.1.9
17
+ *
18
+ * @param int $post_id The post ID it relates to
19
+ * @param int|null $user_id An optional user ID
20
+ *
21
+ * @return array Array with the tickets attendees grouped by purchaser name/email
22
+ */
23
+ public function get_post_attendees_by_purchaser( $post_id, $user_id ) {
24
+ $attendees = $this->get_post_ticket_attendees( $post_id, $user_id );
25
+
26
+ if ( ! $attendees ) {
27
+ return array();
28
+ }
29
+
30
+ $attendee_groups = array();
31
+ foreach ( $attendees as $attendee ) {
32
+ $key = $attendee['purchaser_name'] . '::' . $attendee['purchaser_email'];
33
+
34
+ if ( ! isset( $attendee_groups[ $key ] ) ) {
35
+ $attendee_groups[ $key ] = array();
36
+ }
37
+
38
+ $attendee_groups[ $key ][] = $attendee;
39
+ }
40
+
41
+ return $attendee_groups;
42
+ }
43
+
44
+ /**
45
+ * Fetches from the Cached attendees list the ones that are relevant for this user and event
46
+ *
47
+ * Important to note that this method will bring the attendees from PayPal tickets
48
+ *
49
+ * @since 5.1.9
50
+ *
51
+ * @param int $event_id The Event ID it relates to
52
+ * @param int|null $user_id An Optional User ID
53
+ *
54
+ * @return array Array with the PayPal tickets attendees
55
+ */
56
+ public function get_post_ticket_attendees( $event_id, $user_id ) {
57
+ $module = tribe( Module::class );
58
+
59
+ if ( $user_id ) {
60
+ return $module->get_attendees_by_user_id( $user_id, $event_id );
61
+ }
62
+
63
+ return $module->get_attendees_by_id( $event_id );
64
+ }
65
+
66
+ /**
67
+ * Verifies if the Given Event has Ticket participation restricted
68
+ *
69
+ * @since 5.1.9
70
+ *
71
+ * @param int $event_id The Event/Post ID (optional)
72
+ * @param int $ticket_id The Ticket/RSVP ID (optional)
73
+ * @param int $user_id An User ID (optional)
74
+ *
75
+ * @return boolean
76
+ */
77
+ public function is_ticket_restricted( $event_id = null, $ticket_id = null, $user_id = null ) {
78
+ // By default we always pass the current User
79
+ if ( is_null( $user_id ) ) {
80
+ $user_id = get_current_user_id();
81
+ }
82
+
83
+ /**
84
+ * Allow users to filter if this Event or Ticket has Restricted Tickets
85
+ *
86
+ * @since 4.7.1
87
+ *
88
+ * @param boolean $restricted Is this Event or Ticket Restricted?
89
+ * @param int $event_id The Event/Post ID (optional)
90
+ * @param int $ticket_id The Ticket/RSVP ID (optional)
91
+ * @param int $user_id An User ID (optional)
92
+ */
93
+ return apply_filters( 'tec_tickets_commerce_is_ticket_restricted', false, $event_id, $ticket_id, $user_id );
94
+ }
95
+
96
+ /**
97
+ * Gets a HTML Attribute for input/select/textarea to be disabled
98
+ *
99
+ * @since 5.1.9
100
+ *
101
+ * @param int $event_id The Event/Post ID (optional)
102
+ * @param int $ticket_id The Ticket/RSVP ID (optional)
103
+ *
104
+ * @return boolean
105
+ */
106
+ public function get_restriction_attr( $event_id = null, $ticket_id = null ) {
107
+ $is_disabled = '';
108
+ if ( $this->is_ticket_restricted( $event_id, $ticket_id ) ) {
109
+ $is_disabled = 'disabled title="' . esc_attr__( 'This ticket is no longer active.', 'event-tickets' ) . '"';
110
+ }
111
+
112
+ return $is_disabled;
113
+ }
114
+
115
+ /**
116
+ * Creates the HTML for the status of the PayPal ticket.
117
+ *
118
+ * @since 5.1.9
119
+ *
120
+ * @param string $status The ticket order status
121
+ *
122
+ * @return void
123
+ */
124
+ public function render_ticket_status( $status = null ) {
125
+ $ticket_status = $this->get_ticket_status( $status );
126
+
127
+ echo sprintf( '<span>%s</span>', esc_html( $ticket_status ) );
128
+ }
129
+
130
+ /**
131
+ * Returns the ticket status corresponding to the ticket status slug.
132
+ *
133
+ * @since 5.1.9
134
+ *
135
+ * @param string $status
136
+ *
137
+ * @return string
138
+ */
139
+ public function get_ticket_status( $status ) {
140
+ $ticket_status = __( 'unavailable', 'event-tickets' );
141
+
142
+ if ( ! empty( $status ) ) {
143
+ /** @var \Tribe__Tickets__Status__Manager $status_mgr */
144
+ $status_mgr = tribe( 'tickets.status' );
145
+
146
+ $statuses = $status_mgr->get_all_provider_statuses( 'tpp' );
147
+ $status_strings = [];
148
+ foreach ( $statuses as $s ) {
149
+ $status_strings[ $s->provider_name ] = _x( $s->name, 'a PayPal ticket order status', 'event-tickets' );
150
+ }
151
+
152
+ $ticket_status = \Tribe__Utils__Array::get( $status_strings, $status, reset( $status_strings ) );
153
+ }
154
+
155
+ return $ticket_status;
156
+ }
157
+ }
src/Tickets/Commerce/Traits/Has_Mode.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Traits;
4
+
5
+ /**
6
+ * Trait Has_Mode.
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets\Commerce\Traits
11
+ */
12
+ trait Has_Mode {
13
+
14
+ /**
15
+ * The current working mode: live or sandbox.
16
+ *
17
+ * @since 5.1.9
18
+ *
19
+ * @var string
20
+ */
21
+ protected $mode;
22
+
23
+ /**
24
+ * Valid modes.
25
+ *
26
+ * @since 5.1.9
27
+ *
28
+ * @var array
29
+ */
30
+ protected $valid_modes = [
31
+ 'sandbox', // Default.
32
+ 'live',
33
+ ];
34
+
35
+ /**
36
+ * Sets the mode for the Merchant for handling operations.
37
+ *
38
+ * @since 5.1.9
39
+ *
40
+ * @param string $mode
41
+ *
42
+ * @return $this
43
+ */
44
+ public function set_mode( $mode ) {
45
+ if ( ! in_array( $mode, $this->valid_modes, true ) ) {
46
+ $mode = reset( $this->valid_modes );
47
+ }
48
+
49
+ $this->mode = $mode;
50
+
51
+ return $this;
52
+ }
53
+
54
+ /**
55
+ * Gets the mode for Merchant for handling operations.
56
+ *
57
+ * @since 5.1.9
58
+ *
59
+ * @return string Which mode we are using the Merchant.
60
+ */
61
+ public function get_mode() {
62
+ return $this->mode;
63
+ }
64
+
65
+ /**
66
+ * Determines if we are using sandbox mode.
67
+ *
68
+ * @since 5.1.9
69
+ *
70
+ * @return bool
71
+ */
72
+ public function is_sandbox() {
73
+ return 'sandbox' === $this->get_mode();
74
+ }
75
+ }
src/Tickets/Commerce/Utils/Price.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets\Commerce\Utils;
4
+
5
+ /**
6
+ * Class Price
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ */
11
+ class Price {
12
+ /**
13
+ * Taking a given numerical price it will multiply the by the quantity passed it will not convert the values into
14
+ * float at any point, it will use full integers and strings to calculate, to avoid float point problems.
15
+ *
16
+ * We only allow two decimal points.
17
+ *
18
+ * @since 5.1.9
19
+ *
20
+ * @param string $value Which value we are going to multiply for the subtotal.
21
+ * @param int $quantity Quantity that the value will be multiplied..
22
+ * @param null|string $decimal Which Decimal separator.
23
+ * @param null|string $thousand_sep Which thousand separator.
24
+ *
25
+ * @return string
26
+ */
27
+ public static function sub_total( $value, $quantity, $decimal = null, $thousand_sep = null ) {
28
+ $decimal = $decimal ?: tribe( \Tribe__Tickets__Commerce__Currency::class )->get_currency_locale( 'decimal_point' );
29
+ $thousand_sep = $thousand_sep ?: tribe( \Tribe__Tickets__Commerce__Currency::class )->get_currency_locale( 'thousands_sep' );
30
+ $number = number_format( $value, 2, $decimal, $thousand_sep );
31
+ $number = (int) str_replace( [ $decimal, $thousand_sep ], '', $number );
32
+
33
+ $sub_total = $number * $quantity;
34
+ $sub_total = substr_replace( (string) $sub_total, $decimal, - 2, 0 );
35
+
36
+ return number_format( $sub_total, 2, $decimal, $thousand_sep );
37
+ }
38
+
39
+ /**
40
+ * Taking an array of values it creates the sum of those values, it will not convert the values into float at any
41
+ * point, it will use full integers and strings to calculate, to avoid float point problems.
42
+ *
43
+ * We only allow two decimal points.
44
+ *
45
+ * @since 5.1.9
46
+ *
47
+ * @param array $values Values that need to be summed.
48
+ * @param null|string $decimal Which Decimal separator.
49
+ * @param null|string $thousand_sep Which thousand separator.
50
+ *
51
+ * @return string
52
+ */
53
+ public static function total( array $values, $decimal = null, $thousand_sep = null ) {
54
+ $decimal = $decimal ?: tribe( \Tribe__Tickets__Commerce__Currency::class )->get_currency_locale( 'decimal_point' );
55
+ $thousand_sep = $thousand_sep ?: tribe( \Tribe__Tickets__Commerce__Currency::class )->get_currency_locale( 'thousands_sep' );
56
+
57
+ $values = array_map( static function ( $value ) use ( $decimal, $thousand_sep ) {
58
+ $number = number_format( $value, 2, $decimal, $thousand_sep );
59
+
60
+ return (int) str_replace( [ $decimal, $thousand_sep ], '', $number );
61
+ }, $values );
62
+
63
+
64
+ $total = array_sum( array_filter( $values ) );
65
+ $total = substr_replace( (string) $total, $decimal, - 2, 0 );
66
+
67
+ return number_format( $total, 2, $decimal, $thousand_sep );
68
+ }
69
+ }
src/Tickets/Event.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace TEC\Tickets;
4
+
5
+ /**
6
+ * Class Event
7
+ *
8
+ * @since 5.1.9
9
+ *
10
+ * @package TEC\Tickets
11
+ */
12
+ class Event {
13
+
14
+ /**
15
+ * Value stored for the Events from TEC.
16
+ *
17
+ * @since 5.1.9
18
+ *
19
+ * @var string
20
+ */
21
+ protected static $post_type = 'tribe_events';
22
+
23
+ /**
24
+ * Gets the TEC events CPT, will fallback into the Static variable on this class, but will try to pull from
25
+ * TEC main class constant first.
26
+ *
27
+ * @since 5.1.9
28
+ *
29
+ *
30
+ * @return string
31
+ */
32
+ public static function get_post_type() {
33
+ if ( class_exists( '\Tribe__Events__Main' ) ) {
34
+ return \Tribe__Events__Main::POSTTYPE;
35
+ }
36
+ return static::$post_type;
37
+ }
38
+
39
+ }
src/Tickets/Hooks.php CHANGED
@@ -53,7 +53,12 @@ class Hooks extends tad_DI52_ServiceProvider {
53
  * @since 5.1.6
54
  */
55
  protected function add_filters() {
 
 
 
 
56
 
 
57
  }
58
 
59
  }
53
  * @since 5.1.6
54
  */
55
  protected function add_filters() {
56
+ // add_filter( 'tribe_tickets_get_default_module', [ $this, 'filter_include_tickets_commerce' ], 10, 2 );
57
+ }
58
+
59
+ public function filter_include_tickets_commerce( $module, $modules ) {
60
 
61
+ return $module;
62
  }
63
 
64
  }
src/Tribe/Admin/Ticket_Settings.php CHANGED
@@ -1,14 +1,16 @@
1
  <?php
 
2
  /**
3
  * Manages the admin settings UI in relation to ticket configuration.
4
  */
5
  class Tribe__Tickets__Admin__Ticket_Settings {
 
6
  /**
7
  * Sets up the display of timezone-related settings and listeners to deal with timezone-update
8
  * requests (which are initiated from within the settings screen).
9
  */
10
  public function __construct() {
11
- add_action( 'tribe_settings_do_tabs', array( $this, 'settings_ui' ) );
12
  }
13
 
14
  /**
1
  <?php
2
+
3
  /**
4
  * Manages the admin settings UI in relation to ticket configuration.
5
  */
6
  class Tribe__Tickets__Admin__Ticket_Settings {
7
+
8
  /**
9
  * Sets up the display of timezone-related settings and listeners to deal with timezone-update
10
  * requests (which are initiated from within the settings screen).
11
  */
12
  public function __construct() {
13
+ add_action( 'tribe_settings_do_tabs', [ $this, 'settings_ui' ] );
14
  }
15
 
16
  /**
src/Tribe/Assets.php CHANGED
@@ -22,6 +22,8 @@ class Tribe__Tickets__Assets {
22
 
23
  if ( $this->should_enqueue_common_full() ) {
24
  $tickets_deps[] = 'tribe-common-full-style';
 
 
25
  }
26
 
27
  // Check wether we use v1 or v2. We need to update this when we deprecate tickets v1.
@@ -32,7 +34,7 @@ class Tribe__Tickets__Assets {
32
  [
33
  [ 'event-tickets-reset-css', 'reset.css' ],
34
  [ 'event-tickets-tickets-css', $tickets_stylesheet, $tickets_deps ],
35
- [ 'event-tickets-tickets-rsvp-css', 'rsvp-v1.css', [] ],
36
  [ 'event-tickets-tickets-rsvp-js', 'rsvp.js', [ 'jquery' ] ],
37
  [ 'event-tickets-attendees-list-js', 'attendees-list.js', [ 'jquery' ] ],
38
  [ 'event-tickets-details-js', 'ticket-details.js', [] ],
@@ -47,7 +49,7 @@ class Tribe__Tickets__Assets {
47
  $tickets_main,
48
  'tribe-tickets-forms-style',
49
  'tickets-forms.css',
50
- [],
51
  null,
52
  [
53
  'groups' => [
@@ -85,7 +87,7 @@ class Tribe__Tickets__Assets {
85
  $tickets_main,
86
  'tribe-common-responsive',
87
  'common-responsive.css',
88
- [ 'tribe-common-skeleton-style' ],
89
  null,
90
  [
91
  'conditionals' => [ $this, 'should_enqueue_tickets_loader' ],
@@ -93,6 +95,8 @@ class Tribe__Tickets__Assets {
93
  'tribe-tickets-block-assets',
94
  'tribe-tickets-rsvp',
95
  'tribe-tickets-registration-page',
 
 
96
  ],
97
  ]
98
  );
@@ -165,7 +169,7 @@ class Tribe__Tickets__Assets {
165
  $tickets_main,
166
  'tribe-tickets-registration-page-styles',
167
  'tickets-registration-page.css',
168
- [],
169
  null,
170
  [
171
  'groups' => [
@@ -210,7 +214,7 @@ class Tribe__Tickets__Assets {
210
  $assets = [
211
  [ 'event-tickets-admin-css', 'tickets-admin.css', [ 'tribe-validation-style', 'tribe-jquery-timepicker-css', 'tribe-common-admin' ] ],
212
  [ 'event-tickets-admin-refresh-css', 'tickets-refresh.css', [ 'event-tickets-admin-css', 'tribe-common-admin' ] ],
213
- [ 'event-tickets-admin-tables-css', 'tickets-tables.css', [ 'event-tickets-admin-css' ] ],
214
  [ 'event-tickets-attendees-list-js', 'attendees-list.js', [ 'jquery' ] ],
215
  [ 'event-tickets-admin-accordion-js', 'accordion.js', [] ],
216
  [ 'event-tickets-admin-accordion-css', 'accordion.css', [] ],
@@ -363,6 +367,7 @@ class Tribe__Tickets__Assets {
363
  $admin_tabs = [
364
  'event-tickets',
365
  'event-tickets-commerce',
 
366
  ];
367
 
368
  // Load specifically on Ticket Settings page only.
22
 
23
  if ( $this->should_enqueue_common_full() ) {
24
  $tickets_deps[] = 'tribe-common-full-style';
25
+ } else {
26
+ $tickets_deps[] = 'tec-variables-full';
27
  }
28
 
29
  // Check wether we use v1 or v2. We need to update this when we deprecate tickets v1.
34
  [
35
  [ 'event-tickets-reset-css', 'reset.css' ],
36
  [ 'event-tickets-tickets-css', $tickets_stylesheet, $tickets_deps ],
37
+ [ 'event-tickets-tickets-rsvp-css', 'rsvp-v1.css', [ 'tec-variables-full' ] ],
38
  [ 'event-tickets-tickets-rsvp-js', 'rsvp.js', [ 'jquery' ] ],
39
  [ 'event-tickets-attendees-list-js', 'attendees-list.js', [ 'jquery' ] ],
40
  [ 'event-tickets-details-js', 'ticket-details.js', [] ],
49
  $tickets_main,
50
  'tribe-tickets-forms-style',
51
  'tickets-forms.css',
52
+ [ 'tec-variables-full' ],
53
  null,
54
  [
55
  'groups' => [
87
  $tickets_main,
88
  'tribe-common-responsive',
89
  'common-responsive.css',
90
+ [ 'tribe-common-skeleton-style', 'tec-variables-full' ],
91
  null,
92
  [
93
  'conditionals' => [ $this, 'should_enqueue_tickets_loader' ],
95
  'tribe-tickets-block-assets',
96
  'tribe-tickets-rsvp',
97
  'tribe-tickets-registration-page',
98
+ 'tribe-tickets-commerce',
99
+ 'tribe-tickets-commerce-checkout',
100
  ],
101
  ]
102
  );
169
  $tickets_main,
170
  'tribe-tickets-registration-page-styles',
171
  'tickets-registration-page.css',
172
+ [ 'tec-variables-full' ],
173
  null,
174
  [
175
  'groups' => [
214
  $assets = [
215
  [ 'event-tickets-admin-css', 'tickets-admin.css', [ 'tribe-validation-style', 'tribe-jquery-timepicker-css', 'tribe-common-admin' ] ],
216
  [ 'event-tickets-admin-refresh-css', 'tickets-refresh.css', [ 'event-tickets-admin-css', 'tribe-common-admin' ] ],
217
+ [ 'event-tickets-admin-tables-css', 'tickets-tables.css', [ 'tec-variables-full', 'event-tickets-admin-css' ] ],
218
  [ 'event-tickets-attendees-list-js', 'attendees-list.js', [ 'jquery' ] ],
219
  [ 'event-tickets-admin-accordion-js', 'accordion.js', [] ],
220
  [ 'event-tickets-admin-accordion-css', 'accordion.css', [] ],
367
  $admin_tabs = [
368
  'event-tickets',
369
  'event-tickets-commerce',
370
+ 'payments',
371
  ];
372
 
373
  // Load specifically on Ticket Settings page only.
src/Tribe/Attendee_Repository.php CHANGED
@@ -47,7 +47,7 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
47
  */
48
  protected static $public_order_statuses = [
49
  'yes', // RSVP
50
- 'completed', // PayPal
51
  'wc-completed', // WooCommerce
52
  'publish', // Easy Digital Downloads
53
  ];
@@ -142,8 +142,9 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
142
  */
143
  public function attendee_types() {
144
  return [
145
- 'rsvp' => 'tribe_rsvp_attendees',
146
- 'tribe-commerce' => 'tribe_tpp_attendees',
 
147
  ];
148
  }
149
 
@@ -158,8 +159,9 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
158
  */
159
  public function attendee_to_event_keys() {
160
  return [
161
- 'rsvp' => '_tribe_rsvp_event',
162
- 'tribe-commerce' => '_tribe_tpp_event',
 
163
  ];
164
  }
165
 
@@ -174,8 +176,9 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
174
  */
175
  public function attendee_to_ticket_keys() {
176
  return [
177
- 'rsvp' => '_tribe_rsvp_product',
178
- 'tribe-commerce' => '_tribe_tpp_product',
 
179
  ];
180
  }
181
 
@@ -189,8 +192,9 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
189
  */
190
  protected function attendee_to_order_keys() {
191
  return [
192
- 'rsvp' => '_tribe_rsvp_order',
193
- 'tribe-commerce' => '_tribe_tpp_order',
 
194
  ];
195
  }
196
 
@@ -205,8 +209,9 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
205
  */
206
  public function purchaser_name_keys() {
207
  return [
208
- 'rsvp' => '_tribe_rsvp_full_name',
209
- 'tribe-commerce' => '_tribe_tpp_full_name',
 
210
  ];
211
  }
212
 
@@ -221,8 +226,9 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
221
  */
222
  public function purchaser_email_keys() {
223
  return [
224
- 'rsvp' => '_tribe_rsvp_email',
225
- 'tribe-commerce' => '_tribe_tpp_email',
 
226
  ];
227
  }
228
 
@@ -237,8 +243,9 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
237
  */
238
  public function security_code_keys() {
239
  return [
240
- 'rsvp' => '_tribe_rsvp_security_code',
241
- 'tribe-commerce' => '_tribe_tpp_security_code',
 
242
  ];
243
  }
244
 
@@ -253,8 +260,9 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
253
  */
254
  public function attendee_optout_keys() {
255
  return [
256
- 'rsvp' => '_tribe_rsvp_attendee_optout',
257
- 'tribe-commerce' => '_tribe_tpp_attendee_optout',
 
258
  ];
259
  }
260
 
@@ -267,8 +275,9 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
267
  */
268
  public function checked_in_keys() {
269
  return [
270
- 'rsvp' => '_tribe_rsvp_checkedin',
271
- 'tribe-commerce' => '_tribe_tpp_checkedin',
 
272
  ];
273
  }
274
 
@@ -399,9 +408,10 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
399
  *
400
  * @since 4.8
401
  *
 
 
402
  * @param string|array $event_status
403
  *
404
- * @throws Tribe__Repository__Void_Query_Exception If the requested statuses are not accessible by the user.
405
  */
406
  public function filter_by_event_status( $event_status ) {
407
  $statuses = Arr::list_to_array( $event_status );
@@ -470,10 +480,11 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
470
  *
471
  * @since 4.8
472
  *
473
- * @param string|array $order_status Order status.
 
474
  * @param string $type Type of matching (in, not_in, like).
475
  *
476
- * @throws Tribe__Repository__Void_Query_Exception If the requested statuses are not accessible by the user.
477
  */
478
  public function filter_by_order_status( $order_status, $type = 'in' ) {
479
  $statuses = Arr::list_to_array( $order_status );
@@ -561,9 +572,10 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
561
  *
562
  * @since 4.10.6
563
  *
 
 
564
  * @param string|array $order_status
565
  *
566
- * @throws Tribe__Repository__Void_Query_Exception If the requested statuses are not accessible by the user.
567
  */
568
  public function filter_by_order_status_not_in( $order_status ) {
569
  $this->filter_by_order_status( $order_status, 'not_in' );
@@ -725,12 +737,14 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
725
  *
726
  * @since 5.1.0
727
  *
728
- * @param Tribe__Tickets__Ticket_Object|int $ticket The ticket object or ID.
 
729
  * @param array $attendee_data List of additional attendee data.
730
  *
 
 
731
  * @return WP_Post|false The new post object or false if unsuccessful.
732
  *
733
- * @throws Tribe__Repository__Usage_Error If the argument types are not set as expected.
734
  */
735
  public function create_attendee_for_ticket( $ticket, $attendee_data ) {
736
  // Attempt to get the ticket object from the ticket ID.
@@ -768,17 +782,19 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
768
  *
769
  * @since 5.1.0
770
  *
771
- * @param array $attendee_data List of attendee data to be saved.
 
772
  * @param bool $return_promise Whether to return a promise object or just the ids
773
  * of the updated posts; if `true` then a promise will
774
  * be returned whether the update is happening in background
775
  * or not.
776
  *
 
 
777
  * @return array|Tribe__Promise A list of the post IDs that have been (synchronous) or will
778
  * be (asynchronous) updated if `$return_promise` is set to `false`;
779
  * the Promise object if `$return_promise` is set to `true`.
780
  *
781
- * @throws Tribe__Repository__Usage_Error If the argument types are not set as expected.
782
  */
783
  public function update_attendee( $attendee_data, $return_promise = false ) {
784
  if ( empty( $attendee_data['attendee_id'] ) ) {
@@ -807,7 +823,7 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
807
  $repository = $this;
808
 
809
  return $saved->then(
810
- static function() use ( $repository, $attendee_data ) {
811
  // Trigger the update actions.
812
  $repository->trigger_update_actions( $attendee_data );
813
  }
@@ -825,10 +841,11 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
825
  *
826
  * @since 5.1.0
827
  *
828
- * @param array $attendee_data List of additional attendee data.
 
829
  * @param Tribe__Tickets__Ticket_Object $ticket The ticket object or null if not relying on it.
830
  *
831
- * @throws Tribe__Repository__Usage_Error If the argument types are not set as expected.
832
  */
833
  public function set_attendee_args( $attendee_data, $ticket = null ) {
834
  $args = [
@@ -1038,6 +1055,7 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
1038
  $query->set_args( $args );
1039
  } catch ( Tribe__Repository__Usage_Error $e ) {
1040
  do_action( 'tribe_log', 'error', __CLASS__, [ 'message' => $e->getMessage() ] );
 
1041
  return;
1042
  }
1043
 
@@ -1103,7 +1121,7 @@ class Tribe__Tickets__Attendee_Repository extends Tribe__Repository {
1103
  *
1104
  * @since 5.1.0
1105
  *
1106
- * @param array $attendee_data List of attendee data to be saved.
1107
  */
1108
  public function trigger_update_actions( $attendee_data ) {
1109
  /**
47
  */
48
  protected static $public_order_statuses = [
49
  'yes', // RSVP
50
+ 'completed', // PayPal Legacy
51
  'wc-completed', // WooCommerce
52
  'publish', // Easy Digital Downloads
53
  ];
142
  */
143
  public function attendee_types() {
144
  return [
145
+ 'rsvp' => 'tribe_rsvp_attendees',
146
+ 'tribe-commerce' => 'tribe_tpp_attendees',
147
+ \TEC\Tickets\Commerce::PROVIDER => \TEC\Tickets\Commerce\Attendee::POSTTYPE,
148
  ];
149
  }
150
 
159
  */
160
  public function attendee_to_event_keys() {
161
  return [
162
+ 'rsvp' => '_tribe_rsvp_event',
163
+ 'tribe-commerce' => '_tribe_tpp_event',
164
+ \TEC\Tickets\Commerce::PROVIDER => \TEC\Tickets\Commerce\Attendee::$event_relation_meta_key,
165
  ];
166
  }
167
 
176
  */
177
  public function attendee_to_ticket_keys() {
178
  return [
179
+ 'rsvp' => '_tribe_rsvp_product',
180
+ 'tribe-commerce' => '_tribe_tpp_product',
181
+ \TEC\Tickets\Commerce::PROVIDER => \TEC\Tickets\Commerce\Attendee::$ticket_relation_meta_key,
182
  ];
183
  }
184
 
192
  */
193
  protected function attendee_to_order_keys() {
194
  return [
195
+ 'rsvp' => '_tribe_rsvp_order',
196
+ 'tribe-commerce' => '_tribe_tpp_order',
197
+ \TEC\Tickets\Commerce::PROVIDER => \TEC\Tickets\Commerce\Attendee::$order_relation_meta_key,
198
  ];
199
  }
200
 
209
  */
210
  public function purchaser_name_keys() {
211
  return [
212
+ 'rsvp' => '_tribe_rsvp_full_name',
213
+ 'tribe-commerce' => '_tribe_tpp_full_name',
214
+ \TEC\Tickets\Commerce::PROVIDER => \TEC\Tickets\Commerce\Attendee::$purchaser_name_meta_key,
215
  ];
216
  }
217
 
226
  */
227
  public function purchaser_email_keys() {
228
  return [
229
+ 'rsvp' => '_tribe_rsvp_email',
230
+ 'tribe-commerce' => '_tribe_tpp_email',
231
+ \TEC\Tickets\Commerce::PROVIDER => \TEC\Tickets\Commerce\Attendee::$purchaser_email_meta_key,
232
  ];
233
  }
234
 
243
  */
244
  public function security_code_keys() {
245
  return [
246
+ 'rsvp' => '_tribe_rsvp_security_code',
247
+ 'tribe-commerce' => '_tribe_tpp_security_code',
248
+ \TEC\Tickets\Commerce::PROVIDER => \TEC\Tickets\Commerce\Attendee::$security_code_meta_key,
249
  ];
250
  }
251
 
260
  */
261
  public function attendee_optout_keys() {
262
  return [
263
+ 'rsvp' => '_tribe_rsvp_attendee_optout',
264
+ 'tribe-commerce' => '_tribe_tpp_attendee_optout',
265
+ \TEC\Tickets\Commerce::PROVIDER => \TEC\Tickets\Commerce\Attendee::$optout_meta_key,
266
  ];
267
  }
268
 
275
  */
276
  public function checked_in_keys() {
277
  return [
278
+ 'rsvp' => '_tribe_rsvp_checkedin',
279
+ 'tribe-commerce' => '_tribe_tpp_checkedin',
280
+ \TEC\Tickets\Commerce::PROVIDER => \TEC\Tickets\Commerce\Attendee::$checked_in_meta_key,
281
  ];
282
  }
283
 
408
  *
409
  * @since 4.8
410
  *
411
+ * @throws Tribe__Repository__Void_Query_Exception If the requested statuses are not accessible by the user.
412
+ *
413
  * @param string|array $event_status
414
  *
 
415
  */
416
  public function filter_by_event_status( $event_status ) {
417
  $statuses = Arr::list_to_array( $event_status );
480
  *
481
  * @since 4.8
482
  *
483
+ * @throws Tribe__Repository__Void_Query_Exception If the requested statuses are not accessible by the user.
484
+ *
485
  * @param string $type Type of matching (in, not_in, like).
486
  *
487
+ * @param string|array $order_status Order status.
488
  */
489
  public function filter_by_order_status( $order_status, $type = 'in' ) {
490
  $statuses = Arr::list_to_array( $order_status );
572
  *
573
  * @since 4.10.6
574
  *
575
+ * @throws Tribe__Repository__Void_Query_Exception If the requested statuses are not accessible by the user.
576
+ *
577
  * @param string|array $order_status
578
  *
 
579
  */
580
  public function filter_by_order_status_not_in( $order_status ) {
581
  $this->filter_by_order_status( $order_status, 'not_in' );
737
  *
738
  * @since 5.1.0
739
  *
740
+ * @throws Tribe__Repository__Usage_Error If the argument types are not set as expected.
741
+ *
742
  * @param array $attendee_data List of additional attendee data.
743
  *
744
+ * @param Tribe__Tickets__Ticket_Object|int $ticket The ticket object or ID.
745
+ *
746
  * @return WP_Post|false The new post object or false if unsuccessful.
747
  *
 
748
  */
749
  public function create_attendee_for_ticket( $ticket, $attendee_data ) {
750
  // Attempt to get the ticket object from the ticket ID.
782
  *
783
  * @since 5.1.0
784
  *
785
+ * @throws Tribe__Repository__Usage_Error If the argument types are not set as expected.
786
+ *
787
  * @param bool $return_promise Whether to return a promise object or just the ids
788
  * of the updated posts; if `true` then a promise will
789
  * be returned whether the update is happening in background
790
  * or not.
791
  *
792
+ * @param array $attendee_data List of attendee data to be saved.
793
+ *
794
  * @return array|Tribe__Promise A list of the post IDs that have been (synchronous) or will
795
  * be (asynchronous) updated if `$return_promise` is set to `false`;
796
  * the Promise object if `$return_promise` is set to `true`.
797
  *
 
798
  */
799
  public function update_attendee( $attendee_data, $return_promise = false ) {
800
  if ( empty( $attendee_data['attendee_id'] ) ) {
823
  $repository = $this;
824
 
825
  return $saved->then(
826
+ static function () use ( $repository, $attendee_data ) {
827
  // Trigger the update actions.
828
  $repository->trigger_update_actions( $attendee_data );
829
  }
841
  *
842
  * @since 5.1.0
843
  *
844
+ * @throws Tribe__Repository__Usage_Error If the argument types are not set as expected.
845
+ *
846
  * @param Tribe__Tickets__Ticket_Object $ticket The ticket object or null if not relying on it.
847
  *
848
+ * @param array $attendee_data List of additional attendee data.
849
  */
850
  public function set_attendee_args( $attendee_data, $ticket = null ) {
851
  $args = [
1055
  $query->set_args( $args );
1056
  } catch ( Tribe__Repository__Usage_Error $e ) {
1057
  do_action( 'tribe_log', 'error', __CLASS__, [ 'message' => $e->getMessage() ] );
1058
+
1059
  return;
1060
  }
1061
 
1121
  *
1122
  * @since 5.1.0
1123
  *
1124
+ * @param array $attendee_data List of attendee data to be saved.
1125
  */
1126
  public function trigger_update_actions( $attendee_data ) {
1127
  /**
src/Tribe/Commerce/PayPal/Main.php CHANGED
@@ -1598,7 +1598,7 @@ class Tribe__Tickets__Commerce__PayPal__Main extends Tribe__Tickets__Tickets {
1598
  /**
1599
  * {@inheritdoc}
1600
  */
1601
- protected function get_attendees_by_order_id( $order_id, $ticket_id = null ) {
1602
  if ( ! is_numeric( $order_id ) ) {
1603
  return parent::get_attendees_by_order_id( $order_id, $ticket_id );
1604
  }
1598
  /**
1599
  * {@inheritdoc}
1600
  */
1601
+ public function get_attendees_by_order_id( $order_id, $ticket_id = null ) {
1602
  if ( ! is_numeric( $order_id ) ) {
1603
  return parent::get_attendees_by_order_id( $order_id, $ticket_id );
1604
  }
src/Tribe/Editor/Configuration.php CHANGED
@@ -134,9 +134,12 @@ class Tribe__Tickets__Editor__Configuration implements Tribe__Editor__Configurat
134
  $currency_position = $currency->get_provider_symbol_position( $class_name, null );
135
  }
136
 
 
 
137
  $providers[] = [
138
  'name' => $modules[ $class_name ],
139
  'class' => $class_name,
 
140
  'currency' => html_entity_decode( $currency_symbol ),
141
  'currency_position' => $currency_position,
142
  ];
134
  $currency_position = $currency->get_provider_symbol_position( $class_name, null );
135
  }
136
 
137
+ $html_safe_class = str_replace( [ '\\' ], [ '_' ], $class_name );
138
+
139
  $providers[] = [
140
  'name' => $modules[ $class_name ],
141
  'class' => $class_name,
142
+ 'html_safe_class' => sanitize_html_class( $html_safe_class ),
143
  'currency' => html_entity_decode( $currency_symbol ),
144
  'currency_position' => $currency_position,
145
  ];
src/Tribe/Editor/Provider.php CHANGED
@@ -126,10 +126,21 @@ class Tribe__Tickets__Editor__Provider extends tad_DI52_ServiceProvider {
126
  tribe_callback( 'tickets.editor.blocks.attendees', 'register' )
127
  );
128
 
129
- add_action(
130
- 'block_categories',
131
- tribe_callback( 'tickets.editor', 'block_categories' )
132
- );
 
 
 
 
 
 
 
 
 
 
 
133
  }
134
 
135
  /**
126
  tribe_callback( 'tickets.editor.blocks.attendees', 'register' )
127
  );
128
 
129
+ global $wp_version;
130
+ if( version_compare( $wp_version, '5.8', '<' ) ) {
131
+ // WP version is less then 5.8.
132
+ add_action(
133
+ 'block_categories',
134
+ tribe_callback( 'tickets.editor', 'block_categories' )
135
+ );
136
+ } else {
137
+ // WP version is 5.8 or above.
138
+ add_action(
139
+ 'block_categories_all',
140
+ tribe_callback( 'tickets.editor', 'block_categories' )
141
+ );
142
+ }
143
+
144
  }
145
 
146
  /**
src/Tribe/Event_Repository.php CHANGED
@@ -88,8 +88,9 @@ class Tribe__Tickets__Event_Repository extends Tribe__Repository__Decorator {
88
  */
89
  public function attendee_types() {
90
  return [
91
- 'rsvp' => 'tribe_rsvp_attendees',
92
- 'tribe-commerce' => 'tribe_tpp_attendees',
 
93
  ];
94
  }
95
 
@@ -104,8 +105,9 @@ class Tribe__Tickets__Event_Repository extends Tribe__Repository__Decorator {
104
  */
105
  public function attendee_to_event_keys() {
106
  return [
107
- 'rsvp' => '_tribe_rsvp_event',
108
- 'tribe-commerce' => '_tribe_tpp_event',
 
109
  ];
110
  }
111
 
88
  */
89
  public function attendee_types() {
90
  return [
91
+ 'rsvp' => 'tribe_rsvp_attendees',
92
+ 'tribe-commerce' => 'tribe_tpp_attendees',
93
+ \TEC\Tickets\Commerce::PROVIDER => \TEC\Tickets\Commerce\Attendee::POSTTYPE,
94
  ];
95
  }
96
 
105
  */
106
  public function attendee_to_event_keys() {
107
  return [
108
+ 'rsvp' => '_tribe_rsvp_event',
109
+ 'tribe-commerce' => '_tribe_tpp_event',
110
+ \TEC\Tickets\Commerce::PROVIDER => \TEC\Tickets\Commerce\Attendee::$event_relation_meta_key,
111
  ];
112
  }
113
 
src/Tribe/Main.php CHANGED
@@ -1,5 +1,4 @@
1
  <?php
2
-
3
  use Tribe\Tickets\Events\Service_Provider as Events_Service_Provider;
4
  use Tribe\Tickets\Promoter\Service_Provider as Promoter_Service_Provider;
5
 
@@ -8,7 +7,7 @@ class Tribe__Tickets__Main {
8
  /**
9
  * Current version of this plugin
10
  */
11
- const VERSION = '5.1.8';
12
 
13
  /**
14
  * Used to store the version history.
@@ -302,8 +301,17 @@ class Tribe__Tickets__Main {
302
 
303
  add_action( 'tribe_common_loaded', [ $this, 'bootstrap' ], 0 );
304
 
305
- // Customizer support.
306
- tribe_register_provider( Tribe\Tickets\Service_Providers\Customizer::class );
 
 
 
 
 
 
 
 
 
307
  }
308
 
309
  /**
1
  <?php
 
2
  use Tribe\Tickets\Events\Service_Provider as Events_Service_Provider;
3
  use Tribe\Tickets\Promoter\Service_Provider as Promoter_Service_Provider;
4
 
7
  /**
8
  * Current version of this plugin
9
  */
10
+ const VERSION = '5.1.9';
11
 
12
  /**
13
  * Used to store the version history.
301
 
302
  add_action( 'tribe_common_loaded', [ $this, 'bootstrap' ], 0 );
303
 
304
+ // Customizer support - only loaded on older version of TEC for backwards compatibility.
305
+ if (
306
+ class_exists( 'Tribe__Events__Main' )
307
+ && (
308
+ ! function_exists( 'tribe_events_views_v2_is_enabled' )
309
+ || ! tribe_events_views_v2_is_enabled()
310
+ )
311
+ ) {
312
+ tribe_register_provider( Tribe\Tickets\Service_Providers\Customizer::class );
313
+ }
314
+
315
  }
316
 
317
  /**
src/Tribe/REST/V1/Endpoints/Base.php CHANGED
@@ -50,7 +50,7 @@ abstract class Tribe__Tickets__REST__V1__Endpoints__Base {
50
  * @param Tribe__Tickets__REST__V1__Validator__Interface $validator
51
  */
52
  public function __construct(
53
- Tribe__REST__Messages_Interface $messages,
54
  Tribe__Tickets__REST__Interfaces__Post_Repository $post_repository = null,
55
  Tribe__Tickets__REST__V1__Validator__Interface $validator = null
56
  ) {
50
  * @param Tribe__Tickets__REST__V1__Validator__Interface $validator
51
  */
52
  public function __construct(
53
+ Tribe__REST__Messages_Interface $messages = null,
54
  Tribe__Tickets__REST__Interfaces__Post_Repository $post_repository = null,
55
  Tribe__Tickets__REST__V1__Validator__Interface $validator = null
56
  ) {
src/Tribe/Repositories/Order.php CHANGED
@@ -99,7 +99,7 @@ class Order extends Tribe__Repository {
99
  return;
100
  }
101
 
102
- /** @var Tribe__Tickets__Status__Manager $status_mgr */
103
  $status_mgr = tribe( 'tickets.status' );
104
 
105
  /**
99
  return;
100
  }
101
 
102
+ /** @var \Tribe__Tickets__Status__Manager $status_mgr */
103
  $status_mgr = tribe( 'tickets.status' );
104
 
105
  /**
src/Tribe/Shortcodes/Tribe_Tickets_Checkout.php CHANGED
@@ -8,8 +8,9 @@
8
 
9
  namespace Tribe\Tickets\Shortcodes;
10
 
 
11
  use Tribe\Shortcode\Shortcode_Abstract;
12
- use TEC\Tickets\Commerce\Gateways\PayPal\SDK\Repositories\MerchantDetails;
13
  use TEC\Tickets\Commerce\Gateways\PayPal\Settings;
14
  use Tribe__Tickets__Editor__Template;
15
 
@@ -39,15 +40,27 @@ class Tribe_Tickets_Checkout extends Shortcode_Abstract {
39
  /** @var Tribe__Tickets__Editor__Template $template */
40
  $template = tribe( 'tickets.editor.template' );
41
 
42
- $merchant_details = tribe( MerchantDetails::class );
43
- $details = $merchant_details->getDetails();
 
 
 
 
 
 
 
 
44
 
45
  $args = [
46
- // @todo Set up args here.
47
- 'client_id' => $details->clientId,
48
- 'custom_payments' => $details->supportsCustomPayments,
 
 
49
  ];
50
 
 
 
51
  // Add the rendering attributes into global context.
52
  $template->add_template_globals( $args );
53
 
8
 
9
  namespace Tribe\Tickets\Shortcodes;
10
 
11
+ use TEC\Tickets\Commerce\Checkout;
12
  use Tribe\Shortcode\Shortcode_Abstract;
13
+ use TEC\Tickets\Commerce\Gateways\PayPal\Merchant;
14
  use TEC\Tickets\Commerce\Gateways\PayPal\Settings;
15
  use Tribe__Tickets__Editor__Template;
16
 
40
  /** @var Tribe__Tickets__Editor__Template $template */
41
  $template = tribe( 'tickets.editor.template' );
42
 
43
+ $merchant = tribe( Merchant::class );
44
+
45
+ $data = tribe( Checkout::class )->prepare_data_for_template( $_POST );
46
+
47
+ $post = get_post( $data['post_id'] );
48
+ $is_event = 'tribe_events' === $post->post_type;
49
+ $event = null;
50
+ if ( $is_event && function_exists( 'tribe_get_event' ) ) {
51
+ $event = tribe_get_event( $post );
52
+ }
53
 
54
  $args = [
55
+ 'merchant' => $merchant,
56
+ 'post' => $post,
57
+ 'event' => $event,
58
+ 'provider' => $data['provider'],
59
+ 'tickets' => $data['tickets'],
60
  ];
61
 
62
+ $args['paypal_attribution_id'] = \TEC\Tickets\Commerce\Gateways\PayPal\Gateway::ATTRIBUTION_ID;
63
+
64
  // Add the rendering attributes into global context.
65
  $template->add_template_globals( $args );
66
 
src/Tribe/Status/Manager.php CHANGED
@@ -25,6 +25,7 @@ class Tribe__Tickets__Status__Manager {
25
  'Tribe__Tickets__RSVP' => 'rsvp',
26
  'Tribe__Tickets__Commerce__PayPal__Main' => 'tpp',
27
  'Tribe__Tickets_Plus__Commerce__WooCommerce__Main' => 'woo',
 
28
  ];
29
  /**
30
  * Active Modules
@@ -39,10 +40,10 @@ class Tribe__Tickets__Status__Manager {
39
  * @var array
40
  */
41
  protected $status_managers = [
42
- 'edd' => 'Tribe__Tickets_Plus__Commerce__EDD__Status_Manager',
43
- 'rsvp' => 'Tribe__Tickets__RSVP__Status_Manager',
44
- 'tpp' => 'Tribe__Tickets__Commerce__PayPal__Status_Manager',
45
- 'woo' => 'Tribe__Tickets_Plus__Commerce__WooCommerce__Status_Manager',
46
  ];
47
 
48
  /**
25
  'Tribe__Tickets__RSVP' => 'rsvp',
26
  'Tribe__Tickets__Commerce__PayPal__Main' => 'tpp',
27
  'Tribe__Tickets_Plus__Commerce__WooCommerce__Main' => 'woo',
28
+ \TEC\Tickets\Commerce\Module::class => \TEC\Tickets\Commerce::ABBR,
29
  ];
30
  /**
31
  * Active Modules
40
  * @var array
41
  */
42
  protected $status_managers = [
43
+ 'edd' => 'Tribe__Tickets_Plus__Commerce__EDD__Status_Manager',
44
+ 'rsvp' => 'Tribe__Tickets__RSVP__Status_Manager',
45
+ 'tpp' => 'Tribe__Tickets__Commerce__PayPal__Status_Manager',
46
+ 'woo' => 'Tribe__Tickets_Plus__Commerce__WooCommerce__Status_Manager',
47
  ];
48
 
49
  /**
src/Tribe/Tickets.php CHANGED
@@ -884,7 +884,7 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
884
  *
885
  * @return array List of attendees.
886
  */
887
- protected function get_attendees_by_order_id( $order_id ) {
888
  $ticket_id = null;
889
 
890
  // Support an optional second argument while not causing warnings from other ticket provider classes.
@@ -3415,7 +3415,7 @@ if ( ! class_exists( 'Tribe__Tickets__Tickets' ) ) {
3415
  * @param array $raw_data
3416
  * @param string $save_type
3417
  */
3418
- protected function update_capacity( $ticket, $data, $save_type ) {
3419
  if ( empty( $data ) ) {
3420
  return;
3421
  }
884
  *
885
  * @return array List of attendees.
886
  */
887
+ public function get_attendees_by_order_id( $order_id ) {
888
  $ticket_id = null;
889
 
890
  // Support an optional second argument while not causing warnings from other ticket provider classes.
3415
  * @param array $raw_data
3416
  * @param string $save_type
3417
  */
3418
+ public function update_capacity( $ticket, $data, $save_type ) {
3419
  if ( empty( $data ) ) {
3420
  return;
3421
  }
src/Tribe/Tickets_View.php CHANGED
@@ -1236,20 +1236,6 @@ class Tribe__Tickets__Tickets_View {
1236
  */
1237
  $template->add_template_globals( $args );
1238
 
1239
- // Determine whether to show the previews on the page.
1240
- if (
1241
- defined( 'TRIBE_TICKETS_RSVP_NEW_VIEWS_PREVIEW' )
1242
- && TRIBE_TICKETS_RSVP_NEW_VIEWS_PREVIEW
1243
- ) {
1244
- // Enqueue new assets.
1245
- tribe_asset_enqueue( 'tribe-tickets-rsvp-style' );
1246
- tribe_asset_enqueue( 'tribe-tickets-forms-style' );
1247
- // @todo: Remove this once we solve the common breakpoints vs container based.
1248
- tribe_asset_enqueue( 'tribe-common-responsive' );
1249
-
1250
- return $template->template( 'v2/rsvp-kitchen-sink', $args, $echo );
1251
- }
1252
-
1253
  ob_start();
1254
 
1255
  /**
1236
  */
1237
  $template->add_template_globals( $args );
1238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1239
  ob_start();
1240
 
1241
  /**
src/admin-views/commerce/gateways/paypal/signup-link.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script>
2
+ function onboardedCallback( authCode, sharedId ) {
3
+ fetch( '<?php echo tribe( \TEC\Tickets\Commerce\Gateways\PayPal\REST\On_Boarding_Endpoint::class )->get_route_url() ?>', {
4
+ method: 'POST',
5
+ headers: {
6
+ 'content-type': 'application/json',
7
+ },
8
+ body: JSON.stringify( {
9
+ auth_code: authCode,
10
+ shared_id: sharedId,
11
+ nonce: '<?php echo wp_create_nonce( 'tec-tc-on-boarded' ); ?>',
12
+ } ),
13
+ } );
14
+ }
15
+ </script>
16
+
17
+ <div class="tec-tickets-commerce-connect-paypal-button">
18
+ <a
19
+ target="_blank"
20
+ data-paypal-onboard-complete="onboardedCallback"
21
+ href="<?php echo esc_url( $url ) ?>&displayMode=minibrowser"
22
+ data-paypal-button="true"
23
+ id="connect_to_paypal"
24
+ >
25
+ <?php echo wp_kses( __( 'Connect Automatically with <i>PayPal</i>', 'event-tickets' ), 'post' ); ?>
26
+ </a>
27
+ </div>
src/admin-views/commerce/metabox/capacity.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @var string|int $ticket_capacity
4
+ */
5
+ ?>
6
+
7
+ <div
8
+ class="input_block ticket_advanced_TEC_Tickets_Commerce_Module tribe-dependent"
9
+ data-depends="#provider_TEC_Tickets_Commerce_Module_radio"
10
+ data-condition-is-checked
11
+ >
12
+ <label
13
+ for="Tribe__Tickets__Commerce__PayPal__Main_capacity"
14
+ class="ticket_form_label ticket_form_left"
15
+ >
16
+ <?php esc_html_e( 'Capacity:', 'event-tickets' ); ?>
17
+ </label>
18
+ <input
19
+ type='text' id='TEC_Tickets_Commerce_Module_capacity'
20
+ name='tribe-ticket[capacity]'
21
+ class="ticket_field tribe-tpp-field-capacity ticket_form_right"
22
+ size='7'
23
+ value='<?php echo esc_attr( -1 === (int) $ticket_capacity ? '' : $ticket_capacity ); ?>'
24
+ />
25
+ <span class="tribe_soft_note ticket_form_right"><?php esc_html_e( 'Leave blank for unlimited', 'event-tickets' ); ?></span>
26
+ </div>
27
+ <?php
src/admin-views/commerce/metabox/sku.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use TEC\Tickets\Commerce\Module;
4
+ /**
5
+ * Filters the boolean value that controls whether a sku is displayed or not
6
+ *
7
+ * @since 4.7
8
+ *
9
+ * @param boolean $display_sku
10
+ */
11
+ $display_sku = apply_filters( 'tribe_events_tickets_tpp_display_sku', true );
12
+ $html_safe_provider_class = sanitize_html_class( Module::class );
13
+
14
+ if ( ! $display_sku ) {
15
+ return;
16
+ }
17
+ ?>
18
+
19
+ <div class="'ticket_advanced_<?php echo $html_safe_provider_class; ?> input_block tribe-dependent"
20
+ data-depends="#provider_TEC_Tickets_Commerce_Module_radio"
21
+ data-condition-is-checked
22
+ >
23
+ <label for="ticket_tpp_sku" class="ticket_form_label ticket_form_left"><?php esc_html_e( 'SKU:', 'event-tickets' ); ?></label>
24
+ <input
25
+ type="text"
26
+ id="ticket_sku"
27
+ name="ticket_sku"
28
+ class="ticket_field sku_input ticket_form_right"
29
+ size="14"
30
+ value="<?php echo esc_attr( $sku ); ?>"
31
+ >
32
+ <p class="description ticket_form_right">
33
+ <?php
34
+ echo esc_html(
35
+ sprintf(
36
+ __( 'A unique identifying code for each %s type you\'re selling', 'event-tickets' ),
37
+ tribe_get_ticket_label_singular_lowercase( 'sku' )
38
+ )
39
+ );
40
+ ?>
41
+ </p>
42
+ </div>
src/admin-views/editor/fieldset/settings-provider.php CHANGED
@@ -23,7 +23,7 @@ $default_module_class = (string) Tribe__Tickets__Tickets::get_event_ticket_provi
23
  type="radio"
24
  class="tribe-ticket-editor-field-default_provider settings_field"
25
  name="tribe-tickets[settings][default_provider]"
26
- id="provider_<?php echo esc_attr( $active_provider['class'] . '_radio' ); ?>"
27
  value="<?php echo esc_attr( $active_provider['class'] ); ?>"
28
  checked
29
  >
@@ -52,12 +52,12 @@ $default_module_class = (string) Tribe__Tickets__Tickets::get_event_ticket_provi
52
  ?></em>
53
  </p>
54
  <?php foreach ( $active_providers as $active_provider ) : ?>
55
- <label class="ticket_form_right" for="provider_<?php echo esc_attr( $active_provider['class'] . '_radio' ); ?>">
56
  <input
57
  <?php checked( $default_module_class, $active_provider['class'] ); ?>
58
  type="radio"
59
  name="tribe-tickets[settings][default_provider]"
60
- id="provider_<?php echo esc_attr( $active_provider['class'] . '_radio' ); ?>"
61
  value="<?php echo esc_attr( $active_provider['class'] ); ?>"
62
  class="tribe-ticket-editor-field-default_provider settings_field ticket_field"
63
  aria-labelledby="default_ticket_provider_legend"
23
  type="radio"
24
  class="tribe-ticket-editor-field-default_provider settings_field"
25
  name="tribe-tickets[settings][default_provider]"
26
+ id="provider_<?php echo esc_attr( $active_provider['html_safe_class'] . '_radio' ); ?>"
27
  value="<?php echo esc_attr( $active_provider['class'] ); ?>"
28
  checked
29
  >
52
  ?></em>
53
  </p>
54
  <?php foreach ( $active_providers as $active_provider ) : ?>
55
+ <label class="ticket_form_right" for="provider_<?php echo esc_attr( $active_provider['html_safe_class'] . '_radio' ); ?>">
56
  <input
57
  <?php checked( $default_module_class, $active_provider['class'] ); ?>
58
  type="radio"
59
  name="tribe-tickets[settings][default_provider]"
60
+ id="provider_<?php echo esc_attr( $active_provider['html_safe_class'] . '_radio' ); ?>"
61
  value="<?php echo esc_attr( $active_provider['class'] ); ?>"
62
  class="tribe-ticket-editor-field-default_provider settings_field ticket_field"
63
  aria-labelledby="default_ticket_provider_legend"
src/admin-views/payments/tickets-commerce.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The Template for displaying the Tickets Commerce Payments Settings.
4
+ *
5
+ * @version 5.1.9
6
+ *
7
+ * @todo This whole file needs to be completely reviewed once the designs are correct in place.
8
+ */
9
+
10
+ use TEC\Tickets\Commerce\Gateways\PayPal\Merchant;
11
+ use TEC\Tickets\Commerce\Gateways\PayPal\Signup;
12
+
13
+ $merchant = tribe( Merchant::class );
14
+ $is_merchant_active = $merchant->is_active();
15
+
16
+ $display = '<div class="tec-tickets-commerce-paypal-connect">';
17
+
18
+ if ( $is_merchant_active ) {
19
+ $name = $merchant->get_merchant_id();
20
+
21
+ $disconnect_url = Tribe__Settings::instance()->get_url( [ 'tab' => 'payments', 'tc-action' => 'paypal-disconnect' ] );
22
+ $refresh_url = Tribe__Settings::instance()->get_url( [ 'tab' => 'payments', 'tc-action' => 'paypal-refresh-access-token' ] );
23
+ $refresh_user_info_url = Tribe__Settings::instance()->get_url( [ 'tab' => 'payments', 'tc-action' => 'paypal-refresh-user-info' ] );
24
+
25
+ $disconnect = ' <a href="' . esc_url( $disconnect_url ) . '">' . esc_html__( 'Disconnect', 'event-tickets' ) . '</a>';
26
+ $refresh = ' <a href="' . esc_url( $refresh_url ) . '">' . esc_html__( 'Refresh Access Token', 'event-tickets' ) . '</a>';
27
+ $refresh_user_info = ' <a href="' . esc_url( $refresh_user_info_url ) . '">' . esc_html__( 'Refresh User Info', 'event-tickets' ) . '</a>';
28
+ $display .= '<p>' . esc_html__( 'PayPal Status: Connected', 'event-tickets' ) . '</p>';
29
+ $display .= '<p>' . esc_html( sprintf( __( 'Connected as: %1$s', 'event-tickets' ), $name ) ) . $disconnect . '</p>';
30
+ $display .= '<p>' . $refresh . $refresh_user_info . '</p>';
31
+ } else {
32
+ $display .= '<h2>' . esc_html__( 'Accept online payments with PayPal!', 'event-tickets' ) . '</h2>
33
+ ' . esc_html__( 'Start selling tickets to your events today with PayPal. Attendees can purchase tickets directly on your site using debt or credit cards with no additional fees.',
34
+ 'event-tickets' ) . tribe( Signup::class )->get_link_html();
35
+ }
36
+ $path = tribe_resource_url( 'images/admin/paypal_logo.png', false, null, Tribe__Tickets__Main::instance() );
37
+ $display .= '</div><div class="tec-tickets-commerce-paypal-logo"><img src=' . esc_url( $path ) . ' alt="Tickets Commerce PayPal Logo">';
38
+
39
+ $display .= '
40
+ <ul>
41
+ <li>' . esc_html__( 'Credit and debit card payments', 'event-tickets' ) . '</li>
42
+ <li>' . esc_html__( 'Easy, no API key connection', 'event-tickets' ) . '</li>
43
+ <li>' . esc_html__( 'Accept payments from around the world', 'event-tickets' ) . '</li>
44
+ <li>' . esc_html__( 'Support 3D Secure Payments', 'event-tickets' ) . '</li>
45
+ </ul>
46
+ ';
47
+
48
+ $display .= '</div>';
49
+
50
+ $tickets_fields = [
51
+ 'tribe-form-content-start' => [
52
+ 'type' => 'html',
53
+ 'html' => '<div class="tribe-settings-form-wrap tec-tickets-commerce-payments">',
54
+ ],
55
+ 'tickets-commerce-header' => [
56
+ 'type' => 'html',
57
+ 'html' => '<div class="tec-tickets-commerce-toggle"><label class="tec-tickets-commerce-switch"><input type="checkbox"><span class="tec-tickets-commerce-slider round"></span></label><h2>' . esc_html__( 'Enable TicketsCommerce', 'event-tickets' ) . '</h2></div>',
58
+ ],
59
+ 'tickets-commerce-description' => [
60
+ 'type' => 'html',
61
+ 'html' => '<div class="tec-tickets-commerce-description">' . esc_html__( 'TicketsCommerce allows you to accept payments for tickets with Event Tickets and Event Tickets Plus. Configure payments through PayPal, allowing users to pay with credit card or their PayPal account. Learn More about payment processing with TicketsCommerce.' ) . '</div>',
62
+ ],
63
+ 'tickets-commerce-paypal-description' => [
64
+ 'type' => 'html',
65
+ 'html' => '<div class="tec-tickets-commerce-paypal">' . $display . '</div>',
66
+ ],
67
+ 'tribe-form-content-end' => [
68
+ 'type' => 'html',
69
+ 'html' => '</div>',
70
+ ],
71
+ ];
72
+
73
+ /**
74
+ * Filters the fields to be registered in the Events > Settings > Payments tab.
75
+ *
76
+ * @see Tribe__Field
77
+ * @see Tribe__Settings_Tab
78
+ *
79
+ * @param array $tickets_fields An associative array of fields definitions to register.
80
+ *
81
+ */
82
+ $tickets_fields = apply_filters( 'tribe_tickets_commerce_payments_settings_tab_fields', $tickets_fields );
83
+
84
+ $tickets_tab = [
85
+ 'priority' => 20,
86
+ 'fields' => $tickets_fields,
87
+ 'show_save' => false,
88
+ ];
src/admin-views/settings/tickets-commerce/paypal-commerce/introduction.php CHANGED
@@ -1,40 +1,59 @@
1
  <?php
2
  /**
3
- * Introduction section for the Tickets Commerce > PayPal Commerce gateway settings.
4
  *
5
- * @since 5.1.6
 
6
  *
7
- * @var string $plugin_url [Global] The plugin URL.
8
  */
9
 
10
- // @todo Replace font awesome icon usages.
 
11
 
 
 
 
12
  ?>
 
 
 
 
 
13
 
14
- <div id="give-paypal-commerce-introduction-wrap">
15
- <div class="hero-section">
16
- <div>
17
- <h2><?php esc_html_e( 'Accept payments with PayPal Commerce', 'event-tickets' ); ?></h2>
18
- <p class="give-field-description">
19
- <?php esc_html_e( 'Allow your customers to pay using Debit or Credit Cards directly on your website.', 'event-tickets' ); ?>
 
 
 
 
 
 
 
 
 
20
  </p>
21
- </div>
22
- <div class="paypal-logo">
23
- <img src="<?php echo esc_url( $plugin_url . 'src/resources/images/admin/paypal-logo.svg' ); ?>" width="316" height="84" alt="<?php esc_attr_e( 'PayPal Logo Image', 'event-tickets' ); ?>">
24
- </div>
25
  </div>
26
- <div class="feature-list">
27
- <div>
28
- <i class="fa fa-angle-right"></i> <?php esc_html_e( 'Credit and Debit Card payments', 'event-tickets' ); ?>
29
- </div>
30
- <div>
31
- <i class="fa fa-angle-right"></i> <?php esc_html_e( 'Easy no-API key connection', 'event-tickets' ); ?>
32
- </div>
33
- <div>
34
- <i class="fa fa-angle-right"></i> <?php esc_html_e( 'Accept payments from around the world', 'event-tickets' ); ?>
35
- </div>
36
- <div>
37
- <i class="fa fa-angle-right"></i> <?php esc_html_e( 'Supports 3D Secure payments', 'event-tickets' ); ?>
38
- </div>
 
 
 
39
  </div>
40
- </div>
1
  <?php
2
  /**
3
+ * The Template for displaying the Tickets Commerce Payments Settings.
4
  *
5
+ * @todo This whole file needs to be completely reviewed once the designs are correct in place.
6
+ * @version 5.1.9
7
  *
 
8
  */
9
 
10
+ use TEC\Tickets\Commerce\Gateways\PayPal\Merchant;
11
+ use TEC\Tickets\Commerce\Gateways\PayPal\Signup;
12
 
13
+ $merchant = tribe( Merchant::class );
14
+ $is_merchant_active = $merchant->is_active();
15
+ $path = tribe_resource_url( 'images/admin/paypal-logo.svg', false, null, Tribe__Tickets__Main::instance() );
16
  ?>
17
+ <div class="tec-tickets-commerce-paypal">
18
+ <div id="tec-tickets-commerce-paypal-connect">
19
+ <?php if ( $is_merchant_active ) : ?>
20
+ <?php
21
+ $name = $merchant->get_merchant_id();
22
 
23
+ $disconnect_url = Tribe__Settings::instance()->get_url( [ 'tab' => 'payments', 'tc-action' => 'paypal-disconnect' ] );
24
+ $refresh_url = Tribe__Settings::instance()->get_url( [ 'tab' => 'payments', 'tc-action' => 'paypal-refresh-access-token' ] );
25
+ $refresh_user_info_url = Tribe__Settings::instance()->get_url( [ 'tab' => 'payments', 'tc-action' => 'paypal-refresh-user-info' ] );
26
+
27
+ $disconnect = ' <a href="' . esc_url( $disconnect_url ) . '">' . esc_html__( 'Disconnect', 'event-tickets' ) . '</a>';
28
+ $refresh = ' <a href="' . esc_url( $refresh_url ) . '">' . esc_html__( 'Refresh Access Token', 'event-tickets' ) . '</a>';
29
+ $refresh_user_info = ' <a href="' . esc_url( $refresh_user_info_url ) . '">' . esc_html__( 'Refresh User Info', 'event-tickets' ) . '</a>';
30
+ ?>
31
+ <p><?php esc_html_e( 'PayPal Status: Connected', 'event-tickets' ); ?></p>
32
+ <p><?php echo esc_html( sprintf( __( 'Connected as: %1$s', 'event-tickets' ), $name ) ) . $disconnect; ?></p>
33
+ <p><?php echo $refresh . $refresh_user_info; ?></p>
34
+ <?php else : ?>
35
+ <h2><?php esc_html_e( 'Accept online payments with PayPal!', 'event-tickets' ); ?></h2>
36
+ <p>
37
+ <?php esc_html_e( 'Start selling tickets to your events today with PayPal. Attendees can purchase tickets directly on your site using debt or credit cards with no additional fees.', 'event-tickets' ); ?>
38
  </p>
39
+ <?php echo tribe( Signup::class )->get_link_html(); ?>
40
+ <?php endif; ?>
 
 
41
  </div>
42
+ <div class="tec-tickets-commerce-paypal-logo">
43
+ <img src="<?php echo esc_url( $path ); ?>" width="316" height="84" alt="<?php esc_attr_e( 'PayPal Logo Image', 'event-tickets' ); ?>">
44
+ <ul>
45
+ <li>
46
+ <?php esc_html_e( 'Credit and Debit Card payments', 'event-tickets' ); ?>
47
+ </li>
48
+ <li>
49
+ <?php esc_html_e( 'Easy no-API key connection', 'event-tickets' ); ?>
50
+ </li>
51
+ <li>
52
+ <?php esc_html_e( 'Accept payments from around the world', 'event-tickets' ); ?>
53
+ </li>
54
+ <li>
55
+ <?php esc_html_e( 'Supports 3D Secure payments', 'event-tickets' ); ?>
56
+ </li>
57
+ </ul>
58
  </div>
59
+ </div>
src/functions/commerce/attendees.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Functions and template tags dedicated to attendees in Ticket Commerce.
4
+ *
5
+ * @since 5.1.9
6
+ */
7
+
8
+ use TEC\Tickets\Commerce\Models\Ticket_Model;
9
+
10
+ /**
11
+ * Fetches and returns a decorated post object representing an attendee.
12
+ *
13
+ * @since 5.1.9
14
+ *
15
+ * @param null|int|WP_Post $attendee The attendee ID or post object or `null` to use the global one.
16
+ * @param string|null $output The required return type. One of `OBJECT`, `ARRAY_A`, or `ARRAY_N`, which
17
+ * correspond to a WP_Post object, an associative array, or a numeric array,
18
+ * respectively. Defaults to `OBJECT`.
19
+ * @param string $filter Type of filter to apply.
20
+ * @param bool $force Whether to force a re-fetch ignoring cached results or not.
21
+ *
22
+ * @return array|mixed|void|WP_Post|null The Order post object or array, `null` if not found.
23
+ */
24
+ function tec_tc_get_attendee( $attendee = null, $output = OBJECT, $filter = 'raw', $force = false ) {
25
+ /**
26
+ * Filters the attendee result before any logic applies.
27
+ *
28
+ * Returning a non `null` value here will short-circuit the function and return the value.
29
+ * Note: this value will not be cached and the caching of this value is a duty left to the filtering function.
30
+ *
31
+ * @since 5.1.9
32
+ *
33
+ * @param mixed $return The attendee object to return.
34
+ * @param mixed $attendee The attendee object to fetch.
35
+ * @param string|null $output The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
36
+ * correspond to a `WP_Post` object, an associative array, or a numeric array,
37
+ * respectively. Defaults to `OBJECT`.
38
+ * @param string $filter Type of filter to apply.
39
+ */
40
+ $return = apply_filters( 'tec_tickets_commerce_get_attendee_before', null, $attendee, $output, $filter );
41
+
42
+ if ( null !== $return ) {
43
+ return $return;
44
+ }
45
+
46
+ $post = false;
47
+
48
+ /** @var Tribe__Cache $cache */
49
+ $cache = tribe( 'cache' );
50
+
51
+ $cache_post = get_post( $attendee );
52
+
53
+ if ( empty( $cache_post ) ) {
54
+ return null;
55
+ }
56
+
57
+ $key_fields = [
58
+ $cache_post->ID,
59
+ $cache_post->post_modified,
60
+ // Use the `post_password` field as we show/hide some information depending on that.
61
+ $cache_post->post_password,
62
+ // We must include options on cache key, because options influence the hydrated data on the Order object.
63
+ wp_json_encode( Tribe__Settings_Manager::get_options() ),
64
+ wp_json_encode( [
65
+ get_option( 'start_of_week' ),
66
+ get_option( 'timezone_string' ),
67
+ get_option( 'gmt_offset' )
68
+ ] ),
69
+ $output,
70
+ $filter,
71
+ ];
72
+
73
+ $cache_key = 'tec_tc_get_attendee_' . md5( wp_json_encode( $key_fields ) );
74
+
75
+ if ( ! $force ) {
76
+ $post = $cache->get( $cache_key, Tribe__Cache_Listener::TRIGGER_SAVE_POST );
77
+ }
78
+
79
+ if ( false === $post ) {
80
+ $post = Ticket_Model::from_post( $attendee )->to_post( $output, $filter );
81
+
82
+ if ( empty( $post ) ) {
83
+ return null;
84
+ }
85
+
86
+ /**
87
+ * Filters the attendee post object before caching it and returning it.
88
+ *
89
+ * Note: this value will be cached; as such this filter might not run on each request.
90
+ * If you need to filter the output value on each call of this function then use the `tec_tickets_commerce_get_attendee_before`
91
+ * filter.
92
+ *
93
+ * @since 5.1.9
94
+ *
95
+ * @param WP_Post $post The attendee post object, decorated with a set of custom properties.
96
+ * @param string $output The output format to use.
97
+ * @param string $filter The filter, or context of the fetch.
98
+ */
99
+ $post = apply_filters( 'tec_tickets_commerce_get_attendee', $post, $output, $filter );
100
+
101
+ // Dont try to reset cache when forcing.
102
+ if ( ! $force ) {
103
+ $cache->set( $cache_key, $post, WEEK_IN_SECONDS, Tribe__Cache_Listener::TRIGGER_SAVE_POST );
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Filters the attendee result after the attendee has been built from the function.
109
+ *
110
+ * Note: this value will not be cached and the caching of this value is a duty left to the filtering function.
111
+ *
112
+ * @since 5.1.9
113
+ *
114
+ * @param WP_Post $post The attendee post object to filter and return.
115
+ * @param int|WP_Post $attendee The attendee object to fetch.
116
+ * @param string|null $output The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
117
+ * correspond to a `WP_Post` object, an associative array, or a numeric array,
118
+ * respectively. Defaults to `OBJECT`.
119
+ * @param string $filter Type of filter to apply.
120
+ */
121
+ $post = apply_filters( 'tec_tickets_commerce_get_attendee_after', $post, $attendee, $output, $filter );
122
+
123
+ if ( OBJECT !== $output ) {
124
+ $post = ARRAY_A === $output ? (array) $post : array_values( (array) $post );
125
+ }
126
+
127
+ return $post;
128
+ }
src/functions/commerce/orders.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Functions and template tags dedicated to Orders in Ticket Commerce.
4
+ *
5
+ * @since 5.1.9
6
+ */
7
+
8
+ use TEC\Tickets\Commerce\Models\Order_Model;
9
+
10
+ /**
11
+ * Fetches and returns a decorated post object representing an Order.
12
+ *
13
+ * @since 5.1.9
14
+ *
15
+ * @param null|int|WP_Post $order The order ID or post object or `null` to use the global one.
16
+ * @param string|null $output The required return type. One of `OBJECT`, `ARRAY_A`, or `ARRAY_N`, which
17
+ * correspond to a WP_Post object, an associative array, or a numeric array,
18
+ * respectively. Defaults to `OBJECT`.
19
+ * @param string $filter Type of filter to apply.
20
+ * @param bool $force Whether to force a re-fetch ignoring cached results or not.
21
+ *
22
+ * @return array|WP_Post|null The Order post object or array, `null` if not found.
23
+ */
24
+ function tec_tc_get_order( $order = null, $output = OBJECT, $filter = 'raw', $force = false ) {
25
+ /**
26
+ * Filters the order result before any logic applies.
27
+ *
28
+ * Returning a non `null` value here will short-circuit the function and return the value.
29
+ * Note: this value will not be cached and the caching of this value is a duty left to the filtering function.
30
+ *
31
+ * @since 5.1.9
32
+ *
33
+ * @param mixed $return The order object to return.
34
+ * @param mixed $order The order object to fetch.
35
+ * @param string|null $output The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
36
+ * correspond to a `WP_Post` object, an associative array, or a numeric array,
37
+ * respectively. Defaults to `OBJECT`.
38
+ * @param string $filter Type of filter to apply.
39
+ */
40
+ $return = apply_filters( 'tec_tickets_commerce_get_order_before', null, $order, $output, $filter );
41
+
42
+ if ( null !== $return ) {
43
+ return $return;
44
+ }
45
+
46
+ $post = false;
47
+
48
+ /** @var Tribe__Cache $cache */
49
+ $cache = tribe( 'cache' );
50
+
51
+ $cache_post = get_post( $order );
52
+
53
+ if ( empty( $cache_post ) ) {
54
+ return null;
55
+ }
56
+
57
+ $key_fields = [
58
+ $cache_post->ID,
59
+ $cache_post->post_modified,
60
+ // Use the `post_password` field as we show/hide some information depending on that.
61
+ $cache_post->post_password,
62
+ // We must include options on cache key, because options influence the hydrated data on the Order object.
63
+ wp_json_encode( Tribe__Settings_Manager::get_options() ),
64
+ wp_json_encode( [
65
+ get_option( 'start_of_week' ),
66
+ get_option( 'timezone_string' ),
67
+ get_option( 'gmt_offset' )
68
+ ] ),
69
+ $output,
70
+ $filter,
71
+ ];
72
+
73
+ $cache_key = 'tec_tc_get_order_' . md5( wp_json_encode( $key_fields ) );
74
+
75
+ if ( ! $force ) {
76
+ $post = $cache->get( $cache_key, Tribe__Cache_Listener::TRIGGER_SAVE_POST );
77
+ }
78
+
79
+ if ( false === $post ) {
80
+ $post = Order_Model::from_post( $order )->to_post( $output, $filter );
81
+
82
+ if ( empty( $post ) ) {
83
+ return null;
84
+ }
85
+
86
+ /**
87
+ * Filters the order post object before caching it and returning it.
88
+ *
89
+ * Note: this value will be cached; as such this filter might not run on each request.
90
+ * If you need to filter the output value on each call of this function then use the `tec_tickets_commerce_get_order_before`
91
+ * filter.
92
+ *
93
+ * @since 5.1.9
94
+ *
95
+ * @param WP_Post $post The order post object, decorated with a set of custom properties.
96
+ * @param string $output The output format to use.
97
+ * @param string $filter The filter, or context of the fetch.
98
+ */
99
+ $post = apply_filters( 'tec_tickets_commerce_get_order', $post, $output, $filter );
100
+
101
+ // Dont try to reset cache when forcing.
102
+ if ( ! $force ) {
103
+ $cache->set( $cache_key, $post, WEEK_IN_SECONDS, Tribe__Cache_Listener::TRIGGER_SAVE_POST );
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Filters the order result after the order has been built from the function.
109
+ *
110
+ * Note: this value will not be cached and the caching of this value is a duty left to the filtering function.
111
+ *
112
+ * @since 5.1.9
113
+ *
114
+ * @param WP_Post $post The order post object to filter and return.
115
+ * @param int|WP_Post $order The order object to fetch.
116
+ * @param string|null $output The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
117
+ * correspond to a `WP_Post` object, an associative array, or a numeric array,
118
+ * respectively. Defaults to `OBJECT`.
119
+ * @param string $filter Type of filter to apply.
120
+ */
121
+ $post = apply_filters( 'tec_tickets_commerce_get_order_after', $post, $order, $output, $filter );
122
+
123
+ if ( OBJECT !== $output ) {
124
+ $post = ARRAY_A === $output ? (array) $post : array_values( (array) $post );
125
+ }
126
+
127
+ return $post;
128
+ }
src/functions/commerce/orm.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ use \Tribe__Utils__Array as Arr;
3
+
4
+ /**
5
+ * Builds and returns the correct Orders repository.
6
+ *
7
+ * @since 5.1.9
8
+ *
9
+ * @param string $repository The slug of the repository to build/return.
10
+ *
11
+ * @return Tribe__Repository__Interface An instance of the requested repository
12
+ * class.
13
+ */
14
+ function tec_tc_orders( $repository = 'default' ) {
15
+ $map = [
16
+ 'default' => TEC\Tickets\Commerce\Repositories\Order_Repository::class,
17
+ ];
18
+
19
+ $args = func_num_args() > 1 ? array_slice( func_get_args(), 1 ) : [];
20
+
21
+ /**
22
+ * Filters the map relating orders repository slugs to service container bindings.
23
+ *
24
+ * @since 5.1.9
25
+ *
26
+ * @param array $map A map in the shape [ <repository_slug> => <service_name> ]
27
+ * @param string $repository The currently requested implementation.
28
+ * @param array $args An array of additional call arguments used to call the function beside the
29
+ * repository slug.
30
+ */
31
+ $map = apply_filters( 'tec_tickets_commerce_orders_repository_map', $map, $repository, $args );
32
+
33
+ return tribe( Arr::get( $map, $repository, $map['default'] ) );
34
+ }
35
+
36
+ /**
37
+ * Builds and returns the correct Tickets repository.
38
+ *
39
+ * @since 5.1.9
40
+ *
41
+ * @param string $repository The slug of the repository to build/return.
42
+ *
43
+ * @return Tribe__Repository__Interface An instance of the requested repository
44
+ * class.
45
+ */
46
+ function tec_tc_tickets( $repository = 'default' ) {
47
+ $map = [
48
+ 'default' => TEC\Tickets\Commerce\Repositories\Tickets_Repository::class,
49
+ ];
50
+
51
+ $args = func_num_args() > 1 ? array_slice( func_get_args(), 1 ) : [];
52
+
53
+ /**
54
+ * Filters the map relating tickets repository slugs to service container bindings.
55
+ *
56
+ * @since 5.1.9
57
+ *
58
+ * @param array $map A map in the shape [ <repository_slug> => <service_name> ]
59
+ * @param string $repository The currently requested implementation.
60
+ * @param array $args An array of additional call arguments used to call the function beside the
61
+ * repository slug.
62
+ */
63
+ $map = apply_filters( 'tec_tickets_commerce_tickets_repository_map', $map, $repository, $args );
64
+
65
+ return tribe( Arr::get( $map, $repository, $map['default'] ) );
66
+ }
67
+
68
+ /**
69
+ * Builds and returns the correct Attendees repository.
70
+ *
71
+ * @since 5.1.9
72
+ *
73
+ * @param string $repository The slug of the repository to build/return.
74
+ *
75
+ * @return Tribe__Repository__Interface An instance of the requested repository
76
+ * class.
77
+ */
78
+ function tec_tc_attendees( $repository = 'default' ) {
79
+ $map = [
80
+ 'default' => TEC\Tickets\Commerce\Repositories\Attendees_Repository::class,
81
+ ];
82
+
83
+ $args = func_num_args() > 1 ? array_slice( func_get_args(), 1 ) : [];
84
+
85
+ /**
86
+ * Filters the map relating attendees repository slugs to service container bindings.
87
+ *
88
+ * @since 5.1.9
89
+ *
90
+ * @param array $map A map in the shape [ <repository_slug> => <service_name> ]
91
+ * @param string $repository The currently requested implementation.
92
+ * @param array $args An array of additional call arguments used to call the function beside the
93
+ * repository slug.
94
+ */
95
+ $map = apply_filters( 'tec_tickets_commerce_attendees_repository_map', $map, $repository, $args );
96
+
97
+ return tribe( Arr::get( $map, $repository, $map['default'] ) );
98
+ }
src/functions/commerce/tickets.php ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Functions and template tags dedicated to tickets in Ticket Commerce.
4
+ *
5
+ * @since 5.1.9
6
+ */
7
+
8
+ use TEC\Tickets\Commerce\Models\Ticket_Model;
9
+
10
+ /**
11
+ * Fetches and returns a decorated post object representing an ticket.
12
+ *
13
+ * @since 5.1.9
14
+ *
15
+ * @param null|int|WP_Post $ticket The ticket ID or post object or `null` to use the global one.
16
+ * @param string|null $output The required return type. One of `OBJECT`, `ARRAY_A`, or `ARRAY_N`, which
17
+ * correspond to a WP_Post object, an associative array, or a numeric array,
18
+ * respectively. Defaults to `OBJECT`.
19
+ * @param string $filter Type of filter to apply.
20
+ * @param bool $force Whether to force a re-fetch ignoring cached results or not.
21
+ *
22
+ * @return array|mixed|void|WP_Post|null The Order post object or array, `null` if not found.
23
+ */
24
+ function tec_tc_get_ticket( $ticket = null, $output = OBJECT, $filter = 'raw', $force = false ) {
25
+ /**
26
+ * Filters the ticket result before any logic applies.
27
+ *
28
+ * Returning a non `null` value here will short-circuit the function and return the value.
29
+ * Note: this value will not be cached and the caching of this value is a duty left to the filtering function.
30
+ *
31
+ * @since 5.1.9
32
+ *
33
+ * @param mixed $return The ticket object to return.
34
+ * @param mixed $ticket The ticket object to fetch.
35
+ * @param string|null $output The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
36
+ * correspond to a `WP_Post` object, an associative array, or a numeric array,
37
+ * respectively. Defaults to `OBJECT`.
38
+ * @param string $filter Type of filter to apply.
39
+ */
40
+ $return = apply_filters( 'tec_tickets_commerce_get_ticket_before', null, $ticket, $output, $filter );
41
+
42
+ if ( null !== $return ) {
43
+ return $return;
44
+ }
45
+
46
+ $post = false;
47
+
48
+ /** @var Tribe__Cache $cache */
49
+ $cache = tribe( 'cache' );
50
+
51
+ $cache_post = get_post( $ticket );
52
+
53
+ if ( empty( $cache_post ) ) {
54
+ return null;
55
+ }
56
+
57
+ $key_fields = [
58
+ $cache_post->ID,
59
+ $cache_post->post_modified,
60
+ // Use the `post_password` field as we show/hide some information depending on that.
61
+ $cache_post->post_password,
62
+ // We must include options on cache key, because options influence the hydrated data on the Order object.
63
+ wp_json_encode( Tribe__Settings_Manager::get_options() ),
64
+ wp_json_encode( [
65
+ get_option( 'start_of_week' ),
66
+ get_option( 'timezone_string' ),
67
+ get_option( 'gmt_offset' )
68
+ ] ),
69
+ $output,
70
+ $filter,
71
+ ];
72
+
73
+ $cache_key = 'tec_tc_get_ticket_' . md5( wp_json_encode( $key_fields ) );
74
+
75
+ if ( ! $force ) {
76
+ $post = $cache->get( $cache_key, Tribe__Cache_Listener::TRIGGER_SAVE_POST );
77
+ }
78
+
79
+ if ( false === $post ) {
80
+ $post = Ticket_Model::from_post( $ticket )->to_post( $output, $filter );
81
+
82
+ if ( empty( $post ) ) {
83
+ return null;
84
+ }
85
+
86
+ /**
87
+ * Filters the ticket post object before caching it and returning it.
88
+ *
89
+ * Note: this value will be cached; as such this filter might not run on each request.
90
+ * If you need to filter the output value on each call of this function then use the `tec_tickets_commerce_get_ticket_before`
91
+ * filter.
92
+ *
93
+ * @since 5.1.9
94
+ *
95
+ * @param WP_Post $post The ticket post object, decorated with a set of custom properties.
96
+ * @param string $output The output format to use.
97
+ * @param string $filter The filter, or context of the fetch.
98
+ */
99
+ $post = apply_filters( 'tec_tickets_commerce_get_ticket', $post, $output, $filter );
100
+
101
+ // Dont try to reset cache when forcing.
102
+ if ( ! $force ) {
103
+ $cache->set( $cache_key, $post, WEEK_IN_SECONDS, Tribe__Cache_Listener::TRIGGER_SAVE_POST );
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Filters the ticket result after the ticket has been built from the function.
109
+ *
110
+ * Note: this value will not be cached and the caching of this value is a duty left to the filtering function.
111
+ *
112
+ * @since 5.1.9
113
+ *
114
+ * @param WP_Post $post The ticket post object to filter and return.
115
+ * @param int|WP_Post $ticket The ticket object to fetch.
116
+ * @param string|null $output The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
117
+ * correspond to a `WP_Post` object, an associative array, or a numeric array,
118
+ * respectively. Defaults to `OBJECT`.
119
+ * @param string $filter Type of filter to apply.
120
+ */
121
+ $post = apply_filters( 'tec_tickets_commerce_get_ticket_after', $post, $ticket, $output, $filter );
122
+
123
+ if ( OBJECT !== $output ) {
124
+ $post = ARRAY_A === $output ? (array) $post : array_values( (array) $post );
125
+ }
126
+
127
+ return $post;
128
+ }
src/modules/blocks/rsvp/move-delete/style.pcss CHANGED
@@ -9,7 +9,7 @@
9
  &:first-child {
10
  color: #009fd4;
11
 
12
- &::after {
13
  color: #8d949b;
14
  content: '|';
15
  margin: 0 10px;
9
  &:first-child {
10
  color: #009fd4;
11
 
12
+ &:after {
13
  color: #8d949b;
14
  content: '|';
15
  margin: 0 10px;
src/modules/blocks/ticket/container-content/advanced-options/move-delete/style.pcss CHANGED
@@ -9,7 +9,7 @@
9
  &:first-child {
10
  color: #009fd4;
11
 
12
- &::after {
13
  color: #8d949b;
14
  content: '|';
15
  margin: 0 10px;
9
  &:first-child {
10
  color: #009fd4;
11
 
12
+ &:after {
13
  color: #8d949b;
14
  content: '|';
15
  margin: 0 10px;
src/resources/css/app/rsvp/frontend.css CHANGED
@@ -1 +1 @@
1
- .tribe-block__rsvp{font-family:Helvetica,sans-serif;margin-bottom:30px;margin-top:30px;max-width:580px;position:relative}.tribe-block__rsvp__ticket{border:1px solid #e1e3e6;display:flex;flex-wrap:wrap;position:relative;width:100%}.tribe-block__rsvp__icon{align-items:center;background:#fff;border-bottom:1px dashed #b5bcc2;color:#434343;display:flex;flex:none;flex-direction:column;font-size:14px;font-weight:700;line-height:17px;padding:20px 17px;width:100%}.tribe-block__rsvp__icon svg{margin-bottom:7px}.tribe-block__rsvp__content{background-color:#f5f8f9;flex:auto}.tribe-block__rsvp__details{padding:25px 20px 20px}.tribe-block__rsvp__title{color:#000;font-size:21px;font-weight:700;line-height:28px;margin-bottom:12px}.tribe-block__rsvp__description{color:#545d66;font-size:14px;line-height:18px;margin-bottom:15px}.tribe-block__rsvp__availability{color:#545d66;display:flex;align-items:center;font-size:12px;line-height:18px}.tribe-block__rsvp__quantity{font-size:18px;font-weight:700;margin-right:6px}.tribe-block__rsvp__status{display:flex;flex-wrap:nowrap;padding:0 20px 25px;text-align:center}.tribe-block__rsvp__status>span{flex:none;margin-right:15px;width:calc(50% - 7.5px)}.tribe-block__rsvp__status>span:last-child{margin-right:0}.tribe-block__rsvp__status-button{align-items:center;border:1px solid #545d66;border-radius:4px;background:#fff;color:#545d66;display:flex;font-family:Helvetica,sans-serif;font-size:14px;font-weight:700;height:44px;justify-content:center;line-height:1;padding:0;width:100%}.tribe-block__rsvp__status-button svg{margin-left:9px}.tribe-block__rsvp__status-button:focus,.tribe-block__rsvp__status-button:hover{background:#fff;border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-active{border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-inactive{border:1px solid #e1e3e6;color:#a2aab2}.tribe-block__rsvp__status-button.tribe-inactive:focus,.tribe-block__rsvp__status-button.tribe-inactive:hover{background:#fff;border:1px solid #545d66;color:#545d66}.tribe-block__rsvp__status-button[disabled=disabled]{cursor:default}.tribe-block__rsvp__going-icon,.tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-active .tribe-block__rsvp__going-icon,.tribe-active .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__not-going-icon{fill:#191e23}.tribe-inactive .tribe-block__rsvp__going-icon,.tribe-inactive .tribe-block__rsvp__not-going-icon{fill:#e1e3e6}.tribe-inactive:focus .tribe-block__rsvp__going-icon,.tribe-inactive:focus .tribe-block__rsvp__not-going-icon,.tribe-inactive:hover .tribe-block__rsvp__going-icon,.tribe-inactive:hover .tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-block__rsvp__form{padding:0 20px}.tribe-block__rsvp__form form{border-top:1px solid #e1e3e6;display:flex;padding:30px 0}.tribe-left{flex:none}.tribe-block__rsvp__number-input{padding-right:20px}.tribe-block__rsvp__number-input-inner{align-items:center;display:flex}.tribe-block__rsvp__number-input-inner input[type=number]{-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;background:transparent;border:none;color:#000;font-family:Helvetica,sans-serif;font-size:30px;font-weight:700;height:40px;max-width:48px;padding:4px 0;text-align:center}.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-inner-spin-button,.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;appearance:none}.tribe-block__rsvp__number-input-label{display:block;font-size:14px;font-weight:700;line-height:18px;margin-top:9px;text-align:center}.tribe-block__rsvp__number-input-button{background-color:transparent;height:30px;padding:0;position:relative;width:20px}.tribe-block__rsvp__number-input-button:after,.tribe-block__rsvp__number-input-button:before{background-color:#aeb4bb;content:"";height:2px;position:absolute;width:10px}.tribe-block__rsvp__number-input-button:focus,.tribe-block__rsvp__number-input-button:hover{background:none}.tribe-block__rsvp__number-input-button:focus:after,.tribe-block__rsvp__number-input-button:focus:before,.tribe-block__rsvp__number-input-button:hover:after,.tribe-block__rsvp__number-input-button:hover:before{background-color:#545d66}.tribe-block__rsvp__number-input-button--minus{margin-left:-10px}.tribe-block__rsvp__number-input-button--minus:after,.tribe-block__rsvp__number-input-button--minus:before{right:0}.tribe-block__rsvp__number-input-button--plus{margin-right:-10px}.tribe-block__rsvp__number-input-button--plus:after,.tribe-block__rsvp__number-input-button--plus:before{left:0}.tribe-block__rsvp__number-input-button--plus:after{transform:rotate(90deg)}.tribe-right{flex:auto}.tribe-right input[type=email],.tribe-right input[type=text]{border-color:#e1e3e6;color:#000;display:block;font-family:Helvetica,sans-serif;font-size:16px;height:40px;line-height:18px;margin-bottom:15px;padding:10px 15px;width:100%}.tribe-right input[type=email]::-moz-placeholder,.tribe-right input[type=text]::-moz-placeholder{color:#a2aab2}.tribe-right input[type=email]:-ms-input-placeholder,.tribe-right input[type=text]:-ms-input-placeholder{color:#a2aab2}.tribe-right input[type=email]::placeholder,.tribe-right input[type=text]::placeholder{color:#a2aab2}.tribe-right label{cursor:pointer;font-size:var(--font-size-2);font-weight:400}.tribe-right label[for^=tribe-tickets-attendees-list-optout]{align-items:flex-start;display:flex;margin:0 0 15px;padding-top:7px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border:1px solid #e1e3e6;border-radius:0;cursor:pointer;flex:none;height:16px;margin:1px 10px 0 0;width:16px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:focus{box-shadow:0 0 0 1px #e1e3e6;outline:2px solid transparent;outline-offset:-2px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:checked:before{color:#009fd4;content:"\F147";display:inline-block;float:left;font:normal 21px/1 dashicons;margin:-3px 0 0 -4px;speak:none;vertical-align:middle;width:16px}.tribe-tickets-meta-option-label{color:#000;font-size:14px;line-height:18px}.tribe-block__rsvp__message__error,.tribe-block__rsvp__message__success{color:#000;font-size:14px;line-height:18px;padding:20px}.tribe-block__rsvp__message__error{background:#ffebe8;border:1px solid #c00;display:none;margin-bottom:20px}.tribe-block__rsvp__message__success{background:#ecfae5;border:1px solid #1bd800;margin-top:20px}.tribe-block__rsvp__submit-button{background:#009fd4;color:#fff;font-family:Helvetica,sans-serif;font-size:15px;font-weight:700;line-height:18px;margin:10px 0 0;padding:10px 23px}.tribe-block__rsvp__submit-button:focus,.tribe-block__rsvp__submit-button:hover{background:#007bb4}.tribe-block__rsvp__submit-button:disabled{cursor:not-allowed;background:#a2aab2}.tribe-block__rsvp__form__attendee-meta{margin:0}.tribe-block__rsvp__form__attendee-meta td,.tribe-block__rsvp__form__attendee-meta th{padding:0;border:none;word-break:normal}.tribe-common-c-loader.tribe-block__rsvp__loading{align-items:center;background:hsla(0,0%,100%,.7);height:100%;justify-content:center;left:0;margin:0;padding:0;position:absolute;text-align:center;top:0;width:100%;z-index:99}.tribe-common-c-loader.tribe-block__rsvp__loading svg{max-width:70px;position:absolute;top:35%}.tribe-common-c-loader.tribe-block__rsvp__loading svg circle{fill:#888}@media (min-width:600px){.tribe-block__rsvp__ticket{align-items:stretch;flex-wrap:nowrap}.tribe-block__rsvp__icon{border-bottom:none;border-right:1px dashed #b5bcc2;padding:28px 17px;width:84px}.tribe-block__rsvp__number-input-inner input[type=number]{font-size:36px;height:48px}.tribe-block__rsvp__message__success{padding:10px 30px;text-align:center}}
1
+ .tribe-block__rsvp{font-family:var(--tec-font-family-sans-serif);margin-bottom:30px;margin-top:30px;max-width:580px;position:relative}.tribe-block__rsvp__ticket{border:1px solid #e1e3e6;display:flex;flex-wrap:wrap;position:relative;width:100%}.tribe-block__rsvp__icon{align-items:center;background:#fff;border-bottom:1px dashed #b5bcc2;color:#434343;display:flex;flex:none;flex-direction:column;font-size:14px;font-weight:700;line-height:17px;padding:20px 17px;width:100%}.tribe-block__rsvp__icon svg{margin-bottom:7px}.tribe-block__rsvp__content{background-color:#f5f8f9;flex:auto}.tribe-block__rsvp__details{padding:25px 20px 20px}.tribe-block__rsvp__title{color:#000;font-size:21px;font-weight:700;line-height:28px;margin-bottom:12px}.tribe-block__rsvp__description{color:#545d66;font-size:14px;line-height:18px;margin-bottom:15px}.tribe-block__rsvp__availability{color:#545d66;display:flex;align-items:center;font-size:12px;line-height:18px}.tribe-block__rsvp__quantity{font-size:18px;font-weight:700;margin-right:6px}.tribe-block__rsvp__status{display:flex;flex-wrap:nowrap;padding:0 20px 25px;text-align:center}.tribe-block__rsvp__status>span{flex:none;margin-right:15px;width:calc(50% - 7.5px)}.tribe-block__rsvp__status>span:last-child{margin-right:0}.tribe-block__rsvp__status-button{align-items:center;border:1px solid #545d66;border-radius:4px;background:#fff;color:#545d66;display:flex;font-family:var(--tec-font-family-sans-serif);font-size:14px;font-weight:700;height:44px;justify-content:center;line-height:1;padding:0;width:100%}.tribe-block__rsvp__status-button svg{margin-left:9px}.tribe-block__rsvp__status-button:focus,.tribe-block__rsvp__status-button:hover{background:#fff;border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-active{border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-inactive{border:1px solid #e1e3e6;color:#a2aab2}.tribe-block__rsvp__status-button.tribe-inactive:focus,.tribe-block__rsvp__status-button.tribe-inactive:hover{background:#fff;border:1px solid #545d66;color:#545d66}.tribe-block__rsvp__status-button[disabled=disabled]{cursor:default}.tribe-block__rsvp__going-icon,.tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-active .tribe-block__rsvp__going-icon,.tribe-active .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__not-going-icon{fill:#191e23}.tribe-inactive .tribe-block__rsvp__going-icon,.tribe-inactive .tribe-block__rsvp__not-going-icon{fill:#e1e3e6}.tribe-inactive:focus .tribe-block__rsvp__going-icon,.tribe-inactive:focus .tribe-block__rsvp__not-going-icon,.tribe-inactive:hover .tribe-block__rsvp__going-icon,.tribe-inactive:hover .tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-block__rsvp__form{padding:0 20px}.tribe-block__rsvp__form form{border-top:1px solid #e1e3e6;display:flex;padding:30px 0}.tribe-left{flex:none}.tribe-block__rsvp__number-input{padding-right:20px}.tribe-block__rsvp__number-input-inner{align-items:center;display:flex}.tribe-block__rsvp__number-input-inner input[type=number]{-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;background:transparent;border:none;color:#000;font-family:var(--tec-font-family-sans-serif);font-size:30px;font-weight:700;height:40px;max-width:48px;padding:4px 0;text-align:center}.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-inner-spin-button,.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;appearance:none}.tribe-block__rsvp__number-input-label{display:block;font-size:14px;font-weight:700;line-height:18px;margin-top:9px;text-align:center}.tribe-block__rsvp__number-input-button{background-color:transparent;height:30px;padding:0;position:relative;width:20px}.tribe-block__rsvp__number-input-button:after,.tribe-block__rsvp__number-input-button:before{background-color:#aeb4bb;content:"";height:2px;position:absolute;width:10px}.tribe-block__rsvp__number-input-button:focus,.tribe-block__rsvp__number-input-button:hover{background:none}.tribe-block__rsvp__number-input-button:focus:after,.tribe-block__rsvp__number-input-button:focus:before,.tribe-block__rsvp__number-input-button:hover:after,.tribe-block__rsvp__number-input-button:hover:before{background-color:#545d66}.tribe-block__rsvp__number-input-button--minus{margin-left:-10px}.tribe-block__rsvp__number-input-button--minus:after,.tribe-block__rsvp__number-input-button--minus:before{right:0}.tribe-block__rsvp__number-input-button--plus{margin-right:-10px}.tribe-block__rsvp__number-input-button--plus:after,.tribe-block__rsvp__number-input-button--plus:before{left:0}.tribe-block__rsvp__number-input-button--plus:after{transform:rotate(90deg)}.tribe-right{flex:auto}.tribe-right input[type=email],.tribe-right input[type=text]{border-color:#e1e3e6;color:#000;display:block;font-family:var(--tec-font-family-sans-serif);font-size:16px;height:40px;line-height:18px;margin-bottom:15px;padding:10px 15px;width:100%}.tribe-right input[type=email]::-moz-placeholder,.tribe-right input[type=text]::-moz-placeholder{color:#a2aab2}.tribe-right input[type=email]:-ms-input-placeholder,.tribe-right input[type=text]:-ms-input-placeholder{color:#a2aab2}.tribe-right input[type=email]::placeholder,.tribe-right input[type=text]::placeholder{color:#a2aab2}.tribe-right label{cursor:pointer;font-size:var(--tec-font-size-2);font-weight:400}.tribe-right label[for^=tribe-tickets-attendees-list-optout]{align-items:flex-start;display:flex;margin:0 0 15px;padding-top:7px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border:1px solid #e1e3e6;border-radius:0;cursor:pointer;flex:none;height:16px;margin:1px 10px 0 0;width:16px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:focus{box-shadow:0 0 0 1px #e1e3e6;outline:2px solid transparent;outline-offset:-2px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:checked:before{color:#009fd4;content:"\F147";display:inline-block;float:left;font:normal 21px/1 dashicons;margin:-3px 0 0 -4px;speak:none;vertical-align:middle;width:16px}.tribe-tickets-meta-option-label{color:#000;font-size:14px;line-height:18px}.tribe-block__rsvp__message__error,.tribe-block__rsvp__message__success{color:#000;font-size:14px;line-height:18px;padding:20px}.tribe-block__rsvp__message__error{background:#ffebe8;border:1px solid #c00;display:none;margin-bottom:20px}.tribe-block__rsvp__message__success{background:#ecfae5;border:1px solid #1bd800;margin-top:20px}.tribe-block__rsvp__submit-button{background:#009fd4;color:#fff;font-family:var(--tec-font-family-sans-serif);font-size:15px;font-weight:700;line-height:18px;margin:10px 0 0;padding:10px 23px}.tribe-block__rsvp__submit-button:focus,.tribe-block__rsvp__submit-button:hover{background:#007bb4}.tribe-block__rsvp__submit-button:disabled{cursor:not-allowed;background:#a2aab2}.tribe-block__rsvp__form__attendee-meta{margin:0}.tribe-block__rsvp__form__attendee-meta td,.tribe-block__rsvp__form__attendee-meta th{padding:0;border:none;word-break:normal}.tribe-common-c-loader.tribe-block__rsvp__loading{align-items:center;background:hsla(0,0%,100%,.7);height:100%;justify-content:center;left:0;margin:0;padding:0;position:absolute;text-align:center;top:0;width:100%;z-index:99}.tribe-common-c-loader.tribe-block__rsvp__loading svg{max-width:70px;position:absolute;top:35%}.tribe-common-c-loader.tribe-block__rsvp__loading svg circle{fill:#888}@media (min-width:600px){.tribe-block__rsvp__ticket{align-items:stretch;flex-wrap:nowrap}.tribe-block__rsvp__icon{border-bottom:none;border-right:1px dashed #b5bcc2;padding:28px 17px;width:84px}.tribe-block__rsvp__number-input-inner input[type=number]{font-size:36px;height:48px}.tribe-block__rsvp__message__success{padding:10px 30px;text-align:center}}
src/resources/css/app/rsvp/frontend.min.css CHANGED
@@ -1 +1 @@
1
- .tribe-block__rsvp{font-family:Helvetica,sans-serif;margin-bottom:30px;margin-top:30px;max-width:580px;position:relative}.tribe-block__rsvp__ticket{border:1px solid #e1e3e6;display:flex;flex-wrap:wrap;position:relative;width:100%}.tribe-block__rsvp__icon{align-items:center;background:#fff;border-bottom:1px dashed #b5bcc2;color:#434343;display:flex;flex:none;flex-direction:column;font-size:14px;font-weight:700;line-height:17px;padding:20px 17px;width:100%}.tribe-block__rsvp__icon svg{margin-bottom:7px}.tribe-block__rsvp__content{background-color:#f5f8f9;flex:auto}.tribe-block__rsvp__details{padding:25px 20px 20px}.tribe-block__rsvp__title{color:#000;font-size:21px;font-weight:700;line-height:28px;margin-bottom:12px}.tribe-block__rsvp__description{color:#545d66;font-size:14px;line-height:18px;margin-bottom:15px}.tribe-block__rsvp__availability{color:#545d66;display:flex;align-items:center;font-size:12px;line-height:18px}.tribe-block__rsvp__quantity{font-size:18px;font-weight:700;margin-right:6px}.tribe-block__rsvp__status{display:flex;flex-wrap:nowrap;padding:0 20px 25px;text-align:center}.tribe-block__rsvp__status>span{flex:none;margin-right:15px;width:calc(50% - 7.5px)}.tribe-block__rsvp__status>span:last-child{margin-right:0}.tribe-block__rsvp__status-button{align-items:center;border:1px solid #545d66;border-radius:4px;background:#fff;color:#545d66;display:flex;font-family:Helvetica,sans-serif;font-size:14px;font-weight:700;height:44px;justify-content:center;line-height:1;padding:0;width:100%}.tribe-block__rsvp__status-button svg{margin-left:9px}.tribe-block__rsvp__status-button:focus,.tribe-block__rsvp__status-button:hover{background:#fff;border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-active{border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-inactive{border:1px solid #e1e3e6;color:#a2aab2}.tribe-block__rsvp__status-button.tribe-inactive:focus,.tribe-block__rsvp__status-button.tribe-inactive:hover{background:#fff;border:1px solid #545d66;color:#545d66}.tribe-block__rsvp__status-button[disabled=disabled]{cursor:default}.tribe-block__rsvp__going-icon,.tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-active .tribe-block__rsvp__going-icon,.tribe-active .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__not-going-icon{fill:#191e23}.tribe-inactive .tribe-block__rsvp__going-icon,.tribe-inactive .tribe-block__rsvp__not-going-icon{fill:#e1e3e6}.tribe-inactive:focus .tribe-block__rsvp__going-icon,.tribe-inactive:focus .tribe-block__rsvp__not-going-icon,.tribe-inactive:hover .tribe-block__rsvp__going-icon,.tribe-inactive:hover .tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-block__rsvp__form{padding:0 20px}.tribe-block__rsvp__form form{border-top:1px solid #e1e3e6;display:flex;padding:30px 0}.tribe-left{flex:none}.tribe-block__rsvp__number-input{padding-right:20px}.tribe-block__rsvp__number-input-inner{align-items:center;display:flex}.tribe-block__rsvp__number-input-inner input[type=number]{-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;background:transparent;border:none;color:#000;font-family:Helvetica,sans-serif;font-size:30px;font-weight:700;height:40px;max-width:48px;padding:4px 0;text-align:center}.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-inner-spin-button,.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;appearance:none}.tribe-block__rsvp__number-input-label{display:block;font-size:14px;font-weight:700;line-height:18px;margin-top:9px;text-align:center}.tribe-block__rsvp__number-input-button{background-color:transparent;height:30px;padding:0;position:relative;width:20px}.tribe-block__rsvp__number-input-button:after,.tribe-block__rsvp__number-input-button:before{background-color:#aeb4bb;content:"";height:2px;position:absolute;width:10px}.tribe-block__rsvp__number-input-button:focus,.tribe-block__rsvp__number-input-button:hover{background:none}.tribe-block__rsvp__number-input-button:focus:after,.tribe-block__rsvp__number-input-button:focus:before,.tribe-block__rsvp__number-input-button:hover:after,.tribe-block__rsvp__number-input-button:hover:before{background-color:#545d66}.tribe-block__rsvp__number-input-button--minus{margin-left:-10px}.tribe-block__rsvp__number-input-button--minus:after,.tribe-block__rsvp__number-input-button--minus:before{right:0}.tribe-block__rsvp__number-input-button--plus{margin-right:-10px}.tribe-block__rsvp__number-input-button--plus:after,.tribe-block__rsvp__number-input-button--plus:before{left:0}.tribe-block__rsvp__number-input-button--plus:after{transform:rotate(90deg)}.tribe-right{flex:auto}.tribe-right input[type=email],.tribe-right input[type=text]{border-color:#e1e3e6;color:#000;display:block;font-family:Helvetica,sans-serif;font-size:16px;height:40px;line-height:18px;margin-bottom:15px;padding:10px 15px;width:100%}.tribe-right input[type=email]::-moz-placeholder,.tribe-right input[type=text]::-moz-placeholder{color:#a2aab2}.tribe-right input[type=email]:-ms-input-placeholder,.tribe-right input[type=text]:-ms-input-placeholder{color:#a2aab2}.tribe-right input[type=email]::placeholder,.tribe-right input[type=text]::placeholder{color:#a2aab2}.tribe-right label{cursor:pointer;font-size:var(--font-size-2);font-weight:400}.tribe-right label[for^=tribe-tickets-attendees-list-optout]{align-items:flex-start;display:flex;margin:0 0 15px;padding-top:7px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border:1px solid #e1e3e6;border-radius:0;cursor:pointer;flex:none;height:16px;margin:1px 10px 0 0;width:16px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:focus{box-shadow:0 0 0 1px #e1e3e6;outline:2px solid transparent;outline-offset:-2px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:checked:before{color:#009fd4;content:"\F147";display:inline-block;float:left;font:normal 21px/1 dashicons;margin:-3px 0 0 -4px;speak:none;vertical-align:middle;width:16px}.tribe-tickets-meta-option-label{color:#000;font-size:14px;line-height:18px}.tribe-block__rsvp__message__error,.tribe-block__rsvp__message__success{color:#000;font-size:14px;line-height:18px;padding:20px}.tribe-block__rsvp__message__error{background:#ffebe8;border:1px solid #c00;display:none;margin-bottom:20px}.tribe-block__rsvp__message__success{background:#ecfae5;border:1px solid #1bd800;margin-top:20px}.tribe-block__rsvp__submit-button{background:#009fd4;color:#fff;font-family:Helvetica,sans-serif;font-size:15px;font-weight:700;line-height:18px;margin:10px 0 0;padding:10px 23px}.tribe-block__rsvp__submit-button:focus,.tribe-block__rsvp__submit-button:hover{background:#007bb4}.tribe-block__rsvp__submit-button:disabled{cursor:not-allowed;background:#a2aab2}.tribe-block__rsvp__form__attendee-meta{margin:0}.tribe-block__rsvp__form__attendee-meta td,.tribe-block__rsvp__form__attendee-meta th{padding:0;border:none;word-break:normal}.tribe-common-c-loader.tribe-block__rsvp__loading{align-items:center;background:hsla(0,0%,100%,.7);height:100%;justify-content:center;left:0;margin:0;padding:0;position:absolute;text-align:center;top:0;width:100%;z-index:99}.tribe-common-c-loader.tribe-block__rsvp__loading svg{max-width:70px;position:absolute;top:35%}.tribe-common-c-loader.tribe-block__rsvp__loading svg circle{fill:#888}@media (min-width:600px){.tribe-block__rsvp__ticket{align-items:stretch;flex-wrap:nowrap}.tribe-block__rsvp__icon{border-bottom:none;border-right:1px dashed #b5bcc2;padding:28px 17px;width:84px}.tribe-block__rsvp__number-input-inner input[type=number]{font-size:36px;height:48px}.tribe-block__rsvp__message__success{padding:10px 30px;text-align:center}}
1
+ .tribe-block__rsvp{font-family:var(--tec-font-family-sans-serif);margin-bottom:30px;margin-top:30px;max-width:580px;position:relative}.tribe-block__rsvp__ticket{border:1px solid #e1e3e6;display:flex;flex-wrap:wrap;position:relative;width:100%}.tribe-block__rsvp__icon{align-items:center;background:#fff;border-bottom:1px dashed #b5bcc2;color:#434343;display:flex;flex:none;flex-direction:column;font-size:14px;font-weight:700;line-height:17px;padding:20px 17px;width:100%}.tribe-block__rsvp__icon svg{margin-bottom:7px}.tribe-block__rsvp__content{background-color:#f5f8f9;flex:auto}.tribe-block__rsvp__details{padding:25px 20px 20px}.tribe-block__rsvp__title{color:#000;font-size:21px;font-weight:700;line-height:28px;margin-bottom:12px}.tribe-block__rsvp__description{color:#545d66;font-size:14px;line-height:18px;margin-bottom:15px}.tribe-block__rsvp__availability{color:#545d66;display:flex;align-items:center;font-size:12px;line-height:18px}.tribe-block__rsvp__quantity{font-size:18px;font-weight:700;margin-right:6px}.tribe-block__rsvp__status{display:flex;flex-wrap:nowrap;padding:0 20px 25px;text-align:center}.tribe-block__rsvp__status>span{flex:none;margin-right:15px;width:calc(50% - 7.5px)}.tribe-block__rsvp__status>span:last-child{margin-right:0}.tribe-block__rsvp__status-button{align-items:center;border:1px solid #545d66;border-radius:4px;background:#fff;color:#545d66;display:flex;font-family:var(--tec-font-family-sans-serif);font-size:14px;font-weight:700;height:44px;justify-content:center;line-height:1;padding:0;width:100%}.tribe-block__rsvp__status-button svg{margin-left:9px}.tribe-block__rsvp__status-button:focus,.tribe-block__rsvp__status-button:hover{background:#fff;border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-active{border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-inactive{border:1px solid #e1e3e6;color:#a2aab2}.tribe-block__rsvp__status-button.tribe-inactive:focus,.tribe-block__rsvp__status-button.tribe-inactive:hover{background:#fff;border:1px solid #545d66;color:#545d66}.tribe-block__rsvp__status-button[disabled=disabled]{cursor:default}.tribe-block__rsvp__going-icon,.tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-active .tribe-block__rsvp__going-icon,.tribe-active .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__not-going-icon{fill:#191e23}.tribe-inactive .tribe-block__rsvp__going-icon,.tribe-inactive .tribe-block__rsvp__not-going-icon{fill:#e1e3e6}.tribe-inactive:focus .tribe-block__rsvp__going-icon,.tribe-inactive:focus .tribe-block__rsvp__not-going-icon,.tribe-inactive:hover .tribe-block__rsvp__going-icon,.tribe-inactive:hover .tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-block__rsvp__form{padding:0 20px}.tribe-block__rsvp__form form{border-top:1px solid #e1e3e6;display:flex;padding:30px 0}.tribe-left{flex:none}.tribe-block__rsvp__number-input{padding-right:20px}.tribe-block__rsvp__number-input-inner{align-items:center;display:flex}.tribe-block__rsvp__number-input-inner input[type=number]{-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;background:transparent;border:none;color:#000;font-family:var(--tec-font-family-sans-serif);font-size:30px;font-weight:700;height:40px;max-width:48px;padding:4px 0;text-align:center}.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-inner-spin-button,.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;appearance:none}.tribe-block__rsvp__number-input-label{display:block;font-size:14px;font-weight:700;line-height:18px;margin-top:9px;text-align:center}.tribe-block__rsvp__number-input-button{background-color:transparent;height:30px;padding:0;position:relative;width:20px}.tribe-block__rsvp__number-input-button:after,.tribe-block__rsvp__number-input-button:before{background-color:#aeb4bb;content:"";height:2px;position:absolute;width:10px}.tribe-block__rsvp__number-input-button:focus,.tribe-block__rsvp__number-input-button:hover{background:none}.tribe-block__rsvp__number-input-button:focus:after,.tribe-block__rsvp__number-input-button:focus:before,.tribe-block__rsvp__number-input-button:hover:after,.tribe-block__rsvp__number-input-button:hover:before{background-color:#545d66}.tribe-block__rsvp__number-input-button--minus{margin-left:-10px}.tribe-block__rsvp__number-input-button--minus:after,.tribe-block__rsvp__number-input-button--minus:before{right:0}.tribe-block__rsvp__number-input-button--plus{margin-right:-10px}.tribe-block__rsvp__number-input-button--plus:after,.tribe-block__rsvp__number-input-button--plus:before{left:0}.tribe-block__rsvp__number-input-button--plus:after{transform:rotate(90deg)}.tribe-right{flex:auto}.tribe-right input[type=email],.tribe-right input[type=text]{border-color:#e1e3e6;color:#000;display:block;font-family:var(--tec-font-family-sans-serif);font-size:16px;height:40px;line-height:18px;margin-bottom:15px;padding:10px 15px;width:100%}.tribe-right input[type=email]::-moz-placeholder,.tribe-right input[type=text]::-moz-placeholder{color:#a2aab2}.tribe-right input[type=email]:-ms-input-placeholder,.tribe-right input[type=text]:-ms-input-placeholder{color:#a2aab2}.tribe-right input[type=email]::placeholder,.tribe-right input[type=text]::placeholder{color:#a2aab2}.tribe-right label{cursor:pointer;font-size:var(--tec-font-size-2);font-weight:400}.tribe-right label[for^=tribe-tickets-attendees-list-optout]{align-items:flex-start;display:flex;margin:0 0 15px;padding-top:7px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border:1px solid #e1e3e6;border-radius:0;cursor:pointer;flex:none;height:16px;margin:1px 10px 0 0;width:16px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:focus{box-shadow:0 0 0 1px #e1e3e6;outline:2px solid transparent;outline-offset:-2px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:checked:before{color:#009fd4;content:"\F147";display:inline-block;float:left;font:normal 21px/1 dashicons;margin:-3px 0 0 -4px;speak:none;vertical-align:middle;width:16px}.tribe-tickets-meta-option-label{color:#000;font-size:14px;line-height:18px}.tribe-block__rsvp__message__error,.tribe-block__rsvp__message__success{color:#000;font-size:14px;line-height:18px;padding:20px}.tribe-block__rsvp__message__error{background:#ffebe8;border:1px solid #c00;display:none;margin-bottom:20px}.tribe-block__rsvp__message__success{background:#ecfae5;border:1px solid #1bd800;margin-top:20px}.tribe-block__rsvp__submit-button{background:#009fd4;color:#fff;font-family:var(--tec-font-family-sans-serif);font-size:15px;font-weight:700;line-height:18px;margin:10px 0 0;padding:10px 23px}.tribe-block__rsvp__submit-button:focus,.tribe-block__rsvp__submit-button:hover{background:#007bb4}.tribe-block__rsvp__submit-button:disabled{cursor:not-allowed;background:#a2aab2}.tribe-block__rsvp__form__attendee-meta{margin:0}.tribe-block__rsvp__form__attendee-meta td,.tribe-block__rsvp__form__attendee-meta th{padding:0;border:none;word-break:normal}.tribe-common-c-loader.tribe-block__rsvp__loading{align-items:center;background:hsla(0,0%,100%,.7);height:100%;justify-content:center;left:0;margin:0;padding:0;position:absolute;text-align:center;top:0;width:100%;z-index:99}.tribe-common-c-loader.tribe-block__rsvp__loading svg{max-width:70px;position:absolute;top:35%}.tribe-common-c-loader.tribe-block__rsvp__loading svg circle{fill:#888}@media (min-width:600px){.tribe-block__rsvp__ticket{align-items:stretch;flex-wrap:nowrap}.tribe-block__rsvp__icon{border-bottom:none;border-right:1px dashed #b5bcc2;padding:28px 17px;width:84px}.tribe-block__rsvp__number-input-inner input[type=number]{font-size:36px;height:48px}.tribe-block__rsvp__message__success{padding:10px 30px;text-align:center}}
src/resources/css/attendees.css CHANGED
@@ -5,7 +5,7 @@
5
  * src/resources/postcss/ file. For more information, check out our engineering
6
  * docs on how we handle CSS in our engineering docs.
7
  *
8
- * @see: http://moderntribe.github.io/products-engineering/css/
9
  */
10
 
11
  /**
5
  * src/resources/postcss/ file. For more information, check out our engineering
6
  * docs on how we handle CSS in our engineering docs.
7
  *
8
+ * @see: https://the-events-calendar.github.io/products-engineering/docs/code-standards/css/
9
  */
10
 
11
  /**
src/resources/css/common-responsive.css CHANGED
@@ -5,7 +5,7 @@
5
  * src/resources/postcss/ file. For more information, check out our engineering
6
  * docs on how we handle CSS in our engineering docs.
7
  *
8
- * @see: http://moderntribe.github.io/products-engineering/css/
9
  */
10
 
11
  /**
@@ -15,6 +15,20 @@
15
  * @todo @juanfra: Check this once we define https://github.com/the-events-calendar/tribe-common/pull/1379
16
  */
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  /* -----------------------------------------------------------------------------
19
  *
20
  * Utilities
@@ -303,9 +317,331 @@
303
  * Visually Show: Show element after has been hidden with %visually-hide
304
  * ----------------------------------------------------------------------------- */
305
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
  .event-tickets {
307
 
308
- /* From: base/full/typography/_body.pcss*/
309
 
310
  /* From: base/full/typography/_headings.pcss */
311
 
@@ -384,7 +720,7 @@
384
 
385
  /* From: base/skeleton/forms/_text.pcss */
386
 
387
- /* From: base/skeleton/grid/_rows.pcss*/
388
 
389
  /* -------------------------------------------------------------------------
390
  * Theme Overrides - Twenty Twenty
@@ -394,7 +730,21 @@
394
  background-color: transparent;
395
  }
396
 
397
- @media(--viewport-medium) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
 
399
  .event-tickets .tribe-common-form-control-text__input {
400
  color: var(--tec-color-text-primary);
@@ -487,16 +837,16 @@
487
  }
488
 
489
  .event-tickets .tribe-common-form-control-text__input {
490
- padding: var(--spacer-4) var(--spacer-4) var(--spacer-4) var(--spacer-8)
491
  }
492
 
493
  .event-tickets .tribe-common-g-row--gutters {
494
- margin-left: var(--grid-gutter-half-negative);
495
- margin-right: var(--grid-gutter-half-negative)
496
  }
497
 
498
  .event-tickets .tribe-common-g-row--gutters > .tribe-common-g-col {
499
- padding-left: var(--grid-gutter-half);
500
- padding-right: var(--grid-gutter-half)
501
  }
502
  }
5
  * src/resources/postcss/ file. For more information, check out our engineering
6
  * docs on how we handle CSS in our engineering docs.
7
  *
8
+ * @see: https://the-events-calendar.github.io/products-engineering/docs/code-standards/css/
9
  */
10
 
11
  /**
15
  * @todo @juanfra: Check this once we define https://github.com/the-events-calendar/tribe-common/pull/1379
16
  */
17
 
18
+ /* Import Mixins */
19
+
20
+ /*
21
+ * Common CSS
22
+ *
23
+ * DO NOT EDIT THIS CSS FILE DIRECTLY.
24
+ * -------------------------------------------------------------
25
+ * This file is just a clearing-house, see the pcss directory
26
+ *
27
+ and edit the source files found there.
28
+ */
29
+
30
+ /* Event Tickets Utilities */
31
+
32
  /* -----------------------------------------------------------------------------
33
  *
34
  * Utilities
317
  * Visually Show: Show element after has been hidden with %visually-hide
318
  * ----------------------------------------------------------------------------- */
319
 
320
+ /* Event Tickets Components */
321
+
322
+ /* Accordion Styles */
323
+
324
+ .accordion-header {
325
+ background: none;
326
+ border: 0;
327
+ color: inherit;
328
+ cursor: pointer;
329
+ font-size: 12px;
330
+ font-weight: bold;
331
+ padding: 10px 20px;
332
+ box-sizing: border-box;
333
+ position: relative;
334
+ text-align: left;
335
+ width: 100%;
336
+ }
337
+
338
+ .accordion-header:before {
339
+ background-color: #000;
340
+ border-radius: 100%;
341
+ box-sizing: border-box;
342
+ color: #fff;
343
+ content: '\f132';
344
+ font-family: 'dashicons';
345
+ font-size: 10px;
346
+ line-height: 17px;
347
+ font-weight: 400;
348
+ height: 14px;
349
+ left: 0;
350
+ padding: 0;
351
+ position: absolute;
352
+ top: 12px;
353
+ width: 15px;
354
+ text-align: center;
355
+ padding-right: 1px;
356
+ }
357
+
358
+ .accordion-header:after {
359
+ content: '';
360
+ border-bottom: 1px solid #ddd;
361
+ position: absolute;
362
+ right: 0;
363
+ width: 80%;
364
+ top: 50%;
365
+ transform: translateY(-50%);
366
+ }
367
+
368
+ .accordion-header.is-active:before {
369
+ content: '\f460';
370
+ line-height: 15px;
371
+ }
372
+
373
+ .accordion-header:focus {
374
+ outline: 1px solid #5b9dd9;
375
+ }
376
+
377
+ .accordion-header:hover {
378
+ background: none;
379
+ }
380
+
381
+ .tribe-tickets-editor-history::after {
382
+ width: calc(100% - 80px);
383
+ }
384
+
385
+ .tribe_attendee_meta::after {
386
+ width: calc(100% - 170px);
387
+ }
388
+
389
+ .tribe_advanced_meta::after {
390
+ width: calc(100% - 105px);
391
+ }
392
+
393
+ .accordion-label:focus {
394
+ outline: none;
395
+ }
396
+
397
+ .accordion-content {
398
+ display: none;
399
+ }
400
+
401
+ .ticket_panel .accordion-content {
402
+ margin: 1em 0 2em;
403
+ }
404
+
405
+ .accordion-content.is-active {
406
+ display: block;
407
+ }
408
+
409
+ .tribe-common-c-loader.tribe-tickets-loader__tickets-block,
410
+ .tribe-common-c-loader.tribe-tickets-loader__modal {
411
+ align-items: center;
412
+ background: var(--tec-color-background-transparent);
413
+ display: flex;
414
+ height: 100%;
415
+ justify-content: center;
416
+ left: 0;
417
+ padding: 0;
418
+ position: absolute;
419
+ top: 0;
420
+ width: 100%;
421
+ z-index: var(--tec-z-index-spinner-container);
422
+ }
423
+
424
+ .tribe-common-c-loader.tribe-tickets-loader__modal {
425
+ height: 100vh;
426
+ position: fixed;
427
+ width: 100vw;
428
+ }
429
+
430
+ .event-tickets .tribe-common-c-loader {
431
+ align-items: center;
432
+ background: var(--tec-color-background-transparent);
433
+ display: flex;
434
+ height: 100%;
435
+ justify-content: center;
436
+ left: 0;
437
+ padding: 0;
438
+ position: absolute;
439
+ top: 0;
440
+ width: 100%;
441
+ z-index: var(--tec-z-index-spinner-container);
442
+ }
443
+
444
+ .tribe-common .tribe-tickets__notice {
445
+ padding: var(--tec-spacer-3);
446
+ background-color: var(--tec-color-background-secondary);
447
+ border-radius: var(--tec-border-radius-default);
448
+ margin: var(--tec-spacer-4) 0;
449
+ }
450
+
451
+ .tribe-common .tribe-tickets__notice > *:last-child {
452
+ padding-bottom: 0;
453
+ margin-bottom: 0;
454
+ }
455
+
456
+ .tribe-common .tribe-tickets-notice__title {
457
+ margin: 0;
458
+ position: relative;
459
+ }
460
+
461
+ .tribe-common .tribe-tickets-notice__title:empty {
462
+ display: none;
463
+ }
464
+
465
+ /*
466
+ Error Notices
467
+ */
468
+
469
+ .tribe-common .tribe-tickets__notice--error {
470
+ background-color: var(--tec-color-background-error);
471
+ display: none;
472
+ padding-left: 50px;
473
+ }
474
+
475
+ .tribe-common .tribe-tickets__notice--error .tribe-tickets-notice__title {
476
+ position: relative;
477
+ }
478
+
479
+ .tribe-common .tribe-tickets__notice--error .tribe-tickets-notice__title:before {
480
+ background-image: url( "data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18'%3E%3Cg fill='none' fill-rule='evenodd' transform='translate(1 1)'%3E%3Ccircle cx='8' cy='8' r='7.467' stroke='%23141827' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5'/%3E%3Ccircle cx='8' cy='11.733' r='1.067' fill='%23141827' fill-rule='nonzero'/%3E%3Cpath stroke='%23141827' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M8 3.733v4.8' fill='%23141827'/%3E%3C/g%3E%3C/svg%3E" );
481
+ background-size: contain;
482
+ content: '';
483
+ height: var(--tec-spacer-3);
484
+ left: calc(var(--tec-spacer-7)*-1);
485
+ position: absolute;
486
+ top: 2px;
487
+ width: var(--tec-spacer-3);
488
+ }
489
+
490
+ /*
491
+ "Barred" Notices (visible side borders)
492
+ */
493
+
494
+ .tribe-common .tribe-tickets__notice--barred {
495
+ background-color: var(--tec-color-background);
496
+ border: var(--tec-spacer-0) solid var(--tec-color-border-secondary);
497
+ border-bottom: 0;
498
+ border-radius: 0;
499
+ border-top: 0;
500
+ padding: 0 var(--tec-spacer-2);
501
+ }
502
+
503
+ .tribe-common .tribe-tickets__notice--barred-left {
504
+ border-right: 0;
505
+ padding: 0 0 0 var(--tec-spacer-2);
506
+ }
507
+
508
+ .tribe-common .tribe-tickets__notice--barred-right {
509
+ border-left: 0;
510
+ padding: 0 var(--tec-spacer-2) 0 0;
511
+ }
512
+
513
+ /* -------------------------------------------------------------------------
514
+ * SVG Icons
515
+ * ------------------------------------------------------------------------- */
516
+
517
+ .event-tickets .tribe-tickets-svgicon {
518
+ background-repeat: no-repeat;
519
+ background-size: contain;
520
+ }
521
+
522
+ /* -----------------------------------------------------------------------------
523
+ *
524
+ * Tooltip
525
+ *
526
+ * ----------------------------------------------------------------------------- */
527
+
528
+ /* Defining our tooltipster theme. */
529
+
530
+ .tooltipster-base.tribe-tickets-tooltip-theme {
531
+ background-color: var(--tec-color-background);
532
+ border: 1px solid var(--tec-color-border-default);
533
+ border-radius: var(--tec-border-radius-default);
534
+ box-shadow: var(--tec-box-shadow-tooltip);
535
+ height: auto !important;
536
+ padding: var(--tec-spacer-5);
537
+ max-width: 254px;
538
+ }
539
+
540
+ .tooltipster-base.tribe-tickets-tooltip-theme .tooltipster-box {
541
+ background-color: transparent;
542
+ border: 0;
543
+ border-radius: 0;
544
+ box-shadow: none;
545
+ margin: 0;
546
+ }
547
+
548
+ .tooltipster-base.tribe-tickets-tooltip-theme .tooltipster-box .tooltipster-content {
549
+ color: var(--tec-color-text-primary);
550
+ overflow: inherit;
551
+ padding: 0;
552
+ word-break: break-word;
553
+ }
554
+
555
+ .tooltipster-base.tribe-tickets-tooltip-theme .tooltipster-arrow {
556
+ display: none;
557
+ }
558
+
559
+ /* -----------------------------------------------------------------------------
560
+ *
561
+ * Button: Small
562
+ *
563
+ * Example:
564
+ * <button class="tribe-common-c-btn tribe-common-c-btn--small">...</button>
565
+ * <a href="#" class="tribe-common-c-btn tribe-common-c-btn--small">...</a>
566
+ *
567
+ * ----------------------------------------------------------------------------- */
568
+
569
+ .tribe-common button.tribe-common-c-btn--small, .tribe-common input[type="button"].tribe-common-c-btn--small, .tribe-common input[type="submit"].tribe-common-c-btn--small, .tribe-common a.tribe-common-c-btn--small {
570
+ background-color: var(--tec-color-accent-primary);
571
+ padding: 11px 14px;
572
+ width: auto;
573
+ }
574
+
575
+ /* -----------------------------------------------------------------------------
576
+ *
577
+ * Button: Link
578
+ *
579
+ * Example:
580
+ * <button class="tribe-common-c-btn-link">...</button>
581
+ * <a href="#" class="tribe-common-c-btn-link">...</a>
582
+ *
583
+ * ----------------------------------------------------------------------------- */
584
+
585
+ .tribe-common button.tribe-common-c-btn-link, .tribe-common input[type="button"].tribe-common-c-btn-link, .tribe-common input[type="submit"].tribe-common-c-btn-link, .tribe-common a.tribe-common-c-btn-link {
586
+ color: var(--tec-color-text-primary);
587
+ font-family: var(--tec-font-family-sans-serif);
588
+ font-size: var(--tec-font-size-2);
589
+ line-height: var(--tec-line-height-3);
590
+ font-weight: var(--tec-font-weight-regular);
591
+ border: 0;
592
+ cursor: pointer;
593
+ display: inline-block;
594
+ height: auto;
595
+ padding: 0;
596
+ text-decoration: none;
597
+ width: auto;
598
+ background-color: transparent;
599
+ text-align: center;
600
+ text-decoration: underline;
601
+ transition: var(--tec-transition-color);
602
+ }
603
+
604
+ .tribe-common button.tribe-common-c-btn-link:hover,
605
+ .tribe-common button.tribe-common-c-btn-link:focus,
606
+ .tribe-common input[type="button"].tribe-common-c-btn-link:hover,
607
+ .tribe-common input[type="button"].tribe-common-c-btn-link:focus,
608
+ .tribe-common input[type="submit"].tribe-common-c-btn-link:hover,
609
+ .tribe-common input[type="submit"].tribe-common-c-btn-link:focus,
610
+ .tribe-common a.tribe-common-c-btn-link:hover,
611
+ .tribe-common a.tribe-common-c-btn-link:focus {
612
+ background-color: transparent;
613
+ }
614
+
615
+ .tribe-common button.tribe-common-c-btn-link, .tribe-common input[type="button"].tribe-common-c-btn-link, .tribe-common input[type="submit"].tribe-common-c-btn-link, .tribe-common a.tribe-common-c-btn-link {
616
+
617
+ background-color: transparent;
618
+ color: var(--tec-color-accent-primary);
619
+ padding: 11px 20px;
620
+ width: 100%;
621
+ }
622
+
623
+ .tribe-common button.tribe-common-c-btn-link:focus,
624
+ .tribe-common button.tribe-common-c-btn-link:hover,
625
+ .tribe-common input[type="button"].tribe-common-c-btn-link:focus,
626
+ .tribe-common input[type="button"].tribe-common-c-btn-link:hover,
627
+ .tribe-common input[type="submit"].tribe-common-c-btn-link:focus,
628
+ .tribe-common input[type="submit"].tribe-common-c-btn-link:hover,
629
+ .tribe-common a.tribe-common-c-btn-link:focus,
630
+ .tribe-common a.tribe-common-c-btn-link:hover {
631
+ color: var(--tec-color-accent-primary-hover);
632
+ }
633
+
634
+ .tribe-common button.tribe-common-c-btn-link:active, .tribe-common input[type="button"].tribe-common-c-btn-link:active, .tribe-common input[type="submit"].tribe-common-c-btn-link:active, .tribe-common a.tribe-common-c-btn-link:active {
635
+ color: var(--tec-color-accent-primary-active);
636
+ }
637
+
638
+ .tribe-common button.tribe-common-c-btn-link:disabled, .tribe-common input[type="button"].tribe-common-c-btn-link:disabled, .tribe-common input[type="submit"].tribe-common-c-btn-link:disabled, .tribe-common a.tribe-common-c-btn-link:disabled {
639
+ color: var(--tec-color-accent-primary-background);
640
+ }
641
+
642
  .event-tickets {
643
 
644
+ /* From: base/full/typography/_body.pcss */
645
 
646
  /* From: base/full/typography/_headings.pcss */
647
 
720
 
721
  /* From: base/skeleton/forms/_text.pcss */
722
 
723
+ /* From: base/skeleton/grid/_rows.pcss */
724
 
725
  /* -------------------------------------------------------------------------
726
  * Theme Overrides - Twenty Twenty
730
  background-color: transparent;
731
  }
732
 
733
+ @media (min-width: 768px) {
734
+
735
+ .tribe-common-c-loader.tribe-tickets-loader__tickets-block,
736
+ .tribe-common-c-loader.tribe-tickets-loader__modal {
737
+ padding: 0
738
+ }
739
+
740
+ .event-tickets .tribe-common-c-loader {
741
+ padding: 0
742
+ }
743
+
744
+ .tribe-common button.tribe-common-c-btn-link, .tribe-common input[type="button"].tribe-common-c-btn-link, .tribe-common input[type="submit"].tribe-common-c-btn-link, .tribe-common a.tribe-common-c-btn-link {
745
+ background-color: transparent;
746
+ width: auto
747
+ }
748
 
749
  .event-tickets .tribe-common-form-control-text__input {
750
  color: var(--tec-color-text-primary);
837
  }
838
 
839
  .event-tickets .tribe-common-form-control-text__input {
840
+ padding: var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-8)
841
  }
842
 
843
  .event-tickets .tribe-common-g-row--gutters {
844
+ margin-left: var(--tec-grid-gutter-half-negative);
845
+ margin-right: var(--tec-grid-gutter-half-negative)
846
  }
847
 
848
  .event-tickets .tribe-common-g-row--gutters > .tribe-common-g-col {
849
+ padding-left: var(--tec-grid-gutter-half);
850
+ padding-right: var(--tec-grid-gutter-half)
851
  }
852
  }
src/resources/css/common-responsive.min.css CHANGED
@@ -1 +1 @@
1
- .tribe-theme-twentytwenty .event-tickets{background-color:transparent}@media(--viewport-medium){.event-tickets .tribe-common-form-control-text__input{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3);font-weight:var(--tec-font-weight-regular);border:0}.event-tickets .tribe-common-b1{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-b2{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-b3{font-size:var(--tec-font-size-1);line-height:var(--tec-line-height-0)}.event-tickets .tribe-common-h1{font-size:var(--tec-font-size-10);line-height:var(--tec-line-height-0)}.event-tickets .tribe-common-h2{font-size:var(--tec-font-size-9);line-height:var(--tec-line-height-0)}.event-tickets .tribe-common-h3{font-size:var(--tec-font-size-8);line-height:var(--tec-line-height-1)}.event-tickets .tribe-common-h4{font-size:var(--tec-font-size-7);line-height:var(--tec-line-height-1)}.event-tickets .tribe-common-b1--min-medium,.event-tickets .tribe-common-h6{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-b2--min-medium{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-b3--min-medium{font-size:var(--tec-font-size-1);line-height:var(--tec-line-height-0)}.event-tickets .tribe-common-h3--min-medium{font-size:var(--tec-font-size-8);line-height:var(--tec-line-height-1)}.event-tickets .tribe-common-h4--min-medium{font-size:var(--tec-font-size-7);line-height:var(--tec-line-height-1)}.event-tickets .tribe-common-h5--min-medium{font-size:var(--tec-font-size-4);line-height:var(--tec-line-height-2)}.event-tickets .tribe-common-h6--min-medium{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-h7--min-medium{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-form-control-text__input{padding:var(--spacer-4) var(--spacer-4) var(--spacer-4) var(--spacer-8)}.event-tickets .tribe-common-g-row--gutters{margin-left:var(--grid-gutter-half-negative);margin-right:var(--grid-gutter-half-negative)}.event-tickets .tribe-common-g-row--gutters>.tribe-common-g-col{padding-left:var(--grid-gutter-half);padding-right:var(--grid-gutter-half)}}
1
+ .accordion-header{background:none;border:0;color:inherit;cursor:pointer;font-size:12px;font-weight:700;padding:10px 20px;box-sizing:border-box;position:relative;text-align:left;width:100%}.accordion-header:before{background-color:#000;border-radius:100%;box-sizing:border-box;color:#fff;content:"\f132";font-family:dashicons;font-size:10px;line-height:17px;font-weight:400;height:14px;left:0;padding:0;position:absolute;top:12px;width:15px;text-align:center;padding-right:1px}.accordion-header:after{content:"";border-bottom:1px solid #ddd;position:absolute;right:0;width:80%;top:50%;transform:translateY(-50%)}.accordion-header.is-active:before{content:"\f460";line-height:15px}.accordion-header:focus{outline:1px solid #5b9dd9}.accordion-header:hover{background:none}.tribe-tickets-editor-history:after{width:calc(100% - 80px)}.tribe_attendee_meta:after{width:calc(100% - 170px)}.tribe_advanced_meta:after{width:calc(100% - 105px)}.accordion-label:focus{outline:none}.accordion-content{display:none}.ticket_panel .accordion-content{margin:1em 0 2em}.accordion-content.is-active{display:block}.tribe-common-c-loader.tribe-tickets-loader__modal,.tribe-common-c-loader.tribe-tickets-loader__tickets-block{align-items:center;background:var(--tec-color-background-transparent);display:flex;height:100%;justify-content:center;left:0;padding:0;position:absolute;top:0;width:100%;z-index:var(--tec-z-index-spinner-container)}.tribe-common-c-loader.tribe-tickets-loader__modal{height:100vh;position:fixed;width:100vw}.event-tickets .tribe-common-c-loader{align-items:center;background:var(--tec-color-background-transparent);display:flex;height:100%;justify-content:center;left:0;padding:0;position:absolute;top:0;width:100%;z-index:var(--tec-z-index-spinner-container)}.tribe-common .tribe-tickets__notice{padding:var(--tec-spacer-3);background-color:var(--tec-color-background-secondary);border-radius:var(--tec-border-radius-default);margin:var(--tec-spacer-4) 0}.tribe-common .tribe-tickets__notice>:last-child{padding-bottom:0;margin-bottom:0}.tribe-common .tribe-tickets-notice__title{margin:0;position:relative}.tribe-common .tribe-tickets-notice__title:empty{display:none}.tribe-common .tribe-tickets__notice--error{background-color:var(--tec-color-background-error);display:none;padding-left:50px}.tribe-common .tribe-tickets__notice--error .tribe-tickets-notice__title{position:relative}.tribe-common .tribe-tickets__notice--error .tribe-tickets-notice__title:before{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18'%3E%3Cg fill='none' fill-rule='evenodd' transform='translate(1 1)'%3E%3Ccircle cx='8' cy='8' r='7.467' stroke='%23141827' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5'/%3E%3Ccircle cx='8' cy='11.733' r='1.067' fill='%23141827' fill-rule='nonzero'/%3E%3Cpath stroke='%23141827' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M8 3.733v4.8' fill='%23141827'/%3E%3C/g%3E%3C/svg%3E");background-size:contain;content:"";height:var(--tec-spacer-3);left:calc(var(--tec-spacer-7)*-1);position:absolute;top:2px;width:var(--tec-spacer-3)}.tribe-common .tribe-tickets__notice--barred{background-color:var(--tec-color-background);border:var(--tec-spacer-0) solid var(--tec-color-border-secondary);border-bottom:0;border-radius:0;border-top:0;padding:0 var(--tec-spacer-2)}.tribe-common .tribe-tickets__notice--barred-left{border-right:0;padding:0 0 0 var(--tec-spacer-2)}.tribe-common .tribe-tickets__notice--barred-right{border-left:0;padding:0 var(--tec-spacer-2) 0 0}.event-tickets .tribe-tickets-svgicon{background-repeat:no-repeat;background-size:contain}.tooltipster-base.tribe-tickets-tooltip-theme{background-color:var(--tec-color-background);border:1px solid var(--tec-color-border-default);border-radius:var(--tec-border-radius-default);box-shadow:var(--tec-box-shadow-tooltip);height:auto!important;padding:var(--tec-spacer-5);max-width:254px}.tooltipster-base.tribe-tickets-tooltip-theme .tooltipster-box{background-color:transparent;border:0;border-radius:0;box-shadow:none;margin:0}.tooltipster-base.tribe-tickets-tooltip-theme .tooltipster-box .tooltipster-content{color:var(--tec-color-text-primary);overflow:inherit;padding:0;word-break:break-word}.tooltipster-base.tribe-tickets-tooltip-theme .tooltipster-arrow{display:none}.tribe-common a.tribe-common-c-btn--small,.tribe-common button.tribe-common-c-btn--small,.tribe-common input[type=button].tribe-common-c-btn--small,.tribe-common input[type=submit].tribe-common-c-btn--small{background-color:var(--tec-color-accent-primary);padding:11px 14px;width:auto}.tribe-common a.tribe-common-c-btn-link,.tribe-common button.tribe-common-c-btn-link,.tribe-common input[type=button].tribe-common-c-btn-link,.tribe-common input[type=submit].tribe-common-c-btn-link{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3);font-weight:var(--tec-font-weight-regular);border:0;cursor:pointer;display:inline-block;height:auto;padding:0;text-decoration:none;width:auto;text-align:center;text-decoration:underline;transition:var(--tec-transition-color)}.tribe-common a.tribe-common-c-btn-link:focus,.tribe-common a.tribe-common-c-btn-link:hover,.tribe-common button.tribe-common-c-btn-link:focus,.tribe-common button.tribe-common-c-btn-link:hover,.tribe-common input[type=button].tribe-common-c-btn-link:focus,.tribe-common input[type=button].tribe-common-c-btn-link:hover,.tribe-common input[type=submit].tribe-common-c-btn-link:focus,.tribe-common input[type=submit].tribe-common-c-btn-link:hover{background-color:transparent}.tribe-common a.tribe-common-c-btn-link,.tribe-common button.tribe-common-c-btn-link,.tribe-common input[type=button].tribe-common-c-btn-link,.tribe-common input[type=submit].tribe-common-c-btn-link{background-color:transparent;color:var(--tec-color-accent-primary);padding:11px 20px;width:100%}.tribe-common a.tribe-common-c-btn-link:focus,.tribe-common a.tribe-common-c-btn-link:hover,.tribe-common button.tribe-common-c-btn-link:focus,.tribe-common button.tribe-common-c-btn-link:hover,.tribe-common input[type=button].tribe-common-c-btn-link:focus,.tribe-common input[type=button].tribe-common-c-btn-link:hover,.tribe-common input[type=submit].tribe-common-c-btn-link:focus,.tribe-common input[type=submit].tribe-common-c-btn-link:hover{color:var(--tec-color-accent-primary-hover)}.tribe-common a.tribe-common-c-btn-link:active,.tribe-common button.tribe-common-c-btn-link:active,.tribe-common input[type=button].tribe-common-c-btn-link:active,.tribe-common input[type=submit].tribe-common-c-btn-link:active{color:var(--tec-color-accent-primary-active)}.tribe-common a.tribe-common-c-btn-link:disabled,.tribe-common button.tribe-common-c-btn-link:disabled,.tribe-common input[type=button].tribe-common-c-btn-link:disabled,.tribe-common input[type=submit].tribe-common-c-btn-link:disabled{color:var(--tec-color-accent-primary-background)}.tribe-theme-twentytwenty .event-tickets{background-color:transparent}@media (min-width:768px){.event-tickets .tribe-common-c-loader,.tribe-common-c-loader.tribe-tickets-loader__modal,.tribe-common-c-loader.tribe-tickets-loader__tickets-block{padding:0}.tribe-common a.tribe-common-c-btn-link,.tribe-common button.tribe-common-c-btn-link,.tribe-common input[type=button].tribe-common-c-btn-link,.tribe-common input[type=submit].tribe-common-c-btn-link{background-color:transparent;width:auto}.event-tickets .tribe-common-form-control-text__input{color:var(--tec-color-text-primary);font-family:var(--tec-font-family-sans-serif);font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3);font-weight:var(--tec-font-weight-regular);border:0}.event-tickets .tribe-common-b1{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-b2{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-b3{font-size:var(--tec-font-size-1);line-height:var(--tec-line-height-0)}.event-tickets .tribe-common-h1{font-size:var(--tec-font-size-10);line-height:var(--tec-line-height-0)}.event-tickets .tribe-common-h2{font-size:var(--tec-font-size-9);line-height:var(--tec-line-height-0)}.event-tickets .tribe-common-h3{font-size:var(--tec-font-size-8);line-height:var(--tec-line-height-1)}.event-tickets .tribe-common-h4{font-size:var(--tec-font-size-7);line-height:var(--tec-line-height-1)}.event-tickets .tribe-common-b1--min-medium,.event-tickets .tribe-common-h6{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-b2--min-medium{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-b3--min-medium{font-size:var(--tec-font-size-1);line-height:var(--tec-line-height-0)}.event-tickets .tribe-common-h3--min-medium{font-size:var(--tec-font-size-8);line-height:var(--tec-line-height-1)}.event-tickets .tribe-common-h4--min-medium{font-size:var(--tec-font-size-7);line-height:var(--tec-line-height-1)}.event-tickets .tribe-common-h5--min-medium{font-size:var(--tec-font-size-4);line-height:var(--tec-line-height-2)}.event-tickets .tribe-common-h6--min-medium{font-size:var(--tec-font-size-3);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-h7--min-medium{font-size:var(--tec-font-size-2);line-height:var(--tec-line-height-3)}.event-tickets .tribe-common-form-control-text__input{padding:var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-4) var(--tec-spacer-8)}.event-tickets .tribe-common-g-row--gutters{margin-left:var(--tec-grid-gutter-half-negative);margin-right:var(--tec-grid-gutter-half-negative)}.event-tickets .tribe-common-g-row--gutters>.tribe-common-g-col{padding-left:var(--tec-grid-gutter-half);padding-right:var(--tec-grid-gutter-half)}}
src/resources/css/details.css CHANGED
@@ -5,7 +5,7 @@
5
  * src/resources/postcss/ file. For more information, check out our engineering
6
  * docs on how we handle CSS in our engineering docs.
7
  *
8
- * @see: http://moderntribe.github.io/products-engineering/css/
9
  */
10
 
11
  .tribe__details__poly .tribe__details__summary:before {
@@ -17,7 +17,7 @@
17
  .tribe__details__poly.tribe__details--open .tribe__details__content {
18
  display: block;
19
  }
20
- @media(--viewport-medium) {
21
  .tribe__details__poly .tribe__details__poly.tribe__details--mobile .tribe__details__summary {
22
  display: none;
23
  }
5
  * src/resources/postcss/ file. For more information, check out our engineering
6
  * docs on how we handle CSS in our engineering docs.
7
  *
8
+ * @see: https://the-events-calendar.github.io/products-engineering/docs/code-standards/css/
9
  */
10
 
11
  .tribe__details__poly .tribe__details__summary:before {
17
  .tribe__details__poly.tribe__details--open .tribe__details__content {
18
  display: block;
19
  }
20
+ @media (min-width: 768px) {
21
  .tribe__details__poly .tribe__details__poly.tribe__details--mobile .tribe__details__summary {
22
  display: none;
23
  }
src/resources/css/details.min.css CHANGED
@@ -1 +1 @@
1
- .tribe__details__poly .tribe__details__summary:before{content:"\25bc"}.tribe__details__poly .tribe__details__content{display:none}.tribe__details__poly.tribe__details--open .tribe__details__content{display:block}@media(--viewport-medium){.tribe__details__poly .tribe__details__poly.tribe__details--mobile .tribe__details__summary{display:none}.tribe__details__poly .tribe__details__poly.tribe__details--mobile .tribe__details__content{display:block}}
1
+ .tribe__details__poly .tribe__details__summary:before{content:"\25bc"}.tribe__details__poly .tribe__details__content{display:none}.tribe__details__poly.tribe__details--open .tribe__details__content{display:block}@media (min-width:768px){.tribe__details__poly .tribe__details__poly.tribe__details--mobile .tribe__details__summary{display:none}.tribe__details__poly .tribe__details__poly.tribe__details--mobile .tribe__details__content{display:block}}
src/resources/css/freemius.css CHANGED
@@ -5,7 +5,7 @@
5
  * src/resources/postcss/ file. For more information, check out our engineering
6
  * docs on how we handle CSS in our engineering docs.
7
  *
8
- * @see: http://moderntribe.github.io/products-engineering/css/
9
  */
10
 
11
  .events-cal #fs_connect, .toplevel_page_tribe-common #fs_connect, .toplevel_page_tribe-help #fs_connect, .toplevel_page_tribe-app-shop #fs_connect {
@@ -77,7 +77,7 @@
77
  visibility: hidden;
78
  }
79
 
80
- .events-cal #fs_connect .fs-visual .fs-site-icon::before, .toplevel_page_tribe-common #fs_connect .fs-visual .fs-site-icon::before, .toplevel_page_tribe-help #fs_connect .fs-visual .fs-site-icon::before, .toplevel_page_tribe-app-shop #fs_connect .fs-visual .fs-site-icon::before {
81
  background-image: url( ../images/event-tickets.svg );
82
  background-position: center center;
83
  background-repeat: no-repeat;
@@ -93,7 +93,7 @@
93
  visibility: hidden;
94
  }
95
 
96
- .events-cal #fs_connect .fs-visual .fs-plugin-icon::before, .toplevel_page_tribe-common #fs_connect .fs-visual .fs-plugin-icon::before, .toplevel_page_tribe-help #fs_connect .fs-visual .fs-plugin-icon::before, .toplevel_page_tribe-app-shop #fs_connect .fs-visual .fs-plugin-icon::before {
97
  background-image: url( ../icons/stethoscope.svg );
98
  background-position: center center;
99
  background-repeat: no-repeat;
@@ -226,7 +226,7 @@
226
  background-size: 65%;
227
  }
228
 
229
- .events-cal #fs_connect .fs-permissions.fs-open ul .dashicons::before, .toplevel_page_tribe-common #fs_connect .fs-permissions.fs-open ul .dashicons::before, .toplevel_page_tribe-help #fs_connect .fs-permissions.fs-open ul .dashicons::before, .toplevel_page_tribe-app-shop #fs_connect .fs-permissions.fs-open ul .dashicons::before {
230
  content: '';
231
  }
232
 
5
  * src/resources/postcss/ file. For more information, check out our engineering
6
  * docs on how we handle CSS in our engineering docs.
7
  *
8
+ * @see: https://the-events-calendar.github.io/products-engineering/docs/code-standards/css/
9
  */
10
 
11
  .events-cal #fs_connect, .toplevel_page_tribe-common #fs_connect, .toplevel_page_tribe-help #fs_connect, .toplevel_page_tribe-app-shop #fs_connect {
77
  visibility: hidden;
78
  }
79
 
80
+ .events-cal #fs_connect .fs-visual .fs-site-icon:before, .toplevel_page_tribe-common #fs_connect .fs-visual .fs-site-icon:before, .toplevel_page_tribe-help #fs_connect .fs-visual .fs-site-icon:before, .toplevel_page_tribe-app-shop #fs_connect .fs-visual .fs-site-icon:before {
81
  background-image: url( ../images/event-tickets.svg );
82
  background-position: center center;
83
  background-repeat: no-repeat;
93
  visibility: hidden;
94
  }
95
 
96
+ .events-cal #fs_connect .fs-visual .fs-plugin-icon:before, .toplevel_page_tribe-common #fs_connect .fs-visual .fs-plugin-icon:before, .toplevel_page_tribe-help #fs_connect .fs-visual .fs-plugin-icon:before, .toplevel_page_tribe-app-shop #fs_connect .fs-visual .fs-plugin-icon:before {
97
  background-image: url( ../icons/stethoscope.svg );
98
  background-position: center center;
99
  background-repeat: no-repeat;
226
  background-size: 65%;
227
  }
228
 
229
+ .events-cal #fs_connect .fs-permissions.fs-open ul .dashicons:before, .toplevel_page_tribe-common #fs_connect .fs-permissions.fs-open ul .dashicons:before, .toplevel_page_tribe-help #fs_connect .fs-permissions.fs-open ul .dashicons:before, .toplevel_page_tribe-app-shop #fs_connect .fs-permissions.fs-open ul .dashicons:before {
230
  content: '';
231
  }
232
 
src/resources/css/rsvp-v1.css CHANGED
@@ -5,7 +5,7 @@
5
  * src/resources/postcss/ file. For more information, check out our engineering
6
  * docs on how we handle CSS in our engineering docs.
7
  *
8
- * @see: http://moderntribe.github.io/products-engineering/css/
9
  */
10
 
11
  .tribe-rsvp {
@@ -40,7 +40,7 @@
40
  border-width: 1px;
41
  font-size: 12px;
42
  margin: 0 0 5px;
43
- padding: 0 .6em;
44
  }
45
 
46
  .tribe-rsvp-message-success {
@@ -119,7 +119,7 @@
119
  }
120
 
121
  .user-details p {
122
- margin: 0 0 .5em;
123
  }
124
 
125
  .tribe-answer {
@@ -128,7 +128,7 @@
128
 
129
  .tribe-answer .type-label {
130
  margin-bottom: 0;
131
- padding-right: .5em;
132
  }
133
 
134
  .tribe-answer label {
@@ -177,7 +177,7 @@
177
  }
178
 
179
  /* = Tickets & RSVP Modules Front End Styles
180
- =============================================*/
181
 
182
  /* Title */
183
 
@@ -196,7 +196,7 @@
196
  /* RSVP & Tickets Table */
197
 
198
  .tribe-events-tickets {
199
- background: #f8f8f8;
200
  border: 0;
201
  border-radius: 3px;
202
  max-width: 100%;
@@ -234,7 +234,7 @@
234
  order: 2;
235
  }
236
 
237
- .tribe-events-tickets td.quantity input[type="number"], .tribe-events-tickets td.woocommerce input[type="number"] {
238
  background-color: #fff;
239
  border-radius: 3px;
240
  margin-bottom: 5px;
@@ -255,7 +255,7 @@
255
  }
256
 
257
  .tribe-events-tickets .tribe-link-tickets-message {
258
- background: rgba(200, 200, 200, .8);
259
  bottom: 0;
260
  left: 0;
261
  position: absolute;
@@ -273,18 +273,18 @@
273
  }
274
 
275
  .tribe-events-tickets .tribe-tickets-remaining {
276
- color: #777;
277
  display: block;
278
  font-size: 11px;
279
  }
280
 
281
  .tribe-events-tickets .tribe-tickets-attendees-list-optout label {
282
- color: #777;
283
  font-size: 13px;
284
  }
285
 
286
- .tribe-events-tickets .tribe-tickets-attendees-list-optout input[type="radio"] + label,
287
- .tribe-events-tickets .tribe-tickets-attendees-list-optout input[type="checkbox"] + label {
288
  display: inline-block;
289
  }
290
 
@@ -292,23 +292,23 @@
292
  .tribe-events-tickets .tickets_name p,
293
  .tribe-events-tickets .tickets_description,
294
  .tribe-events-tickets .tickets_price {
295
- color: #464646;
296
  font-size: 15px;
297
  padding: 16px 10px;
298
  }
299
 
300
- .tribe-events-tickets input[type="date"],
301
- .tribe-events-tickets input[type="time"],
302
- .tribe-events-tickets input[type="datetime-local"],
303
- .tribe-events-tickets input[type="week"],
304
- .tribe-events-tickets input[type="month"],
305
- .tribe-events-tickets input[type="text"],
306
- .tribe-events-tickets input[type="email"],
307
- .tribe-events-tickets input[type="url"],
308
- .tribe-events-tickets input[type="password"],
309
- .tribe-events-tickets input[type="search"],
310
- .tribe-events-tickets input[type="tel"],
311
- .tribe-events-tickets input[type="number"],
312
  .tribe-events-tickets textarea,
313
  .tribe-events-tickets select {
314
  background: #fff;
@@ -345,7 +345,7 @@
345
  */
346
 
347
  .tribe-block__rsvp {
348
- font-family: Helvetica, sans-serif, arial;
349
  margin-bottom: 30px;
350
  margin-top: 30px;
351
  max-width: 580px;
@@ -362,7 +362,7 @@
362
 
363
  .tribe-block__rsvp__icon {
364
  align-items: center;
365
- background: #ffffff;
366
  border-bottom: 1px dashed #b5bcc2;
367
  color: #434343;
368
  display: flex;
@@ -384,14 +384,12 @@
384
  flex: auto;
385
  }
386
 
387
- .tribe-block__rsvp__details__status {}
388
-
389
  .tribe-block__rsvp__details {
390
  padding: 25px 20px 20px;
391
  }
392
 
393
  .tribe-block__rsvp__title {
394
- color: #000000;
395
  font-size: 21px;
396
  font-weight: bold;
397
  line-height: 28px;
@@ -440,10 +438,10 @@
440
  align-items: center;
441
  border: 1px solid #545d66;
442
  border-radius: 4px;
443
- background: #ffffff;
444
  color: #545d66;
445
  display: flex;
446
- font-family: Helvetica, sans-serif, arial;
447
  font-size: 14px;
448
  font-weight: bold;
449
  height: 44px;
@@ -459,14 +457,14 @@
459
 
460
  .tribe-block__rsvp__status-button:hover,
461
  .tribe-block__rsvp__status-button:focus {
462
- background: #ffffff;
463
- border: 1px solid #000000;
464
- color: #000000;
465
  }
466
 
467
  .tribe-block__rsvp__status-button.tribe-active {
468
- border: 1px solid #000000;
469
- color: #000000;
470
  }
471
 
472
  .tribe-block__rsvp__status-button.tribe-inactive {
@@ -476,12 +474,12 @@
476
 
477
  .tribe-block__rsvp__status-button.tribe-inactive:hover,
478
  .tribe-block__rsvp__status-button.tribe-inactive:focus {
479
- background: #ffffff;
480
  border: 1px solid #545d66;
481
  color: #545d66;
482
  }
483
 
484
- .tribe-block__rsvp__status-button[disabled="disabled"] {
485
  cursor: default;
486
  }
487
 
@@ -533,14 +531,14 @@
533
  display: flex;
534
  }
535
 
536
- .tribe-block__rsvp__number-input-inner input[type="number"] {
537
  -webkit-appearance: textfield;
538
  -moz-appearance: textfield;
539
  appearance: textfield;
540
  background: transparent;
541
  border: none;
542
- color: #000000;
543
- font-family: Helvetica, sans-serif, arial;
544
  font-size: 30px;
545
  font-weight: bold;
546
  height: 40px;
@@ -549,8 +547,8 @@
549
  text-align: center;
550
  }
551
 
552
- .tribe-block__rsvp__number-input-inner input[type="number"]::-webkit-inner-spin-button,
553
- .tribe-block__rsvp__number-input-inner input[type="number"]::-webkit-outer-spin-button {
554
  -webkit-appearance: none;
555
  appearance: none;
556
  }
@@ -619,12 +617,12 @@
619
  flex: auto;
620
  }
621
 
622
- .tribe-right input[type="text"],
623
- .tribe-right input[type="email"] {
624
  border-color: #e1e3e6;
625
- color: #000000;
626
  display: block;
627
- font-family: Helvetica, sans-serif, arial;
628
  font-size: 16px;
629
  height: 40px;
630
  line-height: 18px;
@@ -633,15 +631,15 @@
633
  width: 100%;
634
  }
635
 
636
- .tribe-right input[type="text"]::-moz-placeholder, .tribe-right input[type="email"]::-moz-placeholder {
637
  color: #a2aab2;
638
  }
639
 
640
- .tribe-right input[type="text"]:-ms-input-placeholder, .tribe-right input[type="email"]:-ms-input-placeholder {
641
  color: #a2aab2;
642
  }
643
 
644
- .tribe-right input[type="text"]::placeholder, .tribe-right input[type="email"]::placeholder {
645
  color: #a2aab2;
646
  }
647
 
@@ -651,18 +649,18 @@
651
  font-weight: normal;
652
  }
653
 
654
- .tribe-right label[for^="tribe-tickets-attendees-list-optout"] {
655
  align-items: flex-start;
656
  display: flex;
657
  margin: 0 0 15px;
658
  padding-top: 7px;
659
  }
660
 
661
- .tribe-right label[for^="tribe-tickets-attendees-list-optout"] input[type="checkbox"] {
662
  -webkit-appearance: none;
663
  -moz-appearance: none;
664
  appearance: none;
665
- background-color: #ffffff;
666
  border: 1px solid #e1e3e6;
667
  border-radius: 0;
668
  cursor: pointer;
@@ -672,15 +670,15 @@
672
  width: 16px;
673
  }
674
 
675
- .tribe-right label[for^="tribe-tickets-attendees-list-optout"] input[type="checkbox"]:focus {
676
  box-shadow: 0 0 0 1px #e1e3e6;
677
  outline: 2px solid transparent;
678
  outline-offset: -2px;
679
  }
680
 
681
- .tribe-right label[for^="tribe-tickets-attendees-list-optout"] input[type="checkbox"]:checked:before {
682
  color: #009fd4;
683
- content: "\f147";
684
  display: inline-block;
685
  float: left;
686
  font: normal 21px/1 dashicons;
@@ -691,7 +689,7 @@
691
  }
692
 
693
  .tribe-tickets-meta-option-label {
694
- color: #000000;
695
  font-size: 14px;
696
  line-height: 18px;
697
  font-weight: normal;
@@ -699,7 +697,7 @@
699
 
700
  .tribe-block__rsvp__message__error,
701
  .tribe-block__rsvp__message__success {
702
- color: #000000;
703
  font-size: 14px;
704
  line-height: 18px;
705
  padding: 20px;
@@ -707,7 +705,7 @@
707
 
708
  .tribe-block__rsvp__message__error {
709
  background: #ffebe8;
710
- border: 1px solid #cc0000;
711
  display: none;
712
  margin-bottom: 20px;
713
  }
@@ -720,8 +718,8 @@
720
 
721
  .tribe-block__rsvp__submit-button {
722
  background: #009fd4;
723
- color: #ffffff;
724
- font-family: Helvetica, sans-serif, arial;
725
  font-size: 15px;
726
  font-weight: bold;
727
  line-height: 18px;
@@ -752,7 +750,7 @@
752
 
753
  .tribe-common-c-loader.tribe-block__rsvp__loading {
754
  align-items: center;
755
- background: rgba( 255, 255, 255, .7 );
756
  height: 100%;
757
  justify-content: center;
758
  left: 0;
@@ -782,16 +780,13 @@
782
  }
783
  }
784
 
785
- @media (min-width: 768px ) {
786
 
787
  .tribe-events-tickets td {
788
  width: auto
789
  }
790
- }
791
 
792
- @media (min-width: 768px) {
793
-
794
- .tribe-events-tickets td.quantity input[type="number"], .tribe-events-tickets td.woocommerce input[type="number"] {
795
  width: 4.375em
796
  }
797
 
@@ -803,18 +798,18 @@
803
  margin: 10px
804
  }
805
 
806
- .tribe-events-tickets input[type="date"],
807
- .tribe-events-tickets input[type="time"],
808
- .tribe-events-tickets input[type="datetime-local"],
809
- .tribe-events-tickets input[type="week"],
810
- .tribe-events-tickets input[type="month"],
811
- .tribe-events-tickets input[type="text"],
812
- .tribe-events-tickets input[type="email"],
813
- .tribe-events-tickets input[type="url"],
814
- .tribe-events-tickets input[type="password"],
815
- .tribe-events-tickets input[type="search"],
816
- .tribe-events-tickets input[type="tel"],
817
- .tribe-events-tickets input[type="number"],
818
  .tribe-events-tickets textarea,
819
  .tribe-events-tickets select {
820
  width: auto
@@ -827,7 +822,7 @@
827
  .tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta > td, .tribe-events-tickets-rsvp tr.tribe-tickets-meta-row > td {
828
  display: table-cell
829
  }
830
- }
831
 
832
  @media (min-width: 600px) {
833
 
@@ -843,7 +838,7 @@
843
  width: 84px
844
  }
845
 
846
- .tribe-block__rsvp__number-input-inner input[type="number"] {
847
  font-size: 36px;
848
  height: 48px
849
  }
5
  * src/resources/postcss/ file. For more information, check out our engineering
6
  * docs on how we handle CSS in our engineering docs.
7
  *
8
+ * @see: https://the-events-calendar.github.io/products-engineering/docs/code-standards/css/
9
  */
10
 
11
  .tribe-rsvp {
40
  border-width: 1px;
41
  font-size: 12px;
42
  margin: 0 0 5px;
43
+ padding: 0 0.6em;
44
  }
45
 
46
  .tribe-rsvp-message-success {
119
  }
120
 
121
  .user-details p {
122
+ margin: 0 0 0.5em;
123
  }
124
 
125
  .tribe-answer {
128
 
129
  .tribe-answer .type-label {
130
  margin-bottom: 0;
131
+ padding-right: 0.5em;
132
  }
133
 
134
  .tribe-answer label {
177
  }
178
 
179
  /* = Tickets & RSVP Modules Front End Styles
180
+ ============================================= */
181
 
182
  /* Title */
183
 
196
  /* RSVP & Tickets Table */
197
 
198
  .tribe-events-tickets {
199
+ background: var(--tec-color-background-secondary);
200
  border: 0;
201
  border-radius: 3px;
202
  max-width: 100%;
234
  order: 2;
235
  }
236
 
237
+ .tribe-events-tickets td.quantity input[type='number'], .tribe-events-tickets td.woocommerce input[type='number'] {
238
  background-color: #fff;
239
  border-radius: 3px;
240
  margin-bottom: 5px;
255
  }
256
 
257
  .tribe-events-tickets .tribe-link-tickets-message {
258
+ background: rgba(200, 200, 200, 0.8);
259
  bottom: 0;
260
  left: 0;
261
  position: absolute;
273
  }
274
 
275
  .tribe-events-tickets .tribe-tickets-remaining {
276
+ color: var(--tec-color-text-secondary);
277
  display: block;
278
  font-size: 11px;
279
  }
280
 
281
  .tribe-events-tickets .tribe-tickets-attendees-list-optout label {
282
+ color: var(--tec-color-text-secondary);
283
  font-size: 13px;
284
  }
285
 
286
+ .tribe-events-tickets .tribe-tickets-attendees-list-optout input[type='radio'] + label,
287
+ .tribe-events-tickets .tribe-tickets-attendees-list-optout input[type='checkbox'] + label {
288
  display: inline-block;
289
  }
290
 
292
  .tribe-events-tickets .tickets_name p,
293
  .tribe-events-tickets .tickets_description,
294
  .tribe-events-tickets .tickets_price {
295
+ color: var(--tec-color-text-secondary);
296
  font-size: 15px;
297
  padding: 16px 10px;
298
  }
299
 
300
+ .tribe-events-tickets input[type='date'],
301
+ .tribe-events-tickets input[type='time'],
302
+ .tribe-events-tickets input[type='datetime-local'],
303
+ .tribe-events-tickets input[type='week'],
304
+ .tribe-events-tickets input[type='month'],
305
+ .tribe-events-tickets input[type='text'],
306
+ .tribe-events-tickets input[type='email'],
307
+ .tribe-events-tickets input[type='url'],
308
+ .tribe-events-tickets input[type='password'],
309
+ .tribe-events-tickets input[type='search'],
310
+ .tribe-events-tickets input[type='tel'],
311
+ .tribe-events-tickets input[type='number'],
312
  .tribe-events-tickets textarea,
313
  .tribe-events-tickets select {
314
  background: #fff;
345
  */
346
 
347
  .tribe-block__rsvp {
348
+ font-family: var(--tec-font-family-sans-serif);
349
  margin-bottom: 30px;
350
  margin-top: 30px;
351
  max-width: 580px;
362
 
363
  .tribe-block__rsvp__icon {
364
  align-items: center;
365
+ background: #fff;
366
  border-bottom: 1px dashed #b5bcc2;
367
  color: #434343;
368
  display: flex;
384
  flex: auto;
385
  }
386
 
 
 
387
  .tribe-block__rsvp__details {
388
  padding: 25px 20px 20px;
389
  }
390
 
391
  .tribe-block__rsvp__title {
392
+ color: #000;
393
  font-size: 21px;
394
  font-weight: bold;
395
  line-height: 28px;
438
  align-items: center;
439
  border: 1px solid #545d66;
440
  border-radius: 4px;
441
+ background: #fff;
442
  color: #545d66;
443
  display: flex;
444
+ font-family: var(--tec-font-family-sans-serif);
445
  font-size: 14px;
446
  font-weight: bold;
447
  height: 44px;
457
 
458
  .tribe-block__rsvp__status-button:hover,
459
  .tribe-block__rsvp__status-button:focus {
460
+ background: #fff;
461
+ border: 1px solid #000;
462
+ color: #000;
463
  }
464
 
465
  .tribe-block__rsvp__status-button.tribe-active {
466
+ border: 1px solid #000;
467
+ color: #000;
468
  }
469
 
470
  .tribe-block__rsvp__status-button.tribe-inactive {
474
 
475
  .tribe-block__rsvp__status-button.tribe-inactive:hover,
476
  .tribe-block__rsvp__status-button.tribe-inactive:focus {
477
+ background: #fff;
478
  border: 1px solid #545d66;
479
  color: #545d66;
480
  }
481
 
482
+ .tribe-block__rsvp__status-button[disabled='disabled'] {
483
  cursor: default;
484
  }
485
 
531
  display: flex;
532
  }
533
 
534
+ .tribe-block__rsvp__number-input-inner input[type='number'] {
535
  -webkit-appearance: textfield;
536
  -moz-appearance: textfield;
537
  appearance: textfield;
538
  background: transparent;
539
  border: none;
540
+ color: #000;
541
+ font-family: var(--tec-font-family-sans-serif);
542
  font-size: 30px;
543
  font-weight: bold;
544
  height: 40px;
547
  text-align: center;
548
  }
549
 
550
+ .tribe-block__rsvp__number-input-inner input[type='number']::-webkit-inner-spin-button,
551
+ .tribe-block__rsvp__number-input-inner input[type='number']::-webkit-outer-spin-button {
552
  -webkit-appearance: none;
553
  appearance: none;
554
  }
617
  flex: auto;
618
  }
619
 
620
+ .tribe-right input[type='text'],
621
+ .tribe-right input[type='email'] {
622
  border-color: #e1e3e6;
623
+ color: #000;
624
  display: block;
625
+ font-family: var(--tec-font-family-sans-serif);
626
  font-size: 16px;
627
  height: 40px;
628
  line-height: 18px;
631
  width: 100%;
632
  }
633
 
634
+ .tribe-right input[type='text']::-moz-placeholder, .tribe-right input[type='email']::-moz-placeholder {
635
  color: #a2aab2;
636
  }
637
 
638
+ .tribe-right input[type='text']:-ms-input-placeholder, .tribe-right input[type='email']:-ms-input-placeholder {
639
  color: #a2aab2;
640
  }
641
 
642
+ .tribe-right input[type='text']::placeholder, .tribe-right input[type='email']::placeholder {
643
  color: #a2aab2;
644
  }
645
 
649
  font-weight: normal;
650
  }
651
 
652
+ .tribe-right label[for^='tribe-tickets-attendees-list-optout'] {
653
  align-items: flex-start;
654
  display: flex;
655
  margin: 0 0 15px;
656
  padding-top: 7px;
657
  }
658
 
659
+ .tribe-right label[for^='tribe-tickets-attendees-list-optout'] input[type='checkbox'] {
660
  -webkit-appearance: none;
661
  -moz-appearance: none;
662
  appearance: none;
663
+ background-color: #fff;
664
  border: 1px solid #e1e3e6;
665
  border-radius: 0;
666
  cursor: pointer;
670
  width: 16px;
671
  }
672
 
673
+ .tribe-right label[for^='tribe-tickets-attendees-list-optout'] input[type='checkbox']:focus {
674
  box-shadow: 0 0 0 1px #e1e3e6;
675
  outline: 2px solid transparent;
676
  outline-offset: -2px;
677
  }
678
 
679
+ .tribe-right label[for^='tribe-tickets-attendees-list-optout'] input[type='checkbox']:checked:before {
680
  color: #009fd4;
681
+ content: '\f147';
682
  display: inline-block;
683
  float: left;
684
  font: normal 21px/1 dashicons;
689
  }
690
 
691
  .tribe-tickets-meta-option-label {
692
+ color: #000;
693
  font-size: 14px;
694
  line-height: 18px;
695
  font-weight: normal;
697
 
698
  .tribe-block__rsvp__message__error,
699
  .tribe-block__rsvp__message__success {
700
+ color: #000;
701
  font-size: 14px;
702
  line-height: 18px;
703
  padding: 20px;
705
 
706
  .tribe-block__rsvp__message__error {
707
  background: #ffebe8;
708
+ border: 1px solid #c00;
709
  display: none;
710
  margin-bottom: 20px;
711
  }
718
 
719
  .tribe-block__rsvp__submit-button {
720
  background: #009fd4;
721
+ color: #fff;
722
+ font-family: var(--tec-font-family-sans-serif);
723
  font-size: 15px;
724
  font-weight: bold;
725
  line-height: 18px;
750
 
751
  .tribe-common-c-loader.tribe-block__rsvp__loading {
752
  align-items: center;
753
+ background: rgba(255, 255, 255, 0.7);
754
  height: 100%;
755
  justify-content: center;
756
  left: 0;
780
  }
781
  }
782
 
783
+ @media (min-width: 768px) {
784
 
785
  .tribe-events-tickets td {
786
  width: auto
787
  }
 
788
 
789
+ .tribe-events-tickets td.quantity input[type='number'], .tribe-events-tickets td.woocommerce input[type='number'] {
 
 
790
  width: 4.375em
791
  }
792
 
798
  margin: 10px
799
  }
800
 
801
+ .tribe-events-tickets input[type='date'],
802
+ .tribe-events-tickets input[type='time'],
803
+ .tribe-events-tickets input[type='datetime-local'],
804
+ .tribe-events-tickets input[type='week'],
805
+ .tribe-events-tickets input[type='month'],
806
+ .tribe-events-tickets input[type='text'],
807
+ .tribe-events-tickets input[type='email'],
808
+ .tribe-events-tickets input[type='url'],
809
+ .tribe-events-tickets input[type='password'],
810
+ .tribe-events-tickets input[type='search'],
811
+ .tribe-events-tickets input[type='tel'],
812
+ .tribe-events-tickets input[type='number'],
813
  .tribe-events-tickets textarea,
814
  .tribe-events-tickets select {
815
  width: auto
822
  .tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta > td, .tribe-events-tickets-rsvp tr.tribe-tickets-meta-row > td {
823
  display: table-cell
824
  }
825
+ }
826
 
827
  @media (min-width: 600px) {
828
 
838
  width: 84px
839
  }
840
 
841
+ .tribe-block__rsvp__number-input-inner input[type='number'] {
842
  font-size: 36px;
843
  height: 48px
844
  }
src/resources/css/rsvp-v1.min.css CHANGED
@@ -1 +1 @@
1
- .tribe-rsvp{padding:20px 0}.tribe-tickets-attendee{padding:10px}.tribe-events-style-full .tribe-events-tickets .tribe-tickets-attendee table,.tribe-events-style-full .tribe-events-tickets .tribe-tickets-attendee td,.tribe-events-style-full .tribe-events-tickets .tribe-tickets-attendee tr,.tribe-events-tickets .tribe-tickets-attendee table,.tribe-events-tickets .tribe-tickets-attendee td,.tribe-events-tickets .tribe-tickets-attendee tr{border:0}.tribe-rsvp-message-display .tribe-rsvp-messages{display:block}.tribe-rsvp-messages{display:none;padding:10px 10px 5px}.tribe-rsvp-message{border-radius:3px;border-style:solid;border-width:1px;font-size:12px;margin:0 0 5px;padding:0 .6em}.tribe-rsvp-message-success{background-color:#ffffe0;border-color:#e6db55}.tribe-rsvp-message-error{background-color:#ffebe8;border-color:#c00}.tribe-tickets-quantity{width:100%}.tickets-unavailable{font-style:italic}.tribe-rsvp-list{list-style:none;padding:0;margin:0}.tribe-rsvp-list>.tribe-item{min-height:105px;padding:20px;border:1px solid #ededed;border-bottom:0}.tribe-rsvp-list>.tribe-item:last-child{border-bottom:1px solid #ededed;margin-bottom:20px}.tribe-rsvp-list>.tribe-item.tribe-disabled{background-color:#efefef;border-color:#ddd;color:#717171}.tribe-rsvp-list>.tribe-item.tribe-disabled:last-child{border-bottom-color:#ddd}.tribe-rsvp-list>.tribe-item .tribe-answer{float:right;display:inline-block}.tribe-rsvp-list>.tribe-item table{border:0;margin:0}.tribe-rsvp-list>.tribe-item td{border:0}.list-attendee{color:#999;display:inline-block;letter-spacing:1px;text-transform:uppercase}.tribe-submit-tickets-form{margin-top:20px}.user-details{margin:0 0 1.5em}.user-details p{margin:0 0 .5em}.tribe-answer{line-height:2}.tribe-answer .type-label{margin-bottom:0;padding-right:.5em}.tribe-answer label{display:block}.tribe-answer select{background:#fff;border:1px solid #ddd;height:30px;line-height:1;margin-left:5px}.tribe-rsvp h2{margin-bottom:20px;line-height:1.2}.event-tickets-meta-label{font-weight:700;margin:0 1em 0 0}.tribe-theme-parent-twentysixteen .comment-content a,.tribe-theme-parent-twentysixteen .entry-content a,.tribe-theme-parent-twentysixteen .entry-footer a:hover,.tribe-theme-parent-twentysixteen .entry-summary a,.tribe-theme-parent-twentysixteen .logged-in-as a,.tribe-theme-parent-twentysixteen .pingback .comment-body>a,.tribe-theme-parent-twentysixteen .site-info a:hover,.tribe-theme-parent-twentysixteen .taxonomy-description a,.tribe-theme-parent-twentysixteen .textwidget a,.tribe-theme-twentysixteen .comment-content a,.tribe-theme-twentysixteen .entry-content a,.tribe-theme-twentysixteen .entry-footer a:hover,.tribe-theme-twentysixteen .entry-summary a,.tribe-theme-twentysixteen .logged-in-as a,.tribe-theme-twentysixteen .pingback .comment-body>a,.tribe-theme-twentysixteen .site-info a:hover,.tribe-theme-twentysixteen .taxonomy-description a,.tribe-theme-twentysixteen .textwidget a{box-shadow:none}.tribe-events-tickets-title.tribe--rsvp{margin:0}.tribe-events-style-full.tribe-events-style-theme h2.tribe-events-tickets-title{font-size:90%}.tribe-link-view-attendee{margin:15px 0}.tribe-events-tickets{background:#f8f8f8;border:0;border-radius:3px;max-width:100%;position:relative}.tribe-events-tickets table,.tribe-events-tickets td,.tribe-events-tickets th{border:0}.tribe-events-tickets tr{display:flex;flex-flow:row wrap}.tribe-events-tickets tr:not(:first-child){border-top:2px solid #dfdfdf}.tribe-events-tickets td{flex:none;padding:8px 10px;width:100%;word-break:normal}.tribe-events-tickets td.tickets_name{font-weight:700}.tribe-events-tickets td.quantity,.tribe-events-tickets td.woocommerce{order:2}.tribe-events-tickets td.quantity input[type=number],.tribe-events-tickets td.woocommerce input[type=number]{background-color:#fff;border-radius:3px;margin-bottom:5px;padding:5px 10px;text-align:left}.tribe-events-tickets td.tickets_submit{order:3}.tribe-events-tickets td.tickets_submit .tribe-button{margin:0 0 10px}.tribe-events-tickets .woocommerce.add-to-cart .tribe-button{margin:10px 0}.tribe-events-tickets .tribe-link-tickets-message{background:hsla(0,0%,78%,.8);bottom:0;left:0;position:absolute;right:0;text-align:center;top:0}.tribe-events-tickets .tribe-link-tickets-message .no-javascript-msg{left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:90%}.tribe-events-tickets .tribe-tickets-remaining{color:#777;display:block;font-size:11px}.tribe-events-tickets .tribe-tickets-attendees-list-optout label{color:#777;font-size:13px}.tribe-events-tickets .tribe-tickets-attendees-list-optout input[type=checkbox]+label,.tribe-events-tickets .tribe-tickets-attendees-list-optout input[type=radio]+label{display:inline-block}.tribe-events-tickets .tickets_description,.tribe-events-tickets .tickets_name,.tribe-events-tickets .tickets_name p,.tribe-events-tickets .tickets_price{color:#464646;font-size:15px;padding:16px 10px}.tribe-events-tickets input[type=date],.tribe-events-tickets input[type=datetime-local],.tribe-events-tickets input[type=email],.tribe-events-tickets input[type=month],.tribe-events-tickets input[type=number],.tribe-events-tickets input[type=password],.tribe-events-tickets input[type=search],.tribe-events-tickets input[type=tel],.tribe-events-tickets input[type=text],.tribe-events-tickets input[type=time],.tribe-events-tickets input[type=url],.tribe-events-tickets input[type=week],.tribe-events-tickets select,.tribe-events-tickets textarea{background:#fff;width:100%}.tribe-events-tickets header{height:auto}.tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta,.tribe-events-tickets-rsvp tr.tribe-tickets-meta-row{display:none}.tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta>td,.tribe-events-tickets-rsvp tr.tribe-tickets-meta-row>td,.tribe-tickets-has-rsvp.tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta,.tribe-tickets-has-rsvp.tribe-events-tickets-rsvp tr.tribe-tickets-meta-row{display:block}.tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta tr,.tribe-events-tickets-rsvp tr.tribe-tickets-meta-row tr{border:0}.tribe-block__rsvp{font-family:Helvetica,sans-serif;margin-bottom:30px;margin-top:30px;max-width:580px;position:relative}.tribe-block__rsvp__ticket{border:1px solid #e1e3e6;display:flex;flex-wrap:wrap;position:relative;width:100%}.tribe-block__rsvp__icon{align-items:center;background:#fff;border-bottom:1px dashed #b5bcc2;color:#434343;display:flex;flex:none;flex-direction:column;font-size:14px;font-weight:700;line-height:17px;padding:20px 17px;width:100%}.tribe-block__rsvp__icon svg{margin-bottom:7px}.tribe-block__rsvp__content{background-color:#f5f8f9;flex:auto}.tribe-block__rsvp__details{padding:25px 20px 20px}.tribe-block__rsvp__title{color:#000;font-size:21px;font-weight:700;line-height:28px;margin-bottom:12px}.tribe-block__rsvp__description{color:#545d66;font-size:14px;line-height:18px;margin-bottom:15px}.tribe-block__rsvp__availability{color:#545d66;display:flex;align-items:center;font-size:12px;line-height:18px}.tribe-block__rsvp__quantity{font-size:18px;font-weight:700;margin-right:6px}.tribe-block__rsvp__status{display:flex;flex-wrap:nowrap;padding:0 20px 25px;text-align:center}.tribe-block__rsvp__status>span{flex:none;margin-right:15px;width:calc(50% - 7.5px)}.tribe-block__rsvp__status>span:last-child{margin-right:0}.tribe-block__rsvp__status-button{align-items:center;border:1px solid #545d66;border-radius:4px;background:#fff;color:#545d66;display:flex;font-family:Helvetica,sans-serif;font-size:14px;font-weight:700;height:44px;justify-content:center;line-height:1;padding:0;width:100%}.tribe-block__rsvp__status-button svg{margin-left:9px}.tribe-block__rsvp__status-button:focus,.tribe-block__rsvp__status-button:hover{background:#fff;border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-active{border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-inactive{border:1px solid #e1e3e6;color:#a2aab2}.tribe-block__rsvp__status-button.tribe-inactive:focus,.tribe-block__rsvp__status-button.tribe-inactive:hover{background:#fff;border:1px solid #545d66;color:#545d66}.tribe-block__rsvp__status-button[disabled=disabled]{cursor:default}.tribe-block__rsvp__going-icon,.tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-active .tribe-block__rsvp__going-icon,.tribe-active .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__not-going-icon{fill:#191e23}.tribe-inactive .tribe-block__rsvp__going-icon,.tribe-inactive .tribe-block__rsvp__not-going-icon{fill:#e1e3e6}.tribe-inactive:focus .tribe-block__rsvp__going-icon,.tribe-inactive:focus .tribe-block__rsvp__not-going-icon,.tribe-inactive:hover .tribe-block__rsvp__going-icon,.tribe-inactive:hover .tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-block__rsvp__form{padding:0 20px}.tribe-block__rsvp__form form{border-top:1px solid #e1e3e6;display:flex;padding:30px 0}.tribe-left{flex:none}.tribe-block__rsvp__number-input{padding-right:20px}.tribe-block__rsvp__number-input-inner{align-items:center;display:flex}.tribe-block__rsvp__number-input-inner input[type=number]{-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;background:transparent;border:none;color:#000;font-family:Helvetica,sans-serif;font-size:30px;font-weight:700;height:40px;max-width:48px;padding:4px 0;text-align:center}.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-inner-spin-button,.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;appearance:none}.tribe-block__rsvp__number-input-label{display:block;font-size:14px;font-weight:700;line-height:18px;margin-top:9px;text-align:center}.tribe-block__rsvp__number-input-button{background-color:transparent;height:30px;padding:0;position:relative;width:20px}.tribe-block__rsvp__number-input-button:after,.tribe-block__rsvp__number-input-button:before{background-color:#aeb4bb;content:"";height:2px;position:absolute;width:10px}.tribe-block__rsvp__number-input-button:focus,.tribe-block__rsvp__number-input-button:hover{background:none}.tribe-block__rsvp__number-input-button:focus:after,.tribe-block__rsvp__number-input-button:focus:before,.tribe-block__rsvp__number-input-button:hover:after,.tribe-block__rsvp__number-input-button:hover:before{background-color:#545d66}.tribe-block__rsvp__number-input-button--minus{margin-left:-10px}.tribe-block__rsvp__number-input-button--minus:after,.tribe-block__rsvp__number-input-button--minus:before{right:0}.tribe-block__rsvp__number-input-button--plus{margin-right:-10px}.tribe-block__rsvp__number-input-button--plus:after,.tribe-block__rsvp__number-input-button--plus:before{left:0}.tribe-block__rsvp__number-input-button--plus:after{transform:rotate(90deg)}.tribe-right{flex:auto}.tribe-right input[type=email],.tribe-right input[type=text]{border-color:#e1e3e6;color:#000;display:block;font-family:Helvetica,sans-serif;font-size:16px;height:40px;line-height:18px;margin-bottom:15px;padding:10px 15px;width:100%}.tribe-right input[type=email]:-ms-input-placeholder,.tribe-right input[type=text]:-ms-input-placeholder{color:#a2aab2}.tribe-right input[type=email]::placeholder,.tribe-right input[type=text]::placeholder{color:#a2aab2}.tribe-right label{cursor:pointer;font-size:14px;font-weight:400}.tribe-right label[for^=tribe-tickets-attendees-list-optout]{align-items:flex-start;display:flex;margin:0 0 15px;padding-top:7px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border:1px solid #e1e3e6;border-radius:0;cursor:pointer;flex:none;height:16px;margin:1px 10px 0 0;width:16px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:focus{box-shadow:0 0 0 1px #e1e3e6;outline:2px solid transparent;outline-offset:-2px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:checked:before{color:#009fd4;content:"\f147";display:inline-block;float:left;font:normal 21px/1 dashicons;margin:-3px 0 0 -4px;speak:none;vertical-align:middle;width:16px}.tribe-tickets-meta-option-label{color:#000;font-size:14px;line-height:18px;font-weight:400}.tribe-block__rsvp__message__error,.tribe-block__rsvp__message__success{color:#000;font-size:14px;line-height:18px;padding:20px}.tribe-block__rsvp__message__error{background:#ffebe8;border:1px solid #c00;display:none;margin-bottom:20px}.tribe-block__rsvp__message__success{background:#ecfae5;border:1px solid #1bd800;margin-top:20px}.tribe-block__rsvp__submit-button{background:#009fd4;color:#fff;font-family:Helvetica,sans-serif;font-size:15px;font-weight:700;line-height:18px;margin:10px 0 0;padding:10px 23px}.tribe-block__rsvp__submit-button:focus,.tribe-block__rsvp__submit-button:hover{background:#007bb4}.tribe-block__rsvp__submit-button:disabled{cursor:not-allowed;background:#a2aab2}.tribe-block__rsvp__form__attendee-meta{margin:0}.tribe-block__rsvp__form__attendee-meta td,.tribe-block__rsvp__form__attendee-meta th{padding:0;border:none;word-break:normal}.tribe-common-c-loader.tribe-block__rsvp__loading{align-items:center;background:hsla(0,0%,100%,.7);height:100%;justify-content:center;left:0;margin:0;padding:0;position:absolute;text-align:center;top:0;width:100%;z-index:99}.tribe-common-c-loader.tribe-block__rsvp__loading svg{max-width:70px;position:absolute;top:35%}.tribe-common-c-loader.tribe-block__rsvp__loading svg circle{fill:#888}@media only screen and (min-width:768px){.tribe-events-tickets tr{display:table-row}}@media (min-width:768px){.tribe-events-tickets td{width:auto}}@media (min-width:768px){.tribe-events-tickets td.quantity input[type=number],.tribe-events-tickets td.woocommerce input[type=number]{width:4.375em}.tribe-events-tickets .woocommerce.add-to-cart{padding:16px}.tribe-events-tickets .woocommerce.add-to-cart .tribe-button{margin:10px}.tribe-events-tickets input[type=date],.tribe-events-tickets input[type=datetime-local],.tribe-events-tickets input[type=email],.tribe-events-tickets input[type=month],.tribe-events-tickets input[type=number],.tribe-events-tickets input[type=password],.tribe-events-tickets input[type=search],.tribe-events-tickets input[type=tel],.tribe-events-tickets input[type=text],.tribe-events-tickets input[type=time],.tribe-events-tickets input[type=url],.tribe-events-tickets input[type=week],.tribe-events-tickets select,.tribe-events-tickets textarea{width:auto}.tribe-tickets-has-rsvp.tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta,.tribe-tickets-has-rsvp.tribe-events-tickets-rsvp tr.tribe-tickets-meta-row{display:table-row}.tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta>td,.tribe-events-tickets-rsvp tr.tribe-tickets-meta-row>td{display:table-cell}}@media (min-width:600px){.tribe-block__rsvp__ticket{align-items:stretch;flex-wrap:nowrap}.tribe-block__rsvp__icon{border-bottom:none;border-right:1px dashed #b5bcc2;padding:28px 17px;width:84px}.tribe-block__rsvp__number-input-inner input[type=number]{font-size:36px;height:48px}.tribe-block__rsvp__message__success{padding:10px 30px;text-align:center}}
1
+ .tribe-rsvp{padding:20px 0}.tribe-tickets-attendee{padding:10px}.tribe-events-style-full .tribe-events-tickets .tribe-tickets-attendee table,.tribe-events-style-full .tribe-events-tickets .tribe-tickets-attendee td,.tribe-events-style-full .tribe-events-tickets .tribe-tickets-attendee tr,.tribe-events-tickets .tribe-tickets-attendee table,.tribe-events-tickets .tribe-tickets-attendee td,.tribe-events-tickets .tribe-tickets-attendee tr{border:0}.tribe-rsvp-message-display .tribe-rsvp-messages{display:block}.tribe-rsvp-messages{display:none;padding:10px 10px 5px}.tribe-rsvp-message{border-radius:3px;border-style:solid;border-width:1px;font-size:12px;margin:0 0 5px;padding:0 .6em}.tribe-rsvp-message-success{background-color:#ffffe0;border-color:#e6db55}.tribe-rsvp-message-error{background-color:#ffebe8;border-color:#c00}.tribe-tickets-quantity{width:100%}.tickets-unavailable{font-style:italic}.tribe-rsvp-list{list-style:none;padding:0;margin:0}.tribe-rsvp-list>.tribe-item{min-height:105px;padding:20px;border:1px solid #ededed;border-bottom:0}.tribe-rsvp-list>.tribe-item:last-child{border-bottom:1px solid #ededed;margin-bottom:20px}.tribe-rsvp-list>.tribe-item.tribe-disabled{background-color:#efefef;border-color:#ddd;color:#717171}.tribe-rsvp-list>.tribe-item.tribe-disabled:last-child{border-bottom-color:#ddd}.tribe-rsvp-list>.tribe-item .tribe-answer{float:right;display:inline-block}.tribe-rsvp-list>.tribe-item table{border:0;margin:0}.tribe-rsvp-list>.tribe-item td{border:0}.list-attendee{color:#999;display:inline-block;letter-spacing:1px;text-transform:uppercase}.tribe-submit-tickets-form{margin-top:20px}.user-details{margin:0 0 1.5em}.user-details p{margin:0 0 .5em}.tribe-answer{line-height:2}.tribe-answer .type-label{margin-bottom:0;padding-right:.5em}.tribe-answer label{display:block}.tribe-answer select{background:#fff;border:1px solid #ddd;height:30px;line-height:1;margin-left:5px}.tribe-rsvp h2{margin-bottom:20px;line-height:1.2}.event-tickets-meta-label{font-weight:700;margin:0 1em 0 0}.tribe-theme-parent-twentysixteen .comment-content a,.tribe-theme-parent-twentysixteen .entry-content a,.tribe-theme-parent-twentysixteen .entry-footer a:hover,.tribe-theme-parent-twentysixteen .entry-summary a,.tribe-theme-parent-twentysixteen .logged-in-as a,.tribe-theme-parent-twentysixteen .pingback .comment-body>a,.tribe-theme-parent-twentysixteen .site-info a:hover,.tribe-theme-parent-twentysixteen .taxonomy-description a,.tribe-theme-parent-twentysixteen .textwidget a,.tribe-theme-twentysixteen .comment-content a,.tribe-theme-twentysixteen .entry-content a,.tribe-theme-twentysixteen .entry-footer a:hover,.tribe-theme-twentysixteen .entry-summary a,.tribe-theme-twentysixteen .logged-in-as a,.tribe-theme-twentysixteen .pingback .comment-body>a,.tribe-theme-twentysixteen .site-info a:hover,.tribe-theme-twentysixteen .taxonomy-description a,.tribe-theme-twentysixteen .textwidget a{box-shadow:none}.tribe-events-tickets-title.tribe--rsvp{margin:0}.tribe-events-style-full.tribe-events-style-theme h2.tribe-events-tickets-title{font-size:90%}.tribe-link-view-attendee{margin:15px 0}.tribe-events-tickets{background:var(--tec-color-background-secondary);border:0;border-radius:3px;max-width:100%;position:relative}.tribe-events-tickets table,.tribe-events-tickets td,.tribe-events-tickets th{border:0}.tribe-events-tickets tr{display:flex;flex-flow:row wrap}.tribe-events-tickets tr:not(:first-child){border-top:2px solid #dfdfdf}.tribe-events-tickets td{flex:none;padding:8px 10px;width:100%;word-break:normal}.tribe-events-tickets td.tickets_name{font-weight:700}.tribe-events-tickets td.quantity,.tribe-events-tickets td.woocommerce{order:2}.tribe-events-tickets td.quantity input[type=number],.tribe-events-tickets td.woocommerce input[type=number]{background-color:#fff;border-radius:3px;margin-bottom:5px;padding:5px 10px;text-align:left}.tribe-events-tickets td.tickets_submit{order:3}.tribe-events-tickets td.tickets_submit .tribe-button{margin:0 0 10px}.tribe-events-tickets .woocommerce.add-to-cart .tribe-button{margin:10px 0}.tribe-events-tickets .tribe-link-tickets-message{background:hsla(0,0%,78%,.8);bottom:0;left:0;position:absolute;right:0;text-align:center;top:0}.tribe-events-tickets .tribe-link-tickets-message .no-javascript-msg{left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:90%}.tribe-events-tickets .tribe-tickets-remaining{color:var(--tec-color-text-secondary);display:block;font-size:11px}.tribe-events-tickets .tribe-tickets-attendees-list-optout label{color:var(--tec-color-text-secondary);font-size:13px}.tribe-events-tickets .tribe-tickets-attendees-list-optout input[type=checkbox]+label,.tribe-events-tickets .tribe-tickets-attendees-list-optout input[type=radio]+label{display:inline-block}.tribe-events-tickets .tickets_description,.tribe-events-tickets .tickets_name,.tribe-events-tickets .tickets_name p,.tribe-events-tickets .tickets_price{color:var(--tec-color-text-secondary);font-size:15px;padding:16px 10px}.tribe-events-tickets input[type=date],.tribe-events-tickets input[type=datetime-local],.tribe-events-tickets input[type=email],.tribe-events-tickets input[type=month],.tribe-events-tickets input[type=number],.tribe-events-tickets input[type=password],.tribe-events-tickets input[type=search],.tribe-events-tickets input[type=tel],.tribe-events-tickets input[type=text],.tribe-events-tickets input[type=time],.tribe-events-tickets input[type=url],.tribe-events-tickets input[type=week],.tribe-events-tickets select,.tribe-events-tickets textarea{background:#fff;width:100%}.tribe-events-tickets header{height:auto}.tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta,.tribe-events-tickets-rsvp tr.tribe-tickets-meta-row{display:none}.tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta>td,.tribe-events-tickets-rsvp tr.tribe-tickets-meta-row>td,.tribe-tickets-has-rsvp.tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta,.tribe-tickets-has-rsvp.tribe-events-tickets-rsvp tr.tribe-tickets-meta-row{display:block}.tribe-events-tickets-rsvp tr.tribe-event-tickets-plus-meta tr,.tribe-events-tickets-rsvp tr.tribe-tickets-meta-row tr{border:0}.tribe-block__rsvp{font-family:var(--tec-font-family-sans-serif);margin-bottom:30px;margin-top:30px;max-width:580px;position:relative}.tribe-block__rsvp__ticket{border:1px solid #e1e3e6;display:flex;flex-wrap:wrap;position:relative;width:100%}.tribe-block__rsvp__icon{align-items:center;background:#fff;border-bottom:1px dashed #b5bcc2;color:#434343;display:flex;flex:none;flex-direction:column;font-size:14px;font-weight:700;line-height:17px;padding:20px 17px;width:100%}.tribe-block__rsvp__icon svg{margin-bottom:7px}.tribe-block__rsvp__content{background-color:#f5f8f9;flex:auto}.tribe-block__rsvp__details{padding:25px 20px 20px}.tribe-block__rsvp__title{color:#000;font-size:21px;font-weight:700;line-height:28px;margin-bottom:12px}.tribe-block__rsvp__description{color:#545d66;font-size:14px;line-height:18px;margin-bottom:15px}.tribe-block__rsvp__availability{color:#545d66;display:flex;align-items:center;font-size:12px;line-height:18px}.tribe-block__rsvp__quantity{font-size:18px;font-weight:700;margin-right:6px}.tribe-block__rsvp__status{display:flex;flex-wrap:nowrap;padding:0 20px 25px;text-align:center}.tribe-block__rsvp__status>span{flex:none;margin-right:15px;width:calc(50% - 7.5px)}.tribe-block__rsvp__status>span:last-child{margin-right:0}.tribe-block__rsvp__status-button{align-items:center;border:1px solid #545d66;border-radius:4px;background:#fff;color:#545d66;display:flex;font-family:var(--tec-font-family-sans-serif);font-size:14px;font-weight:700;height:44px;justify-content:center;line-height:1;padding:0;width:100%}.tribe-block__rsvp__status-button svg{margin-left:9px}.tribe-block__rsvp__status-button:focus,.tribe-block__rsvp__status-button:hover{background:#fff;border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-active{border:1px solid #000;color:#000}.tribe-block__rsvp__status-button.tribe-inactive{border:1px solid #e1e3e6;color:#a2aab2}.tribe-block__rsvp__status-button.tribe-inactive:focus,.tribe-block__rsvp__status-button.tribe-inactive:hover{background:#fff;border:1px solid #545d66;color:#545d66}.tribe-block__rsvp__status-button[disabled=disabled]{cursor:default}.tribe-block__rsvp__going-icon,.tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-active .tribe-block__rsvp__going-icon,.tribe-active .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:focus .tribe-block__rsvp__not-going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__going-icon,.tribe-block__rsvp__status-button:hover .tribe-block__rsvp__not-going-icon{fill:#191e23}.tribe-inactive .tribe-block__rsvp__going-icon,.tribe-inactive .tribe-block__rsvp__not-going-icon{fill:#e1e3e6}.tribe-inactive:focus .tribe-block__rsvp__going-icon,.tribe-inactive:focus .tribe-block__rsvp__not-going-icon,.tribe-inactive:hover .tribe-block__rsvp__going-icon,.tribe-inactive:hover .tribe-block__rsvp__not-going-icon{fill:#a2aab2}.tribe-block__rsvp__form{padding:0 20px}.tribe-block__rsvp__form form{border-top:1px solid #e1e3e6;display:flex;padding:30px 0}.tribe-left{flex:none}.tribe-block__rsvp__number-input{padding-right:20px}.tribe-block__rsvp__number-input-inner{align-items:center;display:flex}.tribe-block__rsvp__number-input-inner input[type=number]{-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;background:transparent;border:none;color:#000;font-family:var(--tec-font-family-sans-serif);font-size:30px;font-weight:700;height:40px;max-width:48px;padding:4px 0;text-align:center}.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-inner-spin-button,.tribe-block__rsvp__number-input-inner input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;appearance:none}.tribe-block__rsvp__number-input-label{display:block;font-size:14px;font-weight:700;line-height:18px;margin-top:9px;text-align:center}.tribe-block__rsvp__number-input-button{background-color:transparent;height:30px;padding:0;position:relative;width:20px}.tribe-block__rsvp__number-input-button:after,.tribe-block__rsvp__number-input-button:before{background-color:#aeb4bb;content:"";height:2px;position:absolute;width:10px}.tribe-block__rsvp__number-input-button:focus,.tribe-block__rsvp__number-input-button:hover{background:none}.tribe-block__rsvp__number-input-button:focus:after,.tribe-block__rsvp__number-input-button:focus:before,.tribe-block__rsvp__number-input-button:hover:after,.tribe-block__rsvp__number-input-button:hover:before{background-color:#545d66}.tribe-block__rsvp__number-input-button--minus{margin-left:-10px}.tribe-block__rsvp__number-input-button--minus:after,.tribe-block__rsvp__number-input-button--minus:before{right:0}.tribe-block__rsvp__number-input-button--plus{margin-right:-10px}.tribe-block__rsvp__number-input-button--plus:after,.tribe-block__rsvp__number-input-button--plus:before{left:0}.tribe-block__rsvp__number-input-button--plus:after{transform:rotate(90deg)}.tribe-right{flex:auto}.tribe-right input[type=email],.tribe-right input[type=text]{border-color:#e1e3e6;color:#000;display:block;font-family:var(--tec-font-family-sans-serif);font-size:16px;height:40px;line-height:18px;margin-bottom:15px;padding:10px 15px;width:100%}.tribe-right input[type=email]:-ms-input-placeholder,.tribe-right input[type=text]:-ms-input-placeholder{color:#a2aab2}.tribe-right input[type=email]::placeholder,.tribe-right input[type=text]::placeholder{color:#a2aab2}.tribe-right label{cursor:pointer;font-size:14px;font-weight:400}.tribe-right label[for^=tribe-tickets-attendees-list-optout]{align-items:flex-start;display:flex;margin:0 0 15px;padding-top:7px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border:1px solid #e1e3e6;border-radius:0;cursor:pointer;flex:none;height:16px;margin:1px 10px 0 0;width:16px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:focus{box-shadow:0 0 0 1px #e1e3e6;outline:2px solid transparent;outline-offset:-2px}.tribe-right label[for^=tribe-tickets-attendees-list-optout] input[type=checkbox]:checked:before{color:#009fd4;content:"\f147";display:inline-block;float:left;font:normal 21px/1 dashicons;margin:-3px 0 0 -4px;speak:none;vertical-align:middle;width:16px}.tribe-tickets-meta-option-label{color:#000;font-size:14px;line-height:18px;font-weight:400}.tribe-block__rsvp__message__error,.tribe-block__rsvp__message__success{color:#000;font-size:14px;line-height:18px;padding:20px}.tribe-block__rsvp__message__error{background:#ffebe8;border:1px solid #c00;display:none;margin-bottom:20px}.tribe-block__rsvp__message__success{background:#ecfae5;border:1px solid #1bd800;margin-top:20px}.tribe-block__rsvp__submit-button{background:#009fd4;color:#fff;font-family:var(--tec-font-family-sans-serif);font-size:15px;font-weight:700;line-height:18px;margin:10px 0 0;padding:10px 23px}.tribe-block__rsvp__submit-button:focus,.tribe-block__rsvp__submit-button:hover{background:#007bb4}.tribe-block__rsvp__submit-button:disabled{cursor:not-allowed;background:#a2aab2}.tribe-block__rsvp__form__attendee-meta{margin:0}.tribe-block__rsvp__form__attendee-meta td,.tribe-block__rsvp__form__attendee-meta th{padding:0;border:none;word-break:normal}.tribe-common