From 5bad6219ebc889aa984eb41021ac405d4efe1d37 Mon Sep 17 00:00:00 2001 From: Glynn Quelch Date: Thu, 9 Apr 2026 12:12:03 +0100 Subject: [PATCH 1/2] Do not unregister the tikckets block for other post types, just modify its insertaion so it cant be inserted when nont on an event post --- OLD/README.md | 105 ++ OLD/build/blocks/calendar/block.json | 135 +++ OLD/build/blocks/calendar/index-rtl.css | 1 + OLD/build/blocks/calendar/index.asset.php | 1 + OLD/build/blocks/calendar/index.css | 1 + OLD/build/blocks/calendar/index.js | 1 + OLD/build/blocks/calendar/style-index-rtl.css | 1 + OLD/build/blocks/calendar/style-index.css | 1 + OLD/build/blocks/calendar/view.asset.php | 1 + OLD/build/blocks/calendar/view.js | 1 + OLD/build/blocks/countdown/block.json | 28 + OLD/build/blocks/countdown/index.asset.php | 1 + OLD/build/blocks/countdown/index.js | 1 + .../blocks/countdown/style-index-rtl.css | 1 + OLD/build/blocks/countdown/style-index.css | 1 + OLD/build/blocks/countdown/view.asset.php | 1 + OLD/build/blocks/countdown/view.js | 1 + OLD/build/blocks/event-info/block.json | 48 + OLD/build/blocks/event-info/index-rtl.css | 1 + OLD/build/blocks/event-info/index.asset.php | 1 + OLD/build/blocks/event-info/index.css | 1 + OLD/build/blocks/event-info/index.js | 1 + OLD/build/blocks/event-tickets/block.json | 27 + OLD/build/blocks/event-tickets/index-rtl.css | 1 + .../blocks/event-tickets/index.asset.php | 1 + OLD/build/blocks/event-tickets/index.css | 1 + OLD/build/blocks/event-tickets/index.js | 1 + .../blocks/event-tickets/style-index-rtl.css | 1 + .../blocks/event-tickets/style-index.css | 1 + OLD/build/blocks/external-link/block.json | 30 + OLD/build/blocks/external-link/index-rtl.css | 1 + .../blocks/external-link/index.asset.php | 1 + OLD/build/blocks/external-link/index.css | 1 + OLD/build/blocks/external-link/index.js | 1 + OLD/build/blocks/inner-blocks/block.json | 18 + OLD/build/blocks/inner-blocks/index.asset.php | 1 + OLD/build/blocks/inner-blocks/index.js | 1 + .../blocks/inner-blocks/style-index-rtl.css | 1 + OLD/build/blocks/inner-blocks/style-index.css | 1 + OLD/build/blocks/loop-event-info/block.json | 75 ++ .../blocks/loop-event-info/index-rtl.css | 2 + .../blocks/loop-event-info/index.asset.php | 1 + OLD/build/blocks/loop-event-info/index.css | 2 + OLD/build/blocks/loop-event-info/index.js | 1 + .../blocks/past-events-notice/block.json | 31 + .../blocks/past-events-notice/index.asset.php | 1 + OLD/build/blocks/past-events-notice/index.js | 1 + OLD/build/blocks/upcoming-events/block.json | 78 ++ .../blocks/upcoming-events/index-rtl.css | 1 + .../blocks/upcoming-events/index.asset.php | 1 + OLD/build/blocks/upcoming-events/index.css | 1 + OLD/build/blocks/upcoming-events/index.js | 1 + OLD/build/js/admin.asset.php | 1 + OLD/build/js/admin.js | 1 + OLD/build/variations/index.asset.php | 1 + OLD/build/variations/index.js | 1 + OLD/plugin.php | 98 ++ OLD/postcss.config.js | 19 + OLD/src/assets/js/admin.js | 58 + OLD/src/back-compat.php | 28 + OLD/src/blocks/calendar/block.json | 130 ++ OLD/src/blocks/calendar/calendar.js | 245 ++++ OLD/src/blocks/calendar/color-panel/index.js | 58 + OLD/src/blocks/calendar/editor.scss | 14 + OLD/src/blocks/calendar/index.js | 266 +++++ OLD/src/blocks/calendar/style.scss | 275 +++++ OLD/src/blocks/calendar/view.js | 15 + OLD/src/blocks/common.scss | 60 + OLD/src/blocks/countdown/block.json | 28 + OLD/src/blocks/countdown/index.js | 44 + OLD/src/blocks/countdown/style.scss | 28 + OLD/src/blocks/countdown/view.js | 62 + OLD/src/blocks/event-info/block.json | 48 + OLD/src/blocks/event-info/editor-compat.scss | 30 + OLD/src/blocks/event-info/editor.scss | 202 ++++ OLD/src/blocks/event-info/index.js | 1055 +++++++++++++++++ OLD/src/blocks/event-tickets/block.json | 27 + .../blocks/event-tickets/draggable/index.js | 94 ++ OLD/src/blocks/event-tickets/editor.scss | 371 ++++++ OLD/src/blocks/event-tickets/index.js | 371 ++++++ .../search-list-control/index.js | 163 +++ OLD/src/blocks/event-tickets/style.scss | 42 + .../ticket-data-control/index.js | 766 ++++++++++++ OLD/src/blocks/external-link/block.json | 22 + OLD/src/blocks/external-link/editor.scss | 3 + OLD/src/blocks/external-link/index.js | 24 + OLD/src/blocks/inner-blocks/block.json | 15 + OLD/src/blocks/inner-blocks/index.js | 25 + OLD/src/blocks/inner-blocks/style.scss | 3 + OLD/src/blocks/loop-event-info/block.json | 61 + OLD/src/blocks/loop-event-info/editor.scss | 0 OLD/src/blocks/loop-event-info/index.js | 97 ++ OLD/src/blocks/loop-event-info/index.scss | 0 OLD/src/blocks/past-events-notice/block.json | 27 + OLD/src/blocks/past-events-notice/index.js | 21 + OLD/src/blocks/upcoming-events/block.json | 67 ++ OLD/src/blocks/upcoming-events/index.js | 279 +++++ OLD/src/blocks/upcoming-events/index.scss | 71 ++ OLD/src/calendar-functions.php | 292 +++++ OLD/src/classes/class-se-admin.php | 81 ++ OLD/src/classes/class-se-block-variations.php | 170 +++ OLD/src/classes/class-se-blocks.php | 898 ++++++++++++++ OLD/src/classes/class-se-calendar-export.php | 116 ++ OLD/src/classes/class-se-calendar.php | 452 +++++++ OLD/src/classes/class-se-event-post-type.php | 561 +++++++++ .../classes/class-se-event-query-dates.php | 157 +++ .../classes/class-se-rest-ticket-products.php | 245 ++++ OLD/src/classes/class-se-settings.php | 608 ++++++++++ OLD/src/classes/class-se-template-loader.php | 153 +++ OLD/src/event-functions.php | 530 +++++++++ OLD/src/init.php | 11 + OLD/src/rest-api.php | 30 + OLD/src/template-functions.php | 488 ++++++++ OLD/src/template-hooks.php | 37 + OLD/src/templates/archive.php | 59 + OLD/src/templates/calendar/calendar-body.php | 53 + .../templates/calendar/calendar-container.php | 37 + .../templates/calendar/calendar-header.php | 33 + OLD/src/templates/calendar/calendar-main.php | 119 ++ .../calendar/calendar-mobile-events.php | 48 + .../templates/calendar/calendar-top-bar.php | 42 + OLD/src/templates/calendar/day/day.php | 44 + OLD/src/templates/calendar/day/event.php | 91 ++ OLD/src/templates/calendar/day/events.php | 34 + .../templates/calendar/mobile-events/day.php | 33 + .../templates/calendar/mobile-events/nav.php | 46 + .../calendar/mobile-events/today.php | 25 + .../calendar/top-bar/current-date.php | 17 + OLD/src/templates/calendar/top-bar/nav.php | 31 + OLD/src/templates/calendar/top-bar/today.php | 21 + OLD/src/templates/content-archive.php | 20 + OLD/src/templates/content-single.php | 20 + OLD/src/templates/single.php | 36 + .../variations/blocks/unregister_blocks.js | 9 + OLD/src/variations/index.js | 2 + OLD/src/variations/query-loop-events/block.js | 128 ++ OLD/src/woocommerce-hooks.php | 95 ++ simple-events (1).zip | Bin 0 -> 196822 bytes src/variations/blocks/unregister_blocks.js | 15 +- 139 files changed, 11819 insertions(+), 3 deletions(-) create mode 100644 OLD/README.md create mode 100644 OLD/build/blocks/calendar/block.json create mode 100644 OLD/build/blocks/calendar/index-rtl.css create mode 100644 OLD/build/blocks/calendar/index.asset.php create mode 100644 OLD/build/blocks/calendar/index.css create mode 100644 OLD/build/blocks/calendar/index.js create mode 100644 OLD/build/blocks/calendar/style-index-rtl.css create mode 100644 OLD/build/blocks/calendar/style-index.css create mode 100644 OLD/build/blocks/calendar/view.asset.php create mode 100644 OLD/build/blocks/calendar/view.js create mode 100644 OLD/build/blocks/countdown/block.json create mode 100644 OLD/build/blocks/countdown/index.asset.php create mode 100644 OLD/build/blocks/countdown/index.js create mode 100644 OLD/build/blocks/countdown/style-index-rtl.css create mode 100644 OLD/build/blocks/countdown/style-index.css create mode 100644 OLD/build/blocks/countdown/view.asset.php create mode 100644 OLD/build/blocks/countdown/view.js create mode 100644 OLD/build/blocks/event-info/block.json create mode 100644 OLD/build/blocks/event-info/index-rtl.css create mode 100644 OLD/build/blocks/event-info/index.asset.php create mode 100644 OLD/build/blocks/event-info/index.css create mode 100644 OLD/build/blocks/event-info/index.js create mode 100644 OLD/build/blocks/event-tickets/block.json create mode 100644 OLD/build/blocks/event-tickets/index-rtl.css create mode 100644 OLD/build/blocks/event-tickets/index.asset.php create mode 100644 OLD/build/blocks/event-tickets/index.css create mode 100644 OLD/build/blocks/event-tickets/index.js create mode 100644 OLD/build/blocks/event-tickets/style-index-rtl.css create mode 100644 OLD/build/blocks/event-tickets/style-index.css create mode 100644 OLD/build/blocks/external-link/block.json create mode 100644 OLD/build/blocks/external-link/index-rtl.css create mode 100644 OLD/build/blocks/external-link/index.asset.php create mode 100644 OLD/build/blocks/external-link/index.css create mode 100644 OLD/build/blocks/external-link/index.js create mode 100644 OLD/build/blocks/inner-blocks/block.json create mode 100644 OLD/build/blocks/inner-blocks/index.asset.php create mode 100644 OLD/build/blocks/inner-blocks/index.js create mode 100644 OLD/build/blocks/inner-blocks/style-index-rtl.css create mode 100644 OLD/build/blocks/inner-blocks/style-index.css create mode 100644 OLD/build/blocks/loop-event-info/block.json create mode 100644 OLD/build/blocks/loop-event-info/index-rtl.css create mode 100644 OLD/build/blocks/loop-event-info/index.asset.php create mode 100644 OLD/build/blocks/loop-event-info/index.css create mode 100644 OLD/build/blocks/loop-event-info/index.js create mode 100644 OLD/build/blocks/past-events-notice/block.json create mode 100644 OLD/build/blocks/past-events-notice/index.asset.php create mode 100644 OLD/build/blocks/past-events-notice/index.js create mode 100644 OLD/build/blocks/upcoming-events/block.json create mode 100644 OLD/build/blocks/upcoming-events/index-rtl.css create mode 100644 OLD/build/blocks/upcoming-events/index.asset.php create mode 100644 OLD/build/blocks/upcoming-events/index.css create mode 100644 OLD/build/blocks/upcoming-events/index.js create mode 100644 OLD/build/js/admin.asset.php create mode 100644 OLD/build/js/admin.js create mode 100644 OLD/build/variations/index.asset.php create mode 100644 OLD/build/variations/index.js create mode 100644 OLD/plugin.php create mode 100644 OLD/postcss.config.js create mode 100644 OLD/src/assets/js/admin.js create mode 100644 OLD/src/back-compat.php create mode 100644 OLD/src/blocks/calendar/block.json create mode 100644 OLD/src/blocks/calendar/calendar.js create mode 100644 OLD/src/blocks/calendar/color-panel/index.js create mode 100644 OLD/src/blocks/calendar/editor.scss create mode 100644 OLD/src/blocks/calendar/index.js create mode 100644 OLD/src/blocks/calendar/style.scss create mode 100644 OLD/src/blocks/calendar/view.js create mode 100644 OLD/src/blocks/common.scss create mode 100644 OLD/src/blocks/countdown/block.json create mode 100644 OLD/src/blocks/countdown/index.js create mode 100644 OLD/src/blocks/countdown/style.scss create mode 100644 OLD/src/blocks/countdown/view.js create mode 100644 OLD/src/blocks/event-info/block.json create mode 100644 OLD/src/blocks/event-info/editor-compat.scss create mode 100644 OLD/src/blocks/event-info/editor.scss create mode 100644 OLD/src/blocks/event-info/index.js create mode 100644 OLD/src/blocks/event-tickets/block.json create mode 100644 OLD/src/blocks/event-tickets/draggable/index.js create mode 100644 OLD/src/blocks/event-tickets/editor.scss create mode 100644 OLD/src/blocks/event-tickets/index.js create mode 100644 OLD/src/blocks/event-tickets/search-list-control/index.js create mode 100644 OLD/src/blocks/event-tickets/style.scss create mode 100644 OLD/src/blocks/event-tickets/ticket-data-control/index.js create mode 100644 OLD/src/blocks/external-link/block.json create mode 100644 OLD/src/blocks/external-link/editor.scss create mode 100644 OLD/src/blocks/external-link/index.js create mode 100644 OLD/src/blocks/inner-blocks/block.json create mode 100644 OLD/src/blocks/inner-blocks/index.js create mode 100644 OLD/src/blocks/inner-blocks/style.scss create mode 100644 OLD/src/blocks/loop-event-info/block.json create mode 100644 OLD/src/blocks/loop-event-info/editor.scss create mode 100644 OLD/src/blocks/loop-event-info/index.js create mode 100644 OLD/src/blocks/loop-event-info/index.scss create mode 100644 OLD/src/blocks/past-events-notice/block.json create mode 100644 OLD/src/blocks/past-events-notice/index.js create mode 100644 OLD/src/blocks/upcoming-events/block.json create mode 100644 OLD/src/blocks/upcoming-events/index.js create mode 100644 OLD/src/blocks/upcoming-events/index.scss create mode 100644 OLD/src/calendar-functions.php create mode 100644 OLD/src/classes/class-se-admin.php create mode 100644 OLD/src/classes/class-se-block-variations.php create mode 100644 OLD/src/classes/class-se-blocks.php create mode 100644 OLD/src/classes/class-se-calendar-export.php create mode 100644 OLD/src/classes/class-se-calendar.php create mode 100644 OLD/src/classes/class-se-event-post-type.php create mode 100644 OLD/src/classes/class-se-event-query-dates.php create mode 100644 OLD/src/classes/class-se-rest-ticket-products.php create mode 100644 OLD/src/classes/class-se-settings.php create mode 100644 OLD/src/classes/class-se-template-loader.php create mode 100644 OLD/src/event-functions.php create mode 100644 OLD/src/init.php create mode 100644 OLD/src/rest-api.php create mode 100644 OLD/src/template-functions.php create mode 100644 OLD/src/template-hooks.php create mode 100644 OLD/src/templates/archive.php create mode 100644 OLD/src/templates/calendar/calendar-body.php create mode 100644 OLD/src/templates/calendar/calendar-container.php create mode 100644 OLD/src/templates/calendar/calendar-header.php create mode 100644 OLD/src/templates/calendar/calendar-main.php create mode 100644 OLD/src/templates/calendar/calendar-mobile-events.php create mode 100644 OLD/src/templates/calendar/calendar-top-bar.php create mode 100644 OLD/src/templates/calendar/day/day.php create mode 100644 OLD/src/templates/calendar/day/event.php create mode 100644 OLD/src/templates/calendar/day/events.php create mode 100644 OLD/src/templates/calendar/mobile-events/day.php create mode 100644 OLD/src/templates/calendar/mobile-events/nav.php create mode 100644 OLD/src/templates/calendar/mobile-events/today.php create mode 100644 OLD/src/templates/calendar/top-bar/current-date.php create mode 100644 OLD/src/templates/calendar/top-bar/nav.php create mode 100644 OLD/src/templates/calendar/top-bar/today.php create mode 100644 OLD/src/templates/content-archive.php create mode 100644 OLD/src/templates/content-single.php create mode 100644 OLD/src/templates/single.php create mode 100644 OLD/src/variations/blocks/unregister_blocks.js create mode 100644 OLD/src/variations/index.js create mode 100644 OLD/src/variations/query-loop-events/block.js create mode 100644 OLD/src/woocommerce-hooks.php create mode 100644 simple-events (1).zip diff --git a/OLD/README.md b/OLD/README.md new file mode 100644 index 0000000..156ca3a --- /dev/null +++ b/OLD/README.md @@ -0,0 +1,105 @@ +# Simple Events + +A simple Gutenberg-first event management plugin that integrates with WooCommerce Box Office. + +**If you want to install this plugin**, DON'T DOWNLOAD THIS REPO. You can download the latest stable version from the [releases page](https://github.com/a8cteam51/simple-events/releases) +or just click [here](https://github.com/a8cteam51/simple-events/releases/latest/download/simple-events.zip). + +## Dependencies + +Simple Events uses [Composer](https://getcomposer.org), a dependency manager for PHP. Visit the official Composer [download instructions](https://getcomposer.org/download/) to install Composer. + +Then, run: + +``` +composer install +``` + +## Building + +Run `npm install` to install all the Node.js dependencies. + +Below you will find some information on how to run scripts. + +### `npm start` +- Use to compile and run the block in development mode. +- Watches for any changes and reports back any errors in your code. + +### `npm run build` +- Use to build production code for your block inside `build` folder. +- Runs once and reports back the gzip file sizes of the produced code. + +## Hooks + +### Next & Previous Links + +**This must be enabled in the `settings` before they are shown.** + +> Change the previous link text (defaults to `<< {Event Title}`) +```php +add_filter('se_event_previous_link_text', function( string $link_text, WP_Post $event ) { + return "Previous Event ({$event->post_title})"; +}, 10, 2); +``` + +> Change the next link text (defaults to `{Event Title} >>`) +```php +add_filter('se_event_next_link_text', function( string $link_text, WP_Post $event ) { + return "Next Event ({$event->post_title})"; +}, 10, 2); +``` + +> Change the link text to the calendar if page set in settings, if not set in settings will not show. (defaults to `View Full Calendar`) +```php +add_filter('se_event_calendar_link_text', function( string $link_text ) { + return "View Full Calendar"; +}, 10, 1); +``` + +### Cron Tasks for Event Start Date + +> When the cron task runs to update the event start date to a future date if its passed and future dates exist. + +#### How often to check events. +```php +add_filter('se_event_update_query_dates_interval', function( int $interval ) { + return 'hourly'; // Please use the WP Cron intervals: https://developer.wordpress.org/reference/functions/wp_get_schedules/ +}, 10, 1); +``` + +#### Age of events to check +```php +add_filter('se_event_update_dates_search_range', function( int $age ) { + return 48 * HOUR_IN_SECONDS; // The number of days to check for events that are older than this. +}, 10, 1); +``` + +#### Skip event +It is possible to skip and event from being updated by adding a filter to the event. +```php +add_filter('se_event_update_query_dates_skip', function( bool $skip, intget $event ) { + // Skip the event if it is a specific event. + if ( $event === 1234 ) { + return true; + } + + return $skip; +}, 10, 2); +``` + +#### Post Update +When an event has been updated, the `se_event_updated_query_dates` is fired. +```php +add_action('se_event_updated_query_dates', function( int $event_id ) { + // Do something with the event. +}, 10, 2); +``` + +## Extensions + +### Featured image with Focal Point +Simple plugin to add a focal point control to the featured post image. + +**If you want to use this plugin extension**, you can find it at https://github.com/a8cteam51/bamberg-ua/tree/trunk/mu-plugins/team51-focal-point + +Copy the `team51-focal-point` folder to your `mu-plugins` directory. diff --git a/OLD/build/blocks/calendar/block.json b/OLD/build/blocks/calendar/block.json new file mode 100644 index 0000000..26fd372 --- /dev/null +++ b/OLD/build/blocks/calendar/block.json @@ -0,0 +1,135 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/calendar", + "title": "Simple Events Calendar", + "icon": "calendar", + "category": "simple-events", + "keywords": [ + "event", + "calendar", + "view", + "Simple Events" + ], + "attributes": { + "alignment": { + "type": "string", + "default": "none" + }, + "eventModalAccess": { + "type": "boolean", + "default": false + }, + "modalBgColor": { + "type": "string", + "default": "" + }, + "modalTextColor": { + "type": "string", + "default": "" + }, + "modalIconColor": { + "type": "string", + "default": "" + }, + "showModalTitle": { + "type": "boolean", + "default": false + }, + "showModalExcerpt": { + "type": "boolean", + "default": false + }, + "showModalWhenNoThumbnails": { + "type": "boolean", + "default": false + }, + "hideNeighbourEvents": { + "type": "boolean", + "default": false + }, + "presentDayBg": { + "type": "string", + "default": "" + }, + "presentDayColor": { + "type": "string", + "default": "" + }, + "presentDayBorder": { + "type": "string", + "default": "" + }, + "eventDaysBg": { + "type": "string", + "default": "" + }, + "eventDaysColor": { + "type": "string", + "default": "" + }, + "eventDaysBorder": { + "type": "string", + "default": "" + }, + "pastDaysBg": { + "type": "string", + "default": "" + }, + "pastDaysColor": { + "type": "string", + "default": "" + }, + "pastDaysBorder": { + "type": "string", + "default": "" + }, + "upcomingDaysBg": { + "type": "string", + "default": "" + }, + "upcomingDaysColor": { + "type": "string", + "default": "" + }, + "upcomingDaysBorder": { + "type": "string", + "default": "" + }, + "monthYearColor": { + "type": "string", + "default": "" + }, + "arrowColor": { + "type": "string", + "default": "" + }, + "arrowPosition": { + "type": "string", + "default": "top" + }, + "mobileArrowPosition": { + "type": "string", + "default": "top" + }, + "showDot": { + "type": "boolean", + "default": true + }, + "eventDotColor": { + "type": "string", + "default": "" + } + }, + "supports": { + "multiple": false, + "reusable": false, + "html": false, + "align": true, + "alignment": false + }, + "editorScript": "file:./index.js", + "editorStyle": "file:./index.css", + "style": "file:./style-index.css", + "viewScript": "file:./view.js" +} \ No newline at end of file diff --git a/OLD/build/blocks/calendar/index-rtl.css b/OLD/build/blocks/calendar/index-rtl.css new file mode 100644 index 0000000..72595a2 --- /dev/null +++ b/OLD/build/blocks/calendar/index-rtl.css @@ -0,0 +1 @@ +.block-editor-panel-color-gradient-settings.block-editor-panel-color-gradient-settings{padding:0;border-top:0} diff --git a/OLD/build/blocks/calendar/index.asset.php b/OLD/build/blocks/calendar/index.asset.php new file mode 100644 index 0000000..fefefa2 --- /dev/null +++ b/OLD/build/blocks/calendar/index.asset.php @@ -0,0 +1 @@ + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n', 'wp-server-side-render'), 'version' => '75657bbc7dd0c39e0948'); diff --git a/OLD/build/blocks/calendar/index.css b/OLD/build/blocks/calendar/index.css new file mode 100644 index 0000000..72595a2 --- /dev/null +++ b/OLD/build/blocks/calendar/index.css @@ -0,0 +1 @@ +.block-editor-panel-color-gradient-settings.block-editor-panel-color-gradient-settings{padding:0;border-top:0} diff --git a/OLD/build/blocks/calendar/index.js b/OLD/build/blocks/calendar/index.js new file mode 100644 index 0000000..9ffd587 --- /dev/null +++ b/OLD/build/blocks/calendar/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,o={461:(e,o,t)=>{const l=window.wp.blocks,n=window.wp.serverSideRender;var s=t.n(n);const r=window.wp.components,a=window.wp.blockEditor,i=window.wp.i18n,v=window.ReactJSXRuntime,d=({title:e,bgAttr:o,colorAttr:t,borderAttr:l,attributes:n,setAttributes:s})=>(0,v.jsx)(r.PanelBody,{title:e,initialOpen:!1,children:(0,v.jsx)(a.PanelColorSettings,{colorSettings:[{label:(0,i.__)("Background Color","simple-events"),value:n[o],onChange:e=>s({[o]:e}),clearable:!0},{label:(0,i.__)("Text Color","simple-events"),value:n[t],onChange:e=>s({[t]:e}),clearable:!0},{label:(0,i.__)("Border Color","simple-events"),value:n[l],onChange:e=>s({[l]:e}),clearable:!0}]})});(0,l.registerBlockType)("simple-events/calendar",{edit:({attributes:e,setAttributes:o})=>(0,v.jsxs)(v.Fragment,{children:[(0,v.jsx)(a.BlockControls,{children:(0,v.jsx)(a.AlignmentToolbar,{value:e.alignment,onChange:e=>{o({alignment:void 0===e?"none":e})},alignmentControls:[]})}),(0,v.jsxs)(a.InspectorControls,{children:[(0,v.jsxs)(r.PanelBody,{title:"Event Configuration",initialOpen:!0,children:[(0,v.jsx)(r.ToggleControl,{label:(0,i.__)("Hide Events on Neighbouring Months","simple-events"),help:(0,i.__)("Used to hide events on the previous and next month for a particular month.","simple-events"),checked:e?.hideNeighbourEvents,onChange:e=>o({hideNeighbourEvents:e})}),(0,v.jsx)(r.ToggleControl,{label:(0,i.__)("Show Dot for Events ( Mobile )","simple-events"),help:(0,i.__)("Toggle to show / hide the dot to indicate events for smaller devices.","simple-events"),checked:e?.showDot,onChange:e=>o({showDot:e})}),(0,v.jsx)(a.PanelColorSettings,{colorSettings:[{label:(0,i.__)("Event Dot Color ( Mobile )","simple-events"),value:e.eventDotColor,onChange:e=>o({eventDotColor:e}),clearable:!0}]})]}),(0,v.jsxs)(r.PanelBody,{title:"Event Modal Configuration",initialOpen:!0,children:[(0,v.jsx)(r.ToggleControl,{label:(0,i.__)("Enable Event Modal","simple-events"),help:(0,i.__)("Enables modal for all events. Modals for specific events can be disabled on the event edit page","simple-events"),checked:e?.eventModalAccess,onChange:e=>o({eventModalAccess:e})}),(0,v.jsx)(r.ToggleControl,{label:(0,i.__)("Show Event Title in Modal","simple-events"),help:(0,i.__)("Toggle to show/hide the title of the event in the modal. Applicable to all events.","simple-events"),checked:e?.showModalTitle,onChange:e=>o({showModalTitle:e})}),(0,v.jsx)(r.ToggleControl,{label:(0,i.__)("Show Event Excerpt in Modal","simple-events"),help:(0,i.__)("Toggle to show/hide the excerpt of the event in the modal. Applicable to all events.","simple-events"),checked:e?.showModalExcerpt,onChange:e=>o({showModalExcerpt:e})}),(0,v.jsx)(r.ToggleControl,{label:(0,i.__)("Show Event Modal when no thumbnail is defined","simple-events"),help:(0,i.__)("Toggle to show/hide the modal even if no thumbnail is defined.","simple-events"),checked:e?.showModalWhenNoThumbnails,onChange:e=>o({showModalWhenNoThumbnails:e})}),(0,v.jsx)("h3",{children:(0,i.__)("Color Configuration","simple-events")}),(0,v.jsx)(a.PanelColorSettings,{colorSettings:[{label:(0,i.__)("Background Color","simple-events"),value:e?.modalBgColor,onChange:e=>o({modalBgColor:e}),clearable:!0},{label:(0,i.__)("Text Color","simple-events"),value:e?.modalTextColor,onChange:e=>o({modalTextColor:e}),clearable:!0},{label:(0,i.__)("Icon Color","simple-events"),value:e?.modalIconColor,onChange:e=>o({modalIconColor:e}),clearable:!0}]})]}),(0,v.jsx)(d,{attributes:e,setAttributes:o,title:(0,i.__)("Today's Date","simple-events"),bgAttr:"presentDayBg",colorAttr:"presentDayColor",borderAttr:"presentDayBorder"}),(0,v.jsx)(d,{attributes:e,setAttributes:o,title:(0,i.__)("Days with Events","simple-events"),bgAttr:"eventDaysBg",colorAttr:"eventDaysColor",borderAttr:"eventDaysBorder"}),(0,v.jsx)(d,{attributes:e,setAttributes:o,title:(0,i.__)("Past Dates","simple-events"),bgAttr:"pastDaysBg",colorAttr:"pastDaysColor",borderAttr:"pastDaysBorder"}),(0,v.jsx)(d,{attributes:e,setAttributes:o,title:(0,i.__)("Upcoming Dates","simple-events"),bgAttr:"upcomingDaysBg",colorAttr:"upcomingDaysColor",borderAttr:"upcomingDaysBorder"}),(0,v.jsx)(r.PanelBody,{title:(0,i.__)("Month and Year","simple-events"),initialOpen:!1,children:(0,v.jsx)(a.PanelColorSettings,{colorSettings:[{label:(0,i.__)("Text Color","simple-events"),value:e.monthYearColor,onChange:e=>o({monthYearColor:e}),clearable:!0}]})}),(0,v.jsxs)(r.PanelBody,{title:(0,i.__)("Arrows","simple-events"),initialOpen:!1,children:[(0,v.jsx)(a.PanelColorSettings,{colorSettings:[{label:(0,i.__)("Arrow Color","simple-events"),value:e.arrowColor,onChange:e=>o({arrowColor:e}),clearable:!0}]}),(0,v.jsx)("br",{}),(0,v.jsx)(r.SelectControl,{label:(0,i.__)("Arrow Position","simple-events"),value:e.arrowPosition,onChange:e=>o({arrowPosition:e}),options:[{label:(0,i.__)("Top","simple-events"),value:"top"},{label:(0,i.__)("Bottom","simple-events"),value:"bottom"}]}),(0,v.jsx)(r.SelectControl,{label:(0,i.__)("Arrow Position ( Mobile )","simple-events"),value:e.mobileArrowPosition,onChange:e=>o({mobileArrowPosition:e}),options:[{label:(0,i.__)("Top","simple-events"),value:"top"},{label:(0,i.__)("Bottom","simple-events"),value:"bottom"}]})]})]}),(0,v.jsx)("div",{...(0,a.useBlockProps)(),children:(0,v.jsx)(s(),{block:"simple-events/calendar",attributes:e})})]}),save:()=>null})}},t={};function l(e){var n=t[e];if(void 0!==n)return n.exports;var s=t[e]={exports:{}};return o[e](s,s.exports,l),s.exports}l.m=o,e=[],l.O=(o,t,n,s)=>{if(!t){var r=1/0;for(d=0;d=s)&&Object.keys(l.O).every((e=>l.O[e](t[i])))?t.splice(i--,1):(a=!1,s0&&e[d-1][2]>s;d--)e[d]=e[d-1];e[d]=[t,n,s]},l.n=e=>{var o=e&&e.__esModule?()=>e.default:()=>e;return l.d(o,{a:o}),o},l.d=(e,o)=>{for(var t in o)l.o(o,t)&&!l.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:o[t]})},l.o=(e,o)=>Object.prototype.hasOwnProperty.call(e,o),(()=>{var e={76:0,108:0};l.O.j=o=>0===e[o];var o=(o,t)=>{var n,s,[r,a,i]=t,v=0;if(r.some((o=>0!==e[o]))){for(n in a)l.o(a,n)&&(l.m[n]=a[n]);if(i)var d=i(l)}for(o&&o(t);vl(461)));n=l.O(n)})(); \ No newline at end of file diff --git a/OLD/build/blocks/calendar/style-index-rtl.css b/OLD/build/blocks/calendar/style-index-rtl.css new file mode 100644 index 0000000..c30a3ac --- /dev/null +++ b/OLD/build/blocks/calendar/style-index-rtl.css @@ -0,0 +1 @@ +.simple-events-calendar{margin-right:auto;margin-left:auto;width:100%;min-height:700px}.simple-events-calendar .simple-events-top-bar{position:relative;display:flex;flex-direction:row;gap:20px;align-items:center;width:100%}.simple-events-calendar .simple-events-top-bar nav{display:block;flex:none}.simple-events-calendar .simple-events-top-bar nav ul{display:flex;list-style:none;margin:10px 0;padding:0}.simple-events-calendar .simple-events-top-bar nav ul li{flex:none}.simple-events-calendar .simple-events-top-bar nav ul li:nth-child(2){position:absolute;left:0}.simple-events-calendar .simple-events-top-bar nav ul li a{display:flex}.simple-events-calendar .simple-events-top-bar nav ul li svg{width:25px}.simple-events-calendar .simple-events-top-bar__today-button{font-size:16px}.simple-events-calendar .simple-events-top-bar__month{font-size:24px}.simple-events-calendar .simple-events-calendar-month__header-row{display:flex}.simple-events-calendar .simple-events-calendar-month__header-column{flex:1;display:flex}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__header-column{justify-content:center}}.simple-events-calendar .simple-events-calendar-month__header-column h3{font-size:18px}.simple-events-calendar .simple-events-calendar-month__week{display:flex}.simple-events-calendar .simple-events-calendar-month__day{display:flex;flex-direction:column;min-height:150px;flex:1;border:1px solid #fff;background-clip:padding-box}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__day{align-items:center;min-height:50px;border:none}}.simple-events-calendar .simple-events-calendar-month__day-date-daynum{line-height:1.4;font-size:24px;padding:8px 12px}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__day-date-daynum{line-height:1.2;font-size:18px;padding:4px 8px}}.simple-events-calendar .simple-events-calendar-month__day--today{background-color:rgba(60,120,200,.3)}.simple-events-calendar .simple-events-calendar-month__day--past>time,.simple-events-calendar .simple-events-calendar-month__day--past .simple-events-calendar-month__calendar-event{opacity:.6}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__day--active{background-color:rgba(15,58,184,.8)}}.simple-events-calendar .simple-events-calendar-month__calendar-event{padding:0 12px 0;margin:0 0 16px 0}.simple-events-calendar .simple-events-calendar-month__calendar-event.se-event-hide-start-time time:first-child{display:none}.simple-events-calendar .simple-events-calendar-month__calendar-event.se-event-hide-start-time .simple-events-calendar-month__calendar-event-datetime-separator{display:none}.simple-events-calendar .simple-events-calendar-month__calendar-event.se-event-hide-end-time time:last-child{display:none}.simple-events-calendar .simple-events-calendar-month__calendar-event.se-event-hide-end-time .simple-events-calendar-month__calendar-event-datetime-separator{display:none}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__calendar-event{margin:0 0 24px 0}}.simple-events-calendar .simple-events-calendar-month__calendar-event-datetime{font-size:13px}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__calendar-event-datetime{font-size:18px}}.simple-events-calendar .simple-events-calendar-month__calendar-event-datetime>*{vertical-align:middle}.simple-events-calendar .simple-events-calendar-month__calendar-event-title{font-size:14px;margin:0}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__calendar-event-title{font-size:18px}}.simple-events-calendar .simple-events-calendar-month__calendar-event-title-link{text-decoration:none}.simple-events-calendar .simple-events-calendar-month__calendar-event-title-link:hover{text-decoration:underline}.simple-events-calendar .simple-events-calendar-month__mobile-events-icon{background-color:#fff;height:8px;width:8px;border-radius:50%}.simple-events-calendar .simple-events-calendar-month-mobile-events__mobile-day{display:none}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month-mobile-events__mobile-day--active{display:block}}.simple-events-calendar .simple-events-mobile__nav-list{display:flex;list-style:none;margin:10px 0;padding:0;justify-content:center;align-items:center}.simple-events-calendar .simple-events-mobile__nav-list-item{flex:1;display:flex}.simple-events-calendar .simple-events-mobile__nav-list-item--prev{justify-content:flex-start;width:33.33%}.simple-events-calendar .simple-events-mobile__nav-list-item--today{justify-content:center;font-size:18px;width:33.33%}.simple-events-calendar .simple-events-mobile__nav-list-item--next{justify-content:flex-end;width:33.33%}.simple-events-calendar .simple-events-mobile__nav-list-item a{display:flex}.simple-events-calendar .simple-events-mobile__nav-list-item svg{width:35px}.simple-events-calendar .disabled{opacity:.4}@media(max-width: 768px){.simple-events-calendar .simple-events-hidden-mobile{display:none !important}}@media(min-width: 768px){.simple-events-calendar .simple-events-hidden-desktop{display:none !important}}.simple-events-calendar-month-mobile-events__mobile-day .se-event-modal.hidden{display:none}.simple-events-calendar-month__events{position:relative}.simple-events-calendar-month__events .se-event-modal{position:absolute;z-index:1000;border:1px solid gray;padding:10px;border-radius:5px;width:300px;top:0;background-color:var(--wp--preset--color--primary, #fff);color:var(--wp--preset--color--secondary, #000)}.simple-events-calendar-month__events .se-event-modal.hidden{display:none}.simple-events-calendar-month__events .se-event-modal__image img{width:100%;height:fit-content;max-height:250px;object-fit:contain;border-radius:5px}.simple-events-calendar-month__events .se-event-modal__flex{display:flex;align-items:center;gap:8px}.simple-events-calendar-month__events .se-event-modal__flex:last-of-type{margin-bottom:5px}.simple-events-calendar-month__events .se-event-modal__flex .se-event-modal__date{font-size:12px;margin:10px 0;line-height:1.5}.simple-events-calendar-month__events .se-event-modal__flex ul{list-style:none;padding:0;margin:0}.simple-events-calendar-month__events .se-event-modal__flex .se-event-modal__title{font-size:15px;margin:0}.simple-events-calendar-month__events .se-event-modal__excerpt{margin:5px 8px 0 0;font-size:14px} diff --git a/OLD/build/blocks/calendar/style-index.css b/OLD/build/blocks/calendar/style-index.css new file mode 100644 index 0000000..624f59b --- /dev/null +++ b/OLD/build/blocks/calendar/style-index.css @@ -0,0 +1 @@ +.simple-events-calendar{margin-left:auto;margin-right:auto;width:100%;min-height:700px}.simple-events-calendar .simple-events-top-bar{position:relative;display:flex;flex-direction:row;gap:20px;align-items:center;width:100%}.simple-events-calendar .simple-events-top-bar nav{display:block;flex:none}.simple-events-calendar .simple-events-top-bar nav ul{display:flex;list-style:none;margin:10px 0;padding:0}.simple-events-calendar .simple-events-top-bar nav ul li{flex:none}.simple-events-calendar .simple-events-top-bar nav ul li:nth-child(2){position:absolute;right:0}.simple-events-calendar .simple-events-top-bar nav ul li a{display:flex}.simple-events-calendar .simple-events-top-bar nav ul li svg{width:25px}.simple-events-calendar .simple-events-top-bar__today-button{font-size:16px}.simple-events-calendar .simple-events-top-bar__month{font-size:24px}.simple-events-calendar .simple-events-calendar-month__header-row{display:flex}.simple-events-calendar .simple-events-calendar-month__header-column{flex:1;display:flex}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__header-column{justify-content:center}}.simple-events-calendar .simple-events-calendar-month__header-column h3{font-size:18px}.simple-events-calendar .simple-events-calendar-month__week{display:flex}.simple-events-calendar .simple-events-calendar-month__day{display:flex;flex-direction:column;min-height:150px;flex:1;border:1px solid #fff;background-clip:padding-box}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__day{align-items:center;min-height:50px;border:none}}.simple-events-calendar .simple-events-calendar-month__day-date-daynum{line-height:1.4;font-size:24px;padding:8px 12px}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__day-date-daynum{line-height:1.2;font-size:18px;padding:4px 8px}}.simple-events-calendar .simple-events-calendar-month__day--today{background-color:rgba(60,120,200,.3)}.simple-events-calendar .simple-events-calendar-month__day--past>time,.simple-events-calendar .simple-events-calendar-month__day--past .simple-events-calendar-month__calendar-event{opacity:.6}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__day--active{background-color:rgba(15,58,184,.8)}}.simple-events-calendar .simple-events-calendar-month__calendar-event{padding:0 12px 0;margin:0 0 16px 0}.simple-events-calendar .simple-events-calendar-month__calendar-event.se-event-hide-start-time time:first-child{display:none}.simple-events-calendar .simple-events-calendar-month__calendar-event.se-event-hide-start-time .simple-events-calendar-month__calendar-event-datetime-separator{display:none}.simple-events-calendar .simple-events-calendar-month__calendar-event.se-event-hide-end-time time:last-child{display:none}.simple-events-calendar .simple-events-calendar-month__calendar-event.se-event-hide-end-time .simple-events-calendar-month__calendar-event-datetime-separator{display:none}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__calendar-event{margin:0 0 24px 0}}.simple-events-calendar .simple-events-calendar-month__calendar-event-datetime{font-size:13px}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__calendar-event-datetime{font-size:18px}}.simple-events-calendar .simple-events-calendar-month__calendar-event-datetime>*{vertical-align:middle}.simple-events-calendar .simple-events-calendar-month__calendar-event-title{font-size:14px;margin:0}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month__calendar-event-title{font-size:18px}}.simple-events-calendar .simple-events-calendar-month__calendar-event-title-link{text-decoration:none}.simple-events-calendar .simple-events-calendar-month__calendar-event-title-link:hover{text-decoration:underline}.simple-events-calendar .simple-events-calendar-month__mobile-events-icon{background-color:#fff;height:8px;width:8px;border-radius:50%}.simple-events-calendar .simple-events-calendar-month-mobile-events__mobile-day{display:none}@media(max-width: 768px){.simple-events-calendar .simple-events-calendar-month-mobile-events__mobile-day--active{display:block}}.simple-events-calendar .simple-events-mobile__nav-list{display:flex;list-style:none;margin:10px 0;padding:0;justify-content:center;align-items:center}.simple-events-calendar .simple-events-mobile__nav-list-item{flex:1;display:flex}.simple-events-calendar .simple-events-mobile__nav-list-item--prev{justify-content:flex-start;width:33.33%}.simple-events-calendar .simple-events-mobile__nav-list-item--today{justify-content:center;font-size:18px;width:33.33%}.simple-events-calendar .simple-events-mobile__nav-list-item--next{justify-content:flex-end;width:33.33%}.simple-events-calendar .simple-events-mobile__nav-list-item a{display:flex}.simple-events-calendar .simple-events-mobile__nav-list-item svg{width:35px}.simple-events-calendar .disabled{opacity:.4}@media(max-width: 768px){.simple-events-calendar .simple-events-hidden-mobile{display:none !important}}@media(min-width: 768px){.simple-events-calendar .simple-events-hidden-desktop{display:none !important}}.simple-events-calendar-month-mobile-events__mobile-day .se-event-modal.hidden{display:none}.simple-events-calendar-month__events{position:relative}.simple-events-calendar-month__events .se-event-modal{position:absolute;z-index:1000;border:1px solid gray;padding:10px;border-radius:5px;width:300px;top:0;background-color:var(--wp--preset--color--primary, #fff);color:var(--wp--preset--color--secondary, #000)}.simple-events-calendar-month__events .se-event-modal.hidden{display:none}.simple-events-calendar-month__events .se-event-modal__image img{width:100%;height:fit-content;max-height:250px;object-fit:contain;border-radius:5px}.simple-events-calendar-month__events .se-event-modal__flex{display:flex;align-items:center;gap:8px}.simple-events-calendar-month__events .se-event-modal__flex:last-of-type{margin-bottom:5px}.simple-events-calendar-month__events .se-event-modal__flex .se-event-modal__date{font-size:12px;margin:10px 0;line-height:1.5}.simple-events-calendar-month__events .se-event-modal__flex ul{list-style:none;padding:0;margin:0}.simple-events-calendar-month__events .se-event-modal__flex .se-event-modal__title{font-size:15px;margin:0}.simple-events-calendar-month__events .se-event-modal__excerpt{margin:5px 0 0 8px;font-size:14px} diff --git a/OLD/build/blocks/calendar/view.asset.php b/OLD/build/blocks/calendar/view.asset.php new file mode 100644 index 0000000..627bb64 --- /dev/null +++ b/OLD/build/blocks/calendar/view.asset.php @@ -0,0 +1 @@ + array('wp-api-fetch', 'wp-dom-ready'), 'version' => 'ae1fb5d2b42761475884'); diff --git a/OLD/build/blocks/calendar/view.js b/OLD/build/blocks/calendar/view.js new file mode 100644 index 0000000..6601351 --- /dev/null +++ b/OLD/build/blocks/calendar/view.js @@ -0,0 +1 @@ +(()=>{"use strict";var e={n:t=>{var a=t&&t.__esModule?()=>t.default:()=>t;return e.d(a,{a}),a},d:(t,a)=>{for(var s in a)e.o(a,s)&&!e.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:a[s]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.domReady;var a=e.n(t);const s=window.wp.apiFetch;var n=e.n(s);class i{constructor(){this.DOM={calendars:".simple-events-calendar",desktopElements:".simple-events-hidden-mobile",navigationItems:"simple-events-navigation-item",calendarDay:"simple-events-calendar-day",mobileEventContainer:"simple-events-calendar-month-mobile-events",status:{dayActive:"simple-events-calendar-month__day--active",mobileDayActive:"simple-events-calendar-month-mobile-events__mobile-day--active"},calendarModal:".se-event-modal",calendarModalContainer:".simple-events-calendar-month__day"},this.calendars=document.querySelectorAll(this.DOM.calendars)}init(){this.calendars.length&&this.calendars.forEach((e=>{this.initListeners(e)}))}initListeners(e){this.addNavigationItemsListeners(e),this.addCalendarDayListeners(e),this.handleModalFunctionality()}isMobile(e){const t=e.querySelectorAll(this.DOM.desktopElements);return!(!t.length||"none"!==window.getComputedStyle(t[0],null).display)}addCalendarDayListeners(e){const t=e.querySelectorAll(`[data-js="${this.DOM.calendarDay}"]`);t.length&&t.forEach((t=>{t.addEventListener("click",(t=>{if(!this.isMobile(e))return;t.preventDefault();let a=!1;const s=e.querySelector(`[data-js="${this.DOM.mobileEventContainer}"]`);if(t.currentTarget.classList.contains(this.DOM.status.dayActive)&&(a=!0),s){const n=s.querySelector("#"+t.currentTarget.dataset.mobileControl),i=s.querySelectorAll("."+this.DOM.status.mobileDayActive),l=e.querySelectorAll("."+this.DOM.status.dayActive);n&&(i.length&&i.forEach((e=>{e.classList.remove(this.DOM.status.mobileDayActive)})),l.length&&l.forEach((e=>{e.classList.remove(this.DOM.status.dayActive)})),a||(t.currentTarget.classList.add(this.DOM.status.dayActive),n.classList.add(this.DOM.status.mobileDayActive)))}}))}))}addNavigationItemsListeners(e){const t=e.querySelectorAll(`[data-js="${this.DOM.navigationItems}"]`);t.length&&t.forEach((t=>{t.addEventListener("click",(t=>{if(t.preventDefault(),t.currentTarget.classList.contains("disabled"))return;const a=t.currentTarget.closest(`[data-js="${this.DOM.navigationItems}"]`).dataset.date;this.sendCalendarRequest(a,e)}))}))}sendCalendarRequest(e,t){n()({path:"/simple-events/calendar",method:"POST",data:{date:e,attributes}}).then((e=>{e.html?(t.innerHTML=e.html,this.initListeners(t)):console.log(e)}))}handleHideTimeout(e){return setTimeout((()=>{e.classList.add("hidden")}),150)}handleModalFunctionality(){document.querySelectorAll(this.DOM.calendarModalContainer).forEach(((e,t)=>{let a=null;const s=e.querySelectorAll(".simple-events-calendar-month__calendar-event-title");if(!s||!s.length)return;let n=null;s.forEach((e=>{e.addEventListener("mouseenter",(e=>{const s=e.currentTarget.closest("article");if(a=s.nextElementSibling,!a)return;a.addEventListener("mouseenter",(()=>{clearTimeout(n)})),a.addEventListener("mouseleave",(()=>{n=this.handleHideTimeout(a)})),a.classList.remove("hidden");const i=(t+1)%7;0!==i&&i<4?a.style.left="80px":a.style.right="80px",t+1>22&&(a.style.top="-220px")})),e.addEventListener("mouseleave",(()=>{a&&(n=this.handleHideTimeout(a))}))}))}))}}a()((()=>{(new i).init()}))})(); \ No newline at end of file diff --git a/OLD/build/blocks/countdown/block.json b/OLD/build/blocks/countdown/block.json new file mode 100644 index 0000000..cd1ab2e --- /dev/null +++ b/OLD/build/blocks/countdown/block.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/countdown", + "title": "Countdown", + "description": "Display a countdown to your next upcoming event.", + "icon": "clock", + "category": "simple-events", + "keywords": [ + "countdown", + "event", + "upcoming", + "Simple Events" + ], + "attributes": { + "className": { + "type": "string", + "default": "" + } + }, + "supports": { + "html": false, + "multiple": false + }, + "editorScript": "file:./index.js", + "style": "file:./style-index.css", + "viewScript": "file:./view.js" +} \ No newline at end of file diff --git a/OLD/build/blocks/countdown/index.asset.php b/OLD/build/blocks/countdown/index.asset.php new file mode 100644 index 0000000..41079ea --- /dev/null +++ b/OLD/build/blocks/countdown/index.asset.php @@ -0,0 +1 @@ + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-i18n', 'wp-server-side-render'), 'version' => '43e0661f0b0ac2bb2abe'); diff --git a/OLD/build/blocks/countdown/index.js b/OLD/build/blocks/countdown/index.js new file mode 100644 index 0000000..f1efb4c --- /dev/null +++ b/OLD/build/blocks/countdown/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,r={385:(e,r,t)=>{window.wp.i18n;const n=window.wp.blocks,o=window.wp.serverSideRender;var i=t.n(o);const s=window.wp.blockEditor,l=window.ReactJSXRuntime;(0,n.registerBlockType)("simple-events/countdown",{edit:({attributes:e})=>{const r=()=>{document.getElementById("event-timer")?"function"==typeof simpleEventsCountdownTimer&&simpleEventsCountdownTimer():setTimeout((()=>r()),100)};return r(),(0,l.jsx)("div",{...(0,s.useBlockProps)(),children:(0,l.jsx)(i(),{block:"simple-events/countdown",attributes:e})})},save:()=>null})}},t={};function n(e){var o=t[e];if(void 0!==o)return o.exports;var i=t[e]={exports:{}};return r[e](i,i.exports,n),i.exports}n.m=r,e=[],n.O=(r,t,o,i)=>{if(!t){var s=1/0;for(u=0;u=i)&&Object.keys(n.O).every((e=>n.O[e](t[p])))?t.splice(p--,1):(l=!1,i0&&e[u-1][2]>i;u--)e[u]=e[u-1];e[u]=[t,o,i]},n.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return n.d(r,{a:r}),r},n.d=(e,r)=>{for(var t in r)n.o(r,t)&&!n.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},n.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),(()=>{var e={449:0,797:0};n.O.j=r=>0===e[r];var r=(r,t)=>{var o,i,[s,l,p]=t,a=0;if(s.some((r=>0!==e[r]))){for(o in l)n.o(l,o)&&(n.m[o]=l[o]);if(p)var u=p(n)}for(r&&r(t);an(385)));o=n.O(o)})(); \ No newline at end of file diff --git a/OLD/build/blocks/countdown/style-index-rtl.css b/OLD/build/blocks/countdown/style-index-rtl.css new file mode 100644 index 0000000..9f3076a --- /dev/null +++ b/OLD/build/blocks/countdown/style-index-rtl.css @@ -0,0 +1 @@ +#event-timer{display:flex;justify-content:center;margin:2rem auto;max-width:350px;padding:2rem 0;text-align:center}@media(min-width: 768px){#event-timer{margin:3rem auto;max-width:550px}}@media(min-width: 1024px){#event-timer{max-width:50vw}}#event-timer .event-timer__col{flex:1 1 0} diff --git a/OLD/build/blocks/countdown/style-index.css b/OLD/build/blocks/countdown/style-index.css new file mode 100644 index 0000000..9f3076a --- /dev/null +++ b/OLD/build/blocks/countdown/style-index.css @@ -0,0 +1 @@ +#event-timer{display:flex;justify-content:center;margin:2rem auto;max-width:350px;padding:2rem 0;text-align:center}@media(min-width: 768px){#event-timer{margin:3rem auto;max-width:550px}}@media(min-width: 1024px){#event-timer{max-width:50vw}}#event-timer .event-timer__col{flex:1 1 0} diff --git a/OLD/build/blocks/countdown/view.asset.php b/OLD/build/blocks/countdown/view.asset.php new file mode 100644 index 0000000..623eb64 --- /dev/null +++ b/OLD/build/blocks/countdown/view.asset.php @@ -0,0 +1 @@ + array(), 'version' => '9dfa9d5a72621fe8fdfb'); diff --git a/OLD/build/blocks/countdown/view.js b/OLD/build/blocks/countdown/view.js new file mode 100644 index 0000000..9001a4f --- /dev/null +++ b/OLD/build/blocks/countdown/view.js @@ -0,0 +1 @@ +!function(){const e=document.getElementById("event-timer");if(!e||!e.dataset.eventStartDate)return void(e&&e.remove());const t=+e.dataset.eventStartDate;let n,r,o,i,a;const m=setInterval(l,1e3),c=e.querySelector(".event-timer__time-days"),s=e.querySelector(".event-timer__time-hours"),v=e.querySelector(".event-timer__time-minutes"),u=e.querySelector(".event-timer__time-seconds");function l(){n=(t-Date.now())/1e3|0,n<=0&&(clearInterval(m),n=0),r=n/86400|0,n-=3600*r*24,o=n/3600|0,n-=3600*o,i=n/60|0,a=n%60|0,r=r<10?"0"+r:r,o=o<10?"0"+o:o,i=i<10?"0"+i:i,a=a<10?"0"+a:a,c.textContent=c&&r,s.textContent=s&&o,v.textContent=v&&i,u.textContent=u&&a}l()}(); \ No newline at end of file diff --git a/OLD/build/blocks/event-info/block.json b/OLD/build/blocks/event-info/block.json new file mode 100644 index 0000000..57f644b --- /dev/null +++ b/OLD/build/blocks/event-info/block.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/event-info", + "title": "Event Information", + "icon": "calendar", + "category": "simple-events", + "keywords": [ + "event", + "information", + "Simple Events" + ], + "attributes": { + "eventVenue": { + "type": "string" + }, + "eventLocation": { + "type": "string" + }, + "eventDates": { + "type": "array" + }, + "eventDateStart": { + "type": "string" + }, + "eventDateEnd": { + "type": "string" + }, + "showOnFrontEnd": { + "type": "boolean", + "default": true + }, + "externalLinkLabel": { + "type": "string" + }, + "externalLink": { + "type": "string" + } + }, + "supports": { + "inserter": false, + "multiple": false, + "reusable": false, + "html": false + }, + "editorScript": "file:./index.js", + "editorStyle": "file:./index.css" +} \ No newline at end of file diff --git a/OLD/build/blocks/event-info/index-rtl.css b/OLD/build/blocks/event-info/index-rtl.css new file mode 100644 index 0000000..9b45b31 --- /dev/null +++ b/OLD/build/blocks/event-info/index-rtl.css @@ -0,0 +1 @@ +.wp-block-simple-events-event-info .components-placeholder__fieldset{flex-direction:column}.wp-block-simple-events-event-info .components-base-control{margin:0 0 8px;text-align:right}.wp-block-simple-events-event-info .components-base-control:last-of-type{margin-bottom:0}.wp-block-simple-events-event-info .components-base-control:last-of-type .components-base-control__field{white-space:nowrap}.wp-block-simple-events-event-info .components-base-control:last-of-type .components-checkbox-control__input-container{align-content:center;align-items:center;display:inline-flex;height:33px;position:relative}.wp-block-simple-events-event-info .components-base-control:last-of-type .components-checkbox-control__input-container .components-checkbox-control__input{height:20px;min-width:20px}.wp-block-simple-events-event-info .components-base-control__label{display:block}.se__button-done{align-self:flex-start;margin-top:10px}.se-datetime-popover .components-popover__content{justify-content:center;width:max-content;padding:1em;position:relative}.se-datetime-popover .components-popover__content .components-datetime__date{margin-top:50px}.se-datetime-popover .components-datetime__time{padding-bottom:0}.se-datetime-popover .components-datetime__time fieldset{margin-bottom:0}.se-datetime-popover .components-datetime__time fieldset legend{display:none}.se-datetime-popover .components-datetime__time .components-datetime__time-wrapper .components-datetime__time-field-time{align-items:center;display:flex}.se-datetime-popover .components-datetime__time .components-datetime__time-field-am-pm{white-space:nowrap}.se-datetime-popover__date fieldset:first-child{display:none}.se-datetime-popover__date .components-datetime__time-field-month-select{height:100%}.se-datetime-popover__time .components-datetime__time fieldset+fieldset{margin-top:10px}.se-datetime-popover__time .components-datetime__timezone{display:none}.se-datetime-popover__set-datetime{margin-top:15px;position:absolute;top:100px}.se-datetimegroup-controls-label{display:flex;font-weight:700}.se-datetimegroup-controls-label+div{margin-top:-4px}.se-datetimegroup-container{border-bottom:1px solid #e2e4e7}.se-datetimegroup-controls{display:grid;grid-template-columns:auto auto 70px;grid-column-gap:10px;margin-top:8px;max-width:450px}.se-datetimegroup-controls .components-dropdown{width:100%}.se-datetimegroup-controls .components-base-control:nth-of-type(3){flex:none;align-self:flex-end;margin-bottom:10px;margin-right:auto}.se-datetimegroup-controls .components-base-control:nth-of-type(3) .components-checkbox-control__input-container{margin-left:8px}.se-datetimegroup-controls .components-base-control:nth-of-type(3) label{font-weight:normal;font-size:14px}.se-datetimegroup-controls .se-datetime-control__delete{grid-column-start:4;margin-top:-68px;margin-left:-50px;margin-right:auto;align-self:center}.se-datetimegroup-controls .se-datetime-popover__button{width:100%;justify-content:center;margin-bottom:0;margin-top:0}.se-datetimegroup-controls .is-button.is-default:not(:disabled){border-color:#7e8993;background-color:#fff;color:#32373c}.se-datetime-addmore{display:flex;margin-top:10px;margin-bottom:20px}.se-location-label{max-width:450px}.se-location-label label{font-weight:700}.se-site-timezone-label{flex-direction:column;font-size:12px;color:#757575}.se-event-calendar-export{margin-top:20px}.se-all-day-checkbox .components-flex{align-items:center} diff --git a/OLD/build/blocks/event-info/index.asset.php b/OLD/build/blocks/event-info/index.asset.php new file mode 100644 index 0000000..19e07cb --- /dev/null +++ b/OLD/build/blocks/event-info/index.asset.php @@ -0,0 +1 @@ + array('lodash', 'moment', 'react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-date', 'wp-element', 'wp-i18n', 'wp-server-side-render'), 'version' => '29c2c2c30de5bc53ac53'); diff --git a/OLD/build/blocks/event-info/index.css b/OLD/build/blocks/event-info/index.css new file mode 100644 index 0000000..1d83654 --- /dev/null +++ b/OLD/build/blocks/event-info/index.css @@ -0,0 +1 @@ +.wp-block-simple-events-event-info .components-placeholder__fieldset{flex-direction:column}.wp-block-simple-events-event-info .components-base-control{margin:0 0 8px;text-align:left}.wp-block-simple-events-event-info .components-base-control:last-of-type{margin-bottom:0}.wp-block-simple-events-event-info .components-base-control:last-of-type .components-base-control__field{white-space:nowrap}.wp-block-simple-events-event-info .components-base-control:last-of-type .components-checkbox-control__input-container{align-content:center;align-items:center;display:inline-flex;height:33px;position:relative}.wp-block-simple-events-event-info .components-base-control:last-of-type .components-checkbox-control__input-container .components-checkbox-control__input{height:20px;min-width:20px}.wp-block-simple-events-event-info .components-base-control__label{display:block}.se__button-done{align-self:flex-start;margin-top:10px}.se-datetime-popover .components-popover__content{justify-content:center;width:max-content;padding:1em;position:relative}.se-datetime-popover .components-popover__content .components-datetime__date{margin-top:50px}.se-datetime-popover .components-datetime__time{padding-bottom:0}.se-datetime-popover .components-datetime__time fieldset{margin-bottom:0}.se-datetime-popover .components-datetime__time fieldset legend{display:none}.se-datetime-popover .components-datetime__time .components-datetime__time-wrapper .components-datetime__time-field-time{align-items:center;display:flex}.se-datetime-popover .components-datetime__time .components-datetime__time-field-am-pm{white-space:nowrap}.se-datetime-popover__date fieldset:first-child{display:none}.se-datetime-popover__date .components-datetime__time-field-month-select{height:100%}.se-datetime-popover__time .components-datetime__time fieldset+fieldset{margin-top:10px}.se-datetime-popover__time .components-datetime__timezone{display:none}.se-datetime-popover__set-datetime{margin-top:15px;position:absolute;top:100px}.se-datetimegroup-controls-label{display:flex;font-weight:700}.se-datetimegroup-controls-label+div{margin-top:-4px}.se-datetimegroup-container{border-bottom:1px solid #e2e4e7}.se-datetimegroup-controls{display:grid;grid-template-columns:auto auto 70px;grid-column-gap:10px;margin-top:8px;max-width:450px}.se-datetimegroup-controls .components-dropdown{width:100%}.se-datetimegroup-controls .components-base-control:nth-of-type(3){flex:none;align-self:flex-end;margin-bottom:10px;margin-left:auto}.se-datetimegroup-controls .components-base-control:nth-of-type(3) .components-checkbox-control__input-container{margin-right:8px}.se-datetimegroup-controls .components-base-control:nth-of-type(3) label{font-weight:normal;font-size:14px}.se-datetimegroup-controls .se-datetime-control__delete{grid-column-start:4;margin-top:-68px;margin-right:-50px;margin-left:auto;align-self:center}.se-datetimegroup-controls .se-datetime-popover__button{width:100%;justify-content:center;margin-bottom:0;margin-top:0}.se-datetimegroup-controls .is-button.is-default:not(:disabled){border-color:#7e8993;background-color:#fff;color:#32373c}.se-datetime-addmore{display:flex;margin-top:10px;margin-bottom:20px}.se-location-label{max-width:450px}.se-location-label label{font-weight:700}.se-site-timezone-label{flex-direction:column;font-size:12px;color:#757575}.se-event-calendar-export{margin-top:20px}.se-all-day-checkbox .components-flex{align-items:center} diff --git a/OLD/build/blocks/event-info/index.js b/OLD/build/blocks/event-info/index.js new file mode 100644 index 0000000..e437968 --- /dev/null +++ b/OLD/build/blocks/event-info/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e={n:t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return e.d(n,{a:n}),n},d:(t,n)=>{for(var s in n)e.o(n,s)&&!e.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:n[s]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.moment;var n=e.n(t);const s=window.lodash,a=window.wp.i18n,l=window.wp.blocks,i=window.wp.element,o=window.wp.components,_=window.wp.serverSideRender;var d=e.n(_);const r=window.wp.date,m=window.wp.blockEditor,c=window.wp.compose,v=window.wp.coreData,p=window.ReactJSXRuntime,u=(0,r.getSettings)(),h=Number(u.timezone.offset),x=u.timezone.string;let g=x;""===x&&(g="UTC"+(h>=0?"+":"")+h);const f=n().tz.names().map((e=>({label:e,value:e})));f.unshift({label:(0,a.__)("Same as site","simple-events"),value:""});const w=e=>{const t=n()().utcOffset(h),a=e.filter((e=>n().unix(e.datetime_end).utcOffset(h).isAfter(t)));if(0===a.length&&e.length>0){const t=e.map((e=>n().unix(e.datetime_start).utcOffset(h))),s=e.map((e=>n().unix(e.datetime_end).utcOffset(h)));return{datetime_start:n().max(t).unix().toString(),datetime_end:n().max(s).unix().toString()}}let l=null,i=null;return a.forEach((e=>{const s=n().unix(e.datetime_start).utcOffset(h),a=n().unix(e.datetime_end).utcOffset(h);if(a.isBefore(t))return;(s.isAfter(t)&&a.isAfter(t)||s.isBefore(t)&&a.isAfter(t))&&((e,n)=>{(!l||e.isBefore(l)||l.isAfter(e)&&l.isBefore(t))&&(l=e),i&&!n.isAfter(i)||(i=n)})(s,a)})),l||(l=n().unix((0,s.head)(a).datetime_start).utcOffset(h)),i||(i=n().unix((0,s.last)(a).datetime_end).utcOffset(h)),{datetime_start:l.unix().toString(),datetime_end:i.unix().toString()}};(0,l.registerBlockType)("simple-events/event-info",{edit:e=>{var t,l,_,r,C,b,j,k,y,T,E;const{attributes:D,setAttributes:B}=e,{editMode:S,showOnFrontEnd:O}=D,[N,z]=(0,v.useEntityProp)("postType","se-event","meta");let M=N?.se_event_timezone;""===M&&(M=x);const P=(e,t=null)=>{if(null===t&&(t=M),""===t)return h;const s=n().tz.zone(t),a=s.untils.findIndex((function(t){return t/1e3>e}));return-1*s.offsets[a]},A=(e,t=!1)=>{const s=n().unix(e).utcOffset(P(e));return t?s.format("YYYY-MM-DD HH:mm"):s},Y=e=>String(n()(e).utcOffset(P(n()(e).unix()),!0).utc().unix()),F=()=>(0,p.jsx)(m.BlockControls,{children:(0,p.jsx)(o.Toolbar,{controls:[{icon:"edit",title:(0,a.__)("Edit","simple-events"),onClick:()=>B({editMode:!S}),isActive:S},{icon:O?"visibility":"hidden",title:(0,a.__)("Show on Front-End?","simple-events"),onClick:()=>{B({showOnFrontEnd:!O}),z({se_event_show_on_frontend:!O})},isActive:O}]})}),L=(0,c.withState)({tempEventDate:null,tempEventTime:null})((({eventDateTime:e,removeDate:t,multiDay:l,tempEventDate:_,tempEventTime:d,setState:r})=>{const m=A(e.datetime_start,!0),c=A(e.datetime_end,!0),v=u.formats.datetime,h=/a(?!\\)/i.test(v.toLowerCase().replace(/\\\\/g,"").split("").reverse().join("")),x=t=>{if(!_&&!d)return;const a=Y(((e,t)=>{const s=n()(t);return n()(e).set({hour:s.get("hour"),minute:s.get("minute")})})(_||(t?m:c),d||(t?m:c))),l=(0,s.clone)(e);t?(l.datetime_start=a,parseInt(l.datetime_start)>=parseInt(l.datetime_end)&&(l.datetime_end=String(parseInt(l.datetime_start)+3600))):(l.datetime_end=a,parseInt(l.datetime_start)>=parseInt(l.datetime_end)&&(l.datetime_start=String(parseInt(l.datetime_end)-3600))),r({tempEventDate:null,tempEventTime:null}),((e,t)=>{if(!(0,s.isEqual)(e,t)){const n=(0,s.sortBy)(N?.se_event_dates.map((n=>n===e?t:n)),"datetime_start");z({...N,se_event_dates:n,se_event_date_start:w(n).datetime_start,se_event_date_end:w(n).datetime_end})}})(e,l)},g=(e,t)=>{const s=n()(e).format("YYYY-MM-DD")===n()(t).format("YYYY-MM-DD");r(s?{tempEventTime:t}:{tempEventDate:t})};return(0,p.jsx)("div",{className:"se-datetimegroup-container",children:(0,p.jsxs)("div",{className:"se-datetimegroup-controls",children:[(0,p.jsx)(o.BaseControl,{label:(0,a.__)("Start Date/Time","simple-events"),children:(0,p.jsx)(o.Dropdown,{contentClassName:"se-datetime-popover se-datetime-popover__time",popoverProps:{placement:"bottom"},renderToggle:({isOpen:t,onToggle:n})=>(0,p.jsx)(o.Button,{className:"se-datetime-popover__button",variant:"secondary",onClick:()=>{n()},"aria-expanded":t,children:e.all_day?wp.date.format("F j, Y",m):wp.date.format(v,m)}),renderContent:()=>(0,p.jsxs)(i.Fragment,{children:[(0,p.jsx)(o.DateTimePicker,{currentDate:m,is12Hour:h,onChange:e=>g(m,e),__nextRemoveHelpButton:!0,__nextRemoveResetButton:!0}),(0,p.jsx)(o.Button,{className:"se-datetime-popover__set-datetime",onClick:()=>x(!0),variant:"secondary",children:(0,a.__)("Set time","simple-events")})]})})}),(0,p.jsx)(o.BaseControl,{label:(0,a.__)("End Date/Time","simple-events"),children:(0,p.jsx)(o.Dropdown,{contentClassName:"se-datetime-popover se-datetime-popover__time",popoverProps:{placement:"bottom"},renderToggle:({isOpen:t,onToggle:n})=>(0,p.jsx)(o.Button,{className:"se-datetime-popover__button",variant:"secondary",onClick:()=>{n()},"aria-expanded":t,disabled:e.all_day,children:e.all_day?"--:--":wp.date.format(v,c)}),renderContent:()=>(0,p.jsxs)(i.Fragment,{children:[(0,p.jsx)(o.DateTimePicker,{currentDate:c,is12Hour:h,onChange:e=>g(c,e),__nextRemoveHelpButton:!0,__nextRemoveResetButton:!0}),(0,p.jsx)(o.Button,{className:"se-datetime-popover__set-datetime",onClick:()=>x(!1),variant:"secondary",text:(0,a.__)("Set time","simple-events")})]})})}),(0,p.jsx)(o.BaseControl,{children:(0,p.jsx)(o.CheckboxControl,{label:(0,a.__)("All day","simple-events"),className:"se-all-day-checkbox",checked:e.all_day,onChange:()=>{const t=(0,s.clone)(e);t.all_day=!e.all_day,t.datetime_start=A(t.datetime_start),t.datetime_end=A(t.datetime_end),t.all_day?(t.datetime_start.startOf("date"),t.datetime_end.endOf("date")):(t.datetime_start.hour(9).minute(0),t.datetime_end.hour(10).minute(0)),t.datetime_start=Y(t.datetime_start),t.datetime_end=Y(t.datetime_end);const n=(0,s.sortBy)(N?.se_event_dates.map((n=>n===e?t:n)),"datetime_start");z({...N,se_event_dates:n,se_event_date_start:w(n).datetime_start,se_event_date_end:w(n).datetime_end})}})}),l&&(0,p.jsx)("div",{className:"se-datetime-control__delete",children:(0,p.jsx)(o.Button,{isDestructive:!0,icon:"no-alt",label:(0,a.__)("Remove date","simple-events"),onClick:()=>t(e)})})]})})})),R=({dates:e})=>{const t=()=>{const t=e&&0!==e.length?e:[];let a=n()().utcOffset(h);a.hour(9),a.minute(0),a.second(0);let l=a.clone();l.hour(10),t.length&&(a=A((0,s.last)(t).datetime_start),l=A((0,s.last)(t).datetime_end)),a.add(1,"days"),l.add(1,"days");const i=(0,s.sortBy)([...t,{datetime_start:wp.date.date("U",a),datetime_end:wp.date.date("U",l),all_day:!1}],"datetime_start");z({...N,se_event_dates:i,se_event_date_start:w(i).datetime_start,se_event_date_end:w(i).datetime_end})},l=t=>{if(!e.length)return;const n=(0,s.pull)(e,t);z({...N,se_event_dates:n,se_event_date_start:w(n).datetime_start,se_event_date_end:w(n).datetime_end})};e&&0!==e.length||t();const _=[];return(0,s.sortBy)(e,"datetime_start").forEach(((t,n)=>{_.push((0,p.jsx)(L,{eventDateTime:t,removeDate:l,multiDay:e.length>1},n))})),(0,p.jsxs)(i.Fragment,{children:[(0,p.jsx)("span",{className:"se-datetimegroup-controls-label",children:(0,a.__)("Date & Time","simple-events")}),_,(0,p.jsx)("div",{className:"se-datetime-addmore",children:(0,p.jsx)(o.Button,{isLink:!0,onClick:()=>t(),children:(0,a.__)("+ Add another date","simple-events")})})]})};return 0!==N?.se_event_location.length||N?.se_event_dates&&N?.se_event_dates?.length||B({editMode:!0}),S?(0,p.jsxs)("div",{...(0,m.useBlockProps)(),children:[F(),(0,p.jsxs)(o.Placeholder,{label:(0,a.__)("Event Information","simple-events"),icon:"calendar",isColumnLayout:!0,className:e.className,children:[(0,p.jsx)(R,{dates:N?.se_event_dates}),(0,p.jsx)(o.TextControl,{className:"se-location-label",label:(0,a.__)("Venue","simple-events"),value:N?.se_event_venue,onChange:e=>z({...N,se_event_venue:e}),type:"text"}),(0,p.jsx)(o.TextControl,{className:"se-location-label",label:(0,a.__)("Location","simple-events"),value:N?.se_event_location,onChange:e=>{z({...N,se_event_location:e})},type:"text"}),(0,p.jsx)(o.TextControl,{className:"se-location-label",label:(0,a.__)("External Link","simple-events"),value:N?.se_event_external_link,onChange:e=>z({...N,se_event_external_link:e}),type:"url"}),N?.se_event_external_link&&(0,p.jsxs)(p.Fragment,{children:[(0,p.jsx)(o.TextControl,{className:"se-location-label",label:(0,a.__)("External Link Label","simple-events"),value:N?.se_event_external_link_label,onChange:e=>z({...N,se_event_external_link_label:e}),type:"text"}),(0,p.jsx)(o.CheckboxControl,{label:(0,a.__)("Open external link from calendar","simple-events"),checked:null!==(t=N?.se_open_external_link)&&void 0!==t&&t,onChange:e=>{z({...N,se_open_external_link:e})}})]}),(0,p.jsx)(o.Button,{className:"se__button-done",variant:"primary",onClick:()=>{B({editMode:!1})},text:(0,a.__)("Done","simple-events")})]}),(0,p.jsxs)(m.InspectorControls,{children:[(0,p.jsxs)(o.PanelBody,{title:(0,a.__)("Settings","simple-events"),children:[(0,p.jsxs)(o.PanelRow,{className:"se-site-timezone-label",children:[(0,a.__)("Site TimeZone","simple-events"),":"," ",(0,p.jsx)("strong",{children:g})," ",(0,p.jsxs)("a",{target:"_blank",href:ajaxurl.replace("admin-ajax.php","options-general.php#timezone_string"),rel:"noreferrer",children:["(",(0,a.__)("Change","simple-events"),")"]})]}),(0,p.jsx)(o.ComboboxControl,{className:"se-timezone-label",label:(0,a.__)("Time Zone","simple-events"),help:(0,a.__)("Events default to the site's time zone as configured in the WordPress settings. If this event is happening in a different region, manually set the time zone here.","simple-events"),value:null!==(l=N?.se_event_timezone)&&void 0!==l?l:x,options:f,onChange:e=>{var t;const a=(0,s.clone)(null!==(t=N?.se_event_dates)&&void 0!==t?t:[]);e=Boolean(e)?e:"",M=e,""===e&&(M=x),a.forEach((e=>{["datetime_start","datetime_end"].forEach((t=>{const s=n().unix(e[t]).utcOffset(P(e[t],N?.se_event_timezone)),a=""!==M?P(e[t],M):h;e[t]=String(s.utcOffset(a,!0).utc().unix())}))})),z({...N,se_event_dates:a,se_event_date_start:w(a).datetime_start,se_event_date_end:w(a).datetime_end,se_event_timezone:e})}}),(0,p.jsx)(o.ToggleControl,{label:(0,a.__)("Display Time Zone in Front-end","simple-events"),checked:null!==(_=N?.se_event_display_timezone)&&void 0!==_&&_,onChange:e=>z({...N,se_event_display_timezone:e})}),(0,p.jsx)(o.ToggleControl,{label:(0,a.__)("Group event dates with matching times","simple-events"),checked:null!==(r=N?.se_event_display_grouped)&&void 0!==r&&r,onChange:e=>z({...N,se_event_display_grouped:e})}),(0,p.jsx)(o.ToggleControl,{label:(0,a.__)("Hide Start Time","simple-events"),help:(0,a.__)("Hides the Start Time on the Front-end"),checked:null!==(C=N?.se_event_hide_start_time)&&void 0!==C&&C,onChange:e=>z({...N,se_event_hide_start_time:e})}),(0,p.jsx)(o.ToggleControl,{label:(0,a.__)("Hide End Timer","simple-events"),help:(0,a.__)("Hides the End Time on the Front-end"),checked:null!==(b=N?.se_event_hide_end_time)&&void 0!==b&&b,onChange:e=>z({...N,se_event_hide_end_time:e})}),(0,p.jsx)(o.ToggleControl,{label:(0,a.__)('Show "Add to calendar" links',"simple-events"),help:(0,a.__)('Shows the "Add to calendar" links on the Front-end',"simple-events"),checked:null!==(j=N?.se_event_add_calendar_links)&&void 0!==j&&j,onChange:e=>z({...N,se_event_add_calendar_links:e})}),(0,p.jsx)(o.ToggleControl,{label:(0,a.__)("Open event in new window","simple-events"),help:(0,a.__)("Open the event in new window from calender","simple-events"),checked:null!==(k=N?.se_event_open_in_new_window)&&void 0!==k&&k,onChange:e=>z({...N,se_event_open_in_new_window:e})})]}),(0,p.jsxs)(o.PanelBody,{title:(0,a.__)("Calendar Modal Configuration","simple-events"),children:[(0,p.jsx)(o.ToggleControl,{label:(0,a.__)("Enable Event Modal","simple-events"),help:(0,a.__)("Enable modal for this event.","simple-events"),checked:null===(y=N?.se_event_modal_access)||void 0===y||y,onChange:e=>z({...N,se_event_modal_access:e})}),(0,p.jsx)(o.ToggleControl,{label:(0,a.__)("Show Event Title in Modal","simple-events"),help:(0,a.__)("Toggle to show/hide the title of the event in the modal.","simple-events"),checked:null===(T=N?.se_show_modal_title)||void 0===T||T,onChange:e=>z({...N,se_show_modal_title:e})}),(0,p.jsx)(o.ToggleControl,{label:(0,a.__)("Show Event Excerpt in Modal","simple-events"),help:(0,a.__)("Toggle to show/hide the excerpt of the event in the modal.","simple-events"),checked:null===(E=N?.se_show_modal_excerpt)||void 0===E||E,onChange:e=>z({...N,se_show_modal_excerpt:e})})]})]})]}):(0,p.jsxs)("div",{...(0,m.useBlockProps)(),children:[F(),(0,p.jsx)(o.Disabled,{children:(0,p.jsx)(d(),{block:"simple-events/event-info",attributes:{eventVenue:N?.se_event_venue,eventLocation:N?.se_event_location,eventDates:N?.se_event_dates,eventTimezone:N?.se_event_timezone,externalLink:N?.se_event_external_link,externalLinkLabel:N?.se_event_external_link_label,addCalendarLinks:N?.se_event_add_calendar_links}})})]})},save:()=>null})})(); \ No newline at end of file diff --git a/OLD/build/blocks/event-tickets/block.json b/OLD/build/blocks/event-tickets/block.json new file mode 100644 index 0000000..24edcce --- /dev/null +++ b/OLD/build/blocks/event-tickets/block.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/event-tickets", + "title": "Event Tickets", + "icon": "tickets-alt", + "category": "simple-events", + "keywords": [ + "event", + "tickets", + "Simple Events" + ], + "attributes": { + "selected": { + "type": "array" + } + }, + "supports": { + "inserter": true, + "multiple": false, + "reusable": false, + "html": false + }, + "editorScript": "file:./index.js", + "editorStyle": "file:./index.css", + "style": "file:./style-index.css" +} \ No newline at end of file diff --git a/OLD/build/blocks/event-tickets/index-rtl.css b/OLD/build/blocks/event-tickets/index-rtl.css new file mode 100644 index 0000000..949a68e --- /dev/null +++ b/OLD/build/blocks/event-tickets/index-rtl.css @@ -0,0 +1 @@ +.wp-block-simple-events-event-tickets .components-placeholder{min-height:0}.wp-block-simple-events-event-tickets .simple-events-tickets+.components-button,.wp-block-simple-events-event-tickets .se-selected-tickets+.components-button,.wp-block-simple-events-event-tickets .se-new-ticket+.components-button{margin:16px auto 0}.wp-block-simple-events-event-tickets .se-selected-tickets_list{padding-right:20px}.wp-block-simple-events-event-tickets .woocommerce-search-list{padding-bottom:0}.wp-block-simple-events-event-tickets .woocommerce-tag .woocommerce-tag__remove.components-icon-button,.wp-block-simple-events-event-tickets .woocommerce-search-list__list .woocommerce-search-list__item{height:auto}.wp-block-simple-events-event-tickets .se-mode-button-container{display:flex;width:100%}.wp-block-simple-events-event-tickets .se-mode-button-container .components-button.is-pressed,.wp-block-simple-events-event-tickets .se-mode-button-container .components-button.is-pressed:hover{background:#ddd;color:var(--wp-admin-theme-color)}.wp-block-simple-events-event-tickets .woocommerce-search-list__search{border-top:none;margin-top:0;padding:0}.wp-block-simple-events-event-tickets .woocommerce-search-list__list.is-not-found{align-items:center;display:flex;justify-content:center}.wp-block-simple-events-event-tickets .components-button .woocommerce-tag__remove{height:40px;padding:6px 12px;position:absolute;left:-48px;top:0}.wp-block-simple-events-event-tickets .components-panel__body-title span[aria-hidden=true] svg{display:none}.wp-block-simple-events-event-tickets .dashicons-edit,.wp-block-simple-events-event-tickets svg.edit{color:var(--wp-admin-theme-color);fill:currentColor;position:absolute;left:16px;top:50%;transform:translateY(-50%);transition:color .1s ease-in-out}.wp-block-simple-events-event-tickets .dashicons-edit{left:0}.wp-block-simple-events-event-tickets .components-panel__body.is-opened{border-bottom:none;padding-top:0}.wp-block-simple-events-event-tickets .components-panel__body.is-opened .components-panel__body-title{height:0;margin:0}.wp-block-simple-events-event-tickets .components-panel__body.is-opened .components-panel__body-title button:focus{box-shadow:none}.wp-block-simple-events-event-tickets .components-panel__body.is-opened .components-panel__body-title span,.wp-block-simple-events-event-tickets .components-panel__body.is-opened .components-panel__body-title .edit{display:none}.wp-block-simple-events-event-tickets .components-panel__body.is-opened .se-ticket-data{margin-top:9px}.wp-block-simple-events-event-tickets .components-disabled{opacity:.5}.wp-block-simple-events-event-tickets .components-disabled svg{color:#000}.wp-block-simple-events-event-tickets .se-selected-tickets+.se-mode-button-container,.wp-block-simple-events-event-tickets .se-selected-tickets+.simple-events-tickets{margin-top:50px}.wp-block-simple-events-event-tickets .se-ticket-data-container{width:calc(100% - 32px);padding-left:0}.wp-block-simple-events-event-tickets .se-new-ticket{margin:-1px 20px 0 0;width:calc(100% - 52px)}.wp-block-simple-events-event-tickets .woocommerce-search-list__list .woocommerce-search-list__item:hover{background:var(--wp-admin-theme-color);color:#fff}.wp-block-simple-events-event-tickets .woocommerce-search-list__list .woocommerce-search-list__item .woocommerce-search-list__item-state{display:none}.se-ticket-data{position:relative}.se-ticket-data .components-spinner{float:none;right:0;margin:0 auto;position:absolute;left:0;top:50%;transform:translateY(-50%)}.se-ticket-data_inner{align-items:center;display:grid;grid-column-gap:10px;grid-row-gap:8px;grid-template-columns:155px 155px 1fr;margin-bottom:20px;width:100%}.se-ticket-data_name{grid-column:1/-1}.se-ticket-data .se-ticket-data_stock-help{align-items:center;align-self:flex-end;display:flex;margin-bottom:4px}.se-ticket-data .se-ticket-data_stock-help .components-button{margin:0;padding:12px 6px}.se-ticket-data .se-help{cursor:help;height:40px}.se-ticket-data .se-help svg{margin:10px 0}.se-ticket-data_sale-price{align-self:start}.se-ticket-data_sale-price .components-base-control__label{width:100%}.se-ticket-data .se-ticket-data_sale-schedule p,.se-ticket-data .se-ticket-data_field-labels p{margin:0 0 8px}.se-ticket-data .se-ticket-data_sale-schedule .components-dropdown{width:100%}.se-ticket-data .se-ticket-data_sale-schedule .components-button{border:1px solid #757575;border-radius:2px;height:auto;margin-bottom:8px;padding:6px 8px;width:100%}.se-ticket-data .se-ticket-data_sale-schedule .se-ticket-data_datetime-placeholder{color:rgba(0,0,0,.5)}.se-ticket-data .se-ticket-data_sale-schedule .se-ticket-data_datetime-placeholder:active,.se-ticket-data .se-ticket-data_sale-schedule .se-ticket-data_datetime-placeholder:focus,.se-ticket-data .se-ticket-data_sale-schedule .se-ticket-data_datetime-placeholder:hover{color:rgba(0,0,0,.5)}.se-ticket-data .se-ticket-data_sale-help{align-items:center;display:flex;margin-bottom:17px}.se-ticket-data .se-ticket-data_sale-help .components-button{margin:0;padding:12px 6px}.se-ticket-data_additional-fields{grid-column:1/-1}.editor-styles-wrapper .se-ticket-data_additional-fields>p{margin:8px 0}.se-ticket-data_field-labels{display:grid;grid-column-gap:10px;grid-template-columns:155px 155px}.se-ticket-data_additional-field{align-items:center;display:grid;grid-column-gap:10px;grid-template-columns:22px 155px 155px 1fr 44px;margin:0 -32px 8px 0}.se-ticket-data_additional-field .components-base-control .components-base-control__field{margin-bottom:0}.se-ticket-data .disabled *{cursor:default}.se-ticket-data .se-ticket-data_additional-field-remove{margin:0}.se-ticket-data_additional-field-options{grid-column:2/2;margin-top:8px}.se-ticket-data .components-base-control .components-base-control__help{margin-bottom:0}.se-ticket-data .components-disabled .components-base-control__help{opacity:.5}.se-draggable-item_dragging{opacity:.5}#editor .se-draggable-item_dragging-clone{background:#fff;pointer-events:none;position:fixed;z-index:1000000000}body:not(.is-dragging-components-draggable) .se-draggable-item_handle{cursor:move;display:flex}.se-selected-tickets{width:100%}.se-selected-tickets_header{align-items:center;display:flex;justify-content:space-between}.se-selected-tickets_header strong{line-height:1;padding:14px 0}.se-selected-tickets .components-button{padding:12px 12px}.se-selected-tickets .components-button span:last-of-type{overflow:hidden;padding-left:34px;text-overflow:ellipsis;white-space:nowrap}.editor-styles-wrapper .se-selected-tickets_list>p{margin:9px 0}.se-selected-tickets_list>.components-spinner{display:block;float:none;margin:5px auto}.se-selected-tickets_list,.se-selected-tickets .se-selected-ticket{position:relative}.se-selected-tickets .se-selected-ticket{margin-top:-1px}.se-selected-tickets .se-selected-ticket>.se-draggable-item_handle{display:flex;right:-32px;padding:12px 6px;position:absolute;top:0}.se-selected-tickets .se-selected-ticket.se-is-open>.se-draggable-item_handle{display:none;pointer-events:none} diff --git a/OLD/build/blocks/event-tickets/index.asset.php b/OLD/build/blocks/event-tickets/index.asset.php new file mode 100644 index 0000000..e76c3f2 --- /dev/null +++ b/OLD/build/blocks/event-tickets/index.asset.php @@ -0,0 +1 @@ + array('lodash', 'react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-date', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-url'), 'version' => 'c1d197a7de185a506cca'); diff --git a/OLD/build/blocks/event-tickets/index.css b/OLD/build/blocks/event-tickets/index.css new file mode 100644 index 0000000..93a452e --- /dev/null +++ b/OLD/build/blocks/event-tickets/index.css @@ -0,0 +1 @@ +.wp-block-simple-events-event-tickets .components-placeholder{min-height:0}.wp-block-simple-events-event-tickets .simple-events-tickets+.components-button,.wp-block-simple-events-event-tickets .se-selected-tickets+.components-button,.wp-block-simple-events-event-tickets .se-new-ticket+.components-button{margin:16px auto 0}.wp-block-simple-events-event-tickets .se-selected-tickets_list{padding-left:20px}.wp-block-simple-events-event-tickets .woocommerce-search-list{padding-bottom:0}.wp-block-simple-events-event-tickets .woocommerce-tag .woocommerce-tag__remove.components-icon-button,.wp-block-simple-events-event-tickets .woocommerce-search-list__list .woocommerce-search-list__item{height:auto}.wp-block-simple-events-event-tickets .se-mode-button-container{display:flex;width:100%}.wp-block-simple-events-event-tickets .se-mode-button-container .components-button.is-pressed,.wp-block-simple-events-event-tickets .se-mode-button-container .components-button.is-pressed:hover{background:#ddd;color:var(--wp-admin-theme-color)}.wp-block-simple-events-event-tickets .woocommerce-search-list__search{border-top:none;margin-top:0;padding:0}.wp-block-simple-events-event-tickets .woocommerce-search-list__list.is-not-found{align-items:center;display:flex;justify-content:center}.wp-block-simple-events-event-tickets .components-button .woocommerce-tag__remove{height:40px;padding:6px 12px;position:absolute;right:-48px;top:0}.wp-block-simple-events-event-tickets .components-panel__body-title span[aria-hidden=true] svg{display:none}.wp-block-simple-events-event-tickets .dashicons-edit,.wp-block-simple-events-event-tickets svg.edit{color:var(--wp-admin-theme-color);fill:currentColor;position:absolute;right:16px;top:50%;transform:translateY(-50%);transition:color .1s ease-in-out}.wp-block-simple-events-event-tickets .dashicons-edit{right:0}.wp-block-simple-events-event-tickets .components-panel__body.is-opened{border-bottom:none;padding-top:0}.wp-block-simple-events-event-tickets .components-panel__body.is-opened .components-panel__body-title{height:0;margin:0}.wp-block-simple-events-event-tickets .components-panel__body.is-opened .components-panel__body-title button:focus{box-shadow:none}.wp-block-simple-events-event-tickets .components-panel__body.is-opened .components-panel__body-title span,.wp-block-simple-events-event-tickets .components-panel__body.is-opened .components-panel__body-title .edit{display:none}.wp-block-simple-events-event-tickets .components-panel__body.is-opened .se-ticket-data{margin-top:9px}.wp-block-simple-events-event-tickets .components-disabled{opacity:.5}.wp-block-simple-events-event-tickets .components-disabled svg{color:#000}.wp-block-simple-events-event-tickets .se-selected-tickets+.se-mode-button-container,.wp-block-simple-events-event-tickets .se-selected-tickets+.simple-events-tickets{margin-top:50px}.wp-block-simple-events-event-tickets .se-ticket-data-container{width:calc(100% - 32px);padding-right:0}.wp-block-simple-events-event-tickets .se-new-ticket{margin:-1px 0 0 20px;width:calc(100% - 52px)}.wp-block-simple-events-event-tickets .woocommerce-search-list__list .woocommerce-search-list__item:hover{background:var(--wp-admin-theme-color);color:#fff}.wp-block-simple-events-event-tickets .woocommerce-search-list__list .woocommerce-search-list__item .woocommerce-search-list__item-state{display:none}.se-ticket-data{position:relative}.se-ticket-data .components-spinner{float:none;left:0;margin:0 auto;position:absolute;right:0;top:50%;transform:translateY(-50%)}.se-ticket-data_inner{align-items:center;display:grid;grid-column-gap:10px;grid-row-gap:8px;grid-template-columns:155px 155px 1fr;margin-bottom:20px;width:100%}.se-ticket-data_name{grid-column:1/-1}.se-ticket-data .se-ticket-data_stock-help{align-items:center;align-self:flex-end;display:flex;margin-bottom:4px}.se-ticket-data .se-ticket-data_stock-help .components-button{margin:0;padding:12px 6px}.se-ticket-data .se-help{cursor:help;height:40px}.se-ticket-data .se-help svg{margin:10px 0}.se-ticket-data_sale-price{align-self:start}.se-ticket-data_sale-price .components-base-control__label{width:100%}.se-ticket-data .se-ticket-data_sale-schedule p,.se-ticket-data .se-ticket-data_field-labels p{margin:0 0 8px}.se-ticket-data .se-ticket-data_sale-schedule .components-dropdown{width:100%}.se-ticket-data .se-ticket-data_sale-schedule .components-button{border:1px solid #757575;border-radius:2px;height:auto;margin-bottom:8px;padding:6px 8px;width:100%}.se-ticket-data .se-ticket-data_sale-schedule .se-ticket-data_datetime-placeholder{color:rgba(0,0,0,.5)}.se-ticket-data .se-ticket-data_sale-schedule .se-ticket-data_datetime-placeholder:active,.se-ticket-data .se-ticket-data_sale-schedule .se-ticket-data_datetime-placeholder:focus,.se-ticket-data .se-ticket-data_sale-schedule .se-ticket-data_datetime-placeholder:hover{color:rgba(0,0,0,.5)}.se-ticket-data .se-ticket-data_sale-help{align-items:center;display:flex;margin-bottom:17px}.se-ticket-data .se-ticket-data_sale-help .components-button{margin:0;padding:12px 6px}.se-ticket-data_additional-fields{grid-column:1/-1}.editor-styles-wrapper .se-ticket-data_additional-fields>p{margin:8px 0}.se-ticket-data_field-labels{display:grid;grid-column-gap:10px;grid-template-columns:155px 155px}.se-ticket-data_additional-field{align-items:center;display:grid;grid-column-gap:10px;grid-template-columns:22px 155px 155px 1fr 44px;margin:0 0 8px -32px}.se-ticket-data_additional-field .components-base-control .components-base-control__field{margin-bottom:0}.se-ticket-data .disabled *{cursor:default}.se-ticket-data .se-ticket-data_additional-field-remove{margin:0}.se-ticket-data_additional-field-options{grid-column:2/2;margin-top:8px}.se-ticket-data .components-base-control .components-base-control__help{margin-bottom:0}.se-ticket-data .components-disabled .components-base-control__help{opacity:.5}.se-draggable-item_dragging{opacity:.5}#editor .se-draggable-item_dragging-clone{background:#fff;pointer-events:none;position:fixed;z-index:1000000000}body:not(.is-dragging-components-draggable) .se-draggable-item_handle{cursor:move;display:flex}.se-selected-tickets{width:100%}.se-selected-tickets_header{align-items:center;display:flex;justify-content:space-between}.se-selected-tickets_header strong{line-height:1;padding:14px 0}.se-selected-tickets .components-button{padding:12px 12px}.se-selected-tickets .components-button span:last-of-type{overflow:hidden;padding-right:34px;text-overflow:ellipsis;white-space:nowrap}.editor-styles-wrapper .se-selected-tickets_list>p{margin:9px 0}.se-selected-tickets_list>.components-spinner{display:block;float:none;margin:5px auto}.se-selected-tickets_list,.se-selected-tickets .se-selected-ticket{position:relative}.se-selected-tickets .se-selected-ticket{margin-top:-1px}.se-selected-tickets .se-selected-ticket>.se-draggable-item_handle{display:flex;left:-32px;padding:12px 6px;position:absolute;top:0}.se-selected-tickets .se-selected-ticket.se-is-open>.se-draggable-item_handle{display:none;pointer-events:none} diff --git a/OLD/build/blocks/event-tickets/index.js b/OLD/build/blocks/event-tickets/index.js new file mode 100644 index 0000000..97f44ef --- /dev/null +++ b/OLD/build/blocks/event-tickets/index.js @@ -0,0 +1 @@ +(()=>{var e,t={131:(e,t,s)=>{"use strict";const n=window.wp.element,i=window.lodash;var a=s(556),o=s.n(a);const r=({countLabel:e,className:t,depth:s=0,controlId:a="",item:o,isSelected:r,isSingle:l,onSelect:c,search:d="",...p})=>{const m=!(0,i.isNil)(e)||!(0,i.isNil)(o.count),u=[t,"woocommerce-search-list__item"];u.push(`depth-${s}`),l&&u.push("is-radio-button"),m&&u.push("has-count");const h=o.breadcrumbs&&o.breadcrumbs.length,g=p.name||`search-list-item-${a}`,_=`${g}-${o.id}`;return(0,n.createElement)("label",{htmlFor:_,className:u.join(" ")},l?(0,n.createElement)("input",{type:"radio",id:_,name:g,value:o.value,onChange:c(o),checked:r,className:"woocommerce-search-list__item-input",...p}):(0,n.createElement)("input",{type:"checkbox",id:_,name:g,value:o.value,onChange:c(o),checked:r,className:"woocommerce-search-list__item-input",...p}),(0,n.createElement)("span",{className:"woocommerce-search-list__item-label"},h?(0,n.createElement)("span",{className:"woocommerce-search-list__item-prefix"},1===(v=o.breadcrumbs).length?(0,i.first)(v):2===v.length?(0,i.first)(v)+" › "+(0,i.last)(v):(0,i.first)(v)+" … "+(0,i.last)(v)):null,(0,n.createElement)("span",{className:"woocommerce-search-list__item-name"},function(e,t){if(!t)return e;const s=new RegExp((0,i.escapeRegExp)(t),"ig");return e.split(s).map(((e,s)=>0===s?e:(0,n.createElement)(n.Fragment,{key:s},(0,n.createElement)("strong",null,t),e)))}(o.name,d))),!!m&&(0,n.createElement)("span",{className:"woocommerce-search-list__item-count"},e||o.count));var v};r.propTypes={className:o().string,countLabel:o().node,controlId:o().node,depth:o().number,item:o().object,name:o().string,isSelected:o().bool,isSingle:o().bool,onSelect:o().func,search:o().string};const l=r,c=window.wp.i18n,d=window.wp.components,p=window.wp.compose,m=window.ReactJSXRuntime,u={clear:(0,c.__)("Clear all selected tickets","simple-events"),list:(0,c.__)("Ticket Products","simple-events"),resultsList:(0,c.__)("Results","simple-events"),noItems:(0,c.__)("Your store doesn't have any ticket products.","simple-events"),noResults:(0,c.__)("No results for %s","simple-events"),search:(0,c.__)("Search for a ticket product:","simple-events"),updated:(0,c.__)("Ticket products search results updated.","simple-events")};class h extends n.Component{constructor(){super(...arguments),this.onSelect=this.onSelect.bind(this),this.renderList=this.renderList.bind(this)}componentDidUpdate(e){const{onSearch:t,search:s}=this.props;s!==e.search&&"function"==typeof t&&t(s)}onSelect(e){const{onChange:t,selected:s}=this.props;return()=>{t([...s,e])}}getFilteredList(e,t){if(!t)return e;const s=new RegExp((0,i.escapeRegExp)(t),"i");return this.props.debouncedSpeak(u.updated),e.map((e=>!!s.test(e.name)&&e)).filter(Boolean)}renderList(e,t=0){const{search:s}=this.props;return e?e.map((e=>(0,m.jsx)(l,{depth:t,isSingle:!1,item:e,onSelect:this.onSelect,search:s}))):null}renderListSection(){const{isLoading:e,search:t}=this.props;if(e)return(0,m.jsx)("div",{className:"woocommerce-search-list__list is-loading",children:(0,m.jsx)(d.Spinner,{})});const s=this.getFilteredList(this.props.list,t);return s.length?(0,m.jsx)(d.MenuGroup,{label:t?u.resultsList:u.list,className:"woocommerce-search-list__list",children:this.renderList(s)}):(0,m.jsxs)("div",{className:"woocommerce-search-list__list is-not-found",children:[(0,m.jsx)(d.Icon,{className:"woocommerce-search-list__not-found-icon",role:"img","aria-hidden":"true",focusable:"false",icon:"warning"}),(0,m.jsx)("span",{className:"woocommerce-search-list__not-found-text",children:t?(0,c.sprintf)(u.noResults,t):u.noItems})]})}render(){const{className:e="",search:t,setState:s}=this.props;return(0,m.jsxs)("div",{className:`woocommerce-search-list ${e}`,children:[(0,m.jsx)("div",{className:"woocommerce-search-list__search",children:(0,m.jsx)(d.TextControl,{label:u.search,type:"search",value:t,onChange:e=>s({search:e})})}),this.renderListSection()]})}}const g=(0,p.compose)([(0,p.withState)({search:""}),d.withSpokenMessages])(h),_=e=>{const t=(0,n.useRef)(),{startDrag:s}=(0,p.__experimentalUseDragging)({onDragStart:e=>{const s=t.current,n=e.target.closest(".se-draggable-item").cloneNode(!0);n.classList.add("se-draggable-item_dragging-clone"),n.style.top=`${s.getBoundingClientRect().top}px`,n.style.width=`${s.offsetWidth}px`,s.classList.add("se-draggable-item_dragging"),s.parentElement.appendChild(n),document.body.classList.add("is-dragging-components-draggable")},onDragMove:e=>{e.preventDefault();const s=e.target.closest(".se-draggable-item"),n=document.querySelector(".se-draggable-item_dragging-clone"),i=e.clientY,a=n.parentElement.getBoundingClientRect();!s||ia.bottom||(s.after(t.current),n.style.top=i-n.clientHeight/2+"px")},onDragEnd:()=>{t.current.classList.remove("se-draggable-item_dragging"),document.querySelector(".se-draggable-item_dragging-clone").remove(),document.body.classList.remove("is-dragging-components-draggable");const s=[...t.current.parentElement.children].map((e=>Number(e.dataset.index)));e.onChange(s)}}),{className:i=""}=e;return(0,m.jsxs)("div",{className:`se-draggable-item ${i}`,"data-index":e.index,ref:t,children:[(0,m.jsx)("div",{className:"se-draggable-item_handle",onMouseDown:s,children:(0,m.jsx)(d.Icon,{icon:(0,m.jsx)("svg",{width:"18",height:"18",xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 18 18",role:"img","aria-hidden":"true",focusable:"false",children:(0,m.jsx)("path",{d:"M13,8c0.6,0,1-0.4,1-1s-0.4-1-1-1s-1,0.4-1,1S12.4,8,13,8z M5,6C4.4,6,4,6.4,4,7s0.4,1,1,1s1-0.4,1-1S5.6,6,5,6z M5,10 c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S5.6,10,5,10z M13,10c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S13.6,10,13,10z M9,6 C8.4,6,8,6.4,8,7s0.4,1,1,1s1-0.4,1-1S9.6,6,9,6z M9,10c-0.6,0-1,0.4-1,1s0.4,1,1,1s1-0.4,1-1S9.6,10,9,10z"})})})}),e.children]})},v=window.wp.apiFetch;var f=s.n(v);const x=window.wp.htmlEntities,b=window.wp.date,j=s(503),k=window.seSettings.BOTicketFieldTypes||[],w=()=>{const e=Object.entries(k).map((([e,t])=>({value:e,label:t})));return e.unshift({value:"",label:(0,c.__)("Type","simple-events")}),e},y=(0,m.jsx)(d.SVG,{width:"20",height:"20",viewBox:"0 0 20 20",focusable:"false",role:"img",xmlns:"http://www.w3.org/2000/svg",children:(0,m.jsx)(d.Path,{d:"M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm5.657 6.586H4.343v2.828h11.314V8.586z"})}),C=(0,p.withState)({dataLoaded:!1,loading:!1,name:"",price:"",saleData:!1,saleDateFrom:"",saleDateTo:"",salePrice:"",stock:"",additionalFields:[{label:(0,c.__)("First Name","simple-events"),type:"first_name",required:!0},{label:(0,c.__)("Last Name","simple-events"),type:"last_name",required:!0},{label:(0,c.__)("Email Address","simple-events"),type:"email",required:!0}]})((({dataLoaded:e,editingProduct:t,index:s,loading:a,name:o,price:r,saleData:l,saleDateFrom:u,saleDateTo:h,salePrice:g,stock:v,additionalFields:k,setState:C,attributes:S,setAttributes:T,title:N,onRemove:F,onReorder:B,onSave:M})=>{t&&!e&&(C({loading:!0,dataLoaded:!0}),f()({path:`/wc/v2/products/${t}`}).then((e=>{const t=Object.values(e.meta_data.find((e=>"_ticket_fields"===e.key)).value);C({name:e.name,price:e.regular_price,saleData:!!e.date_on_sale_from,saleDateFrom:e.date_on_sale_from,saleDateTo:e.date_on_sale_to,salePrice:e.sale_price,stock:e.stock_quantity,additionalFields:t,loading:!1})})));const L=(e,t,s)=>{(0,i.isEqual)(t,s)||("From"===e&&C({saleDateFrom:s}),"To"===e&&C({saleDateTo:s}))},O=(0,p.withState)({tempDate:""})((({label:e,value:t,tempDate:s,setState:n})=>{const i=(0,b.getSettings)(),a=s||t,o=/a(?!\\)/i.test(i.formats.time.toLowerCase().replace(/\\\\/g,"").split("").reverse().join(""));return(0,m.jsx)(d.Dropdown,{contentClassName:"se-datetime-popover se-datetime-popover__date",onToggle:()=>{s&&(L(e,t,s),n({tempDate:void 0}))},position:"bottom center",renderContent:()=>(0,m.jsx)(d.TimePicker,{currentTime:a,is12Hour:o,onChange:e=>n({tempDate:e})}),renderToggle:({isOpen:s,onToggle:n})=>(0,m.jsx)(d.Button,{className:t?"":"se-ticket-data_datetime-placeholder",onClick:n,"aria-expanded":s,children:t?(0,b.date)("Y-m-d",a):`${e}…`})})})),D=e=>{const t=k;t.splice(e,1),C({additionalFields:t})},E=(0,p.withState)({fields:[]})((({fields:e,setState:t,fieldset:s,index:n,onChange:i})=>{const a=["first_name","last_name","email"].includes(s.type);return(0,m.jsxs)(_,{className:"se-ticket-data_additional-field",index:n,onChange:e=>i(e.map((e=>k[e]))),children:[(0,m.jsx)(d.TextControl,{autoComplete:"off",disabled:a,label:(0,c.__)("Field label","simple-events"),hideLabelFromVision:!0,placeholder:(0,c.__)("Field label","simple-events"),value:s.label,onChange:i=>{const a=e;a[n]=Object.assign(s,{label:i}),t({fields:a})},onBlur:()=>t({additionalFields:e})}),(0,m.jsx)(d.SelectControl,{disabled:a,label:(0,c.__)("Field type","simple-events"),hideLabelFromVision:!0,value:s.type,options:w(),onChange:e=>{const i=k;i[n]=Object.assign(s,{type:e}),t({additionalFields:i})}}),(0,m.jsx)(d.CheckboxControl,{className:a?"disabled":"",checked:s.required,disabled:a,label:(0,c.__)("Required","simple-events"),onChange:e=>{const i=k;i[n]=Object.assign(s,{required:e}),t({additionalFields:i})}}),!a&&(0,m.jsx)(d.Button,{className:"se-ticket-data_additional-field-remove",label:sprintf((0,c.__)("Remove field","simple-events")),onClick:()=>D(n),children:y}),["select","radio","checkbox"].includes(s.type)&&(0,m.jsx)(d.TextareaControl,{className:"se-ticket-data_additional-field-options",label:(0,c.__)("Options","simple-events"),hideLabelFromVision:!0,help:(0,c.__)("Comma-separated list of available options","simple-events"),value:s.options,onChange:i=>{const a=e;a[n]=Object.assign(s,{options:i}),t({fields:a})},onBlur:()=>t({additionalFields:e})})]})})),P=(0,m.jsxs)(n.Fragment,{children:[(0,m.jsxs)("div",{className:"se-ticket-data_inner",children:[(0,m.jsx)(d.TextControl,{autoComplete:"off",className:"se-ticket-data_name",label:(0,c.__)("Name","simple-events"),value:(0,x.decodeEntities)(o),onChange:e=>C({name:e})}),(0,m.jsx)(d.TextControl,{autoComplete:"off",className:"se-ticket-data_price",label:(0,c.__)("Price","simple-events"),type:"number",min:"0",value:r,onChange:e=>C({price:e})}),(0,m.jsx)(d.TextControl,{autoComplete:"off",className:"se-ticket-data_stock",label:(0,c.__)("Stock","simple-events"),type:"number",min:"0",value:v,onChange:e=>C({stock:e})}),(0,m.jsxs)("div",{className:"se-ticket-data_stock-help",children:[(0,m.jsx)(d.Tooltip,{text:(0,c.__)('If less than 1, ticket will appear as "Sold Out".',"simple-events"),children:(0,m.jsx)("div",{className:"se-help",children:(0,m.jsx)(d.Dashicon,{icon:"editor-help",size:20})})}),!l&&(0,m.jsx)(d.Button,{isLink:!0,onClick:()=>C({saleData:!0}),children:(0,c.__)("+ Add sale price","simple-events")})]}),l&&(0,m.jsxs)(n.Fragment,{children:[(0,m.jsx)(d.TextControl,{autoComplete:"off",className:"se-ticket-data_sale-price",label:(0,c.__)("Sale price","simple-events"),type:"number",min:"0",value:g,onChange:e=>C({salePrice:e})}),(0,m.jsxs)("div",{className:"se-ticket-data_sale-schedule",children:[(0,m.jsx)("p",{children:(0,c.__)("Sale dates")}),(0,m.jsx)(O,{label:(0,c.__)("From","simple-events"),value:u}),(0,m.jsx)(O,{label:(0,c.__)("To","simple-events"),value:h})]}),(0,m.jsxs)("div",{className:"se-ticket-data_sale-help",children:[(0,m.jsx)(d.Tooltip,{text:(0,c.__)('The sale will start at 00:00:00 of "From" date and end at 23:59:59 of "To" date.',"simple-events"),children:(0,m.jsx)("div",{className:"se-help",children:(0,m.jsx)(d.Dashicon,{icon:"editor-help",size:20})})}),(0,m.jsx)(d.Button,{isLink:!0,onClick:()=>C({saleData:!1,saleDateFrom:"",saleDateTo:""}),children:(0,c.__)("Cancel","simple-events")})]})]}),(0,m.jsxs)("div",{className:"se-ticket-data_additional-fields",children:[(0,m.jsx)("p",{children:(0,m.jsx)("strong",{children:(0,c.__)("Ticket Fields","simple-events")})}),(0,m.jsxs)("div",{className:"se-ticket-data_fields",children:[(0,m.jsxs)("div",{className:"se-ticket-data_field-labels",children:[(0,m.jsx)("p",{children:(0,c.__)("Label","simple-events")}),(0,m.jsx)("p",{children:(0,c.__)("Type","simple-events")})]}),k.map(((e,t)=>(0,m.jsx)(E,{fieldset:e,index:t,onChange:e=>C({additionalFields:e}),additionalFields:k})))]}),(0,m.jsx)(d.Button,{isLink:!0,onClick:()=>(()=>{const e=k,t=(0,i.concat)(...e,{label:"",type:"",required:!1});C({additionalFields:t})})(),children:(0,c.__)("+ Add Field","simple-events")})]})]}),(0,m.jsx)(d.Button,{isPrimary:!0,onClick:()=>{C({loading:!0}),(async()=>{let e="/wc/v2/products";const s={name:o,regular_price:r,sale_price:g,stock_quantity:v,meta_data:[]};g&&l&&u&&h&&(s.date_on_sale_from=`${(0,b.date)("Y-m-d",u)}T00:00:00`,s.date_on_sale_to=`${(0,b.date)("Y-m-d",h)}T23:59:59`);const n={};return k.forEach((({label:e,type:t,required:s,options:i=""})=>{if(""!==t){const a=j(e+t);n[a]={label:e,type:t,required:s,options:i,autofill:"none",email_contact:"yes",email_gravatar:"yes"}}})),0!==Object.keys(n).length&&s.meta_data.push({key:"_ticket_fields",value:n}),t||(s.virtual=!0,s.meta_data.push({key:"_ticket",value:"yes"}),v&&(s.manage_stock=!0)),t&&(e+=`/${t}`),await f()({path:e,method:t?"PUT":"POST",data:s})})().then((e=>{if(!t){const t=S.selected||[];t.push(e.id),M(t)}C({loading:!1}),S.editMode&&(document.querySelector(`.se-selected-ticket[data-index="${S.editMode}"]`).querySelector("h2 button").click(),T({editMode:null}))}))},children:(0,c.__)(t?"Update Ticket":"Create ticket","simple-events")}),(0,m.jsx)(d.Button,{isLink:!0,onClick:e=>{S.editMode?e.target.closest(".se-ticket-data-container").querySelector("h2 button").click():T({addMode:!1})},children:(0,c.__)("Cancel","simple-events")})]}),R=(0,m.jsx)("div",{className:"se-ticket-data",children:a?(0,m.jsxs)(n.Fragment,{children:[(0,m.jsx)(d.Disabled,{children:P}),(0,m.jsx)(d.Spinner,{})]}):P}),A=(0,m.jsxs)(n.Fragment,{children:[t?(0,m.jsxs)(n.Fragment,{children:[(0,m.jsx)("span",{className:"screen-reader-text",children:(0,c.__)("Edit ","simple-events")}),(0,m.jsx)("span",{"aria-hidden":"true",children:(0,x.decodeEntities)(N)})]}):(0,m.jsx)("span",{className:"screen-reader-text",children:(0,c.__)("Create new ticket","simple-events")}),(0,m.jsxs)(d.SVG,{className:"edit",width:"20",height:"20",viewBox:"0 0 20 20",focusable:"false",role:"img",xmlns:"http://www.w3.org/2000/svg",children:[(0,m.jsx)(d.Path,{d:"M3.012 15.92l1.212-4.36L14.834.92l3.178 3.134-10.56 10.634z"}),(0,m.jsx)(d.Path,{d:"M1.988 18.276v1.453h8v-1.453z"})]}),(0,m.jsx)(d.Button,{className:"woocommerce-tag__remove",onClick:e=>{S.editMode&&s===S.editMode?T({editMode:null}):e.stopPropagation(),F()},label:sprintf((0,c.__)("Remove %s","simple-events"),o),children:y})]}),q=(0,m.jsx)(n.Fragment,{children:t?(0,m.jsx)(_,{className:S.editMode&&s===S.editMode?"se-selected-ticket se-is-open":"se-selected-ticket",index:s,onChange:B,children:(0,m.jsx)(d.PanelBody,{className:"se-ticket-data-container",initialOpen:!1,onToggle:()=>{if(S.editMode)T({editMode:null});else{C({dataLoaded:!1}),T({editMode:t});const e=document.activeElement.closest(".se-ticket-data-container"),s=()=>{const t=e.querySelector(".se-ticket-data_name input");t?t.focus():setTimeout(s,10)};s()}T({searchMode:!1})},title:A,children:R})}):(0,m.jsx)(d.PanelBody,{className:"se-ticket-data-container se-new-ticket",initialOpen:!0,title:A,children:R})});return(0,m.jsx)(n.Fragment,{children:S.editMode&&t!==S.editMode||S.addMode&&t?(0,m.jsx)(d.Disabled,{children:q}):q})})),S=window.wp.blocks,T=window.wp.url,N=window.wp.blockEditor,F=window.seSettings.productCount||50,B=window.seSettings.isLargeCatalog||!1,M=window.seSettings.isWCActive||!1,L=window.seSettings.isBOActive||!1,O=()=>{const e=[];return M||e.push("WooCommerce"),L||e.push("WooCommerce Box Office"),e.length?(0,m.jsx)("p",{children:(0,c.sprintf)((0,c.__)("%s must be installed and active to use this block.","simple-events"),e.join((0,c.__)(" and ","simple-events")))}):null},D=(0,p.withState)({loading:!0,selected:[],products:[],search:""})((e=>{var t;const{setState:s,setAttributes:a,attributes:o,loading:r,selected:l,products:p,search:u}=e,h=null!==(t=o.selected)&&void 0!==t?t:[],_=h.length;_&&!l.length&&s({selected:h}),o.newTicketAdded&&(s({loading:!0}),a({newTicketAdded:!1})),r&&(async({selected:e=[],search:t=""})=>{const s=["product","product_variation"];let n=0,a=[],o=null;for(;nf()({path:e}))));return(0,i.uniqBy)((0,i.flatten)(r),"id").map((e=>({id:parseInt(e.id,10),name:e.name})))})({savedSelected:h,search:u}).then((e=>{s({products:e,loading:!1})})).catch((()=>{s({products:[],loading:!1})}));const v=(0,i.debounce)((e=>{s({loading:!0,search:e})}),400),x=e=>{s({selected:e}),a({selected:e})},b=(e=p)=>l.map((t=>e.find((e=>e.id===t)))),j=(0,m.jsxs)(n.Fragment,{children:[(0,m.jsx)(g,{className:"simple-events-tickets",isLoading:r,list:l?p.filter((({id:e})=>!l.includes(e)&&!isNaN(e))):p,selected:l?p.filter((({id:e})=>l.includes(e))):[],onChange:e=>{let t=l;e.length>l.length?t.push(e.pop().id):t=b(e).filter(Boolean).map((({id:e})=>e)),x(t)},onSearch:B?v:null}),(0,m.jsx)(d.Button,{isPrimary:!0,onClick:()=>a({searchMode:!1}),children:(0,c.__)("Done adding existing tickets","simple-events")})]}),k=(0,m.jsxs)("div",{className:"se-selected-tickets",children:[(0,m.jsx)("div",{className:"se-selected-tickets_header",children:!r&&1<_?(0,m.jsx)(d.Button,{isLink:!0,isDestructive:!0,onClick:()=>x([]),"aria-label":(0,c.__)("Clear all selected tickets","simple-events"),children:(0,c.__)("Clear all","simple-events")}):null}),(0,m.jsx)("div",{className:"se-selected-tickets_list",children:_&&(0,m.jsx)(n.Fragment,{children:r||o.newTicketAdded?(0,m.jsx)(d.Spinner,{}):b().map(((t,s)=>(0,m.jsx)(C,{...e,editingProduct:t.id,index:t.id,onRemove:()=>{const e=l;e.splice(s,1),x(e)},onReorder:e=>{a({selected:e})},title:t.name})))})})]});return(0,m.jsxs)(n.Fragment,{children:[_?k:(0,m.jsx)("p",{children:(0,c.__)("No tickets have been added to this event.","simple-events")}),o.searchMode&&j]})}));(0,S.registerBlockType)("simple-events/event-tickets",{edit:e=>{const{attributes:t,setAttributes:s}=e,{addMode:i,editMode:a,searchMode:o,selected:r}=t;return(0,m.jsx)("div",{...(0,N.useBlockProps)(),children:(0,m.jsx)(d.Placeholder,{icon:"tickets-alt",label:(0,c.__)("Event Tickets","simple-events"),children:M&&L?(0,m.jsxs)(n.Fragment,{children:[(0,m.jsx)(D,{...e}),i&&(0,m.jsx)(C,{...e,onRemove:()=>s({addMode:!1}),onSave:e=>s({selected:e,newTicketAdded:!0,addMode:!1})}),!i&&!a&&!o&&(0,m.jsxs)("div",{className:"se-mode-button-container",children:[(0,m.jsx)(d.Button,{isSecondary:!0,onClick:()=>s({addMode:!0}),children:(0,c.__)("Create new ticket","simple-events")}),(0,m.jsx)(d.Button,{isSecondary:!0,onClick:()=>s({searchMode:!0}),children:(0,c.__)("Add existing tickets","simple-events")})]})]}):O()})})},save:()=>null})},151:e=>{var t={utf8:{stringToBytes:function(e){return t.bin.stringToBytes(unescape(encodeURIComponent(e)))},bytesToString:function(e){return decodeURIComponent(escape(t.bin.bytesToString(e)))}},bin:{stringToBytes:function(e){for(var t=[],s=0;s{function t(e){return!!e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}e.exports=function(e){return null!=e&&(t(e)||function(e){return"function"==typeof e.readFloatLE&&"function"==typeof e.slice&&t(e.slice(0,0))}(e)||!!e._isBuffer)}},503:(e,t,s)=>{var n,i,a,o,r;n=s(939),i=s(151).utf8,a=s(206),o=s(151).bin,(r=function(e,t){e.constructor==String?e=t&&"binary"===t.encoding?o.stringToBytes(e):i.stringToBytes(e):a(e)?e=Array.prototype.slice.call(e,0):Array.isArray(e)||e.constructor===Uint8Array||(e=e.toString());for(var s=n.bytesToWords(e),l=8*e.length,c=1732584193,d=-271733879,p=-1732584194,m=271733878,u=0;u>>24)|4278255360&(s[u]<<24|s[u]>>>8);s[l>>>5]|=128<>>9<<4)]=l;var h=r._ff,g=r._gg,_=r._hh,v=r._ii;for(u=0;u>>0,d=d+x>>>0,p=p+b>>>0,m=m+j>>>0}return n.endian([c,d,p,m])})._ff=function(e,t,s,n,i,a,o){var r=e+(t&s|~t&n)+(i>>>0)+o;return(r<>>32-a)+t},r._gg=function(e,t,s,n,i,a,o){var r=e+(t&n|s&~n)+(i>>>0)+o;return(r<>>32-a)+t},r._hh=function(e,t,s,n,i,a,o){var r=e+(t^s^n)+(i>>>0)+o;return(r<>>32-a)+t},r._ii=function(e,t,s,n,i,a,o){var r=e+(s^(t|~n))+(i>>>0)+o;return(r<>>32-a)+t},r._blocksize=16,r._digestsize=16,e.exports=function(e,t){if(null==e)throw new Error("Illegal argument "+e);var s=n.wordsToBytes(r(e,t));return t&&t.asBytes?s:t&&t.asString?o.bytesToString(s):n.bytesToHex(s)}},556:(e,t,s)=>{e.exports=s(694)()},694:(e,t,s)=>{"use strict";var n=s(925);function i(){}function a(){}a.resetWarningCache=i,e.exports=function(){function e(e,t,s,i,a,o){if(o!==n){var r=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw r.name="Invariant Violation",r}}function t(){return e}e.isRequired=e;var s={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:a,resetWarningCache:i};return s.PropTypes=s,s}},925:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},939:e=>{var t,s;t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",s={rotl:function(e,t){return e<>>32-t},rotr:function(e,t){return e<<32-t|e>>>t},endian:function(e){if(e.constructor==Number)return 16711935&s.rotl(e,8)|4278255360&s.rotl(e,24);for(var t=0;t0;e--)t.push(Math.floor(256*Math.random()));return t},bytesToWords:function(e){for(var t=[],s=0,n=0;s>>5]|=e[s]<<24-n%32;return t},wordsToBytes:function(e){for(var t=[],s=0;s<32*e.length;s+=8)t.push(e[s>>>5]>>>24-s%32&255);return t},bytesToHex:function(e){for(var t=[],s=0;s>>4).toString(16)),t.push((15&e[s]).toString(16));return t.join("")},hexToBytes:function(e){for(var t=[],s=0;s>>6*(3-a)&63)):s.push("=");return s.join("")},base64ToBytes:function(e){e=e.replace(/[^A-Z0-9+\/]/gi,"");for(var s=[],n=0,i=0;n>>6-2*i);return s}},e.exports=s}},s={};function n(e){var i=s[e];if(void 0!==i)return i.exports;var a=s[e]={exports:{}};return t[e](a,a.exports,n),a.exports}n.m=t,e=[],n.O=(t,s,i,a)=>{if(!s){var o=1/0;for(d=0;d=a)&&Object.keys(n.O).every((e=>n.O[e](s[l])))?s.splice(l--,1):(r=!1,a0&&e[d-1][2]>a;d--)e[d]=e[d-1];e[d]=[s,i,a]},n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var s in t)n.o(t,s)&&!n.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:t[s]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={88:0,640:0};n.O.j=t=>0===e[t];var t=(t,s)=>{var i,a,[o,r,l]=s,c=0;if(o.some((t=>0!==e[t]))){for(i in r)n.o(r,i)&&(n.m[i]=r[i]);if(l)var d=l(n)}for(t&&t(s);cn(131)));i=n.O(i)})(); \ No newline at end of file diff --git a/OLD/build/blocks/event-tickets/style-index-rtl.css b/OLD/build/blocks/event-tickets/style-index-rtl.css new file mode 100644 index 0000000..ac36e95 --- /dev/null +++ b/OLD/build/blocks/event-tickets/style-index-rtl.css @@ -0,0 +1 @@ +.wp-block-se-event-tickets__heading{margin:0 0 32px}.wp-block-se-event-tickets__ticket-row{display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;width:100%;margin:0 0 16px}.wp-block-se-event-tickets__ticket-column{display:flex;flex-direction:column;flex-basis:100%}.wp-block-se-event-tickets__ticket-column--title{flex:3}.wp-block-se-event-tickets__ticket-column--price{flex:2}.wp-block-se-event-tickets__ticket-column--buy{flex:1}.wp-block-se-event-tickets__ticket-stock{display:block;opacity:.6;font-size:.75em}.wp-block-se-event-tickets__button{text-align:center} diff --git a/OLD/build/blocks/event-tickets/style-index.css b/OLD/build/blocks/event-tickets/style-index.css new file mode 100644 index 0000000..ac36e95 --- /dev/null +++ b/OLD/build/blocks/event-tickets/style-index.css @@ -0,0 +1 @@ +.wp-block-se-event-tickets__heading{margin:0 0 32px}.wp-block-se-event-tickets__ticket-row{display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;width:100%;margin:0 0 16px}.wp-block-se-event-tickets__ticket-column{display:flex;flex-direction:column;flex-basis:100%}.wp-block-se-event-tickets__ticket-column--title{flex:3}.wp-block-se-event-tickets__ticket-column--price{flex:2}.wp-block-se-event-tickets__ticket-column--buy{flex:1}.wp-block-se-event-tickets__ticket-stock{display:block;opacity:.6;font-size:.75em}.wp-block-se-event-tickets__button{text-align:center} diff --git a/OLD/build/blocks/external-link/block.json b/OLD/build/blocks/external-link/block.json new file mode 100644 index 0000000..9d22a62 --- /dev/null +++ b/OLD/build/blocks/external-link/block.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/external-link", + "title": "External Tickets", + "description": "Add a link to an external ticket website.", + "icon": "admin-links", + "category": "simple-events", + "keywords": [ + "event info", + "tickets", + "link", + "Simple Events", + "meta" + ], + "usesContext": [ + "postId" + ], + "attributes": { + "thePostId": { + "type": "integer", + "default": 0 + } + }, + "supports": { + "html": false + }, + "editorScript": "file:./index.js", + "editorStyle": "file:./index.css" +} \ No newline at end of file diff --git a/OLD/build/blocks/external-link/index-rtl.css b/OLD/build/blocks/external-link/index-rtl.css new file mode 100644 index 0000000..9104436 --- /dev/null +++ b/OLD/build/blocks/external-link/index-rtl.css @@ -0,0 +1 @@ +.wp-block-se-event-link{pointer-events:none} diff --git a/OLD/build/blocks/external-link/index.asset.php b/OLD/build/blocks/external-link/index.asset.php new file mode 100644 index 0000000..6de9625 --- /dev/null +++ b/OLD/build/blocks/external-link/index.asset.php @@ -0,0 +1 @@ + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-server-side-render'), 'version' => 'e180eaf0a2b263deac10'); diff --git a/OLD/build/blocks/external-link/index.css b/OLD/build/blocks/external-link/index.css new file mode 100644 index 0000000..9104436 --- /dev/null +++ b/OLD/build/blocks/external-link/index.css @@ -0,0 +1 @@ +.wp-block-se-event-link{pointer-events:none} diff --git a/OLD/build/blocks/external-link/index.js b/OLD/build/blocks/external-link/index.js new file mode 100644 index 0000000..3ae1840 --- /dev/null +++ b/OLD/build/blocks/external-link/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e={n:t=>{var s=t&&t.__esModule?()=>t.default:()=>t;return e.d(s,{a:s}),s},d:(t,s)=>{for(var n in s)e.o(s,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:s[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"simple-events/external-link","title":"External Tickets","description":"Add a link to an external ticket website.","icon":"admin-links","category":"simple-events","keywords":["event info","tickets","link","Simple Events","meta"],"usesContext":["postId"],"attributes":{"thePostId":{"type":"integer","default":0}},"supports":{"html":false},"editorScript":"file:./index.js","editorStyle":"file:./index.css"}'),s=window.wp.blockEditor,n=window.wp.blocks,i=window.wp.serverSideRender;var o=e.n(i);const r=window.ReactJSXRuntime;(0,n.registerBlockType)(t,{edit:({attributes:{thePostId:e},context:{postId:n}})=>{const i=(0,s.useBlockProps)();return(0,r.jsx)("div",{...i,children:(0,r.jsx)(o(),{block:t.name,attributes:{thePostId:n}})})},save:e=>null})})(); \ No newline at end of file diff --git a/OLD/build/blocks/inner-blocks/block.json b/OLD/build/blocks/inner-blocks/block.json new file mode 100644 index 0000000..607cfe3 --- /dev/null +++ b/OLD/build/blocks/inner-blocks/block.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/inner-blocks", + "title": "Event Blocks", + "category": "simple-events", + "supports": { + "inserter": false, + "multiple": true, + "reusable": false, + "align": [ + "wide", + "full" + ], + "layout": true + }, + "editorScript": "file:./index.js" +} \ No newline at end of file diff --git a/OLD/build/blocks/inner-blocks/index.asset.php b/OLD/build/blocks/inner-blocks/index.asset.php new file mode 100644 index 0000000..f6817f6 --- /dev/null +++ b/OLD/build/blocks/inner-blocks/index.asset.php @@ -0,0 +1 @@ + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-i18n'), 'version' => 'f4ca020f4e96839bd58f'); diff --git a/OLD/build/blocks/inner-blocks/index.js b/OLD/build/blocks/inner-blocks/index.js new file mode 100644 index 0000000..1188f22 --- /dev/null +++ b/OLD/build/blocks/inner-blocks/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e,r={149:()=>{window.wp.i18n;const e=window.wp.blocks,r=window.wp.blockEditor,o=window.ReactJSXRuntime;(0,e.registerBlockType)("simple-events/inner-blocks",{edit:()=>(0,o.jsx)("div",{...(0,r.useBlockProps)(),children:(0,o.jsx)(r.InnerBlocks,{templateLock:!1})}),save:()=>(0,o.jsx)(r.InnerBlocks.Content,{})})}},o={};function n(e){var s=o[e];if(void 0!==s)return s.exports;var i=o[e]={exports:{}};return r[e](i,i.exports,n),i.exports}n.m=r,e=[],n.O=(r,o,s,i)=>{if(!o){var t=1/0;for(a=0;a=i)&&Object.keys(n.O).every((e=>n.O[e](o[p])))?o.splice(p--,1):(l=!1,i0&&e[a-1][2]>i;a--)e[a]=e[a-1];e[a]=[o,s,i]},n.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),(()=>{var e={817:0,749:0};n.O.j=r=>0===e[r];var r=(r,o)=>{var s,i,[t,l,p]=o,c=0;if(t.some((r=>0!==e[r]))){for(s in l)n.o(l,s)&&(n.m[s]=l[s]);if(p)var a=p(n)}for(r&&r(o);cn(149)));s=n.O(s)})(); \ No newline at end of file diff --git a/OLD/build/blocks/inner-blocks/style-index-rtl.css b/OLD/build/blocks/inner-blocks/style-index-rtl.css new file mode 100644 index 0000000..6de3e3c --- /dev/null +++ b/OLD/build/blocks/inner-blocks/style-index-rtl.css @@ -0,0 +1 @@ +.block-editor-block-list__block[data-type="simple-events/inner-blocks"]:not(.is-selected):not(.has-child-selected) .block-editor-default-block-appender{display:block} diff --git a/OLD/build/blocks/inner-blocks/style-index.css b/OLD/build/blocks/inner-blocks/style-index.css new file mode 100644 index 0000000..6de3e3c --- /dev/null +++ b/OLD/build/blocks/inner-blocks/style-index.css @@ -0,0 +1 @@ +.block-editor-block-list__block[data-type="simple-events/inner-blocks"]:not(.is-selected):not(.has-child-selected) .block-editor-default-block-appender{display:block} diff --git a/OLD/build/blocks/loop-event-info/block.json b/OLD/build/blocks/loop-event-info/block.json new file mode 100644 index 0000000..63232d5 --- /dev/null +++ b/OLD/build/blocks/loop-event-info/block.json @@ -0,0 +1,75 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/loop-event-info", + "title": "Event Metadata", + "description": "Display event meta in a custom query loop.", + "icon": "tag", + "category": "simple-events", + "keywords": [ + "event info", + "date", + "location", + "Simple Events", + "meta" + ], + "usesContext": [ + "postId" + ], + "attributes": { + "textAlign": { + "type": "string", + "default": "left" + }, + "thePostId": { + "type": "integer", + "default": 0 + }, + "metaName": { + "enum": [ + "location", + "venue", + "dates", + "date", + "time" + ], + "type": "string", + "default": "dates" + }, + "metaPrefix": { + "type": "string", + "default": "" + }, + "addCalendarLinks": { + "type": "boolean" + } + }, + "supports": { + "html": false, + "align": true, + "typography": { + "fontSize": true, + "lineHeight": true, + "__experimentalFontFamily": true, + "__experimentalFontWeight": true, + "__experimentalFontStyle": true, + "__experimentalTextTransform": true, + "__experimentalTextDecoration": true, + "__experimentalLetterSpacing": true, + "__experimentalDefaultControls": { + "fontSize": true + } + }, + "spacing": { + "margin": true, + "padding": true, + "blockGap": true + }, + "color": { + "text": true + } + }, + "editorScript": "file:./index.js", + "editorStyle": "file:./editor.css", + "style": "file:./style.css" +} \ No newline at end of file diff --git a/OLD/build/blocks/loop-event-info/index-rtl.css b/OLD/build/blocks/loop-event-info/index-rtl.css new file mode 100644 index 0000000..139597f --- /dev/null +++ b/OLD/build/blocks/loop-event-info/index-rtl.css @@ -0,0 +1,2 @@ + + diff --git a/OLD/build/blocks/loop-event-info/index.asset.php b/OLD/build/blocks/loop-event-info/index.asset.php new file mode 100644 index 0000000..a140fec --- /dev/null +++ b/OLD/build/blocks/loop-event-info/index.asset.php @@ -0,0 +1 @@ + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-i18n', 'wp-server-side-render'), 'version' => '942591a32ff4f3a153b6'); diff --git a/OLD/build/blocks/loop-event-info/index.css b/OLD/build/blocks/loop-event-info/index.css new file mode 100644 index 0000000..139597f --- /dev/null +++ b/OLD/build/blocks/loop-event-info/index.css @@ -0,0 +1,2 @@ + + diff --git a/OLD/build/blocks/loop-event-info/index.js b/OLD/build/blocks/loop-event-info/index.js new file mode 100644 index 0000000..f4593f3 --- /dev/null +++ b/OLD/build/blocks/loop-event-info/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e={n:t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return e.d(n,{a:n}),n},d:(t,n)=>{for(var a in n)e.o(n,a)&&!e.o(t,a)&&Object.defineProperty(t,a,{enumerable:!0,get:n[a]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"simple-events/loop-event-info","title":"Event Metadata","description":"Display event meta in a custom query loop.","icon":"tag","category":"simple-events","keywords":["event info","date","location","Simple Events","meta"],"usesContext":["postId"],"attributes":{"textAlign":{"type":"string","default":"left"},"thePostId":{"type":"integer","default":0},"metaName":{"enum":["location","venue","dates","date","time"],"type":"string","default":"dates"},"metaPrefix":{"type":"string","default":""},"addCalendarLinks":{"type":"boolean"}},"supports":{"html":false,"align":true,"typography":{"fontSize":true,"lineHeight":true,"__experimentalFontFamily":true,"__experimentalFontWeight":true,"__experimentalFontStyle":true,"__experimentalTextTransform":true,"__experimentalTextDecoration":true,"__experimentalLetterSpacing":true,"__experimentalDefaultControls":{"fontSize":true}},"spacing":{"margin":true,"padding":true,"blockGap":true},"color":{"text":true}},"editorScript":"file:./index.js","editorStyle":"file:./editor.css","style":"file:./style.css"}'),n=window.wp.i18n,a=window.wp.blocks,l=window.wp.components,o=window.wp.serverSideRender;var i=e.n(o);const s=window.wp.blockEditor,r=window.ReactJSXRuntime;(0,a.registerBlockType)(t,{edit:({attributes:{metaName:e,metaPrefix:a,thePostId:o,textAlign:d,addCalendarLinks:p},setAttributes:m,context:{postId:u}})=>(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(s.InspectorControls,{children:(0,r.jsxs)(l.PanelBody,{title:(0,n.__)("Display Options","simple-events"),children:[(0,r.jsx)(l.SelectControl,{label:(0,n.__)("Show what event info?","simple-events"),value:e,options:[{label:(0,n.__)("Date & Time","simple-events"),value:"dates"},{label:(0,n.__)("Location","simple-events"),value:"location"},{label:(0,n.__)("Venue","simple-events"),value:"venue"},{label:(0,n.__)("Date Only","simple-events"),value:"date"},{label:(0,n.__)("Time Only","simple-events"),value:"time"}],onChange:e=>m({metaName:e}),__nextHasNoMarginBottom:!0}),(0,r.jsx)(l.TextControl,{label:(0,n.__)("Prefix","simple-events"),value:a,onChange:e=>m({metaPrefix:e}),__nextHasNoMarginBottom:!0}),(0,r.jsx)(l.ToggleControl,{label:(0,n.__)('Show "Add to calendar" links',"simple-events"),checked:p,onChange:e=>m({addCalendarLinks:e})})]})}),(0,r.jsx)(s.BlockControls,{group:"block",children:(0,r.jsx)(s.AlignmentControl,{value:d,onChange:e=>{m({textAlign:e})}})}),(0,r.jsx)("div",{...(0,s.useBlockProps)(),children:(0,r.jsx)(i(),{block:t.name,attributes:{metaName:e,metaPrefix:a,textAlign:d,thePostId:u,addCalendarLinks:p}})})]}),save:e=>null})})(); \ No newline at end of file diff --git a/OLD/build/blocks/past-events-notice/block.json b/OLD/build/blocks/past-events-notice/block.json new file mode 100644 index 0000000..90311e8 --- /dev/null +++ b/OLD/build/blocks/past-events-notice/block.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/past-events-notice", + "title": "Past Events Notice", + "description": "Display the notice message set in the Simple Events settings.", + "icon": "megaphone", + "category": "simple-events", + "keywords": [ + "past-events", + "notice", + "Simple Events" + ], + "supports": { + "html": false, + "align": true, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true, + "blockGap": true + }, + "color": { + "text": true + } + }, + "editorScript": "file:./index.js" +} \ No newline at end of file diff --git a/OLD/build/blocks/past-events-notice/index.asset.php b/OLD/build/blocks/past-events-notice/index.asset.php new file mode 100644 index 0000000..af393d1 --- /dev/null +++ b/OLD/build/blocks/past-events-notice/index.asset.php @@ -0,0 +1 @@ + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks'), 'version' => '62ffcf7acbdcff27842a'); diff --git a/OLD/build/blocks/past-events-notice/index.js b/OLD/build/blocks/past-events-notice/index.js new file mode 100644 index 0000000..88237da --- /dev/null +++ b/OLD/build/blocks/past-events-notice/index.js @@ -0,0 +1 @@ +(()=>{"use strict";const e=window.wp.blocks,t=window.wp.blockEditor,s=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":2,"name":"simple-events/past-events-notice","title":"Past Events Notice","description":"Display the notice message set in the Simple Events settings.","icon":"megaphone","category":"simple-events","keywords":["past-events","notice","Simple Events"],"supports":{"html":false,"align":true,"typography":{"fontSize":true,"lineHeight":true},"spacing":{"margin":true,"padding":true,"blockGap":true},"color":{"text":true}},"editorScript":"file:./index.js"}'),n=window.ReactJSXRuntime;(0,e.registerBlockType)(s,{edit:()=>{var e;return(0,n.jsx)(t.InnerBlocks,{template:[["core/paragraph",{content:null!==(e=seSettings?.pastEventsNotice)&&void 0!==e?e:"Event has passed"}]]})},save:()=>(0,n.jsx)(t.InnerBlocks.Content,{})})})(); \ No newline at end of file diff --git a/OLD/build/blocks/upcoming-events/block.json b/OLD/build/blocks/upcoming-events/block.json new file mode 100644 index 0000000..efca385 --- /dev/null +++ b/OLD/build/blocks/upcoming-events/block.json @@ -0,0 +1,78 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/upcoming-events", + "title": "Events Feed", + "description": "Display upcoming events, past events or events between a date range.", + "icon": "layout", + "category": "simple-events", + "keywords": [ + "event", + "upcoming", + "Simple Events" + ], + "attributes": { + "className": { + "type": "string", + "default": "" + }, + "count": { + "type": "number", + "default": 10 + }, + "columns": { + "type": "number", + "default": 3 + }, + "layout": { + "type": "string", + "default": "list" + }, + "align": { + "type": "string", + "default": "" + }, + "feedType": { + "type": "string", + "default": "upcoming", + "enum": [ + "upcoming", + "past", + "mixed", + "range" + ] + }, + "showYearDividers": { + "type": "boolean", + "default": false + }, + "overrideFeedOrder": { + "type": "boolean", + "default": false + }, + "feedOrder": { + "type": "string", + "default": "ASC", + "enum": [ + "ASC", + "DESC" + ] + }, + "dateRange": { + "type": "object", + "default": { + "from": "", + "to": "" + } + } + }, + "supports": { + "html": false, + "align": [ + "wide", + "full" + ] + }, + "editorScript": "file:./index.js", + "style": "file:./index.css" +} \ No newline at end of file diff --git a/OLD/build/blocks/upcoming-events/index-rtl.css b/OLD/build/blocks/upcoming-events/index-rtl.css new file mode 100644 index 0000000..525a724 --- /dev/null +++ b/OLD/build/blocks/upcoming-events/index-rtl.css @@ -0,0 +1 @@ +.wp-block-se-upcoming-events ul{list-style:none;margin:0;padding:0}.wp-block-se-upcoming-events ul .se-event-date{font-weight:bold}.wp-block-se-upcoming-events ul .se-event-location{margin-bottom:1rem}.wp-block-se-upcoming-events ul li h2.entry-title{font-size:max(2.5rem,28px)}.wp-block-se-upcoming-events ul li h2.entry-title a{color:var(--wp--preset--color--primary, #28303d)}.wp-block-se-upcoming-events ul li h2.entry-title a:hover{text-decoration:underline}.wp-block-se-upcoming-events ul li>a{background:var(--wp--preset--color--primary, #28303d);color:var(--wp--preset--color--white, #fff);padding:1rem 1.5rem;display:inline-block;font-size:max(1rem,16px);text-transform:uppercase;text-decoration:none;letter-spacing:.05em;font-weight:bold}.wp-block-se-upcoming-events ul li>a:hover{background:var(--wp--preset--color--black, #000)}.wp-block-se-upcoming-events-view-grid ul{display:grid;grid-template-columns:1fr;gap:20px}@media(min-width: 768px){.wp-block-se-upcoming-events-view-grid.wp-block-se-upcoming-events-columns-2 ul,.wp-block-se-upcoming-events-view-grid.wp-block-se-upcoming-events-columns-3 ul,.wp-block-se-upcoming-events-view-grid.wp-block-se-upcoming-events-columns-4 ul{grid-template-columns:1fr 1fr}}@media(min-width: 1024px){.wp-block-se-upcoming-events-view-grid.wp-block-se-upcoming-events-columns-3 ul{grid-template-columns:1fr 1fr 1fr}.wp-block-se-upcoming-events-view-grid.wp-block-se-upcoming-events-columns-4 ul{grid-template-columns:1fr 1fr 1fr 1fr}} diff --git a/OLD/build/blocks/upcoming-events/index.asset.php b/OLD/build/blocks/upcoming-events/index.asset.php new file mode 100644 index 0000000..6be6b7a --- /dev/null +++ b/OLD/build/blocks/upcoming-events/index.asset.php @@ -0,0 +1 @@ + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n', 'wp-primitives', 'wp-server-side-render'), 'version' => 'e7063f90b7238e53eda6'); diff --git a/OLD/build/blocks/upcoming-events/index.css b/OLD/build/blocks/upcoming-events/index.css new file mode 100644 index 0000000..525a724 --- /dev/null +++ b/OLD/build/blocks/upcoming-events/index.css @@ -0,0 +1 @@ +.wp-block-se-upcoming-events ul{list-style:none;margin:0;padding:0}.wp-block-se-upcoming-events ul .se-event-date{font-weight:bold}.wp-block-se-upcoming-events ul .se-event-location{margin-bottom:1rem}.wp-block-se-upcoming-events ul li h2.entry-title{font-size:max(2.5rem,28px)}.wp-block-se-upcoming-events ul li h2.entry-title a{color:var(--wp--preset--color--primary, #28303d)}.wp-block-se-upcoming-events ul li h2.entry-title a:hover{text-decoration:underline}.wp-block-se-upcoming-events ul li>a{background:var(--wp--preset--color--primary, #28303d);color:var(--wp--preset--color--white, #fff);padding:1rem 1.5rem;display:inline-block;font-size:max(1rem,16px);text-transform:uppercase;text-decoration:none;letter-spacing:.05em;font-weight:bold}.wp-block-se-upcoming-events ul li>a:hover{background:var(--wp--preset--color--black, #000)}.wp-block-se-upcoming-events-view-grid ul{display:grid;grid-template-columns:1fr;gap:20px}@media(min-width: 768px){.wp-block-se-upcoming-events-view-grid.wp-block-se-upcoming-events-columns-2 ul,.wp-block-se-upcoming-events-view-grid.wp-block-se-upcoming-events-columns-3 ul,.wp-block-se-upcoming-events-view-grid.wp-block-se-upcoming-events-columns-4 ul{grid-template-columns:1fr 1fr}}@media(min-width: 1024px){.wp-block-se-upcoming-events-view-grid.wp-block-se-upcoming-events-columns-3 ul{grid-template-columns:1fr 1fr 1fr}.wp-block-se-upcoming-events-view-grid.wp-block-se-upcoming-events-columns-4 ul{grid-template-columns:1fr 1fr 1fr 1fr}} diff --git a/OLD/build/blocks/upcoming-events/index.js b/OLD/build/blocks/upcoming-events/index.js new file mode 100644 index 0000000..d3329e0 --- /dev/null +++ b/OLD/build/blocks/upcoming-events/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e={n:t=>{var n=t&&t.__esModule?()=>t.default:()=>t;return e.d(n,{a:n}),n},d:(t,n)=>{for(var o in n)e.o(n,o)&&!e.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:n[o]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.i18n,n=window.wp.blocks,o=window.wp.components,l=window.wp.serverSideRender;var s=e.n(l);const i=window.wp.blockEditor,r=window.wp.element,a=window.wp.primitives,d=(0,r.createElement)(a.SVG,{viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg"},(0,r.createElement)(a.Path,{d:"M4 4v1.5h16V4H4zm8 8.5h8V11h-8v1.5zM4 20h16v-1.5H4V20zm4-8c0-1.1-.9-2-2-2s-2 .9-2 2 .9 2 2 2 2-.9 2-2z"})),c=(0,r.createElement)(a.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24"},(0,r.createElement)(a.Path,{d:"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7.8 16.5H5c-.3 0-.5-.2-.5-.5v-6.2h6.8v6.7zm0-8.3H4.5V5c0-.3.2-.5.5-.5h6.2v6.7zm8.3 7.8c0 .3-.2.5-.5.5h-6.2v-6.8h6.8V19zm0-7.8h-6.8V4.5H19c.3 0 .5.2.5.5v6.2z",fillRule:"evenodd",clipRule:"evenodd"})),v=(0,r.createElement)(a.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24"},(0,r.createElement)(a.Path,{d:"M20.1 5.1L16.9 2 6.2 12.7l-1.3 4.4 4.5-1.3L20.1 5.1zM4 20.8h8v-1.5H4v1.5z"})),m=window.ReactJSXRuntime;(0,n.registerBlockType)("simple-events/upcoming-events",{edit:({attributes:e,setAttributes:n})=>{const{count:l,layout:a,columns:p,feedType:u,feedOrder:w,overrideFeedOrder:g,showYearDividers:h,dateRange:x}=e,[C,b]=(0,r.useState)(!1);return(0,m.jsxs)("div",{...(0,i.useBlockProps)(),children:[(0,m.jsxs)(i.InspectorControls,{children:[(0,m.jsxs)(o.PanelBody,{title:(0,t.__)("Display Options","simple-events"),className:"panelbody-custom-latest-posts",children:[(0,m.jsx)(o.SelectControl,{label:(0,t.__)("Feed layout","simple-events"),value:a,options:[{label:"List",value:"list"},{label:"Grid",value:"grid"}],onChange:e=>n({layout:e}),__nextHasNoMarginBottom:!0}),"grid"===a&&(0,m.jsx)(o.RangeControl,{label:(0,t.__)("Grid columns","simple-events"),value:p,onChange:e=>n({columns:e}),min:1,max:4}),(0,m.jsx)(o.Button,{variant:"primary",onClick:()=>b(!C),children:C?(0,t.__)('Hide "no results" view',"simple-events"):(0,t.__)('Edit "no results" view',"simple-events")})]}),(0,m.jsxs)(o.PanelBody,{title:(0,t.__)("Event Options","simple-events"),className:"panelbody-custom-latest-posts",children:[(0,m.jsx)(o.SelectControl,{label:(0,t.__)("Feed type","simple-events"),value:u,options:[{label:"Future Events",value:"upcoming"},{label:"Past Events",value:"past"},{label:"Past & Future Events",value:"mixed"},{label:"Events in a Date Range",value:"range"}],onChange:e=>n({feedType:e})}),"range"===u&&(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(o.BaseControl,{label:"From Date: "+new Date(x.from).toLocaleString("en-US"),children:(0,m.jsx)(o.Dropdown,{position:"bottom left",renderToggle:({isOpen:e,onToggle:t})=>(0,m.jsx)(o.Button,{isSecondary:!0,onClick:t,"aria-expanded":e,children:e?"Close Calendar":"Pick 'From' Date"}),renderContent:()=>(0,m.jsx)(o.TimePicker,{currentDate:x.from,onChange:e=>n({dateRange:{...x,from:e}})})})}),(0,m.jsx)(o.BaseControl,{label:"To Date: "+new Date(x.to).toLocaleString("en-US"),children:(0,m.jsx)(o.Dropdown,{position:"bottom left",renderToggle:({isOpen:e,onToggle:t})=>(0,m.jsx)(o.Button,{isSecondary:!0,onClick:t,"aria-expanded":e,children:e?"Close Calendar":"Pick 'To' Date"}),renderContent:()=>(0,m.jsx)(o.TimePicker,{currentDate:x.to,onChange:e=>n({dateRange:{...x,to:e}})})})})]}),(0,m.jsx)(o.RangeControl,{label:(0,t.__)("Number of Events","simple-events"),value:l,onChange:e=>n({count:e}),min:1,max:50}),(0,m.jsx)(o.ToggleControl,{label:"Show Year Dividers",checked:h,onChange:e=>n({showYearDividers:e})}),(0,m.jsx)(o.ToggleControl,{label:"Override Default Order",checked:g,onChange:e=>n({overrideFeedOrder:e})}),g&&(0,m.jsx)(o.SelectControl,{label:"Feed Order",value:w,options:[{label:"Oldest First",value:"ASC"},{label:"Newest First",value:"DESC"}],onChange:e=>n({feedOrder:e})})]})]}),(0,m.jsx)(i.BlockControls,{children:(0,m.jsx)(o.ToolbarGroup,{controls:[{icon:d,title:(0,t.__)("List view","simple-events"),onClick:()=>n({layout:"list"}),isActive:"list"===a},{icon:c,title:(0,t.__)("Grid view","simple-events"),onClick:()=>n({layout:"grid"}),isActive:"grid"===a},{icon:v,title:(0,t.__)('Edit "no results" view',"simple-events"),onClick:()=>b(!C),isActive:C}]})}),C?(0,m.jsx)(i.InnerBlocks,{}):(0,m.jsx)(o.Disabled,{children:(0,m.jsx)(s(),{block:"simple-events/upcoming-events",attributes:e})})]})},save:e=>(0,m.jsx)(i.InnerBlocks.Content,{})})})(); \ No newline at end of file diff --git a/OLD/build/js/admin.asset.php b/OLD/build/js/admin.asset.php new file mode 100644 index 0000000..4c784e0 --- /dev/null +++ b/OLD/build/js/admin.asset.php @@ -0,0 +1 @@ + array(), 'version' => 'f7b2e838744dc7050779'); diff --git a/OLD/build/js/admin.js b/OLD/build/js/admin.js new file mode 100644 index 0000000..ac6e7c6 --- /dev/null +++ b/OLD/build/js/admin.js @@ -0,0 +1 @@ +jQuery(document).ready((function(e){e("#se_ajax_btn").on("click",(function(){e(this).prop("disabled",!0);const t=e(this).data("action");e.ajax({url:ajaxurl,type:"POST",data:{action:t},success:function(t){e("#se_ajax_response").html(`

${t?.data}

`)},error:function(){e("#se_ajax_response").html("

Something went wrong!

")},complete:function(){e("#se_ajax_btn").prop("disabled",!1),setTimeout((()=>{e("#se_ajax_response").html("")}),2e3)}})}));const t=e('input[name="se_options[skip_cart]"]'),n=e('input[name="se_options[empty_cart_before_adding_tickets]"]');e(window).on("load",(function(){t&&!t.is(":checked")&&(n.prop("checked",!1),n.closest("tr").hide())})),t.on("input",(function(){e(this).is(":checked")?n.closest("tr").show():(n.prop("checked",!1),n.closest("tr").hide())}))})); \ No newline at end of file diff --git a/OLD/build/variations/index.asset.php b/OLD/build/variations/index.asset.php new file mode 100644 index 0000000..6c379cd --- /dev/null +++ b/OLD/build/variations/index.asset.php @@ -0,0 +1 @@ + array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-dom-ready', 'wp-hooks', 'wp-i18n'), 'version' => 'fc68ac1a366af59ac8bc'); diff --git a/OLD/build/variations/index.js b/OLD/build/variations/index.js new file mode 100644 index 0000000..0c9d37a --- /dev/null +++ b/OLD/build/variations/index.js @@ -0,0 +1 @@ +(()=>{"use strict";var e={n:t=>{var o=t&&t.__esModule?()=>t.default:()=>t;return e.d(o,{a:o}),o},d:(t,o)=>{for(var s in o)e.o(o,s)&&!e.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:o[s]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)};const t=window.wp.blockEditor,o=window.wp.blocks,s=window.wp.hooks,n=window.wp.components,r=window.wp.i18n,a=window.ReactJSXRuntime,i="se-events/query-loop-events";(0,o.registerBlockVariation)("core/query",{name:i,title:"Query Loop Events",description:"Displays query loop events with upcoming, past settings",category:"simple-events",isActive:({namespace:e,query:t})=>e===i&&"se-event"===t.postType,icon:"layout",attributes:{namespace:i,query:{perPage:6,pages:0,offset:0,postType:"se-event",order:"asc",orderBy:"date",author:"",search:"",exclude:[],sticky:"",inherit:!1,inheritTaxQuery:!0,feedType:"default"}},innerBlocks:[["core/post-template",{},[["core/post-title"],["core/post-date"]]],["core/query-pagination"],["core/query-no-results"]],scope:["inserter"],allowedControls:["taxQuery","search","feedType"]});const l=({attributes:e,setAttributes:t})=>{const{query:o}=e,s=o.feedType||"default",r=o.order||"asc";return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.SelectControl,{label:"Feed Type",value:s,options:[{label:"Default",value:"default"},{label:"Upcoming",value:"upcoming"},{label:"Past",value:"past"}],onChange:e=>{t({query:{...o,feedType:e}})},__nextHasNoMarginBottom:!0}),(0,a.jsx)(n.SelectControl,{label:"Feed Order",value:r,options:[{label:"Oldest First",value:"asc"},{label:"Newest First",value:"desc"}],onChange:e=>{t({query:{...o,order:e}})},__nextHasNoMarginBottom:!0})]})};(0,s.addFilter)("editor.BlockEdit","se-events/my-awesome-pattern",(e=>o=>function(e){return e.attributes.namespace===i}(o)?(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(e,{...o}),(0,a.jsx)(t.InspectorControls,{children:(0,a.jsx)(n.PanelBody,{title:(0,r.__)("Events Query Loop","simple-events"),className:"query-loop-events-panel",children:(0,a.jsx)(l,{...o})})})]}):(0,a.jsx)(e,{...o})));const p=window.wp.domReady;e.n(p)()((function(){window?.seSettings?.postType&&"se-event"!==window.seSettings.postType&&(0,o.unregisterBlockType)("simple-events/event-tickets")}))})(); \ No newline at end of file diff --git a/OLD/plugin.php b/OLD/plugin.php new file mode 100644 index 0000000..7fdb5ee --- /dev/null +++ b/OLD/plugin.php @@ -0,0 +1,98 @@ +Simple Events is corrupted. Please reinstall!', 'simple-events' ); + $html_message = wp_sprintf( '
%s
', wpautop( $message ) ); + echo wp_kses_post( $html_message ); + } + ); + return; +} +require_once SE_PLUGIN_DIR . '/vendor/autoload.php'; + +// Initialize the plugin if system requirements check out. +$se_requirements = validate_plugin_requirements( SE_BASENAME ); +define( 'SE_REQUIREMENTS', $se_requirements ); + +if ( $se_requirements instanceof WP_Error ) { + add_action( + 'admin_notices', + static function () use ( $se_requirements ) { + $html_message = wp_sprintf( '
%s
', $se_requirements->get_error_message() ); + echo wp_kses_post( $html_message ); + } + ); + return; +} + +require_once SE_SRC_PATH . '/classes/class-se-event-post-type.php'; +require_once SE_SRC_PATH . '/classes/class-se-blocks.php'; +require_once SE_SRC_PATH . '/classes/class-se-block-variations.php'; +require_once SE_SRC_PATH . '/classes/class-se-template-loader.php'; +require_once SE_SRC_PATH . '/classes/class-se-settings.php'; +require_once SE_SRC_PATH . '/classes/class-se-admin.php'; +require_once SE_SRC_PATH . '/classes/class-se-calendar-export.php'; +require_once SE_SRC_PATH . '/classes/class-se-calendar.php'; +require_once SE_SRC_PATH . '/classes/class-se-event-query-dates.php'; + +require_once SE_SRC_PATH . '/calendar-functions.php'; +require_once SE_SRC_PATH . '/event-functions.php'; +require_once SE_SRC_PATH . '/template-functions.php'; +require_once SE_SRC_PATH . '/template-hooks.php'; +require_once SE_SRC_PATH . '/woocommerce-hooks.php'; +require_once SE_SRC_PATH . '/rest-api.php'; +require_once SE_SRC_PATH . '/back-compat.php'; + +/** + * Add a flag to leverage for flushing rewrite rules. + * + * @return void + */ +function simple_events_activate() { + if ( ! get_option( 'simple_events_flush_rewrite_rules_flag' ) ) { + add_option( 'simple_events_flush_rewrite_rules_flag', true ); + } +} +register_activation_hook( __FILE__, 'simple_events_activate' ); diff --git a/OLD/postcss.config.js b/OLD/postcss.config.js new file mode 100644 index 0000000..ad99dd2 --- /dev/null +++ b/OLD/postcss.config.js @@ -0,0 +1,19 @@ +const postcssPlugins = require( '@wordpress/postcss-plugins-preset' ); + +module.exports = ( ctx ) => { + const isDevelopment = ( 'development' === ctx.env ); + const isSass = ( '.scss' === ctx.file.extname ); + + return { + map: { + inline: isDevelopment, + annotation: true + }, + parser: isSass ? 'postcss-scss' : false, + plugins: [ + ...( isSass ? [ require( '@csstools/postcss-sass' ) ] : [] ), + ...postcssPlugins, + // Additional plugins here. + ] + }; +}; \ No newline at end of file diff --git a/OLD/src/assets/js/admin.js b/OLD/src/assets/js/admin.js new file mode 100644 index 0000000..1aa6c57 --- /dev/null +++ b/OLD/src/assets/js/admin.js @@ -0,0 +1,58 @@ +/** + * Simple EventsAdmin functionalities. + * + * @package simple-events + */ + +jQuery( document ).ready( function( $ ) { + + // Handle Ticket Only Order Completion.. + $( '#se_ajax_btn' ).on( 'click', function() { + // Disable button and extract action. + $( this ).prop( 'disabled', true ); + const action = $( this ).data( 'action' ); + + // Perform AJAX request. + $.ajax( { + url: ajaxurl, + type: 'POST', + data: { + action: action, + }, + success: function( response ) { + $( '#se_ajax_response' ).html( `

${response?.data}

` ); + }, + error: function() { + $( '#se_ajax_response' ).html( '

Something went wrong!

' ); + }, + complete: function() { + $( '#se_ajax_btn' ).prop( 'disabled', false ); + setTimeout( () => { + $( '#se_ajax_response' ).html( '' ); + }, 2000 ); + }, + } ); + } ); + + // Handle Skip Cart and Empty Cart options. + const skipCart = $( 'input[name="se_options[skip_cart]"]' ); + const emptyCartBeforeAddingTickets = $( 'input[name="se_options[empty_cart_before_adding_tickets]"]' ); + + // If Skip Cart is not enabled, disable Empty Cart Before Adding Tickets. + $( window ).on( 'load', function () { + if( skipCart && ! skipCart.is( ':checked' ) ) { + emptyCartBeforeAddingTickets.prop( 'checked', false ); + emptyCartBeforeAddingTickets.closest( 'tr' ).hide(); + } + } ); + + // Handle Skip Cart option change. + skipCart.on( 'input', function() { + if( $( this ).is( ':checked' ) ) { + emptyCartBeforeAddingTickets.closest( 'tr' ).show(); + } else { + emptyCartBeforeAddingTickets.prop( 'checked', false ); + emptyCartBeforeAddingTickets.closest( 'tr' ).hide(); + } + } ); +} ); diff --git a/OLD/src/back-compat.php b/OLD/src/back-compat.php new file mode 100644 index 0000000..6f50ea2 --- /dev/null +++ b/OLD/src/back-compat.php @@ -0,0 +1,28 @@ +=' ) ) + ) { + $classes .= ' se-datepicker-compat'; + } + + return $classes; +} + +add_filter( 'admin_body_class', 'se_pre_gutenberg_14_3_0_compat' ); diff --git a/OLD/src/blocks/calendar/block.json b/OLD/src/blocks/calendar/block.json new file mode 100644 index 0000000..06337f1 --- /dev/null +++ b/OLD/src/blocks/calendar/block.json @@ -0,0 +1,130 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/calendar", + "title": "Simple Events Calendar", + "icon": "calendar", + "category": "simple-events", + "keywords": ["event", "calendar", "view", "Simple Events"], + "attributes": { + "alignment": { + "type": "string", + "default": "none" + }, + "eventModalAccess": { + "type": "boolean", + "default": false + }, + "modalBgColor": { + "type": "string", + "default": "" + }, + "modalTextColor": { + "type": "string", + "default": "" + }, + "modalIconColor": { + "type": "string", + "default": "" + }, + "showModalTitle": { + "type": "boolean", + "default": false + }, + "showModalExcerpt": { + "type": "boolean", + "default": false + }, + "showModalWhenNoThumbnails": { + "type": "boolean", + "default": false + }, + "hideNeighbourEvents": { + "type": "boolean", + "default": false + }, + "presentDayBg": { + "type": "string", + "default": "" + }, + "presentDayColor": { + "type": "string", + "default": "" + }, + "presentDayBorder": { + "type": "string", + "default": "" + }, + "eventDaysBg": { + "type": "string", + "default": "" + }, + "eventDaysColor": { + "type": "string", + "default": "" + }, + "eventDaysBorder": { + "type": "string", + "default": "" + }, + "pastDaysBg": { + "type": "string", + "default": "" + }, + "pastDaysColor": { + "type": "string", + "default": "" + }, + "pastDaysBorder": { + "type": "string", + "default": "" + }, + "upcomingDaysBg": { + "type": "string", + "default": "" + }, + "upcomingDaysColor": { + "type": "string", + "default": "" + }, + "upcomingDaysBorder": { + "type": "string", + "default": "" + }, + "monthYearColor": { + "type": "string", + "default": "" + }, + "arrowColor": { + "type": "string", + "default": "" + }, + "arrowPosition": { + "type": "string", + "default": "top" + }, + "mobileArrowPosition": { + "type": "string", + "default": "top" + }, + "showDot": { + "type": "boolean", + "default": true + }, + "eventDotColor": { + "type": "string", + "default": "" + } + }, + "supports": { + "multiple": false, + "reusable": false, + "html": false, + "align": true, + "alignment": false + }, + "editorScript": "file:./index.js", + "editorStyle": "file:./index.css", + "style": "file:./style-index.css", + "viewScript": "file:./view.js" +} diff --git a/OLD/src/blocks/calendar/calendar.js b/OLD/src/blocks/calendar/calendar.js new file mode 100644 index 0000000..9c13d3d --- /dev/null +++ b/OLD/src/blocks/calendar/calendar.js @@ -0,0 +1,245 @@ +/* global attributes */ +import apiFetch from '@wordpress/api-fetch'; + +export default class Calendar { + constructor() { + this.DOM = { + calendars: '.simple-events-calendar', + desktopElements: '.simple-events-hidden-mobile', + navigationItems: 'simple-events-navigation-item', + calendarDay: 'simple-events-calendar-day', + mobileEventContainer: 'simple-events-calendar-month-mobile-events', + status: { + dayActive: 'simple-events-calendar-month__day--active', + mobileDayActive: 'simple-events-calendar-month-mobile-events__mobile-day--active', + }, + calendarModal: '.se-event-modal', + calendarModalContainer: '.simple-events-calendar-month__day' + }; + + this.calendars = document.querySelectorAll( this.DOM.calendars ); + } + + /** + * Init Class + */ + init() { + if ( this.calendars.length ) { + this.calendars.forEach( ( calendarItem ) => { + this.initListeners( calendarItem ); + } ); + } + } + + /** + * Init listeners + * + * @param calendarItem + */ + initListeners( calendarItem ) { + this.addNavigationItemsListeners( calendarItem ); + this.addCalendarDayListeners( calendarItem ); + this.handleModalFunctionality(); + } + + /** + * Check if mobile view + * + * @param calendarItem + * @return {boolean} + */ + isMobile( calendarItem ) { + const mobileElements = calendarItem.querySelectorAll( this.DOM.desktopElements ); + if ( mobileElements.length ) { + if ( 'none' === window.getComputedStyle( mobileElements[ 0 ], null ).display ) { + return true; + } + } + + return false; + } + + /** + * Add Calendar day listeners + * + * @param calendarItem + */ + addCalendarDayListeners( calendarItem ) { + const calendarDays = calendarItem.querySelectorAll( `[data-js="${ this.DOM.calendarDay }"]` ); + + if ( calendarDays.length ) { + calendarDays.forEach( ( item ) => { + item.addEventListener( 'click', ( event ) => { + if ( ! this.isMobile( calendarItem ) ) { + return; + } + + event.preventDefault(); + let isActive = false; + const mobileDaysContainer = calendarItem.querySelector( `[data-js="${ this.DOM.mobileEventContainer }"]` ); + + if ( event.currentTarget.classList.contains( this.DOM.status.dayActive ) ) { + isActive = true; + } + + if ( mobileDaysContainer ) { + const mobileDay = mobileDaysContainer.querySelector( '#' + event.currentTarget.dataset.mobileControl ); + const activeMobileDays = mobileDaysContainer.querySelectorAll( '.' + this.DOM.status.mobileDayActive ); + const activeDays = calendarItem.querySelectorAll( '.' + this.DOM.status.dayActive ); + + if ( mobileDay ) { + if ( activeMobileDays.length ) { + activeMobileDays.forEach( ( item ) => { + item.classList.remove( this.DOM.status.mobileDayActive ); + } ); + } + if ( activeDays.length ) { + activeDays.forEach( ( item ) => { + item.classList.remove( this.DOM.status.dayActive ); + } ); + } + + if ( ! isActive ) { + event.currentTarget.classList.add( this.DOM.status.dayActive ); + mobileDay.classList.add( this.DOM.status.mobileDayActive ); + } + } + } + } ); + } ); + } + } + + /** + * Add navigation items listeners + * + * @param calendarItem + */ + addNavigationItemsListeners( calendarItem ) { + const navigation = calendarItem.querySelectorAll( `[data-js="${ this.DOM.navigationItems }"]` ); + + if ( navigation.length ) { + navigation.forEach( ( item ) => { + item.addEventListener( 'click', ( event ) => { + event.preventDefault(); + + if ( event.currentTarget.classList.contains( 'disabled' ) ) { + return; + } + + const date = event.currentTarget.closest( `[data-js="${ this.DOM.navigationItems }"]` ).dataset.date; + this.sendCalendarRequest( date, calendarItem ); + } ); + } ); + } + } + + /** + * Send calendar API request + * + * @param date + * @param calendarItem + */ + sendCalendarRequest( date, calendarItem ) { + /** + * Convert GET request to POST + * Implemented to send block attributes in body instead of URL. + */ + apiFetch( { + path: '/simple-events/calendar', + method: 'POST', + data: { + date, + attributes, + }, + } ).then( ( result ) => { + if ( result.html ) { + calendarItem.innerHTML = result.html; + this.initListeners( calendarItem ); + } else { + console.log( result ); + } + }); + } + + /** + * Sets a timeout to hide the modal after 500 milliseconds. + * + * @param {Element} modal - The modal element to hide. + * @return {number} The ID of the timeout that can be used to clear it. + */ + handleHideTimeout( modal ) { + return setTimeout( () => { + modal.classList.add( 'hidden' ); + }, 150 ); + } + + /** + * Handles the modal functionality for the calendar. + * + * @return {void} + */ + handleModalFunctionality() { + // Target all modal containers. + const modalContainer = document.querySelectorAll( this.DOM.calendarModalContainer ); + modalContainer.forEach( ( element, idx ) => { + let modal = null; + // Target event titles. + const titles = element.querySelectorAll( '.simple-events-calendar-month__calendar-event-title' ); + + if ( ! titles || ! titles.length ) { + return; + } + + let hideTimeout = null; + + titles.forEach( ( title ) => { + // On hovering an event's title, show its corresponding modal. + title.addEventListener( 'mouseenter', ( e ) => { + const article = e.currentTarget.closest( 'article' ); + modal = article.nextElementSibling; + + if ( ! modal ) { + return; + } + + // Keep the modal open when hovered, remove timeout. + modal.addEventListener( 'mouseenter', () => { + clearTimeout( hideTimeout ); + } ); + + // Hide the modal after cursor leaves the modal. + modal.addEventListener( 'mouseleave', () => { + hideTimeout = this.handleHideTimeout( modal ); + } ); + + modal.classList.remove( 'hidden' ); + + // Position of the event in the calendar. + const position = ( idx + 1 ) % 7; + + // Set the modal's position based on its position in the calendar. + if ( position !== 0 && position < 4 ) { + modal.style.left = '80px'; + } else { + modal.style.right = '80px'; + } + if ( ( idx + 1 ) > 22 ) { + modal.style.top = '-220px'; + } + } ); + + title.addEventListener( 'mouseleave', () => { + + if ( ! modal ) { + return; + } + + // Hide the modal on leaving the title. + hideTimeout = this.handleHideTimeout( modal ); + } ); + } ); + + } ); + } +} diff --git a/OLD/src/blocks/calendar/color-panel/index.js b/OLD/src/blocks/calendar/color-panel/index.js new file mode 100644 index 0000000..c78d755 --- /dev/null +++ b/OLD/src/blocks/calendar/color-panel/index.js @@ -0,0 +1,58 @@ +/** + * Dependencies + */ +import { PanelColorSettings } from '@wordpress/block-editor'; +import { PanelBody } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * Renders a color panel component with customizable attributes. + * + * @param {Object} props - The properties passed to the component. + * @param {string} props.title - The title of the color panel. + * @param {string} props.bgAttr - The attribute for the background color. + * @param {string} props.colorAttr - The attribute for the text color. + * @param {string} props.borderAttr - The attribute for the border color. + * @param {Object} props.attributes - The attributes object. + * @param {Function} props.setAttributes - The function to update the attributes. + */ +const ColorPanel = ( { + title, + bgAttr, + colorAttr, + borderAttr, + attributes, + setAttributes, +} ) => { + return ( + + + setAttributes( { [ bgAttr ]: value } ), + clearable: true, + }, + { + label: __( 'Text Color', 'simple-events' ), + value: attributes[ colorAttr ], + onChange: ( value ) => + setAttributes( { [ colorAttr ]: value } ), + clearable: true, + }, + { + label: __( 'Border Color', 'simple-events' ), + value: attributes[ borderAttr ], + onChange: ( value ) => + setAttributes( { [ borderAttr ]: value } ), + clearable: true, + }, + ] } + /> + + ); +}; + +export default ColorPanel; diff --git a/OLD/src/blocks/calendar/editor.scss b/OLD/src/blocks/calendar/editor.scss new file mode 100644 index 0000000..6113e77 --- /dev/null +++ b/OLD/src/blocks/calendar/editor.scss @@ -0,0 +1,14 @@ +/** + * #.# Editor Styles + * + * CSS for just Backend enqueued after style.scss + * which makes it higher in priority. + */ + +.wp-block-simple-events-calendar { +} + +.block-editor-panel-color-gradient-settings.block-editor-panel-color-gradient-settings { + padding: 0; + border-top: 0; +} diff --git a/OLD/src/blocks/calendar/index.js b/OLD/src/blocks/calendar/index.js new file mode 100644 index 0000000..3726d2d --- /dev/null +++ b/OLD/src/blocks/calendar/index.js @@ -0,0 +1,266 @@ +/** + * BLOCK: Calendar + * + * Calendar view. + */ + +import './style.scss'; +import './editor.scss'; + +import { registerBlockType } from '@wordpress/blocks'; +import ServerSideRender from '@wordpress/server-side-render'; +import { PanelBody, ToggleControl, SelectControl } from '@wordpress/components'; +import { + BlockControls, + useBlockProps, + AlignmentToolbar, + InspectorControls, + PanelColorSettings, +} from '@wordpress/block-editor'; +import ColorPanel from './color-panel'; +import { __ } from '@wordpress/i18n'; + +registerBlockType( 'simple-events/calendar', { + edit: ( { attributes, setAttributes } ) => { + const onChangeAlignment = ( newAlignment ) => { + setAttributes( { + alignment: newAlignment === undefined ? 'none' : newAlignment, + } ); + }; + + return ( + <> + + + + + + + setAttributes( { hideNeighbourEvents: value } ) + } + /> + + setAttributes( { showDot: value } ) + } + /> + + setAttributes( { + eventDotColor: value, + } ), + clearable: true, + }, + ] } + /> + + + setAttributes( { eventModalAccess: value } ) } + /> + setAttributes( { showModalTitle: value } ) } + /> + setAttributes( { showModalExcerpt: value } ) } + /> + setAttributes( { showModalWhenNoThumbnails: value } ) } + /> +

{ __( 'Color Configuration', 'simple-events' ) }

+ setAttributes( { modalBgColor: value } ), + clearable: true, + }, + { + label: __( 'Text Color', 'simple-events' ), + value: attributes?.modalTextColor, + onChange: ( value ) => setAttributes( { modalTextColor: value } ), + clearable: true, + }, + { + label: __( 'Icon Color', 'simple-events' ), + value: attributes?.modalIconColor, + onChange: ( value ) => setAttributes( { modalIconColor: value } ), + clearable: true, + } + ] } + /> +
+ + + + + + + setAttributes( { + monthYearColor: value, + } ), + clearable: true, + }, + ] } + /> + + + + setAttributes( { arrowColor: value } ), + clearable: true, + }, + ] } + /> +
+ + setAttributes( { arrowPosition: value } ) + } + options={ [ + { + label: __( 'Top', 'simple-events' ), + value: 'top', + }, + { + label: __( 'Bottom', 'simple-events' ), + value: 'bottom', + }, + ] } + /> + + setAttributes( { mobileArrowPosition: value } ) + } + options={ [ + { + label: __( 'Top', 'simple-events' ), + value: 'top', + }, + { + label: __( 'Bottom', 'simple-events' ), + value: 'bottom', + }, + ] } + /> +
+
+
+ +
+ + ); + }, + + save: () => { + return null; + }, +} ); diff --git a/OLD/src/blocks/calendar/style.scss b/OLD/src/blocks/calendar/style.scss new file mode 100644 index 0000000..15d344b --- /dev/null +++ b/OLD/src/blocks/calendar/style.scss @@ -0,0 +1,275 @@ +/** + * #.# Styles + * + * CSS for both Frontend. + */ + +@import '../common.scss'; +.simple-events-calendar { + margin-left: auto; + margin-right: auto; + width: 100%; + min-height: 700px; + .simple-events-top-bar { + position: relative; + display: flex; + flex-direction: row; + gap: 20px; + align-items: center; + width: 100%; + nav { + display: block; + flex: none; + ul { + display: flex; + list-style: none; + margin: 10px 0; + padding: 0; + li { + flex: none; + &:nth-child(2) { + position: absolute; + right: 0; + } + a { + display: flex; + } + svg { + width: 25px; + } + } + } + } + &__today-button { + font-size: $font-size-sm; + } + &__month { + font-size: $font-size-xl; + } + } + .simple-events-calendar-month { + &__body {} + &__header { + &-row { + display: flex; + } + &-column { + flex: 1; + display: flex; + @include max-mobile { + justify-content: center; + } + h3 { + font-size: $font-size-md; + } + } + } + &__body {} + &__week { + display: flex; + } + &__day { + display: flex; + flex-direction: column; + min-height: 150px; + flex: 1; + border: 1px solid rgba(255, 255, 255, 1); + -webkit-background-clip: padding-box; + /* for Safari */ + background-clip: padding-box; + /* for IE9+, Firefox 4+, Opera, Chrome */ + @include max-mobile { + align-items: center; + min-height: 50px; + border: none; + } + &-date-daynum { + line-height: 1.4; + font-size: $font-size-xl; + padding: $spacer-xs $spacer-sm; + @include max-mobile { + line-height: 1.2; + font-size: $font-size-md; + padding: $spacer-xxs $spacer-xs; + } + } + &--today { + background-color: rgba(60, 120, 200, 0.3); + } + &--past>time, + &--past .simple-events-calendar-month__calendar-event { + opacity: 0.6; + } + &--active { + @include max-mobile { + background-color: rgba(15, 58, 184, 0.8); + } + } + } + &__calendar-event { + padding: 0 $spacer-sm 0; + margin: 0 0 $spacer-md 0; + &.se-event-hide-start-time { + // Hide first time. + time:first-child { + display: none; + } + .simple-events-calendar-month__calendar-event-datetime-separator { + display: none; + } + } + &.se-event-hide-end-time { + // Hide last time. + time:last-child { + display: none; + } + .simple-events-calendar-month__calendar-event-datetime-separator { + display: none; + } + } + @include max-mobile { + margin: 0 0 $spacer-xl 0; + } + &-datetime { + font-size: 13px; + @include max-mobile { + font-size: $font-size-md; + } + >* { + vertical-align: middle; + } + } + &-title { + font-size: $font-size-xs; + margin: 0; + @include max-mobile { + font-size: $font-size-md; + } + &-link { + text-decoration: none; + &:hover { + text-decoration: underline; + } + } + } + } + &__mobile-events-icon { + background-color: white; + height: 8px; + width: 8px; + border-radius: 50%; + } + } + .simple-events-calendar-month-mobile { + &-events__mobile-day { + display: none; + &--active { + @include max-mobile { + display: block; + } + } + } + } + .simple-events-mobile__nav { + &-list { + display: flex; + list-style: none; + margin: 10px 0; + padding: 0; + justify-content: center; + align-items: center; + &-item { + flex: 1; + display: flex; + &--prev { + justify-content: flex-start; + width: 33.33%; + } + &--today { + justify-content: center; + font-size: $font-size-md; + width: 33.33%; + } + &--next { + justify-content: flex-end; + width: 33.33%; + } + a { + display: flex; + } + svg { + width: 35px; + } + } + } + } + .disabled { + opacity: 0.4; + } + .simple-events-hidden-mobile { + @include max-mobile { + display: none !important; + } + } + .simple-events-hidden-desktop { + @include tablet { + display: none !important; + } + } +} + +.simple-events-calendar-month-mobile-events__mobile-day .se-event-modal.hidden { + display: none; +} + +.simple-events-calendar-month__events { + position: relative; + .se-event-modal { + position: absolute; + z-index: 1000; + border: 1px solid #808080; + padding: 10px; + border-radius: 5px; + width: 300px; + top: 0; + background-color: var(--wp--preset--color--primary, #fff); + color: var(--wp--preset--color--secondary, #000); + $parent: &; + &.hidden { + display: none; + } + &__image img { + width: 100%; + height: fit-content; + max-height: 250px; + object-fit: contain; + border-radius: 5px; + } + &__flex { + display: flex; + align-items: center; + gap: 8px; + &:last-of-type { + margin-bottom: 5px; + } + .se-event-modal__date { + font-size: 12px; + margin: 10px 0; + line-height: 1.5; + } + ul { + list-style: none; + padding: 0; + margin: 0; + } + .se-event-modal__title { + font-size: 15px; + margin: 0; + } + } + &__excerpt { + margin: 5px 0 0 8px; + font-size: 14px; + } + } +} \ No newline at end of file diff --git a/OLD/src/blocks/calendar/view.js b/OLD/src/blocks/calendar/view.js new file mode 100644 index 0000000..e3b410d --- /dev/null +++ b/OLD/src/blocks/calendar/view.js @@ -0,0 +1,15 @@ +import domReady from '@wordpress/dom-ready'; +import Calendar from './calendar'; + +/** + * DOM Ready + */ +domReady( () => { + /** + * Init Calendar + * + * @type {Calendar} + */ + const calendar = new Calendar(); + calendar.init(); +} ); diff --git a/OLD/src/blocks/common.scss b/OLD/src/blocks/common.scss new file mode 100644 index 0000000..5dc3cfa --- /dev/null +++ b/OLD/src/blocks/common.scss @@ -0,0 +1,60 @@ +/** + * #.# Common SCSS + * + * Can include things like variables and mixins + * that are used across the project. +*/ + +// Colors. +$black: rgb(41, 41, 41); +$white: #f4f4f4; +$gray: #dedede; +$green: #bada55; +$red: orangered; + +// Breakpoints +$breakpoint-mobile: 480px; +$breakpoint-tablet: 768px; +$breakpoint-desktop: 1024px; + +// Fonts Sizes +$font-size-xxs: 12px; +$font-size-xs: 14px; +$font-size-sm: 16px; +$font-size-md: 18px; +$font-size-lg: 20px; +$font-size-xl: 24px; +$font-size-xxl: 32px; + +// Spacer +$spacer-xxs: 4px; +$spacer-xs: 8px; +$spacer-sm: 12px; +$spacer-md: 16px; +$spacer-lg: 20px; +$spacer-xl: 24px; +$spacer-xxl: 32px; + +@mixin tablet { + @media (min-width: $breakpoint-tablet) { + @content; + } +} + +@mixin desktop-medium { + @media (min-width: $breakpoint-desktop) { + @content; + } +} + +@mixin max-tablet { + @media (max-width: $breakpoint-desktop) { + @content; + } +} + +@mixin max-mobile { + @media (max-width: $breakpoint-tablet) { + @content; + } +} diff --git a/OLD/src/blocks/countdown/block.json b/OLD/src/blocks/countdown/block.json new file mode 100644 index 0000000..c0711dc --- /dev/null +++ b/OLD/src/blocks/countdown/block.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/countdown", + "title": "Countdown", + "description": "Display a countdown to your next upcoming event.", + "icon": "clock", + "category": "simple-events", + "keywords": [ + "countdown", + "event", + "upcoming", + "Simple Events" + ], + "attributes": { + "className": { + "type": "string", + "default": "" + } + }, + "supports": { + "html": false, + "multiple": false + }, + "editorScript": "file:./index.js", + "style": "file:./style-index.css", + "viewScript": "file:./view.js" +} \ No newline at end of file diff --git a/OLD/src/blocks/countdown/index.js b/OLD/src/blocks/countdown/index.js new file mode 100644 index 0000000..16dcb7d --- /dev/null +++ b/OLD/src/blocks/countdown/index.js @@ -0,0 +1,44 @@ +/** + * BLOCK: Countdown + * + * Displays a countdown to the next upcoming post. + */ + +import './style.scss'; + +// Import JS dependencies. +import { __ } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; +import ServerSideRender from '@wordpress/server-side-render'; +import { useBlockProps } from '@wordpress/block-editor'; + + +registerBlockType( 'simple-events/countdown', { + edit: ( { attributes } ) => { + // Fire `simpleEventsCountdownTimer()` once the `#event-timer` element loads. + const loadTimerScript = () => { + if ( document.getElementById( 'event-timer' ) ) { + if ( typeof simpleEventsCountdownTimer === 'function' ) { + simpleEventsCountdownTimer(); // eslint-disable-line no-undef + } + } else { + setTimeout( () => loadTimerScript(), 100 ); + } + }; + + loadTimerScript(); + + return ( +
+ +
+ ); + }, + + save: () => { + return null; + }, +} ); diff --git a/OLD/src/blocks/countdown/style.scss b/OLD/src/blocks/countdown/style.scss new file mode 100644 index 0000000..1d910d3 --- /dev/null +++ b/OLD/src/blocks/countdown/style.scss @@ -0,0 +1,28 @@ +/** + * #.# Styles + * + * CSS for both Frontend+Backend. + */ +@import '../common.scss'; + +#event-timer { + display: flex; + justify-content: center; + margin: 2rem auto; + max-width: 350px; + padding: 2rem 0; + text-align: center; + + @include tablet { + margin: 3rem auto; + max-width: 550px; + } + + @include desktop-medium { + max-width: 50vw; + } + + .event-timer__col { + flex: 1 1 0; + } +} \ No newline at end of file diff --git a/OLD/src/blocks/countdown/view.js b/OLD/src/blocks/countdown/view.js new file mode 100644 index 0000000..a812450 --- /dev/null +++ b/OLD/src/blocks/countdown/view.js @@ -0,0 +1,62 @@ +/* eslint-disable no-bitwise */ +function simpleEventsCountdownTimer() { + const eventTimerElement = document.getElementById( 'event-timer' ); + + if ( ! eventTimerElement || ! eventTimerElement.dataset.eventStartDate ) { + if ( eventTimerElement ) { + eventTimerElement.remove(); + } + + return; + } + + const startDate = +eventTimerElement.dataset.eventStartDate; + let diff, days, hours, minutes, seconds; + const interval = setInterval( eventsTimer, 1000 ); + const daysElement = eventTimerElement.querySelector( + '.event-timer__time-days' + ); + const hoursElement = eventTimerElement.querySelector( + '.event-timer__time-hours' + ); + const minutesElement = eventTimerElement.querySelector( + '.event-timer__time-minutes' + ); + const secondsElement = eventTimerElement.querySelector( + '.event-timer__time-seconds' + ); + + function eventsTimer() { + // get the number of seconds that have elapsed since + diff = ( ( startDate - Date.now() ) / 1000 ) | 0; + + if ( diff <= 0 ) { + clearInterval( interval ); + diff = 0; + } + + days = ( diff / ( 3600 * 24 ) ) | 0; + diff -= days * 3600 * 24; + + hours = ( diff / 3600 ) | 0; + diff -= hours * 3600; + + minutes = ( diff / 60 ) | 0; + seconds = diff % 60 | 0; + + days = days < 10 ? '0' + days : days; + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + seconds = seconds < 10 ? '0' + seconds : seconds; + + daysElement.textContent = daysElement && days; + hoursElement.textContent = hoursElement && hours; + minutesElement.textContent = minutesElement && minutes; + secondsElement.textContent = secondsElement && seconds; + } + + // we don't want to wait a full second before the timer starts + eventsTimer(); +} + +simpleEventsCountdownTimer(); diff --git a/OLD/src/blocks/event-info/block.json b/OLD/src/blocks/event-info/block.json new file mode 100644 index 0000000..21872a9 --- /dev/null +++ b/OLD/src/blocks/event-info/block.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/event-info", + "title": "Event Information", + "icon": "calendar", + "category": "simple-events", + "keywords": [ + "event", + "information", + "Simple Events" + ], + "attributes": { + "eventVenue": { + "type": "string" + }, + "eventLocation": { + "type": "string" + }, + "eventDates": { + "type": "array" + }, + "eventDateStart": { + "type": "string" + }, + "eventDateEnd": { + "type": "string" + }, + "showOnFrontEnd": { + "type": "boolean", + "default": true + }, + "externalLinkLabel": { + "type": "string" + }, + "externalLink": { + "type": "string" + } + }, + "supports": { + "inserter": false, + "multiple": false, + "reusable": false, + "html": false + }, + "editorScript": "file:./index.js", + "editorStyle": "file:./index.css" +} diff --git a/OLD/src/blocks/event-info/editor-compat.scss b/OLD/src/blocks/event-info/editor-compat.scss new file mode 100644 index 0000000..74a9fce --- /dev/null +++ b/OLD/src/blocks/event-info/editor-compat.scss @@ -0,0 +1,30 @@ +/** + * #.# Back compat for Editor Styles + * + * CSS for just Backend enqueued after style.scss + * which makes it higher in priority. + */ + +.se-datepicker-compat { + .se-datetime-popover__date { + fieldset:first-child { + display: block; + } + + fieldset+fieldset { + display: none; + } + } + + .se-datetime-popover__time { + .components-datetime__time { + fieldset:first-child { + display: none; + } + + fieldset+fieldset { + display: block; + } + } + } +} \ No newline at end of file diff --git a/OLD/src/blocks/event-info/editor.scss b/OLD/src/blocks/event-info/editor.scss new file mode 100644 index 0000000..222e043 --- /dev/null +++ b/OLD/src/blocks/event-info/editor.scss @@ -0,0 +1,202 @@ +/** + * #.# Editor Styles + * + * CSS for just Backend enqueued after style.scss + * which makes it higher in priority. + */ + +.wp-block-simple-events-event-info { + .components-placeholder__fieldset { + flex-direction: column; + } + + .components-base-control { + margin: 0 0 8px; + text-align: left; + + &:last-of-type { + margin-bottom: 0; + + .components-base-control__field { + white-space: nowrap; + } + + .components-checkbox-control__input-container { + align-content: center; + align-items: center; + display: inline-flex; + height: 33px; + position: relative; + + .components-checkbox-control__input { + height: 20px; + min-width: 20px; + } + } + } + } + + .components-base-control__label { + display: block; + } +} + +.se__button-done { + align-self: flex-start; + margin-top: 10px; +} + +.se-datetime-popover { + .components-popover__content { + justify-content: center; + width: max-content; + padding: 1em; + position: relative; + + .components-datetime__date { + margin-top: 50px; + } + } + + .components-datetime__time { + padding-bottom: 0; + + fieldset { + margin-bottom: 0; + + legend { + display: none; + } + } + + .components-datetime__time-wrapper .components-datetime__time-field-time { + align-items: center; + display: flex; + } + + .components-datetime__time-field-am-pm { + white-space: nowrap; + } + } +} + +/* Date: remove time */ +.se-datetime-popover__date { + fieldset:first-child { + display: none; + } + + .components-datetime__time-field-month-select { + height: 100%; + } +} + +/* Time: remove date */ +.se-datetime-popover__time { + .components-datetime__time { + fieldset + fieldset { + margin-top: 10px; + } + } + + .components-datetime__timezone { + display: none; + } +} + +/* Set date/time button */ +.se-datetime-popover__set-datetime { + margin-top: 15px; + position: absolute; + top: 100px; +} + +.se-datetimegroup-controls-label { + display: flex; + font-weight: 700; + + + div { + margin-top: -4px; + } +} + +.se-datetimegroup-container { + border-bottom: 1px solid #e2e4e7; +} + +.se-datetimegroup-controls { + display: grid; + grid-template-columns: auto auto 70px; + grid-column-gap: 10px; + margin-top: 8px; + max-width: 450px; + + .components-dropdown { + width: 100%; + } + + .components-base-control:nth-of-type(3) { + flex: none; + align-self: flex-end; + margin-bottom: 10px; + margin-left: auto; + + .components-checkbox-control__input-container { + margin-right: 8px; + } + + label { + font-weight: normal; + font-size: 14px; + } + } + + .se-datetime-control__delete { + grid-column-start: 4; + margin-top: -68px; + margin-right: -50px; + margin-left: auto; + align-self: center; + } + + .se-datetime-popover__button { + width: 100%; + justify-content: center; + margin-bottom: 0; + margin-top: 0; + } + + .is-button.is-default:not(:disabled) { + border-color: #7e8993; + background-color: #fff; + color: #32373c; + } +} + +.se-datetime-addmore { + display: flex; + margin-top: 10px; + margin-bottom: 20px; +} + +.se-location-label { + max-width: 450px; + + label { + font-weight: 700; + } +} + +.se-site-timezone-label { + flex-direction: column; + font-size: 12px; + color: rgb(117, 117, 117); +} + +.se-event-calendar-export { + margin-top: 20px; +} + +.se-all-day-checkbox .components-flex { + align-items: center; +} \ No newline at end of file diff --git a/OLD/src/blocks/event-info/index.js b/OLD/src/blocks/event-info/index.js new file mode 100644 index 0000000..391407f --- /dev/null +++ b/OLD/src/blocks/event-info/index.js @@ -0,0 +1,1055 @@ +/* global lodash, ajaxurl */ +/** + * BLOCK: Events Info + * + * Event date and location management. + */ + +import './editor.scss'; + +import moment from 'moment'; +import { clone, isEqual, sortBy, head, last, pull } from 'lodash'; +import { __ } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; +import { Fragment } from '@wordpress/element'; +import { + PanelRow, + Placeholder, + BaseControl, + Dropdown, + Button, + TextControl, + Toolbar, + Disabled, + CheckboxControl, + ComboboxControl, + DateTimePicker, + PanelBody, + ToggleControl, +} from '@wordpress/components'; +import ServerSideRender from '@wordpress/server-side-render'; +import { getSettings } from '@wordpress/date'; +import { + BlockControls, + InspectorControls, + useBlockProps, +} from '@wordpress/block-editor'; +import { withState } from '@wordpress/compose'; +import { useEntityProp } from '@wordpress/core-data'; + +/** + * Constants + */ +const DEFAULT_START_HOUR = 9; +const DEFAULT_END_HOUR = 10; +const DATE_SETTINGS = getSettings(); // eslint-disable-line no-restricted-syntax + +const OFFSET = Number(DATE_SETTINGS.timezone.offset); +const TIMEZONE = DATE_SETTINGS.timezone.string; +let TIMEZONE_NAME = TIMEZONE; +if ('' === TIMEZONE) { + TIMEZONE_NAME = 'UTC' + (OFFSET >= 0 ? '+' : '') + OFFSET; +} +const FORMAT = 'YYYY-MM-DD HH:mm'; +const TIMEZONES = moment.tz + .names() + .map((tz) => ({ label: tz, value: tz })); + +// Add an option to use the site settings. +// (This label is as helpful as we can be since manual offsets have no string.) +TIMEZONES.unshift({ + label: __('Same as site', 'simple-events'), + value: '', +}); + +/** + * Get the start and end date from a collection of dates. + * Will remove any event that has passed. + * + * @param {{all_day: boolean, datetime_start: string, datetime_end: string}[]} dates The dates to check. + * + * returns {{ datetime_start: string, datetime_end: string }} + */ +const getStartAndEndDate = (dates) => { + // iterate over and remove any that has passed. + const now = moment().utcOffset(OFFSET); + const filteredDates = dates.filter((date) => { + + const endDate = moment.unix(date.datetime_end).utcOffset(OFFSET); + return endDate.isAfter(now); + }); + + // If we have no filtered dates, but we had dates, before. + if (filteredDates.length === 0 && dates.length > 0) { + // Extract all start dates with the offset. + const allStartDates = dates.map((date) => + moment.unix(date.datetime_start).utcOffset(OFFSET) + ); + const allEndDates = dates.map((date) => + moment.unix(date.datetime_end).utcOffset(OFFSET) + ); + + // Return the latest start date and earliest end date. + return { + datetime_start: moment.max(allStartDates).unix().toString(), + datetime_end: moment.max(allEndDates).unix().toString(), + } + } + + let startDate = null; + let endDate = null; + + // Loop over the dates and set the start date as the earliest and the end as the latest. + filteredDates.forEach((date) => { + const startDateMoment = moment.unix(date.datetime_start).utcOffset(OFFSET); + const endDateMoment = moment.unix(date.datetime_end).utcOffset(OFFSET); + + // If the end date has passed, skip it. + if (endDateMoment.isBefore(now)) { + return; + } + + /** + * Closure for setting the start or end date. + * @param {moment.Moment} startDateMoment + * @param {moment.Moment} endDateMoment + */ + const setDate = (startDateMoment, endDateMoment) => { + // If the start date is before the current start date, set it. + if (!startDate || startDateMoment.isBefore(startDate) || (startDate.isAfter(startDateMoment) && startDate.isBefore(now))) { + startDate = startDateMoment; + } + + // If the end date is after the current end date, set it. + if (!endDate || endDateMoment.isAfter(endDate)) { + endDate = endDateMoment; + } + }; + + // If the start date if after now + if (startDateMoment.isAfter(now) && endDateMoment.isAfter(now)) { + setDate(startDateMoment, endDateMoment); + } else if (startDateMoment.isBefore(now) && endDateMoment.isAfter(now)) { + setDate(startDateMoment, endDateMoment); + } + }); + + // If we have no startDate or endDate, just get the first from dates. + if (!startDate) { + startDate = moment.unix(head(filteredDates).datetime_start).utcOffset(OFFSET); + } + if (!endDate) { + endDate = moment.unix(last(filteredDates).datetime_end).utcOffset(OFFSET); + } + + return { + datetime_start: startDate.unix().toString(), + datetime_end: endDate.unix().toString(), + }; +} + + +/** + * Register: a Gutenberg Block. + * + * Registers a new block provided a unique name and an object defining its + * behavior. Once registered, the block is made editor as an option to any + * editor interface where blocks are implemented. + * + * @link https://wordpress.org/gutenberg/handbook/block-api/ + * @param {string} name Block name. + * @param {Object} settings Block settings. + * @return {?WPBlock} The block, if it has been successfully + * registered; otherwise `undefined`. + */ +registerBlockType('simple-events/event-info', { + /** + * The edit function describes the structure of your block in the context of the editor. + * This represents what the editor will render when the block is used. + * + * The "edit" property must be a valid function. + * + * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/ + * + * @param {Object} props Props. + * @return {JSX.Element} JSX Component. + */ + edit: (props) => { + const { attributes, setAttributes } = props; + const { editMode, showOnFrontEnd } = attributes; + + const [meta, setMeta] = useEntityProp( + 'postType', + 'se-event', + 'meta' + ); + + + // Sets the default timezone for calculations. + + let currentTimezone = meta?.se_event_timezone; + if ('' === currentTimezone) { + currentTimezone = TIMEZONE; + } + + const getDstOffset = (timestamp, timezone = null) => { + // Return no offset if the event timezone is the same as the site. + if (null === timezone) { + timezone = currentTimezone; + } + + if ('' === timezone) { + return OFFSET; + } + + // Get the timezone details. + const timezoneDetails = moment.tz.zone(timezone); + + // Get the index of the current timezone offset i.e DST or non-DST. -1 at the end to account for search algorithm. + const untilIndex = timezoneDetails.untils.findIndex(function ( + number + ) { + return number / 1000 > timestamp; + }); + + return timezoneDetails.offsets[untilIndex] * -1; + }; + + /** + * Creates a moment in the site timezone from the provided unix timestamp. + * + * @param {string} timestamp Timestamp to convert to a moment. + * @param {boolean} formatted Whether to return a human-readable formatted string. + * @return {Mixed} Human readable formatted string if `formatted` is true, + * moment object otherwise. + */ + const getMoment = (timestamp, formatted = false) => { + const dateTime = moment + .unix(timestamp) + .utcOffset(getDstOffset(timestamp)); + + if (!formatted) { + return dateTime; + } + + return dateTime.format(FORMAT); + }; + + /** + * Creates a timestamp from the provided date string. + * + * @param {string} dateTime Date string to convert to a timestamp. + * @return {string} The timestamp, cast as a string. + */ + const getTimestamp = (dateTime) => { + return String( + moment(dateTime) + .utcOffset( + getDstOffset(moment(dateTime).unix()), + true + ) + .utc() + .unix() + ); + }; + + const onDone = () => { + setAttributes({ editMode: false }); + }; + + const onChangeEventLocation = (value) => { + setMeta({ + ...meta, + se_event_location: value, + }); + }; + + const maybeUpdateEventDateTime = (oldDate, newDate) => { + if (!isEqual(oldDate, newDate)) { + const updatedDates = sortBy( + meta?.se_event_dates.map((item) => + item === oldDate ? newDate : item + ), + 'datetime_start' + ); + + setMeta({ + ...meta, + se_event_dates: updatedDates, + se_event_date_start: getStartAndEndDate(updatedDates).datetime_start, + se_event_date_end: getStartAndEndDate(updatedDates).datetime_end, + }); + } + }; + + const getBlockControls = () => ( + + + setAttributes({ editMode: !editMode }), + isActive: editMode, + }, + { + icon: showOnFrontEnd ? 'visibility' : 'hidden', + title: __('Show on Front-End?', 'simple-events'), + onClick: () => { + setAttributes({ + showOnFrontEnd: !showOnFrontEnd, + }); + setMeta({ + se_event_show_on_frontend: !showOnFrontEnd, + }); + }, + isActive: showOnFrontEnd, + }, + ]} + /> + + ); + + const DateTimeGroup = withState({ + tempEventDate: null, + tempEventTime: null, + })( + ({ + eventDateTime, + removeDate, + multiDay, + tempEventDate, + tempEventTime, + setState, + }) => { + const eventStart = getMoment( + eventDateTime.datetime_start, + true + ); + const eventEnd = getMoment(eventDateTime.datetime_end, true); + const timeFormat = DATE_SETTINGS.formats.datetime; + + // To know if the current timezone is a 12 hour time with look for an "a" in the time format. + // We also make sure this a is not escaped by a "/". + const is12HourTime = /a(?!\\)/i.test( + timeFormat + .toLowerCase() // Test only the lower case a + .replace(/\\\\/g, '') // Replace "//" with empty strings + .split('') + .reverse() + .join('') // Reverse the string and test for "a" not followed by a slash + ); + + /** + * Combines a given date and time into a moment object. + * + * @param {string} date The date to combine. + * @param {string} time The time to combine. + * + * @return {moment} The combined date and time. + */ + const combineDateAndTime = (date, time) => { + const timeMoment = moment(time); + const dateMoment = moment(date); + + // Set the timeMoment's time to the dateMoment. + return dateMoment.set({ + hour: timeMoment.get('hour'), + minute: timeMoment.get('minute'), + }); + }; + + /** + * Handle the set date and time button click. + * + * @param {boolean} isStartChange Whether this is start or end date change. + * + * @return {void} + */ + const setDateTimeHandler = (isStartChange) => { + // Ensure we have either new date or time in state. + if (!tempEventDate && !tempEventTime) { + return; + } + + const newDate = + tempEventDate || + (isStartChange ? eventStart : eventEnd); + const newTime = + tempEventTime || + (isStartChange ? eventStart : eventEnd); + + // Combine the new date and time and convert to a timestamp. + const newDateTime = getTimestamp( + combineDateAndTime(newDate, newTime) + ); + + const newEventDateTime = clone(eventDateTime); + + if (isStartChange) { + newEventDateTime.datetime_start = newDateTime; + + // Check if the new start time is after the cuurent end time. + if ( + parseInt(newEventDateTime.datetime_start) >= + parseInt(newEventDateTime.datetime_end) + ) { + // Set the new end time to be 1 hour after the start dateTime. + newEventDateTime.datetime_end = String( + parseInt(newEventDateTime.datetime_start) + + 3600 + ); + } + } else { + newEventDateTime.datetime_end = newDateTime; + + // Check if the new end time is before the current start time. + if ( + parseInt(newEventDateTime.datetime_start) >= + parseInt(newEventDateTime.datetime_end) + ) { + // Set the new start time to be 1 hour before the end dateTime. + newEventDateTime.datetime_start = String( + parseInt(newEventDateTime.datetime_end) - 3600 + ); + } + } + + // Reset the temp date and time. + setState({ + tempEventDate: null, + tempEventTime: null, + }); + + + maybeUpdateEventDateTime(eventDateTime, newEventDateTime); + }; + + /** + * Handles DateTimePicker changes. + * + * @param {string} currentDateTime The current dateTime. + * @param {string} newDateTime The new selected dateTime. + * + * @return {void} + */ + const datePickerHandler = (currentDateTime, newDateTime) => { + // Compare the date without time to see if the time or date was changed. + const isDateChange = + moment(currentDateTime).format('YYYY-MM-DD') === + moment(newDateTime).format('YYYY-MM-DD'); + const stateUpdate = isDateChange + ? { tempEventTime: newDateTime } + : { tempEventDate: newDateTime }; + setState(stateUpdate); + }; + + return ( +
+
+ + ( + + )} + renderContent={() => ( + + + datePickerHandler( + eventStart, + newDateTime + ) + } + __nextRemoveHelpButton + __nextRemoveResetButton + /> + + + )} + /> + + + ( + + )} + renderContent={() => ( + + + datePickerHandler( + eventEnd, + newDateTime + ) + } + __nextRemoveHelpButton + __nextRemoveResetButton + /> +
+ )} +
+ + ); + } + ); + + const EventDateTime = ({ dates }) => { + const addNewDate = () => { + const existingDates = + !dates || 0 === dates.length ? [] : dates; + + // Set default date and time. + let eventStart = moment().utcOffset(OFFSET); + + eventStart.hour(DEFAULT_START_HOUR); + eventStart.minute(0); + eventStart.second(0); + + let eventEnd = eventStart.clone(); + + eventEnd.hour(DEFAULT_END_HOUR); + + // Override with existing date if there is one. + if (existingDates.length) { + eventStart = getMoment( + last(existingDates).datetime_start + ); + eventEnd = getMoment(last(existingDates).datetime_end); + } + + // Set default date to be +1 day from the last date. + eventStart.add(1, 'days'); + eventEnd.add(1, 'days'); + + const updatedDates = sortBy( + [ + ...existingDates, + { + datetime_start: wp.date.date('U', eventStart), + datetime_end: wp.date.date('U', eventEnd), + all_day: false, + }, + ], + 'datetime_start' + ); + + setMeta({ + ...meta, + se_event_dates: updatedDates, + se_event_date_start: getStartAndEndDate(updatedDates).datetime_start, + se_event_date_end: getStartAndEndDate(updatedDates).datetime_end, + }); + }; + + const removeDate = (date) => { + if (!dates.length) { + return; + } + + const updatedDates = pull(dates, date); + + setMeta({ + ...meta, + se_event_dates: updatedDates, + se_event_date_start: getStartAndEndDate(updatedDates).datetime_start, + se_event_date_end: getStartAndEndDate(updatedDates).datetime_end, + }); + }; + + // If no dates, add a date. + if (!dates || 0 === dates.length) { + addNewDate(); + } + + const datesOutput = []; + + sortBy(dates, 'datetime_start').forEach((date, index) => { + datesOutput.push( + 1} + /> + ); + }); + + return ( + + + {__('Date & Time', 'simple-events')} + + {datesOutput} +
+ +
+
+ ); + }; + + const renderPreview = () => ( +
+ {getBlockControls()} + + + +
+ ); + + // Show editMode if no location or date set. + if ( + meta?.se_event_location.length === 0 && + (!meta?.se_event_dates || !meta?.se_event_dates?.length) + ) { + setAttributes({ editMode: true }); + } + + if (!editMode) { + return renderPreview(); + } + + return ( +
+ {getBlockControls()} + + + setMeta({ ...meta, se_event_venue: value })} + type="text" + /> + + + setMeta({ ...meta, se_event_external_link: url }) + } + type="url" + /> + {meta?.se_event_external_link && ( + <> + + setMeta({ + ...meta, + se_event_external_link_label: value, + }) + } + type="text" + /> + { + setMeta({ + ...meta, + se_open_external_link: value, + }); + }} + /> + + + )} + +
+ ); + }, + + /** + * The save function defines the way in which the different attributes should be combined + * into the final markup, which is then serialized by Gutenberg into post_content. + * + * The "save" property must be specified and must be a valid function. + * + * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/ + * + * @param {Object} props Props. + * @return {Mixed} JSX Frontend HTML. + */ + save: () => { + return null; + }, +}); diff --git a/OLD/src/blocks/event-tickets/block.json b/OLD/src/blocks/event-tickets/block.json new file mode 100644 index 0000000..62d9268 --- /dev/null +++ b/OLD/src/blocks/event-tickets/block.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/event-tickets", + "title": "Event Tickets", + "icon": "tickets-alt", + "category": "simple-events", + "keywords": [ + "event", + "tickets", + "Simple Events" + ], + "attributes": { + "selected": { + "type": "array" + } + }, + "supports": { + "inserter": true, + "multiple": false, + "reusable": false, + "html": false + }, + "editorScript": "file:./index.js", + "editorStyle": "file:./index.css", + "style": "file:./style-index.css" +} diff --git a/OLD/src/blocks/event-tickets/draggable/index.js b/OLD/src/blocks/event-tickets/draggable/index.js new file mode 100644 index 0000000..dbeed77 --- /dev/null +++ b/OLD/src/blocks/event-tickets/draggable/index.js @@ -0,0 +1,94 @@ +import { Icon } from '@wordpress/components'; +import { useRef } from '@wordpress/element'; +import { __experimentalUseDragging as useDragging } from '@wordpress/compose'; + +const DraggableItem = ( props ) => { + const sortableItemRef = useRef(); + + const onDragStart = ( event ) => { + const element = sortableItemRef.current; + const clone = event.target + .closest( '.se-draggable-item' ) + .cloneNode( true ); + + clone.classList.add( 'se-draggable-item_dragging-clone' ); + clone.style.top = `${ element.getBoundingClientRect().top }px`; + clone.style.width = `${ element.offsetWidth }px`; + element.classList.add( 'se-draggable-item_dragging' ); + element.parentElement.appendChild( clone ); + + document.body.classList.add( 'is-dragging-components-draggable' ); + }; + + const onDragMove = ( event ) => { + event.preventDefault(); + + const target = event.target.closest( '.se-draggable-item' ); + const clone = document.querySelector( + '.se-draggable-item_dragging-clone' + ); + const cursor = event.clientY; + const bounds = clone.parentElement.getBoundingClientRect(); + + if ( ! target || cursor < bounds.top || cursor > bounds.bottom ) { + return; + } + + target.after( sortableItemRef.current ); + + clone.style.top = `${ cursor - clone.clientHeight / 2 }px`; + }; + + const onDragEnd = () => { + sortableItemRef.current.classList.remove( + 'se-draggable-item_dragging' + ); + + document.querySelector( '.se-draggable-item_dragging-clone' ).remove(); + document.body.classList.remove( 'is-dragging-components-draggable' ); + + const sortableItems = sortableItemRef.current.parentElement.children; + const updatedOrder = [ ...sortableItems ].map( ( item ) => + Number( item.dataset.index ) + ); + + props.onChange( updatedOrder ); + }; + + const { startDrag } = useDragging( { + onDragStart, + onDragMove, + onDragEnd, + } ); + + const { className = '' } = props; + + return ( +
+
+
+ { props.children } +
+ ); +}; + +export default DraggableItem; diff --git a/OLD/src/blocks/event-tickets/editor.scss b/OLD/src/blocks/event-tickets/editor.scss new file mode 100644 index 0000000..a92fb3f --- /dev/null +++ b/OLD/src/blocks/event-tickets/editor.scss @@ -0,0 +1,371 @@ +/** + * #.# Editor Styles + * + * CSS for just Backend enqueued after style.scss + * which makes it higher in priority. + */ +.wp-block-simple-events-event-tickets { + .components-placeholder { + min-height: 0; + } + + .simple-events-tickets, + .se-selected-tickets, + .se-new-ticket { + +.components-button { + margin: 16px auto 0; + } + } + + .se-selected-tickets_list { + padding-left: 20px; + } + + .woocommerce-search-list { + padding-bottom: 0; + } + + .woocommerce-tag .woocommerce-tag__remove.components-icon-button, + .woocommerce-search-list__list .woocommerce-search-list__item { + height: auto; + } + + .se-mode-button-container { + display: flex; + width: 100%; + + .components-button.is-pressed, + .components-button.is-pressed:hover { + background: #ddd; + color: var(--wp-admin-theme-color); + } + } + + .woocommerce-search-list__search { + border-top: none; + margin-top: 0; + padding: 0; + } + + .woocommerce-search-list__list.is-not-found { + align-items: center; + display: flex; + justify-content: center; + } + + .components-button .woocommerce-tag__remove { + height: 40px; + padding: 6px 12px; + position: absolute; + right: -48px; + top: 0; + } + + .components-panel__body-title { + + span[aria-hidden='true'] svg { + display: none; + } + } + + .dashicons-edit, + svg.edit { + color: var(--wp-admin-theme-color); + fill: currentColor; + position: absolute; + right: 16px; + top: 50%; + transform: translateY(-50%); + transition: color .1s ease-in-out; + } + + .dashicons-edit { + right: 0; + } + + .components-panel__body.is-opened { + border-bottom: none; + padding-top: 0; + + .components-panel__body-title { + height: 0; + margin: 0; + + button:focus { + box-shadow: none; + } + + span, + .edit { + display: none; + } + } + + .se-ticket-data { + margin-top: 9px; + } + } + + .components-disabled { + opacity: .5; + + svg { + color: #000; + } + } + + .se-selected-tickets+.se-mode-button-container, + .se-selected-tickets+.simple-events-tickets { + margin-top: 50px; + } + + .se-ticket-data-container { + width: calc(100% - 32px); + padding-right: 0; + } + + .se-new-ticket { + margin: -1px 0 0 20px; + width: calc(100% - 52px); + } + + // Search list + .woocommerce-search-list__list .woocommerce-search-list__item { + &:hover { + background: var(--wp-admin-theme-color); + color: #fff; + } + + .woocommerce-search-list__item-state { + display: none; + } + } +} + +.se-ticket-data { + position: relative; + + .components-spinner { + float: none; + left: 0; + margin: 0 auto; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); + + } + + &_inner { + align-items: center; + display: grid; + grid-column-gap: 10px; + grid-row-gap: 8px; + grid-template-columns: 155px 155px 1fr; + margin-bottom: 20px; + width: 100%; + } + + &_name { + grid-column: 1 / -1; + } + + & &_stock-help { + align-items: center; + align-self: flex-end; + display: flex; + margin-bottom: 4px; + + .components-button { + margin: 0; + padding: 12px 6px; + } + } + + .se-help { + cursor: help; + height: 40px; + + svg { + margin: 10px 0; + } + } + + &_sale-price { + align-self: start; + + .components-base-control__label { + width: 100%; + } + } + + & &_sale-schedule, + & &_field-labels { + p { + margin: 0 0 8px; + } + } + + & &_sale-schedule { + .components-dropdown { + width: 100%; + } + + .components-button { + border: 1px solid #757575; + border-radius: 2px; + height: auto; + margin-bottom: 8px; + padding: 6px 8px; + width: 100%; + } + + .se-ticket-data_datetime-placeholder { + color: rgba(0, 0, 0, 0.5); + + &:active, + &:focus, + &:hover { + color: rgba(0, 0, 0, 0.5); + } + } + } + + & &_sale-help { + align-items: center; + display: flex; + margin-bottom: 17px; + + .components-button { + margin: 0; + padding: 12px 6px; + } + } + + &_additional-fields { + grid-column: 1 / -1; + + .editor-styles-wrapper &>p { + margin: 8px 0; + } + } + + &_field-labels { + display: grid; + grid-column-gap: 10px; + grid-template-columns: 155px 155px; + } + + &_additional-field { + align-items: center; + display: grid; + grid-column-gap: 10px; + grid-template-columns: 22px 155px 155px 1fr 44px; + margin: 0 0 8px -32px; + + .components-base-control .components-base-control__field { + margin-bottom: 0; + } + } + + .disabled * { + cursor: default; + } + + & &_additional-field-remove { + margin: 0; + } + + &_additional-field-options { + grid-column: 2 / 2; + margin-top: 8px; + } + + .components-base-control .components-base-control__help { + margin-bottom: 0; + } + + .components-disabled .components-base-control__help { + opacity: .5; + } +} + +.se-draggable-item { + &_dragging { + opacity: .5; + } + + #editor &_dragging-clone { + background: #fff; + pointer-events: none; + position: fixed; + z-index: 1000000000; + } + + body:not(.is-dragging-components-draggable) &_handle { + cursor: move; + display: flex; + } +} + +.se-selected-tickets { + width: 100%; + + &_header { + align-items: center; + display: flex; + justify-content: space-between; + + strong { + line-height: 1; + padding: 14px 0; + } + } + + .components-button { + padding: 12px 12px; + + span:last-of-type { + overflow: hidden; + padding-right: 34px; + text-overflow: ellipsis; + white-space: nowrap; + } + } + + &_list { + .editor-styles-wrapper &>p { + margin: 9px 0; + } + + >.components-spinner { + display: block; + float: none; + margin: 5px auto; + } + } + + &_list, + .se-selected-ticket { + position: relative; + } + + .se-selected-ticket { + margin-top: -1px; + + >.se-draggable-item_handle { + display: flex; + left: -32px; + padding: 12px 6px; + position: absolute; + top: 0; + } + } + + .se-selected-ticket.se-is-open { + >.se-draggable-item_handle { + display: none; + pointer-events: none; + } + } +} \ No newline at end of file diff --git a/OLD/src/blocks/event-tickets/index.js b/OLD/src/blocks/event-tickets/index.js new file mode 100644 index 0000000..6b616a8 --- /dev/null +++ b/OLD/src/blocks/event-tickets/index.js @@ -0,0 +1,371 @@ +/** + * BLOCK: Event Tickets + * + * Fetches tickets from WooCommerce. + */ +import './style.scss'; +import './editor.scss'; + +import SearchListControl from './search-list-control'; +import TicketDataControl from './ticket-data-control'; + +import { __, sprintf } from '@wordpress/i18n'; +import apiFetch from "@wordpress/api-fetch"; +import { registerBlockType } from '@wordpress/blocks'; +import { Placeholder, Button, Spinner } from '@wordpress/components'; +import { Fragment } from '@wordpress/element'; +import { addQueryArgs } from '@wordpress/url'; +import { withState } from '@wordpress/compose'; +import { useBlockProps } from '@wordpress/block-editor'; +import { flatten, uniqBy, debounce } from 'lodash'; + +const productCount = window.seSettings.productCount || 50; +const isLargeCatalog = window.seSettings.isLargeCatalog || false; +const isWCActive = window.seSettings.isWCActive || false; +const isBOActive = window.seSettings.isBOActive || false; + +const renderMissingDependencies = () => { + const dependencies = []; + + if ( ! isWCActive ) { + dependencies.push( 'WooCommerce' ); + } + + if ( ! isBOActive ) { + dependencies.push( 'WooCommerce Box Office' ); + } + + return dependencies.length ? ( +

+ { sprintf( + __( + '%s must be installed and active to use this block.', + 'simple-events' + ), + dependencies.join( __( ' and ', 'simple-events' ) ) + ) } +

+ ) : null; +}; + +/** + * Get a promise that resolves to a list of products from the API. + * + * @param {string} - A query string with the search term. + * @return {Array} - An array of products. + */ +const getProducts = async ( { selected = [], search = '' } ) => { + const postTypes = [ 'product', 'product_variation' ]; + const pageSize = 25; + let offset = 0; + let requests = []; + let queryArgs = null; + + while ( offset < productCount ) { + queryArgs = { + post_type: postTypes, + offset: offset, + per_page: pageSize, + status: 'publish', + search, + }; + + requests.push( addQueryArgs( 'simple-events/tickets', queryArgs ) ); + offset += pageSize; + } + + if ( selected.length ) { + requests.push( + addQueryArgs( 'simple-events/tickets', { + status: 'publish', + include: selected, + } ) + ); + } + + const data = await Promise.all( + requests.map( ( path ) => apiFetch( { path } ) ) + ); + + return uniqBy( flatten( data ), 'id' ).map( ( item ) => { + return { + id: parseInt( item.id, 10 ), + name: item.name, + }; + } ); +}; + +const TicketSelection = withState( { + loading: true, + selected: [], + products: [], + search: '', +} )( ( props ) => { + const { + setState, + setAttributes, + attributes, + loading, + selected, + products, + search, + } = props; + + + + // Read selected from attributes. + const savedSelected = attributes.selected ?? []; + const selectedCount = savedSelected.length; + + if ( selectedCount && ! selected.length ) { + setState( { selected: savedSelected } ); + } + + // Reload products if a new ticket has been added. + if ( attributes.newTicketAdded ) { + setState( { loading: true } ); + setAttributes( { newTicketAdded: false } ); + } + + // Load products. + if ( loading ) { + getProducts( { savedSelected, search } ) + .then( ( data ) => { + setState( { products: data, loading: false } ); + } ) + .catch( () => { + setState( { products: [], loading: false } ); + } ); + } + + const debounceSearch = debounce( ( searchValue ) => { + setState( { loading: true, search: searchValue } ); + }, 400 ); + + const onChange = ( ids ) => { + setState( { selected: ids } ); + setAttributes( { selected: ids } ); + }; + + const getSelectedProducts = ( items = products ) => { + return selected.map( ( id ) => + items.find( ( item ) => item.id === id ) + ); + }; + + const searchList = ( + + ! selected.includes( id ) && ! isNaN( id ) + ) + : products + } + selected={ + selected + ? products.filter( ( { id } ) => + selected.includes( id ) + ) + : [] + } + onChange={ ( items ) => { + let updatedSelected = selected; + + if ( items.length > selected.length ) { + updatedSelected.push( items.pop().id ); + } else { + updatedSelected = getSelectedProducts( items ) + .filter( Boolean ) + .map( ( { id } ) => id ); + } + + onChange( updatedSelected ); + } } + onSearch={ isLargeCatalog ? debounceSearch : null } + /> + + + ); + + const selectedList = ( +
+
+ { ! loading && 1 < selectedCount ? ( + + ) : null } +
+ +
+ { selectedCount && ( + + { loading || attributes.newTicketAdded ? ( + + ) : ( + getSelectedProducts().map( ( item, i ) => ( + { + const updatedSelected = selected; + + updatedSelected.splice( i, 1 ); + + onChange( updatedSelected ); + } } + onReorder={ ( reorderedSelected ) => { + setAttributes( { + selected: reorderedSelected, + } ); + } } + title={ item.name } + /> + ) ) + ) } + + ) } +
+
+ ); + + return ( + + { ! selectedCount ? ( +

+ { __( + 'No tickets have been added to this event.', + 'simple-events' + ) } +

+ ) : ( + selectedList + ) } + { attributes.searchMode && searchList } +
+ ); +} ); + +/** + * Register: a Gutenberg Block. + * + * Registers a new block provided a unique name and an object defining its + * behavior. Once registered, the block is made editor as an option to any + * editor interface where blocks are implemented. + * + * @link https://wordpress.org/gutenberg/handbook/block-api/ + * @param {string} name Block name. + * @param {Object} settings Block settings. + * @return {?WPBlock} The block, if it has been successfully + * registered; otherwise `undefined`. + */ +registerBlockType( 'simple-events/event-tickets', { + /** + * The edit function describes the structure of your block in the context of the editor. + * This represents what the editor will render when the block is used. + * + * The "edit" property must be a valid function. + * + * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/ + * + * @param {Object} props Props. + * @return {Mixed} JSX Component. + */ + edit: ( props ) => { + const { attributes, setAttributes } = props; + const { addMode, editMode, searchMode, selected } = attributes; + + return ( +
+ + { isWCActive && isBOActive ? ( + + + { addMode && ( + + setAttributes( { addMode: false } ) + } + onSave={ ( updatedSelected ) => + setAttributes( { + selected: updatedSelected, + newTicketAdded: true, + addMode: false, + } ) + } + /> + ) } + { ! addMode && ! editMode && ! searchMode && ( +
+ + +
+ ) } +
+ ) : ( + renderMissingDependencies() + ) } +
+
+ ); + }, + + /** + * The save function defines the way in which the different attributes should be combined + * into the final markup, which is then serialized by Gutenberg into post_content. + * + * The "save" property must be specified and must be a valid function. + * + * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/ + * + * @param {Object} props Props. + * @return {Mixed} JSX Frontend HTML. + */ + save: () => { + return null; + }, +} ); diff --git a/OLD/src/blocks/event-tickets/search-list-control/index.js b/OLD/src/blocks/event-tickets/search-list-control/index.js new file mode 100644 index 0000000..9a36413 --- /dev/null +++ b/OLD/src/blocks/event-tickets/search-list-control/index.js @@ -0,0 +1,163 @@ +/** + * Internal dependencies + */ +import SearchListItem from '@woocommerce/components/build-module/search-list-control/item'; + +/** + * External dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; +import { + MenuGroup, + Spinner, + TextControl, + Icon, + withSpokenMessages, +} from '@wordpress/components'; +import { Component } from '@wordpress/element'; +import { compose, withState } from '@wordpress/compose'; +import { escapeRegExp } from 'lodash'; + +const Messages = { + clear: __( 'Clear all selected tickets', 'simple-events' ), + list: __( 'Ticket Products', 'simple-events' ), + resultsList: __( 'Results', 'simple-events' ), + noItems: __( + "Your store doesn't have any ticket products.", + 'simple-events' + ), + noResults: __( 'No results for %s', 'simple-events' ), + search: __( 'Search for a ticket product:', 'simple-events' ), + updated: __( 'Ticket products search results updated.', 'simple-events' ), +}; + +/** + * Component to display a searchable, selectable list of items. + */ +export class SearchListControl extends Component { + constructor() { + super( ...arguments ); + + this.onSelect = this.onSelect.bind( this ); + this.renderList = this.renderList.bind( this ); + } + + componentDidUpdate( prevProps ) { + const { onSearch, search } = this.props; + + if ( search !== prevProps.search && typeof onSearch === 'function' ) { + onSearch( search ); + } + } + + onSelect( item ) { + const { onChange, selected } = this.props; + + return () => { + onChange( [ ...selected, item ] ); + }; + } + + getFilteredList( list, search ) { + if ( ! search ) { + return list; + } + + const re = new RegExp( escapeRegExp( search ), 'i' ); + + this.props.debouncedSpeak( Messages.updated ); + + const filteredList = list + .map( ( item ) => ( re.test( item.name ) ? item : false ) ) + .filter( Boolean ); + + return filteredList; + } + + renderList( list, depth = 0 ) { + const { search } = this.props; + + if ( ! list ) { + return null; + } + + return list.map( ( item ) => ( + + ) ); + } + + renderListSection() { + const { isLoading, search } = this.props; + + if ( isLoading ) { + return ( +
+ +
+ ); + } + + const list = this.getFilteredList( this.props.list, search ); + + if ( ! list.length ) { + return ( +
+
+ ); + } + + return ( + + { this.renderList( list ) } + + ); + } + + render() { + const { className = '', search, setState } = this.props; + + return ( +
+
+ setState( { search: value } ) } + /> +
+ + { this.renderListSection() } +
+ ); + } +} + +export default compose( [ + withState( { + search: '', + } ), + withSpokenMessages, +] )( SearchListControl ); diff --git a/OLD/src/blocks/event-tickets/style.scss b/OLD/src/blocks/event-tickets/style.scss new file mode 100644 index 0000000..c84ff66 --- /dev/null +++ b/OLD/src/blocks/event-tickets/style.scss @@ -0,0 +1,42 @@ +.wp-block-se-event-tickets { + &__heading { + margin: 0 0 32px; + } + + &__ticket-row { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + width: 100%; + margin: 0 0 16px; + } + + &__ticket-column { + display: flex; + flex-direction: column; + flex-basis: 100%; + + &--title { + flex: 3; + } + + &--price { + flex: 2; + } + + &--buy { + flex: 1; + } + } + + &__ticket-stock { + display: block; + opacity: 0.6; + font-size: .75em; + } + + &__button { + text-align: center; + } +} \ No newline at end of file diff --git a/OLD/src/blocks/event-tickets/ticket-data-control/index.js b/OLD/src/blocks/event-tickets/ticket-data-control/index.js new file mode 100644 index 0000000..3e0ba75 --- /dev/null +++ b/OLD/src/blocks/event-tickets/ticket-data-control/index.js @@ -0,0 +1,766 @@ +/** + * Internal dependencies + */ +import DraggableItem from '../draggable'; + +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; +import apiFetch from "@wordpress/api-fetch"; +import { + Button, + Disabled, + TextControl, + SelectControl, + CheckboxControl, + Spinner, + Dashicon, + PanelBody, + TimePicker, + Dropdown, + Tooltip, + TextareaControl, + Path, + SVG, +} from '@wordpress/components'; +import { Fragment } from '@wordpress/element'; +import { withState } from '@wordpress/compose'; +import { decodeEntities } from '@wordpress/html-entities'; +import { getSettings, date } from '@wordpress/date'; +import { concat, isEqual } from 'lodash'; +const md5 = require( 'md5' ); + +const BOTicketFieldTypes = window.seSettings.BOTicketFieldTypes || []; + +const fieldTypeOptions = () => { + const options = Object.entries( BOTicketFieldTypes ).map( + ( [ key, value ] ) => { + return { value: key, label: value }; + } + ); + + options.unshift( { value: '', label: __( 'Type', 'simple-events' ) } ); + + return options; +}; + +const removeIcon = ( + + + +); + +/** + * The block details interface. + * + * @param {*} param0 + * @return {Object} + */ +const TicketDataControl = ( { + dataLoaded, + editingProduct, + index, + loading, + name, + price, + saleData, + saleDateFrom, + saleDateTo, + salePrice, + stock, + additionalFields, + setState, + attributes, + setAttributes, + title, + onRemove, + onReorder, + onSave, +} ) => { + // Load data if this is an existing product being edited. + if ( editingProduct && ! dataLoaded ) { + setState( { + loading: true, + dataLoaded: true, + } ); + + apiFetch( { path: `/wc/v2/products/${ editingProduct }` } ).then( + ( response ) => { + const ticketFields = Object.values( + response.meta_data.find( + ( item ) => item.key === '_ticket_fields' + ).value + ); + + setState( { + name: response.name, + price: response.regular_price, + saleData: response.date_on_sale_from ? true : false, + saleDateFrom: response.date_on_sale_from, + saleDateTo: response.date_on_sale_to, + salePrice: response.sale_price, + stock: response.stock_quantity, + additionalFields: ticketFields, + loading: false, + } ); + } + ); + } + + /** + * Saves a new product post or updates an existing one. + */ + const saveProduct = async () => { + let path = '/wc/v2/products'; + + const productData = { + name, + regular_price: price, + sale_price: salePrice, + stock_quantity: stock, + meta_data: [], + }; + + if ( salePrice && saleData && saleDateFrom && saleDateTo ) { + productData.date_on_sale_from = `${ date( + 'Y-m-d', + saleDateFrom + ) }T00:00:00`; + productData.date_on_sale_to = `${ date( + 'Y-m-d', + saleDateTo + ) }T23:59:59`; + } + + const ticketFields = {}; + + additionalFields.forEach( + ( { label, type, required, options = '' } ) => { + if ( '' !== type ) { + const key = md5( label + type ); + ticketFields[ key ] = { + label, + type, + required, + options, + autofill: 'none', + email_contact: 'yes', + email_gravatar: 'yes', + }; + } + } + ); + + if ( Object.keys( ticketFields ).length !== 0 ) { + productData.meta_data.push( { + key: '_ticket_fields', + value: ticketFields, + } ); + } + + if ( ! editingProduct ) { + productData.virtual = true; + productData.meta_data.push( { key: '_ticket', value: 'yes' } ); + + if ( stock ) { + productData.manage_stock = true; + } + } + + if ( editingProduct ) { + path += `/${ editingProduct }`; + } + + return await apiFetch( { + path, + method: editingProduct ? 'PUT' : 'POST', + data: productData, + } ); + }; + + /** + * Update the given date with the new selection from TimePicker. + * + * @param {string} whichDate Which date to update. + * @param {string} oldDate The previous date value. + * @param {string} newDate The new date value. + */ + const maybeUpdateDateTime = ( whichDate, oldDate, newDate ) => { + if ( isEqual( oldDate, newDate ) ) { + return; + } + + if ( whichDate === 'From' ) { + setState( { saleDateFrom: newDate } ); + } + + if ( whichDate === 'To' ) { + setState( { saleDateTo: newDate } ); + } + }; + + /** + * The sale scheduling interface. + */ + const DateField = withState( { + tempDate: '', + } )( ( { label, value, tempDate, setState } ) => { + const settings = getSettings(); + const displayDate = tempDate ? tempDate : value; + + // To know if the current timezone is a 12 hour time with look for an "a" in the time format. + // We also make sure this a is not escaped by a "/". + const is12HourTime = /a(?!\\)/i.test( + settings.formats.time + .toLowerCase() // Test only the lower case a + .replace( /\\\\/g, '' ) // Replace "//" with empty strings + .split( '' ) + .reverse() + .join( '' ) // Reverse the string and test for "a" not followed by a slash + ); + + return ( + { + if ( tempDate ) { + // Send to the parent scope to update state there. + maybeUpdateDateTime( label, value, tempDate ); + setState( { tempDate: undefined } ); + } + } } + position="bottom center" + renderContent={ () => ( + + setState( { tempDate: newDate } ) + } + /> + ) } + renderToggle={ ( { isOpen, onToggle } ) => ( + + ) } + /> + ); + } ); + + /** + * Remove the field at the given index. + * (Done in this scope to ensure that the component updates.) + * + * @param {number} i The index of the field to remove. + */ + const removeFieldset = ( i ) => { + const updatedFields = additionalFields; + + updatedFields.splice( i, 1 ); + + setState( { additionalFields: updatedFields } ); + }; + + /** + * Displays the interface for adding or editing additional fields. + */ + const TicketFieldSet = withState( { + fields: [], + } )( ( { fields, setState, fieldset, index, onChange } ) => { + const defaultRequired = [ 'first_name', 'last_name', 'email' ].includes( + fieldset.type + ); + + return ( + + onChange( order.map( ( i ) => additionalFields[ i ] ) ) + } + > + { + const updatedFields = fields; + + updatedFields[ index ] = Object.assign( fieldset, { + label: value, + } ); + + setState( { fields: updatedFields } ); + } } + onBlur={ () => setState( { additionalFields: fields } ) } + /> + { + const updatedFields = additionalFields; + + updatedFields[ index ] = Object.assign( fieldset, { + type, + } ); + + setState( { additionalFields: updatedFields } ); + } } + /> + { + const updatedFields = additionalFields; + + updatedFields[ index ] = Object.assign( fieldset, { + required, + } ); + + setState( { additionalFields: updatedFields } ); + } } + /> + { ! defaultRequired && ( + + ) } + { [ 'select', 'radio', 'checkbox' ].includes( + fieldset.type + ) && ( + { + const updatedFields = fields; + + updatedFields[ index ] = Object.assign( fieldset, { + options: value, + } ); + + setState( { fields: updatedFields } ); + } } + onBlur={ () => + setState( { additionalFields: fields } ) + } + /> + ) } + + ); + } ); + + /** + * Adds a new additional field to the product. + */ + const addFieldset = () => { + const existingFields = additionalFields; + const updatedFields = concat( ...existingFields, { + label: '', + type: '', + required: false, + } ); + + setState( { additionalFields: updatedFields } ); + }; + + /** + * The product information form. + * @param name + * @param price + * @param stock + * @param salePrice + * @param e + */ + const ticketDataForm = ( + +
+ setState( { name } ) } + /> + + setState( { price } ) } + /> + + setState( { stock } ) } + /> + +
+ +
+ +
+
+ + { ! saleData && ( + + ) } +
+ + { saleData && ( + + + setState( { salePrice } ) + } + /> + +
+

{ __( 'Sale dates' ) }

+ + + + +
+ +
+ +
+ +
+
+ + +
+
+ ) } + +
+

+ + { __( 'Ticket Fields', 'simple-events' ) } + +

+
+
+

{ __( 'Label', 'simple-events' ) }

+

{ __( 'Type', 'simple-events' ) }

+
+ { additionalFields.map( ( field, index ) => ( + + setState( { additionalFields } ) + } + additionalFields={ additionalFields } + /> + ) ) } +
+ +
+
+ + +
+ ); + + const ticketDataFormContainer = ( +
+ { loading ? ( + + { ticketDataForm } + + + ) : ( + ticketDataForm + ) } +
+ ); + + const labelTextNode = ( + + { editingProduct ? ( + + + { __( 'Edit ', 'simple-events' ) } + + + + ) : ( + + { __( 'Create new ticket', 'simple-events' ) } + + ) } + + + + + + + ); + + const item = ( + + { editingProduct ? ( + + { + if ( attributes.editMode ) { + setAttributes( { editMode: null } ); + } else { + // Ensure that the most current data is loaded in. + setState( { dataLoaded: false } ); + + setAttributes( { editMode: editingProduct } ); + + // Set focus on the name field. + const ticketContainer = + document.activeElement.closest( + '.se-ticket-data-container' + ); + + const focusNameInput = () => { + const nameInput = + ticketContainer.querySelector( + '.se-ticket-data_name input' + ); + + if ( nameInput ) { + nameInput.focus(); + } else { + setTimeout( focusNameInput, 10 ); + } + }; + + focusNameInput(); + } + + setAttributes( { searchMode: false } ); + } } + title={ labelTextNode } + > + { ticketDataFormContainer } + + + ) : ( + + { ticketDataFormContainer } + + ) } + + ); + + return ( + + { ( attributes.editMode && + editingProduct !== attributes.editMode ) || + ( attributes.addMode && editingProduct ) ? ( + { item } + ) : ( + item + ) } + + ); +}; + +export default withState( { + dataLoaded: false, + loading: false, + name: '', + price: '', + saleData: false, + saleDateFrom: '', + saleDateTo: '', + salePrice: '', + stock: '', + additionalFields: [ + { + label: __( 'First Name', 'simple-events' ), + type: 'first_name', + required: true, + }, + { + label: __( 'Last Name', 'simple-events' ), + type: 'last_name', + required: true, + }, + { + label: __( 'Email Address', 'simple-events' ), + type: 'email', + required: true, + }, + ], +} )( TicketDataControl ); diff --git a/OLD/src/blocks/external-link/block.json b/OLD/src/blocks/external-link/block.json new file mode 100644 index 0000000..809ed90 --- /dev/null +++ b/OLD/src/blocks/external-link/block.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/external-link", + "title": "External Tickets", + "description": "Add a link to an external ticket website.", + "icon": "admin-links", + "category": "simple-events", + "keywords": ["event info", "tickets", "link", "Simple Events", "meta"], + "usesContext": ["postId"], + "attributes": { + "thePostId": { + "type": "integer", + "default": 0 + } + }, + "supports": { + "html": false + }, + "editorScript": "file:./index.js", + "editorStyle": "file:./index.css" +} diff --git a/OLD/src/blocks/external-link/editor.scss b/OLD/src/blocks/external-link/editor.scss new file mode 100644 index 0000000..6003dd2 --- /dev/null +++ b/OLD/src/blocks/external-link/editor.scss @@ -0,0 +1,3 @@ +.wp-block-se-event-link { + pointer-events: none; +} diff --git a/OLD/src/blocks/external-link/index.js b/OLD/src/blocks/external-link/index.js new file mode 100644 index 0000000..ee10a67 --- /dev/null +++ b/OLD/src/blocks/external-link/index.js @@ -0,0 +1,24 @@ +import './editor.scss'; +import metadata from './block.json'; + +import { useBlockProps } from '@wordpress/block-editor'; +import { registerBlockType } from '@wordpress/blocks'; +import ServerSideRender from '@wordpress/server-side-render'; + +registerBlockType( metadata, { + edit: ({ attributes: { thePostId }, context: { postId } }) => { + const blockProps = useBlockProps(); + + return ( +
+ +
+ ); + }, + save: (props) => null, +}); diff --git a/OLD/src/blocks/inner-blocks/block.json b/OLD/src/blocks/inner-blocks/block.json new file mode 100644 index 0000000..3a213c3 --- /dev/null +++ b/OLD/src/blocks/inner-blocks/block.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/inner-blocks", + "title": "Event Blocks", + "category": "simple-events", + "supports": { + "inserter": false, + "multiple": true, + "reusable": false, + "align": ["wide", "full"], + "layout": true + }, + "editorScript": "file:./index.js" +} diff --git a/OLD/src/blocks/inner-blocks/index.js b/OLD/src/blocks/inner-blocks/index.js new file mode 100644 index 0000000..4a6898e --- /dev/null +++ b/OLD/src/blocks/inner-blocks/index.js @@ -0,0 +1,25 @@ +/** + * BLOCK: Inner Blocks + * + * Single block that nests other blocks using the InnerBlocks component. + */ + +import './style.scss'; + +import { __ } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; +import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; + +registerBlockType( 'simple-events/inner-blocks', { + edit: () => { + return ( +
+ +
+ ); + }, + + save: () => { + return ; + }, +} ); diff --git a/OLD/src/blocks/inner-blocks/style.scss b/OLD/src/blocks/inner-blocks/style.scss new file mode 100644 index 0000000..20119f9 --- /dev/null +++ b/OLD/src/blocks/inner-blocks/style.scss @@ -0,0 +1,3 @@ +.block-editor-block-list__block[data-type='simple-events/inner-blocks']:not(.is-selected):not(.has-child-selected) .block-editor-default-block-appender { + display: block; +} \ No newline at end of file diff --git a/OLD/src/blocks/loop-event-info/block.json b/OLD/src/blocks/loop-event-info/block.json new file mode 100644 index 0000000..7a6d35f --- /dev/null +++ b/OLD/src/blocks/loop-event-info/block.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/loop-event-info", + "title": "Event Metadata", + "description": "Display event meta in a custom query loop.", + "icon": "tag", + "category": "simple-events", + "keywords": ["event info", "date", "location", "Simple Events", "meta"], + "usesContext": ["postId"], + "attributes": { + "textAlign": { + "type": "string", + "default": "left" + }, + "thePostId": { + "type": "integer", + "default": 0 + }, + "metaName": { + "enum": ["location", "venue", "dates", "date", "time"], + "type": "string", + "default": "dates" + }, + "metaPrefix": { + "type": "string", + "default": "" + }, + "addCalendarLinks": { + "type": "boolean" + } + }, + "supports": { + "html": false, + "align": true, + "typography": { + "fontSize": true, + "lineHeight": true, + "__experimentalFontFamily": true, + "__experimentalFontWeight": true, + "__experimentalFontStyle": true, + "__experimentalTextTransform": true, + "__experimentalTextDecoration": true, + "__experimentalLetterSpacing": true, + "__experimentalDefaultControls": { + "fontSize": true + } + }, + "spacing": { + "margin": true, + "padding": true, + "blockGap": true + }, + "color": { + "text": true + } + }, + "editorScript": "file:./index.js", + "editorStyle": "file:./editor.css", + "style": "file:./style.css" +} diff --git a/OLD/src/blocks/loop-event-info/editor.scss b/OLD/src/blocks/loop-event-info/editor.scss new file mode 100644 index 0000000..e69de29 diff --git a/OLD/src/blocks/loop-event-info/index.js b/OLD/src/blocks/loop-event-info/index.js new file mode 100644 index 0000000..e0bdfe6 --- /dev/null +++ b/OLD/src/blocks/loop-event-info/index.js @@ -0,0 +1,97 @@ +import './index.scss'; +import './editor.scss'; +import metadata from './block.json'; + +import { __ } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; +import { + PanelBody, + SelectControl, + TextControl, + ToggleControl, +} from '@wordpress/components' +import ServerSideRender from '@wordpress/server-side-render'; +import { + AlignmentControl, + useBlockProps, + InspectorControls, + BlockControls, +} from '@wordpress/block-editor'; + +registerBlockType(metadata, { + edit: ({ attributes: { metaName, metaPrefix, thePostId, textAlign, addCalendarLinks }, setAttributes, context: { postId } }) => { + return ( + <> + + + + setAttributes({ metaName: value }) + } + __nextHasNoMarginBottom + /> + + setAttributes({ metaPrefix: value }) + } + __nextHasNoMarginBottom + /> + + setAttributes({ addCalendarLinks: value } ) + } + /> + + + + { + setAttributes({ textAlign: nextAlign }); + }} + /> + +
+ +
+ + ); + }, + + /** + * The save function defines the way in which the different attributes should be combined + * into the final markup, which is then serialized by Gutenberg into post_content. + * + * The "save" property must be specified and must be a valid function. + * + * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/ + * + * @param {Object} props Props. + * @return {Mixed} JSX Frontend HTML. + */ + save: (props) => null, +}); diff --git a/OLD/src/blocks/loop-event-info/index.scss b/OLD/src/blocks/loop-event-info/index.scss new file mode 100644 index 0000000..e69de29 diff --git a/OLD/src/blocks/past-events-notice/block.json b/OLD/src/blocks/past-events-notice/block.json new file mode 100644 index 0000000..e7e12c2 --- /dev/null +++ b/OLD/src/blocks/past-events-notice/block.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/past-events-notice", + "title": "Past Events Notice", + "description": "Display the notice message set in the Simple Events settings.", + "icon": "megaphone", + "category": "simple-events", + "keywords": ["past-events", "notice", "Simple Events"], + "supports": { + "html": false, + "align": true, + "typography": { + "fontSize": true, + "lineHeight": true + }, + "spacing": { + "margin": true, + "padding": true, + "blockGap": true + }, + "color": { + "text": true + } + }, + "editorScript": "file:./index.js" +} diff --git a/OLD/src/blocks/past-events-notice/index.js b/OLD/src/blocks/past-events-notice/index.js new file mode 100644 index 0000000..60db2b2 --- /dev/null +++ b/OLD/src/blocks/past-events-notice/index.js @@ -0,0 +1,21 @@ +/* global seSettings */ +import { registerBlockType } from "@wordpress/blocks"; +import { InnerBlocks } from "@wordpress/block-editor"; + +import metadata from "./block.json"; + +registerBlockType( metadata, { + edit: () => ( + + ), + save: () => ( + + ) +} ); diff --git a/OLD/src/blocks/upcoming-events/block.json b/OLD/src/blocks/upcoming-events/block.json new file mode 100644 index 0000000..e2018ee --- /dev/null +++ b/OLD/src/blocks/upcoming-events/block.json @@ -0,0 +1,67 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "simple-events/upcoming-events", + "title": "Events Feed", + "description": "Display upcoming events, past events or events between a date range.", + "icon": "layout", + "category": "simple-events", + "keywords": [ + "event", + "upcoming", + "Simple Events" + ], + "attributes": { + "className": { + "type": "string", + "default": "" + }, + "count": { + "type": "number", + "default": 10 + }, + "columns": { + "type": "number", + "default": 3 + }, + "layout": { + "type": "string", + "default": "list" + }, + "align": { + "type": "string", + "default": "" + }, + "feedType": { + "type": "string", + "default": "upcoming", + "enum": [ "upcoming", "past", "mixed", "range" ] + }, + "showYearDividers": { + "type": "boolean", + "default": false + }, + "overrideFeedOrder": { + "type": "boolean", + "default": false + }, + "feedOrder": { + "type": "string", + "default": "ASC", + "enum": [ "ASC", "DESC" ] + }, + "dateRange": { + "type": "object", + "default": { + "from": "", + "to": "" + } + } + }, + "supports": { + "html": false, + "align": [ "wide", "full" ] + }, + "editorScript": "file:./index.js", + "style": "file:./index.css" +} diff --git a/OLD/src/blocks/upcoming-events/index.js b/OLD/src/blocks/upcoming-events/index.js new file mode 100644 index 0000000..76482c3 --- /dev/null +++ b/OLD/src/blocks/upcoming-events/index.js @@ -0,0 +1,279 @@ +/** + * BLOCK: Upcoming Events + * + * Displays upcoming event posts. + */ +import './index.scss'; + +import { __ } from '@wordpress/i18n'; +import { registerBlockType } from '@wordpress/blocks'; +import { + Disabled, + PanelBody, + RangeControl, + ToolbarGroup, + SelectControl, + TimePicker, + BaseControl, + Button, + Dropdown, + ToggleControl, +} from '@wordpress/components'; +import ServerSideRender from '@wordpress/server-side-render'; +import { + InspectorControls, + BlockControls, + useBlockProps, + InnerBlocks, +} from '@wordpress/block-editor'; +import { list, grid, edit } from '@wordpress/icons'; +import { useState } from '@wordpress/element'; + +registerBlockType( 'simple-events/upcoming-events', { + edit: ( { attributes, setAttributes } ) => { + const { count, layout, columns, feedType, feedOrder, overrideFeedOrder, showYearDividers, dateRange } = attributes; + + const [ noEvents, setNoEvents ] = useState( false ); + + return ( +
+ + + + setAttributes( { layout: value } ) + } + __nextHasNoMarginBottom + /> + { 'grid' === layout && ( + + setAttributes( { columns: value } ) + } + min={ 1 } + max={ 4 } + /> + ) } + + + + + setAttributes( { feedType: value } ) + } + /> + { 'range' === feedType && ( + <> + + ( + + ) } + renderContent={ () => { + return ( + + setAttributes( { + dateRange: { + ...dateRange, + from: value, + }, + } ) + } + /> + ); + } } + /> + + + ( + + ) } + renderContent={ () => { + return ( + + setAttributes( { + dateRange: { + ...dateRange, + to: value, + }, + } ) + } + /> + ); + } } + /> + + + ) } + + setAttributes( { count: value } ) + } + min={ 1 } + max={ 50 } + /> + setAttributes( { showYearDividers: value } ) } + /> + setAttributes( { overrideFeedOrder: value } ) } + /> + { overrideFeedOrder && setAttributes( { feedOrder: value } ) } + /> } + + + + + setAttributes( { layout: 'list' } ), + isActive: layout === 'list', + }, + { + icon: grid, + title: __( 'Grid view', 'simple-events' ), + onClick: () => + setAttributes( { layout: 'grid' } ), + isActive: layout === 'grid', + }, + { + icon: edit, + title: __( + 'Edit "no results" view', + 'simple-events' + ), + onClick: () => setNoEvents( ! noEvents ), + isActive: noEvents, + }, + ] } + /> + + { noEvents ? ( + + ) : ( + + + + ) } +
+ ); + }, + + /** + * The save function defines the way in which the different attributes should be combined + * into the final markup, which is then serialized by Gutenberg into post_content. + * + * The "save" property must be specified and must be a valid function. + * + * @link https://wordpress.org/gutenberg/handbook/block-api/block-edit-save/ + * + * @param {Object} props Props. + * @return {Mixed} JSX Frontend HTML. + */ + save: ( props ) => , +} ); diff --git a/OLD/src/blocks/upcoming-events/index.scss b/OLD/src/blocks/upcoming-events/index.scss new file mode 100644 index 0000000..b2fb45e --- /dev/null +++ b/OLD/src/blocks/upcoming-events/index.scss @@ -0,0 +1,71 @@ +@import '../common.scss'; + +.wp-block-se-upcoming-events { + ul { + list-style: none; + margin: 0; + padding: 0; + + .se-event-date { + font-weight: bold; + } + + .se-event-location { + margin-bottom: 1rem; + } + + li { + h2.entry-title { + font-size: max( 2.5rem, 28px ); + + a { + color: var(--wp--preset--color--primary, #28303d); + + &:hover { + text-decoration: underline; + } + } + } + + > a { + background: var(--wp--preset--color--primary, #28303d); + color: var(--wp--preset--color--white, #fff); + padding: 1rem 1.5rem; + display: inline-block; + font-size: max( 1rem, 16px ); + text-transform: uppercase; + text-decoration: none; + letter-spacing: 0.05em; + font-weight: bold; + + &:hover { + background: var(--wp--preset--color--black, #000); + } + } + } + } + + &-view-grid { + ul { + display: grid; + grid-template-columns: 1fr; + gap: 20px; + } + @include tablet { + &.wp-block-se-upcoming-events-columns-2 ul, + &.wp-block-se-upcoming-events-columns-3 ul, + &.wp-block-se-upcoming-events-columns-4 ul { + grid-template-columns: 1fr 1fr; + } + } + @include desktop-medium { + &.wp-block-se-upcoming-events-columns-3 ul { + grid-template-columns: 1fr 1fr 1fr; + } + + &.wp-block-se-upcoming-events-columns-4 ul { + grid-template-columns: 1fr 1fr 1fr 1fr; + } + } + } +} diff --git a/OLD/src/calendar-functions.php b/OLD/src/calendar-functions.php new file mode 100644 index 0000000..90c7ec2 --- /dev/null +++ b/OLD/src/calendar-functions.php @@ -0,0 +1,292 @@ +format( 'F Y' ); + } catch ( Exception $e ) { + return ''; + } +} + +/** + * Returns element classes based on particular day. + * + * @param array $day_data Day's data. + * + * @return string + */ +function se_get_day_element_classes( $day_data ): string { + $classes = array( 'simple-events-calendar-month__day' ); + + if ( $day_data['is_other_month'] ) { + $classes[] = 'simple-events-calendar-month__day--other-month'; + } + + if ( $day_data['is_previous_month'] ) { + $classes[] = 'simple-events-calendar-month__day--previous-month'; + } + + if ( $day_data['is_next_month'] ) { + $classes[] = 'simple-events-calendar-month__day--next-month'; + } + + if ( $day_data['is_past'] ) { + $classes[] = 'simple-events-calendar-month__day--past'; + } + + if ( $day_data['is_today'] ) { + $classes[] = 'simple-events-calendar-month__day--today simple-events-calendar-month__day--active'; + } + + if ( ! $day_data['is_past'] ) { + $classes[] = 'simple-events-calendar-month__day--upcoming'; + } + + if ( ! empty( $day_data['events'] ) ) { + $classes[] = 'simple-events-calendar-month__day--has-events'; + } + + return implode( ' ', $classes ); +} + +/** + * Returns element classes based on particular day. + * + * @param array $day_data Day's data. + * + * @return string + */ +function se_get_day_mobile_classes( $day_data ): string { + + $classes = array( 'simple-events-calendar-month-mobile-events__mobile-day' ); + + if ( $day_data['is_today'] ) { + $classes[] = 'simple-events-calendar-month-mobile-events__mobile-day--active'; + } + + return implode( ' ', $classes ); +} + +/** + * Returns the mobile day id. + * + * @param array $day_data Day's data. + * + * @return string + */ +function se_get_mobile_day_id( $day_data ): string { + return sprintf( 'simple-events-calendar-mobile__day-%s', $day_data['date_formatted'] ); +} + + +/** + * Determines if the event should be hidden based on the given block and day attributes. + * + * @param array $attributes The attributes of the event. + * @param array $day The day of the event. + * + * @return boolean Returns true if the event should be hidden, false otherwise. + */ +function se_hide_event( $attributes, $day ): bool { + if ( ! $attributes['hideNeighbourEvents'] ) { + return false; + } + + return $day['is_previous_month'] || $day['is_next_month']; +} + +/** + * Verify if any of the attributes are valid colors. + * + * @param array $attributes The attributes to be checked. + * @param string $prefix The prefix for the attribute keys. + * + * @return boolean Returns true if any of the attributes are valid colors, false otherwise. + */ +function se_verify_attributes( $attributes, $prefix ): bool { + $text_color_bool = isset( $attributes[ $prefix . 'Color' ] ) && sanitize_hex_color( $attributes[ $prefix . 'Color' ] ); + $bg_color_bool = isset( $attributes[ $prefix . 'Bg' ] ) && sanitize_hex_color( $attributes[ $prefix . 'Bg' ] ); + $border_color_bool = isset( $attributes[ $prefix . 'Border' ] ) && sanitize_hex_color( $attributes[ $prefix . 'Border' ] ); + + if ( $text_color_bool || $bg_color_bool || $border_color_bool ) { + return true; + } + + return false; +} + +/** + * Generates the customized CSS for repeated elements based on the given attributes. + * + * @param array $attributes The attributes used to generate the CSS. + * @param string $prefix The prefix to use for attribute keys. + * @param string &$customized_css The CSS string to append the generated CSS to. + * + * @return string The updated customized CSS string. + */ +function se_generate_repeated_css( $attributes, $prefix, &$customized_css ): string { + + if ( isset( $attributes[ $prefix . 'Color' ] ) && sanitize_hex_color( $attributes[ $prefix . 'Color' ] ) ) { + $customized_css .= sprintf( + '.simple-events-calendar-month__calendar-event-title-link { + color: %1$s; + } + color: %1$s;', + sanitize_hex_color( $attributes[ $prefix . 'Color' ] ) + ); + } + + if ( isset( $attributes[ $prefix . 'Bg' ] ) && sanitize_hex_color( $attributes[ $prefix . 'Bg' ] ) ) { + $customized_css .= sprintf( 'background-color: %s;', sanitize_hex_color( $attributes[ $prefix . 'Bg' ] ) ); + } + + if ( isset( $attributes[ $prefix . 'Border' ] ) && sanitize_hex_color( $attributes[ $prefix . 'Border' ] ) ) { + $customized_css .= sprintf( 'border-color: %s;', sanitize_hex_color( $attributes[ $prefix . 'Border' ] ) ); + } + + $customized_css .= "}}\n"; + + return $customized_css; +} + +/** + * Applies customizations to the simple events calendar based on the provided attributes. + * + * @param array $attributes The attributes used to customize the calendar. + * + * @return string The customized CSS string. + */ +function se_apply_customization( $attributes ): string { + + $customized_css = ''; + + if ( se_verify_attributes( $attributes, 'upcomingDays' ) ) { + // Customization for Upcoming Days + $customized_css .= '.simple-events-calendar { + .simple-events-calendar-month__day--upcoming {'; + + se_generate_repeated_css( $attributes, 'upcomingDays', $customized_css ); + } + + if ( se_verify_attributes( $attributes, 'eventDays' ) ) { + // Customization for Event Days + $customized_css .= '.simple-events-calendar { + .simple-events-calendar-month__day--has-events {'; + + se_generate_repeated_css( $attributes, 'eventDays', $customized_css ); + } + + if ( se_verify_attributes( $attributes, 'presentDay' ) ) { + // Customization for Present Day + $customized_css .= '.simple-events-calendar { + .simple-events-calendar-month__day--active {'; + + se_generate_repeated_css( $attributes, 'presentDay', $customized_css ); + } + + if ( se_verify_attributes( $attributes, 'pastDays' ) ) { + // Customization for Past Days + $customized_css .= '.simple-events-calendar { + .simple-events-calendar-month__day--past {'; + + se_generate_repeated_css( $attributes, 'pastDays', $customized_css ); + } + + if ( isset( $attributes['monthYearColor'] ) && sanitize_hex_color( $attributes['monthYearColor'] ) ) { + // Customization for Month Year + $customized_css .= sprintf( + '.simple-events-top-bar, + .simple-events-calendar .simple-events-top-bar__today-button { + color: %s !important; + }', + esc_attr( $attributes['monthYearColor'] ) + ); + } + + if ( isset( $attributes['arrowColor'] ) && sanitize_hex_color( $attributes['arrowColor'] ) ) { + // Customization for Arrow + $customized_css .= sprintf( + '.simple-events-calendar .simple-events-top-bar nav ul li a, + .simple-events-calendar .simple-events-top-bar nav ul li svg, + .simple-events-calendar .simple-events-mobile__nav-list-item a { + color: %s; + }', + esc_attr( $attributes['arrowColor'] ) + ); + } + + if ( isset( $attributes['eventDotColor'] ) && sanitize_hex_color( $attributes['eventDotColor'] ) ) { + // Customization for Arrow Hover + $customized_css .= sprintf( + '.simple-events-calendar .simple-events-calendar-month__mobile-events-icon { + background-color: %s; + }', + esc_attr( $attributes['eventDotColor'] ) + ); + } + + if ( isset( $attributes['modalBgColor'] ) && sanitize_hex_color( $attributes['modalBgColor'] ) ) { + // Customization for Modal + $customized_css .= sprintf( + '.simple-events-calendar .simple-events-calendar-month__events .se-event-modal { + background-color: %s; + }', + esc_attr( $attributes['modalBgColor'] ) + ); + } + + if ( isset( $attributes['modalTextColor'] ) && sanitize_hex_color( $attributes['modalTextColor'] ) ) { + // Customization for Modal + $customized_css .= sprintf( + '.simple-events-calendar .simple-events-calendar-month__events .se-event-modal, + .simple-events-calendar .simple-events-calendar-month__events .se-event-modal h6 { + color: %s; + }', + esc_attr( $attributes['modalTextColor'] ) + ); + } + + if ( isset( $attributes['modalIconColor'] ) && sanitize_hex_color( $attributes['modalIconColor'] ) ) { + // Customization for Modal + $customized_css .= sprintf( + '.simple-events-calendar .simple-events-calendar-month__events .se-event-modal .dashicons:before { + color: %s; + }', + esc_attr( $attributes['modalIconColor'] ) + ); + } + + return $customized_css; +} diff --git a/OLD/src/classes/class-se-admin.php b/OLD/src/classes/class-se-admin.php new file mode 100644 index 0000000..ad438f5 --- /dev/null +++ b/OLD/src/classes/class-se-admin.php @@ -0,0 +1,81 @@ + false, + 'strategy' => 'async', + ) + ); + } + + /** + * Add a new column to the se-event admin page. + * + * @param array $columns The array of existing columns in the event list table. + * + * @return array The modified array of columns. + */ + public static function customize_event_columns( $columns ) { + $columns['event-date-time'] = esc_html__( 'Event Date/Time', 'simple-events' ); + $columns['event-location'] = esc_html__( 'Event Location', 'simple-events' ); + return $columns; + } + + /** + * Add custom data to the se-event admin page for custom columns. + * + * @param string $column Column key of Admin Panel. + * @param integer $post_id Post ID of the row in the Admin Panel. + * + * @return void + */ + public static function customize_event_columns_data( $column, $post_id ) { + switch ( $column ) { + case 'event-date-time': + echo wp_kses_post( se_event_get_formatted_dates( $post_id ) ); + break; + case 'event-location': + $location = se_event_get_location( $post_id ); + echo esc_html( $location ? $location : '-' ); + break; + } + } +} + +SE_Admin::init(); diff --git a/OLD/src/classes/class-se-block-variations.php b/OLD/src/classes/class-se-block-variations.php new file mode 100644 index 0000000..3a4ed18 --- /dev/null +++ b/OLD/src/classes/class-se-block-variations.php @@ -0,0 +1,170 @@ +parsed_block = $parsed_block; + + if ( $this->is_events_variation( $parsed_block ) ) { + add_filter( 'query_loop_block_query_vars', array( $this, 'build_query' ), 10, 1 ); + } + } + + /** + * Return a custom query based on attributes, filters and global WP_Query. + * + * @param WP_Query $query The WordPress Query. + * + * @return WP_Query + */ + public function build_query( $query ) { + $parsed_block = $this->parsed_block; + if ( ! $this->is_events_variation( $parsed_block ) ) { + return $query; + } + + $query['sub-type'] = self::QUERY_LOOP_EVENTS; + + if ( ! isset( $parsed_block['attrs']['query']['feedType'] ) ) { + $parsed_block['attrs']['query']['feedType'] = 'default'; + } + + $feed_type = $parsed_block['attrs']['query']['feedType']; + $feed_order = $parsed_block['attrs']['query']['order']; + + // Inherit taxonomy query from global WP_Query if in taxonomy archive context + if ( ! empty( $parsed_block['attrs']['query']['inheritTaxQuery'] ) ) { + global $wp_query; + if ( is_tax() && ! empty( $wp_query->tax_query ) ) { + $query['tax_query'] = $wp_query->tax_query->queries; + } + } + + return $this->set_event_query_args( $query, $feed_type, $feed_order ); + } + + /** + * Set the query args for the event loop query admin. + * + * @param mixed $args The arguments for the query. + * @param mixed $request The request object. + * + * @return mixed The result of the set event query args. + */ + public function set_admin_query( $args, $request ) { + + $feed_type = $request->get_param( 'feedType' ); + $feed_order = $request->get_param( 'order' ); + + return $this->set_event_query_args( $args, $feed_type, $feed_order ); + } + + /** + * Set the Event Query Loop Args. + * + * @param mixed $args The arguments for the query. + * @param mixed $feed_type The feed type. + * @param mixed $feed_order The feed order. + * + * @return mixed The result of the set event query args. + */ + private function set_event_query_args( $args, $feed_type, $feed_order = 'ASC' ) { + + if ( 'upcoming' === $feed_type ) { + $args['meta_query'] = array( + array( + 'key' => 'se_event_date_end', + 'value' => wp_date( 'U' ), + 'compare' => '>=', + ), + ); + + $args['orderby'] = 'meta_value'; + $args['meta_key'] = 'se_event_date_start'; + $args['order'] = $feed_order; + } + + if ( 'past' === $feed_type ) { + $args['meta_query'] = array( + array( + 'key' => 'se_event_date_end', + 'value' => wp_date( 'U' ), + 'compare' => '<', + ), + ); + + $args['orderby'] = 'meta_value'; + $args['meta_key'] = 'se_event_date_start'; + $args['order'] = $feed_order; + } + + /** + * A filter to customize the args of the event query loop. + * + * @param array $args The built args passed in to the query. + * @param string|null $feed_type The feed type. + * @param string|null $feed_order The feed order. + */ + return apply_filters( 'se_pre_set_event_query_loop_args', $args, $feed_type, $feed_order ); + } +} + +( new SE_Block_Variations() )->init(); diff --git a/OLD/src/classes/class-se-blocks.php b/OLD/src/classes/class-se-blocks.php new file mode 100644 index 0000000..bdf2f6f --- /dev/null +++ b/OLD/src/classes/class-se-blocks.php @@ -0,0 +1,898 @@ + +
+

+ npm install', + 'npm run build', + '' . esc_html( str_replace( ABSPATH, '', SE_PLUGIN_DIR ) ) . '' + ); + ?> +

+
+ 'simple-events', + 'title' => esc_html__( 'Simple Events', 'simple-events' ), + ), + ) + ); + } + + /** + * Enqueue block assets. + * + * @return void + */ + public static function block_assets() { + + // JS globals. + $block_settings = array(); + + if ( class_exists( 'WooCommerce' ) ) { + $product_counts = wp_count_posts( 'product' ); + + $block_settings['isWCActive'] = true; + $block_settings['isLargeCatalog'] = $product_counts->publish > 200; + $block_settings['productCount'] = $product_counts->publish; + + if ( class_exists( 'WC_Box_Office' ) ) { + $block_settings['isBOActive'] = true; + } + + if ( function_exists( 'wc_box_office_ticket_field_types' ) ) { + $block_settings['BOTicketFieldTypes'] = wc_box_office_ticket_field_types(); + } + } + + $options = get_option( 'se_options' ); + $value = isset( $options['past_event_notice'] ) ? $options['past_event_notice'] : esc_html__( 'Event has passed', 'simple-events' ); + + // For Past events notice block. + $block_settings['pastEventsNotice'] = $value; + $block_settings['postType'] = get_post_type(); + + wp_localize_script( + 'wp-blocks', + 'seSettings', + $block_settings + ); + + if ( file_exists( SE_PLUGIN_DIR . '/build/variations/index.asset.php' ) ) { + $variations = include_once SE_PLUGIN_DIR . '/build/variations/index.asset.php'; + + wp_enqueue_script( + 'se-block-variations', + SE_PLUGIN_URL . '/build/variations/index.js', + $variations['dependencies'], + $variations['version'], + true + ); + } + } + + /** + * Register blocks. + * + * @return void + */ + public static function register_block_type() { + // Event Info. + register_block_type( + SE_PLUGIN_DIR . '/build/blocks/event-info', + array( + 'render_callback' => array( __CLASS__, 'event_info_render' ), + ) + ); + + // Event Tickets. + register_block_type( + SE_PLUGIN_DIR . '/build/blocks/event-tickets', + array( + 'render_callback' => array( __CLASS__, 'event_tickets_render' ), + ) + ); + + // Inner Blocks. + register_block_type( SE_PLUGIN_DIR . '/build/blocks/inner-blocks' ); + + // Upcoming Events. + register_block_type( + SE_PLUGIN_DIR . '/build/blocks/upcoming-events', + array( + 'render_callback' => array( __CLASS__, 'upcoming_events_render' ), + ) + ); + + // Next Event Countdown. + register_block_type( + SE_PLUGIN_DIR . '/build/blocks/countdown', + array( + 'render_callback' => array( __CLASS__, 'countdown_render' ), + ) + ); + + // Calendar View. + register_block_type( + SE_PLUGIN_DIR . '/build/blocks/calendar', + array( + 'render_callback' => array( __CLASS__, 'calendar_render' ), + ) + ); + + // Event meta in query loop. + register_block_type( + SE_PLUGIN_DIR . '/build/blocks/loop-event-info', + array( + 'render_callback' => array( __CLASS__, 'loop_event_info_render' ), + ) + ); + + // Event external links. + register_block_type( + SE_PLUGIN_DIR . '/build/blocks/external-link', + array( + 'render_callback' => array( __CLASS__, 'loop_event_external_link_render' ), + ) + ); + + // Past Events Notice + register_block_type( + SE_PLUGIN_DIR . '/build/blocks/past-events-notice', + array( + 'render_callback' => array( __CLASS__, 'past_events_notice_render' ), + ) + ); + } + + + /** + * Render event info block. + * + * @param array $attributes The attributes for the event. + * @param string $content The content of the event. + * @param object $block The block object. + * + * @return HTML The rendered event information. + */ + public static function event_info_render( $attributes, $content, $block ) { + + // Check if we're looking at the block on the front-end. + if ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) { + // If yes, check if we're supposed to show the block on the front-end. + if ( false === $attributes['showOnFrontEnd'] ) { + return ''; + } + } + + $post_ID = isset( $block->context['postId'] ) ? $block->context['postId'] : get_the_ID(); + + $output = ''; + + // Event time / date. + $event_dates = get_post_meta( $post_ID, 'se_event_dates', true ); + + // Previewing? + if ( ! empty( $attributes['eventDates'] ) ) { + $event_dates = $attributes['eventDates']; + } + + // Set up timezone. Defaults to site settings if the post has no timezone meta. + $event_timezone = get_post_meta( $post_ID, 'se_event_timezone', true ); + + // Previewing? + if ( isset( $attributes['eventTimezone'] ) ) { + $event_timezone = $attributes['eventTimezone']; + } + + $dates_output = ''; + + if ( ! empty( $event_dates ) ) { + $dates_count = count( $event_dates ); + $date_heading = '

' . _n( 'Date', 'Dates', $dates_count, 'simple-events' ) . '

'; + + /** + * Filter the markup used for the date heading. + * + * @param string $date_heading The HTML used to display the date heading. + * @param int $dates_count The number of event dates. + */ + $dates_output .= apply_filters( 'se_event_info_date_heading', $date_heading, $dates_count ); + $dates_output .= se_event_get_formatted_dates( $post_ID, false, false, $event_dates ); + } + + // Event location. + $event_location = get_post_meta( $post_ID, 'se_event_location', true ); + $event_venue = get_post_meta( $post_ID, 'se_event_venue', true ); + + $event_link = get_post_meta( $post_ID, 'se_event_external_link', true ); + $event_link_label = get_post_meta( $post_ID, 'se_event_external_link_label', true ); + + // Previewing? + if ( isset( $attributes['eventLocation'] ) ) { + $event_location = $attributes['eventLocation']; + } + + if ( isset( $attributes['eventVenue'] ) ) { + $event_venue = $attributes['eventVenue']; + } + + // Previewing? + if ( isset( $attributes['externalLink'] ) ) { + $event_link = $attributes['externalLink']; + } + + if ( isset( $attributes['externalLinkLabel'] ) ) { + $event_link_label = $attributes['externalLinkLabel']; + } + + if ( ! empty( $dates_output ) ) { + $output .= '
'; + + if ( ! empty( $dates_output ) ) { + $output .= $dates_output; + } + + if ( ! empty( $event_venue ) ) { + $output .= '

' . __( 'Venue', 'simple-events' ) . '

'; + $output .= '

' . wp_kses_post( $event_venue ) . '

'; + } + + if ( ! empty( $event_location ) ) { + $output .= '

' . __( 'Location', 'simple-events' ) . '

'; + $output .= '

' . wp_kses_post( $event_location ) . '

'; + } + + if ( ! empty( $event_link ) ) { + $cta = apply_filters( 'se_event_external_link_text', $event_link_label, $event_link ); + + $output .= '

' . $cta . '

'; + } + + $output .= '
'; + } + + // Add "Add to calendar links" if the attribute is set to true. + $calendar_links = get_post_meta( $post_ID, 'se_event_add_calendar_links', true ); + if ( $calendar_links ) { + $output .= se_template_calendar_links( false ); + } + + return apply_filters( 'simple_events_event_info_render', $output, $event_dates, $event_timezone, $event_location, $attributes ); + } + + /** + * Render event tickets block. + * + * @param array $attributes The attributes for the event. + * + * @return HTML The rendered event information. + */ + public static function event_tickets_render( $attributes = array() ) { + $output = ''; + + if ( ! empty( $attributes['selected'] ) ) { + $output .= '
'; + $output .= '
'; + $output .= '

' . __( 'Tickets', 'simple-events' ) . '

'; + + $available_tickets = ''; + $unavailable_tickets = ''; + + foreach ( $attributes['selected'] as $product ) { + $product = wc_get_product( (int) $product ); + + if ( ! $product ) { + continue; + } + + if ( $product->is_type( 'variable' ) ) { + $variations = $product->get_available_variations(); + + foreach ( $variations as $variation ) { + $variation = wc_get_product( $variation['variation_id'] ); + + if ( ! $variation ) { + continue; + } + + $ticket_render = self::render_ticket( $variation ); + + if ( $ticket_render['available'] ) { + $available_tickets .= $ticket_render['output']; + } else { + $unavailable_tickets .= $ticket_render['output']; + } + } + } else { + $ticket_render = self::render_ticket( $product ); + + if ( $ticket_render['available'] ) { + $available_tickets .= $ticket_render['output']; + } else { + $unavailable_tickets .= $ticket_render['output']; + } + } + } + + $output .= $available_tickets; + $output .= $unavailable_tickets; + $output .= '
'; + $output .= '
'; + } + + return apply_filters( 'simple_events_event_tickets_render', $output, $attributes ); + } + + /** + * Render single ticket. + * + * @param WC_Product $product WooCommerce product. + * + * @return array + */ + private static function render_ticket( $product ) { + + $name = $product->get_name(); + $price = wc_price( $product->get_price() ); + $stock = ( $product->managing_stock() ? $product->get_stock_quantity() : false ); + + $available = 'outofstock' !== $product->get_stock_status() && ! empty( $stock ) && 0 < $stock; + + $row_class = 'wp-block-se-event-tickets__ticket-row'; + $row_class .= ( $available ) ? '' : ' wp-block-se-event-tickets__ticket-row--unavailable'; + + $product_output = '
'; + $product_output .= '
' . $name . '
'; + + $product_output .= '
'; + $product_output .= $price; + + /* translators: %s: number tickets in stock */ + $product_output .= '' . sprintf( __( '%s available', 'simple-events' ), 0 < $stock ? $stock : 0 ) . ''; + $product_output .= '
'; + + $product_output .= '
'; + + if ( $available ) { + $attributes = array( + /* translators: %s: event title */ + 'aria-label' => sprintf( __( 'Buy ticket "%s"', 'simple-events' ), $product->get_name() ), + 'rel' => 'nofollow', + 'class' => 'wp-block-se-event-tickets__button button add_to_cart_button', + ); + + $button = sprintf( + '%s', + esc_url( $product->get_permalink() ), + wc_implode_html_attributes( $attributes ), + esc_html( __( 'Buy Ticket', 'simple-events' ) ) + ); + + $product_output .= $button; + } else { + $product_output .= __( 'No longer available for sale', 'simple-events' ); + } + + $product_output .= '
'; + $product_output .= '
'; + + return array( + 'available' => $available, + 'output' => $product_output, + ); + } + + /** + * Render upcoming events block. + * + * @param array $attributes Block attributes. + * @param string $content Block content. + * + * @return HTML Upcoming events render. + */ + public static function upcoming_events_render( $attributes = array(), $content = '' ) { + $events_query_args = array(); + $events_query = null; + $output = ''; + + if ( ! empty( $attributes['count'] ) ) { + + // By default shows the "mixed" feed type (no meta_query). + $events_query_args = array( + 'post_type' => SE_Event_Post_Type::$post_type, + 'post_status' => 'publish', + 'posts_per_page' => absint( $attributes['count'] ), + ); + + // Handle "future events" feed type + if ( 'upcoming' === $attributes['feedType'] ) { + $events_query_args['meta_query'] = array( + array( + 'key' => 'se_event_date_end', + 'value' => wp_date( 'U' ), + 'compare' => '>=', + ), + ); + } + + // Handle "past events" feed type + if ( 'past' === $attributes['feedType'] ) { + $events_query_args['meta_query'] = array( + array( + 'key' => 'se_event_date_end', + 'value' => wp_date( 'U' ), + 'compare' => '<=', + ), + ); + } + + // Handle "range" feed type + if ( + 'range' === $attributes['feedType'] + && ! empty( $attributes['dateRange']['from'] ) + && ! empty( $attributes['dateRange']['to'] ) + ) { + $events_query_args['meta_query'] = array( + array( + 'key' => 'se_event_date_start', + 'value' => strtotime( $attributes['dateRange']['from'] ), + 'compare' => '>=', + ), + array( + 'key' => 'se_event_date_end', + 'value' => strtotime( $attributes['dateRange']['to'] ), + 'compare' => '<=', + ), + ); + } + + // If feed order is overridden, set the order to custom query var. + if ( ! empty( $attributes['overrideFeedOrder'] ) ) { + $events_query_args['se_event_order'] = $attributes['feedOrder']; + } + + $show_year_dividers = ! empty( $attributes['showYearDividers'] ); + + $events_query = new \WP_Query( $events_query_args ); + + if ( $events_query->have_posts() ) { + $container_class[] = 'wp-block-se-upcoming-events'; + $container_class[] = 'wp-block-se-upcoming-events-view-' . $attributes['layout']; + $container_class[] = 'wp-block-se-upcoming-events-columns-' . $attributes['columns']; + $container_class[] = 'align' . $attributes['align']; + $container_class[] = ( ! empty( $attributes['className'] ) ) ? $attributes['className'] : ''; + $current_year = ''; + + $output .= '
'; + $output .= '
    '; + + while ( $events_query->have_posts() ) { + $events_query->the_post(); + + if ( $show_year_dividers ) { + $year_output = self::get_year_divider( get_the_ID(), $current_year ); + $current_year = $year_output['current_year']; + $output .= $year_output['output']; + } + + $output .= SE_TEMPLATE_LOADER::get_template_part( 'content', 'archive', true, array(), true ); + } + $output .= '
'; + $output .= '
'; + } else { + // If nothing was found, output the inner blocks. + $output = $content; + } + + wp_reset_postdata(); + } + + /** + * A filter to customize the render of the upcoming-events block. + * + * @param string $output The output html. May be an empty string. + * @param WP_Query $events_query The query object used to generate the output. + * @param array $events_query_args The built args passed in to the query. + * @param array $attributes The attributes passed to the block renderer. + */ + return apply_filters( 'se_upcoming_events_render', $output, $events_query, $events_query_args, $attributes ); + } + + /** + * Get year divider markup for events list. + * + * @param integer $post_id The post ID. + * @param string $current_loop_year The current year in the loop. + * + * @return array + */ + public static function get_year_divider( $post_id, $current_loop_year ): array { + $event_year = get_post_meta( $post_id, 'se_event_date_start', true ); + $post_year = gmdate( 'Y', $event_year ); + $output = ''; + + if ( $current_loop_year !== $post_year ) { + $output .= '
  • ' . esc_html( $post_year ) . '
  • '; + } + + return array( + 'output' => $output, + 'current_year' => $post_year, + ); + } + + /** + * Render next event countdown block. + * + * @param array $attributes The attributes passed to the block renderer. + * + * @return HTML Countdown render. + */ + public static function countdown_render( $attributes = array() ) { + $output = ''; + + $events_query_args = array( + 'se_countdown' => true, + 'post_type' => SE_Event_Post_Type::$post_type, + 'post_status' => 'publish', + 'posts_per_page' => 1, + 'orderby' => 'meta_value', + 'meta_key' => 'se_event_date_start', + 'order' => 'ASC', + 'meta_query' => array( + array( + 'key' => 'se_event_date_start', + 'value' => wp_date( 'U' ), + 'compare' => '>=', + ), + ), + ); + + $events_query = new \WP_Query( $events_query_args ); + + $event_id = ( 'se-event' === get_post_type( get_the_ID() ) ) ? get_the_ID() : false; + + if ( $events_query->have_posts() ) { + ob_start(); + + while ( $events_query->have_posts() ) { + $events_query->the_post(); + + $container_class = 'wp-block-se-next-event-countdown'; + $container_class .= ( ! empty( $attributes['className'] ) ) ? ' ' . $attributes['className'] : ''; + + $start_date = get_post_meta( get_the_ID(), 'se_event_date_start', true ); + + /** + * Adding filter to manage the use of countdown block in events single post (CPT). + */ + $start_date = apply_filters( 'se_countdown_start_date', $start_date, $event_id ); + + $time_until_start = $start_date * 1000; + ?> +
    +
    +

    00

    +

    days

    +
    +
    +

    00

    +

    hours

    +
    +
    +

    00

    +

    minutes

    +
    +
    +

    00

    +

    seconds

    +
    +
    + create_date_time( 'now' ); + $previous_date_time = SE_Calendar::get_instance()->get_previous_month_with_events( $current_date_time ); + $next_date_time = SE_Calendar::get_instance()->get_next_month_with_events( $current_date_time ); + + $current_date = $current_date_time->format( 'Y-m-01' ); + $month_data = SE_Calendar::get_instance()->get_month_days( $current_date ); + + if ( ! $month_data['month_has_events'] ) { + if ( $next_date_time ) { + $current_date = $next_date_time->format( 'Y-m-01' ); + $month_data = SE_Calendar::get_instance()->get_month_days( $current_date ); + $next_date_time = SE_Calendar::get_instance()->get_next_month_with_events( $next_date_time ); + } elseif ( $previous_date_time ) { + $current_date = $previous_date_time->format( 'Y-m-01' ); + $month_data = SE_Calendar::get_instance()->get_month_days( $current_date ); + $previous_date_time = SE_Calendar::get_instance()->get_previous_month_with_events( $previous_date_time ); + } + } + + // Passing Attributes to the calendar block. Required as the API request replaces the block attribute with default array + wp_add_inline_script( 'simple-events-calendar-view-script', 'const attributes = ' . wp_json_encode( $attributes ) . ';', 'before' ); + + $output = SE_Template_Loader::get_template_part( + 'calendar/calendar', + 'container', + true, + array( + 'attributes' => $attributes, + 'current_date' => $current_date, + 'days' => $month_data['days'], + 'month_has_events' => $month_data['month_has_events'], + 'previous_date' => $previous_date_time?->format( 'Y-m-01' ), + 'next_date' => $next_date_time?->format( 'Y-m-01' ), + ), + true + ); + + return apply_filters( 'simple_events_calendar_render', $output ); + } + + /** + * Renders the loop event info block. + * + * @param array $attributes Block attributes. + * @param string $content Block default content. + * @param WP_Block $block Block instance. + * + * @return string Returns the filtered post date for the current post wrapped inside "time" tags. + */ + public static function loop_event_info_render( $attributes, $content, $block ): string { + + $output = ''; + $prefix = ''; + $post_ID = ( isset( $attributes['thePostId'] ) && $attributes['thePostId'] > 0 ) ? $attributes['thePostId'] : $block->context['postId']; + + if ( isset( $attributes['metaPrefix'] ) ) { + $prefix = '' . esc_html( $attributes['metaPrefix'] ) . ''; + } + + // Generate output based on meta name. + if ( ! empty( $post_ID ) ) { + switch ( $attributes['metaName'] ) { + case 'location': + $output = se_event_get_location( $post_ID ); + break; + case 'venue': + $output = se_event_get_venue( $post_ID ); + break; + case 'dates': + $output = se_event_get_future_dates( $post_ID ); + break; + case 'date': + $output = se_event_get_future_dates( $post_ID, true, false ); + break; + case 'time': + $output = se_event_get_future_dates( $post_ID, false, true ); + break; + } + } + + // If post ID is empty at this point, we're in the FSE editor. + if ( empty( $post_ID ) ) { + // Generate placeholder output based on meta name. + switch ( $attributes['metaName'] ) { + case 'location': + $output = esc_html__( 'Example Location Name', 'simple-events' ); + break; + case 'venue': + $output = esc_html__( 'Example Venue Name', 'simple-events' ); + break; + case 'dates': + $output = esc_html__( 'June 20, 2023 9:00 am - 10:00 am', 'simple-events' ); + break; + case 'date': + $output = esc_html__( 'June 28, 2023', 'simple-events' ); + break; + case 'time': + $output = esc_html__( '9:00 am - 10:00 am', 'simple-events' ); + break; + } + } + + // Add calendar links if the attribute is set to true. + if ( isset( $attributes['addCalendarLinks'] ) && $attributes['addCalendarLinks'] ) { + $output .= se_template_calendar_links( false ); + } + + // Add gutenberg generated wrapper atts. + $output = sprintf( + '
    %s%s
    ', + get_block_wrapper_attributes( + array( + 'class' => 'has-text-align-' . esc_attr( $attributes['textAlign'] ), + ) + ), + $prefix, + $output + ); + + return apply_filters( 'simple_events_loop_info_render', $output, $attributes, $content, $block ); + } + + /** + * Renders the loop external link block. + * + * @param array $attributes Block attributes. + * @param string $content Block default content. + * @param WP_Block $block Block instance. + * + * @return string Returns the html for the link block. + */ + public static function loop_event_external_link_render( $attributes, $content, $block ): string { + $post_ID = ( isset( $attributes['thePostId'] ) && $attributes['thePostId'] > 0 ) ? $attributes['thePostId'] : $block->context['postId']; + + if ( ! $post_ID ) { + return sprintf( + '%s', + esc_html__( 'Tickets', 'simple-events' ) + ); + } + + $has_meta = get_post_meta( $post_ID, 'se_event_external_link', true ); + $event_link = $has_meta ? $has_meta : get_the_permalink( $post_ID ); + $link_text = $has_meta ? __( 'Tickets', 'simple-events' ) : __( 'Details', 'simple-events' ); + $cta = apply_filters( 'se_event_loop_external_link_text', $link_text, $has_meta ); + $link_target = $has_meta && ! strstr( wp_parse_url( $has_meta, PHP_URL_HOST ), wp_parse_url( get_site_url(), PHP_URL_HOST ) ) ? 'target="_blank" rel="nofollow"' : ''; + + if ( ! $event_link ) { + return ''; + } + + $output = sprintf( + '%s', + esc_url( $event_link ), + $link_target, + esc_html( $cta ) + ); + + return apply_filters( 'simple_events_loop_link_render', $output, $attributes, $content, $block ); + } + + /** + * Renders the notice for past events. + * + * @param array $attributes The attributes passed to the function. + * @param string $content The content passed to the function. + * + * @return void + */ + public static function past_events_notice_render( $attributes, $content ) { + if ( + 'se-event' !== get_post_type() || // If not an event. + ! se_event_is_expired( get_the_ID() ) || // If event has expired. + defined( 'REST_REQUEST' ) // If event is being edited. + ) { + return; + } + + return wp_kses_post( $content ); + } + + /** + * Loads the asset file for the given script or style. + * Returns a default if the asset file is not found. + * + * @param string $file_path The name of the file without the extension. + * + * @return array The asset file contents. + */ + public static function get_asset_file( $file_path ) { + $asset_path = SE_PLUGIN_DIR . $file_path . '.asset.php'; + + return file_exists( $asset_path ) + ? include $asset_path + : array( + 'dependencies' => array(), + 'version' => SE_VERSION, + ); + } + + /** + * Add custom query vars. + * + * @param array $vars The current query vars. + * + * @return array $vars The updated query vars. + */ + public static function add_event_query_vars( $vars ) { + $vars[] = 'se_event_order'; + + return $vars; + } +} + +SE_Blocks::init(); diff --git a/OLD/src/classes/class-se-calendar-export.php b/OLD/src/classes/class-se-calendar-export.php new file mode 100644 index 0000000..6fc8db7 --- /dev/null +++ b/OLD/src/classes/class-se-calendar-export.php @@ -0,0 +1,116 @@ + SE_Event_Post_Type::$post_type, + 'post_status' => 'publish', + 'posts_per_page' => 10, + 'fields' => 'ids', + ); + + $events = get_posts( apply_filters( 'se_calendar_export_query_args', $events_query_args ) ); + } + + // Get dates. + if ( ! empty( $events ) ) { + foreach ( $events as $event_id ) { + $event_dates = se_event_get_dates( $event_id ); + + foreach ( $event_dates as $event_date ) { + $v_event = new \Eluceo\iCal\Component\Event(); + + if ( empty( $event_date['datetime_start'] ) || empty( $event_date['datetime_end'] ) ) { + continue; + } + + $date_start = new \DateTime(); + $date_start->setTimestamp( $event_date['datetime_start'] ); + + $date_end = new \DateTime(); + $date_end->setTimestamp( $event_date['datetime_end'] ); + + $v_event + ->setDtStart( $date_start ) + ->setDtEnd( $date_end ) + ->setSummary( se_event_get_title( $event_id ) ); + + // Ensure we're working with a boolean. + $event_date['all_day'] = filter_var( $event_date['all_day'], FILTER_VALIDATE_BOOLEAN ); + + if ( $event_date['all_day'] ) { + $v_event->setNoTime( true ); + } + + $v_calendar->addComponent( $v_event ); + } + } + } + + header( 'Content-Type: text/calendar; charset=utf-8' ); + header( 'Content-Disposition: attachment; filename="cal.ics"' ); + + echo $v_calendar->render(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped + + exit; + } +} + +SE_Calendar_Export::init(); diff --git a/OLD/src/classes/class-se-calendar.php b/OLD/src/classes/class-se-calendar.php new file mode 100644 index 0000000..b13db20 --- /dev/null +++ b/OLD/src/classes/class-se-calendar.php @@ -0,0 +1,452 @@ + array( 'POST' ), + 'callback' => array( $this, 'api_get_month_days' ), + 'permission_callback' => function () { + return true; + }, + ) + ); + } + + /** + * Return an array with the days of the week, numbered with respect to the start_of_week WP option + * + * @param string $format The display format for the days of the week. + * + * @return array Days of the week. + **@category Events + */ + public function simple_events_get_days_of_week( $format = null ) { + global $wp_locale; + + for ( $i = 0; $i <= 6; $i++ ) { + $day = $wp_locale->get_weekday( $i ); + $weekdays['full'][ $i ] = $day; + $weekdays['short'][ $i ] = $wp_locale->get_weekday_abbrev( $day ); + $weekdays['initial'][ $i ] = $wp_locale->get_weekday_initial( $day ); + } + + switch ( $format ) { + case 'min': + $days_of_week = $weekdays['initial']; + break; + + case 'short': + $days_of_week = $weekdays['short']; + break; + + default: + $days_of_week = $weekdays['full']; + break; + } + + $start_of_week = get_option( 'start_of_week', 0 ); + for ( $i = 0; $i < $start_of_week; $i++ ) { + $day = $days_of_week[ $i ]; + unset( $days_of_week[ $i ] ); + $days_of_week[ $i ] = $day; + } + + return apply_filters( 'simple_events_get_days_of_week', $days_of_week ); + } + + + /** + * A function to create a DateTime object with an optional timezone. + * + * @param mixed $date_time The date and time to create the object from. + * @param string|null $timezone The optional timezone to use for the object. If null, the site timezone is used. + * + * @return DateTime The created DateTime object. + */ + public function create_date_time( $date_time, $timezone = null ): DateTime { + /** + * If no timezone is passed, use the site timezone + */ + if ( null === $timezone ) { + $timezone = wp_timezone_string(); + } + + try { + $date_time_object = new DateTime( $date_time, new DateTimeZone( $timezone ) ); + } catch ( Exception $e ) { + $date_time_object = new DateTime(); + // todo handle exception + } + + return $date_time_object; + } + + + /** + * Create a DateTime object from a timestamp, with an optional timezone. + * + * @param mixed $timestamp The Unix timestamp to create the DateTime object from. + * @param string|null $timezone The timezone to be used, or null to use the site timezone. + * + * @return DateTime The created DateTime object. + */ + public function create_date_time_from_timestamp( $timestamp, $timezone = null ): DateTime { + /** + * If no timezone is passed, use the site timezone + */ + if ( null === $timezone ) { + $timezone = wp_timezone_string(); + } + + try { + $date_time_object = new DateTime( 'now', new DateTimeZone( $timezone ) ); + $date_time_object->setTimestamp( $timestamp ); + } catch ( Exception $e ) { + $date_time_object = new DateTime(); + // todo handle exception + } + + return $date_time_object->setTimestamp( $timestamp ); + } + + + /** + * Retrieves the days of the month and related event information. + * + * @param mixed $date The date to retrieve month information for. + * + * @return array The array containing month and event information. + */ + public function get_month_days( $date ): array { + $start_of_week = get_option( 'start_of_week', 0 ); + $current_date = $this->create_date_time( $date ); + $current_day = $this->create_date_time( 'now' )->setTime( 0, 0, 0 ); + $current_day_formatted = $current_day->format( 'Y-m-d' ); + $current_month = $current_date->format( 'n' ); + $data = array(); + $data['month_has_events'] = false; + + $start_day = $this->get_start_day( $current_date, $start_of_week ); + $end_day = $this->get_end_day( $current_date, $start_of_week ); + + $period = new DatePeriod( $start_day, new DateInterval( 'P1D' ), $end_day ); + + foreach ( $period as $day ) { + $day->setTime( 0, 0, 0 ); + $day_formatted = $day->format( 'Y-m-d' ); + $day_month = $day->format( 'n' ); + $events = $this->get_events_by_date( $day ); + + if ( ! $data['month_has_events'] && ! empty( $events ) && $day_month === $current_month ) { + $data['month_has_events'] = true; + } + + $data['days'][] = array( + 'date' => $day, + 'date_formatted' => $day_formatted, + 'events' => $events, + 'is_other_month' => $day_month !== $current_month, + 'is_previous_month' => $day_month < $current_month, + 'is_next_month' => $day_month > $current_month, + 'is_past' => $day < $current_day, + 'is_today' => $day_formatted === $current_day_formatted, + ); + } + return $data; + } + + + + /** + * Get month days from the API request. + * + * @param WP_REST_Request $request The REST request object. + * + * @return WP_REST_Response + */ + public function api_get_month_days( WP_REST_Request $request ) { + // Get the body from the request. + $request_body = $request->get_json_params(); + + // Check if the request has a date. + $request_date = $request_body['date']; + + if ( ! $request_date ) { + $request_date = 'now'; + } + + $request_date_time = $this->create_date_time( $request_date ); + $previous_date_time = self::get_instance()->get_previous_month_with_events( $request_date_time ); + $next_date_time = self::get_instance()->get_next_month_with_events( $request_date_time ); + + // Retrieve attributes for template part. + $request_attributes = $request_body['attributes']; + + if ( ! $request_attributes ) { + $request_attributes = array( 'align' => 'wide' ); + } + + $month_data = $this->get_month_days( $request_date ); + + $output = SE_Template_Loader::get_template_part( + 'calendar/calendar', + 'main', + true, + array( + 'attributes' => $request_attributes, + 'current_date' => $request_date_time->format( 'Y-m-01' ), + 'days' => $month_data['days'], + 'month_has_events' => $month_data['month_has_events'], + 'previous_date' => $previous_date_time?->format( 'Y-m-01' ), + 'next_date' => $next_date_time?->format( 'Y-m-01' ), + ), + true + ); + + $output = apply_filters( 'simple_events_api_calendar_render', $output ); + + $response_data = array( + 'html' => $output, + ); + + $response = new WP_REST_Response( $response_data ); + + $response->set_status( 200 ); + + return $response; + } + + /** + * Get first previous event with events. + * + * @param DateTime $current_date Current date. + * + * @return DateTime|null + */ + public function get_previous_month_with_events( $current_date ) { + global $wpdb; + + $previous_date_time = clone $current_date; + $previous_date_time->modify( 'first day of this month' ); + $previous_date_time->settime( 0, 0, 0 ); + + $sql_query = $wpdb->prepare( + "SELECT start_meta.meta_value from {$wpdb->prefix}postmeta as start_meta WHERE start_meta.meta_key = 'se_event_date_start' AND start_meta.meta_value < %s ORDER BY start_meta.meta_value DESC LIMIT 1;", + $previous_date_time->getTimestamp() + ); + + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared + $previous_event = $wpdb->get_row( $sql_query ); // the query is prepared above + + if ( empty( $previous_event ) ) { + return null; + } + + return $this->create_date_time_from_timestamp( $previous_event->meta_value ); + } + + /** + * Get first next event with events. + * + * @param DateTime $current_date Current date. + * + * @return DateTime|null + */ + public function get_next_month_with_events( $current_date ) { + global $wpdb; + + $next_date_time = clone $current_date; + $next_date_time->modify( 'last day of this month' ); + $next_date_time->settime( 23, 23, 59 ); + + $sql_query = $wpdb->prepare( + "SELECT start_meta.meta_value from {$wpdb->prefix}postmeta as start_meta WHERE start_meta.meta_key = 'se_event_date_start' AND start_meta.meta_value > %s ORDER BY start_meta.meta_value ASC LIMIT 1;", + $next_date_time->getTimestamp() + ); + + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared + $next_event = $wpdb->get_row( $sql_query ); // the query is prepared above + + // If we dont have a next date, check if we have any end dates. + if ( empty( $next_event ) ) { + $sql_query = $wpdb->prepare( + "SELECT end_meta.meta_value from {$wpdb->prefix}postmeta as end_meta WHERE end_meta.meta_key = 'se_event_date_end' AND end_meta.meta_value > %s ORDER BY end_meta.meta_value ASC LIMIT 1;", + $next_date_time->getTimestamp() + ); + + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared + $next_event = $wpdb->get_row( $sql_query ); // the query is prepared above + } + + if ( empty( $next_event ) ) { + return null; + } + + return $this->create_date_time_from_timestamp( $next_event->meta_value ); + } + + + /** + * Retrieves events from the database for a given date. + * + * @param mixed $date The date to retrieve events for. + * + * @return array The array of events for the given date. + */ + private function get_events_by_date( $date ): array { + global $wpdb; + + $day_events = array(); + + $start_timestamp = $date->setTime( 0, 0, 0 )->getTimeStamp(); + $end_timestamp = $date->setTime( 23, 59, 59 )->getTimestamp(); + + $sql_query = $wpdb->prepare( + " +SELECT * from {$wpdb->prefix}posts +INNER JOIN {$wpdb->prefix}postmeta AS start_meta ON {$wpdb->prefix}posts.ID = start_meta.post_id AND start_meta.meta_key = 'se_event_date_start' +INNER JOIN {$wpdb->prefix}postmeta AS end_meta ON {$wpdb->prefix}posts.ID = end_meta.post_id AND end_meta.meta_key = 'se_event_date_end' +WHERE wp_posts.post_type = %s AND (wp_posts.post_status = 'publish') AND +((start_meta.meta_value >= %s AND start_meta.meta_value < %s) +OR +(start_meta.meta_value < %s AND end_meta.meta_value > %s) +OR +(end_meta.meta_value <= %s AND end_meta.meta_value > %s)) +GROUP BY {$wpdb->prefix}posts.ID +ORDER BY start_meta.meta_value ASC;", + 'se-event', + $start_timestamp, + $end_timestamp, + $start_timestamp, + $end_timestamp, + $end_timestamp, + $start_timestamp + ); + + // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared + $all_events = $wpdb->get_results( $sql_query ); // the query is prepared above + if ( $all_events ) { + foreach ( $all_events as $event ) { + $event_dates = se_event_get_dates( $event->ID ); + + if ( ! $event_dates ) { + continue; + } + + foreach ( $event_dates as $event_date ) { + $event->event_start_date = $this->create_date_time_from_timestamp( $event_date['datetime_start'] ); + $event->event_end_date = $this->create_date_time_from_timestamp( $event_date['datetime_end'] ); + $event->hide_start_time = '1' === get_post_meta( $event->ID, 'se_event_hide_start_time', true ); + $event->hide_end_time = '1' === get_post_meta( $event->ID, 'se_event_hide_end_time', true ); + if ( $event_date['datetime_start'] >= $start_timestamp && $event_date['datetime_start'] <= $end_timestamp ) { + $new_event = clone $event; + $new_event->event_start_date = $this->create_date_time_from_timestamp( $event_date['datetime_start'] ); + $new_event->event_end_date = $this->create_date_time_from_timestamp( $event_date['datetime_end'] ); + $new_event->open_in_new_window = (bool) get_post_meta( $event->ID, 'se_event_open_in_new_window', true ); + + $day_events[] = $new_event; + } + } + } + } + return $day_events; + } + + + + /** + * Get the start day based on the given date and start of the week. + * + * @param mixed $date The date for which to calculate the start day. + * @param integer $start_of_week The start of the week (0-6, where 0 is Sunday). + * + * @return DateTime The start day based on the given date and start of the week. + */ + private function get_start_day( $date, $start_of_week ) { + $start_date = clone $date; + $start_day_interval = 0; + + $start_day_week_position = $date->format( 'w' ); + + if ( $start_of_week > 0 && 0 === intval( $start_day_week_position ) ) { + $start_day_week_position = 7; + } + + if ( 0 !== intval( $start_day_week_position ) ) { + $start_day_interval = abs( 1 - $start_day_week_position ); + } + + return $start_date->sub( new DateInterval( 'P' . $start_day_interval . 'D' ) ); + } + + + /** + * Get the end day based on the given date and start of the week. + * + * @param Date $date The date to calculate the end day from. + * @param integer $start_of_week The start of the `week (0-6, where 0 is Sunday). + * + * @return DateTime The end day based on the given date and start of the week. + */ + private function get_end_day( $date, $start_of_week ) { + $end_date = clone $date; + $last_day_interval = 0; + + $last_day_of_month = $end_date->modify( 'last day of this month' ); + $last_day_week_position = $last_day_of_month->format( 'w' ); + + if ( $start_of_week > 0 && 0 === intval( $last_day_week_position ) ) { + $last_day_week_position = 7; + } + + if ( 0 !== intval( $last_day_week_position ) ) { + $last_day_interval = 7 - $last_day_week_position; + } + + $end_date->setTime( 23, 59, 59 ); + + return $end_date->add( new DateInterval( 'P' . $last_day_interval . 'D' ) ); + } +} diff --git a/OLD/src/classes/class-se-event-post-type.php b/OLD/src/classes/class-se-event-post-type.php new file mode 100644 index 0000000..c7b91b3 --- /dev/null +++ b/OLD/src/classes/class-se-event-post-type.php @@ -0,0 +1,561 @@ + array( + 'name' => __( 'Events', 'simple-events' ), + 'singular_name' => __( 'Event', 'simple-events' ), + 'all_items' => __( 'All Events', 'simple-events' ), + 'archives' => __( 'Event Archives', 'simple-events' ), + 'attributes' => __( 'Event Attributes', 'simple-events' ), + 'insert_into_item' => __( 'Insert into Event', 'simple-events' ), + 'uploaded_to_this_item' => __( 'Uploaded to this Event', 'simple-events' ), + 'featured_image' => _x( 'Featured Image', 'se-event', 'simple-events' ), + 'set_featured_image' => _x( 'Set featured image', 'se-event', 'simple-events' ), + 'remove_featured_image' => _x( 'Remove featured image', 'se-event', 'simple-events' ), + 'use_featured_image' => _x( 'Use as featured image', 'se-event', 'simple-events' ), + 'filter_items_list' => __( 'Filter Events list', 'simple-events' ), + 'items_list_navigation' => __( 'Events list navigation', 'simple-events' ), + 'items_list' => __( 'Events list', 'simple-events' ), + 'new_item' => __( 'New Event', 'simple-events' ), + 'add_new' => __( 'Add New', 'simple-events' ), + 'add_new_item' => __( 'Add New Event', 'simple-events' ), + 'edit_item' => __( 'Edit Event', 'simple-events' ), + 'view_item' => __( 'View Event', 'simple-events' ), + 'view_items' => __( 'View Events', 'simple-events' ), + 'search_items' => __( 'Search Events', 'simple-events' ), + 'not_found' => __( 'No Events found', 'simple-events' ), + 'not_found_in_trash' => __( 'No Events found in trash', 'simple-events' ), + 'parent_item_colon' => __( 'Parent Event:', 'simple-events' ), + 'menu_name' => __( 'Events', 'simple-events' ), + ), + 'public' => true, + 'hierarchical' => false, + 'show_ui' => true, + 'show_in_nav_menus' => true, + 'supports' => array( + 'title', + 'editor', + 'thumbnail', + 'custom-fields', + 'excerpt', + 'author', + ), + 'rewrite' => array( + 'slug' => 'event', + 'with_front' => false, + ), + 'has_archive' => self::$slug, + 'query_var' => true, + 'menu_position' => null, + 'menu_icon' => 'dashicons-calendar-alt', + 'show_in_rest' => true, + 'rest_base' => self::$post_type, + 'rest_controller_class' => 'WP_REST_Posts_Controller', + 'template' => $template, + 'template_lock' => 'insert', + 'taxonomies' => array( + 'post_tag', + ), + ) + ); + } + + /** + * Taxonomy registration. + * + * @return void + */ + public static function register_taxonomy() { + register_taxonomy( + self::$post_type . '-category', + self::$post_type, + array( + 'description' => __( 'Categories for simple event posts', 'simple-events' ), + 'public' => true, + 'hierarchical' => true, + 'show_in_rest' => true, + 'show_admin_column' => true, + 'rewrite' => array( + 'slug' => 'events/category', + 'with_front' => false, + ), + ) + ); + } + + /** + * Defines protected meta keys for the event post type. + * + * This method registers meta keys that are used to store event-related data. + * + * @param boolean $is_protected Whether the meta keys should be protected. + * @param string $meta_key The meta key to register. + * @param string $meta_type The type of the meta key. + * + * @return boolean + */ + public static function is_protected_meta( bool $is_protected, string $meta_key, string $meta_type = 'string' ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed + $protected_keys = array( 'se_event_date_end', 'se_event_date_start' ); + + if ( in_array( $meta_key, $protected_keys, true ) ) { + return true; + } + return $is_protected; + } + + /** + * Register meta keys. + * + * @return void + */ + public static function register_meta() { + register_meta( + 'post', + 'se_event_location', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'string', + 'object_subtype' => self::$post_type, + ) + ); + + register_meta( + 'post', + 'se_event_venue', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'string', + 'object_subtype' => self::$post_type, + ) + ); + + register_meta( + 'post', + 'se_event_dates', + array( + 'single' => true, + 'type' => 'array', + 'show_in_rest' => array( + 'schema' => array( + 'items' => array( + 'type' => 'object', + 'properties' => array( + 'datetime_start' => array( + 'type' => 'string', + ), + 'datetime_end' => array( + 'type' => 'string', + ), + 'all_day' => array( + 'type' => 'boolean', + ), + ), + ), + ), + ), + ) + ); + + register_meta( + 'post', + 'se_event_date_start', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'string', + 'object_subtype' => self::$post_type, + 'auth_callback' => function () { + return current_user_can( 'edit_posts' ); + }, + ) + ); + + register_meta( + 'post', + 'se_event_date_end', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'string', + 'object_subtype' => self::$post_type, + 'auth_callback' => function () { + return current_user_can( 'edit_posts' ); + }, + ) + ); + + register_meta( + 'post', + 'se_event_timezone', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'string', + 'object_subtype' => self::$post_type, + ) + ); + + register_meta( + 'post', + 'se_event_display_timezone', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + 'object_subtype' => self::$post_type, + ) + ); + + register_meta( + 'post', + 'se_event_display_grouped', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + 'object_subtype' => self::$post_type, + 'default' => true, + ) + ); + + register_meta( + 'post', + 'se_event_hide_end_time', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + 'object_subtype' => self::$post_type, + 'default' => false, + ) + ); + + register_meta( + 'post', + 'se_event_hide_start_time', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + 'object_subtype' => self::$post_type, + 'default' => false, + ) + ); + + register_meta( + 'post', + 'se_event_add_calendar_links', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + 'object_subtype' => self::$post_type, + 'default' => false, + ) + ); + + register_meta( + 'post', + 'se_event_open_in_new_window', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + 'object_subtype' => self::$post_type, + 'default' => false, + ) + ); + register_meta( + 'post', + 'se_event_external_link', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'string', + 'object_subtype' => self::$post_type, + ) + ); + + register_meta( + 'post', + 'se_event_external_link_label', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'string', + 'object_subtype' => self::$post_type, + 'default' => esc_html__( 'Tickets', 'simple-events' ), + ) + ); + + register_meta( + 'post', + 'se_open_external_link', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + 'object_subtype' => self::$post_type, + 'default' => false, + ) + ); + + register_meta( + 'post', + 'se_event_modal_access', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + 'object_subtype' => self::$post_type, + 'default' => true, + ) + ); + + register_meta( + 'post', + 'se_show_modal_title', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + 'object_subtype' => self::$post_type, + 'default' => true, + ) + ); + + register_meta( + 'post', + 'se_show_modal_excerpt', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + 'object_subtype' => self::$post_type, + 'default' => true, + ) + ); + + register_meta( + 'post', + 'se_event_show_on_frontend', + array( + 'show_in_rest' => true, + 'single' => true, + 'type' => 'boolean', + 'object_subtype' => self::$post_type, + 'default' => true, + ) + ); + } + + /** + * Flush rewrite rules if the flag added during activation exists. + * + * @return void + */ + public static function maybe_flush_rewrite_rules() { + if ( get_option( 'simple_events_flush_rewrite_rules_flag' ) ) { + delete_option( 'simple_events_flush_rewrite_rules_flag' ); + flush_rewrite_rules(); + } + } + + /** + * Order events by date. + * + * @param WP_Query $query WP_Query instance. + * + * @return void + */ + public static function pre_get_posts( $query ) { + if ( is_admin() || ( defined( 'REST_API_REQUEST' ) && REST_API_REQUEST ) || ( isset( $query->query['type'] ) && 'calendar' === $query->query['type'] ) ) { + return; + } + + $options = get_option( 'se_options' ); + $sort_order = ( isset( $options['reverse_events_order'] ) ) ? 'DESC' : 'ASC'; + + // Check if there's an override for the sort order through the 'se_pre_get_posts_order_override' filter. + $order_override = apply_filters( 'se_pre_get_posts_order_override', $query->get( 'se_event_order' ), $query ); + + // If a custom order override exists, use it. Otherwise, stick with the existing sort order. + $sort_order = ! empty( $order_override ) ? $order_override : $sort_order; + + if ( + ( $query->is_main_query() && ( is_post_type_archive( self::$post_type ) + || is_tax( self::$post_type . '-category' ) ) ) + || ( ! $query->is_main_query() && self::$post_type === $query->get( 'post_type' ) && ! $query->get( 'se_countdown' ) && $query->get( 'sub-type' ) !== SE_Block_Variations::QUERY_LOOP_EVENTS ) + ) { + $query->set( 'orderby', 'meta_value' ); + $query->set( 'meta_key', 'se_event_date_start' ); + $query->set( 'order', apply_filters( 'se_pre_get_posts_order', $sort_order, $query ) ); + + // Values for which passed events should be hidden on Feed. + $event_options = array( 'hide_events_on_both', 'hide_events_on_feed', 'on' ); + + if ( isset( $options['hide_past_events'] ) && in_array( $options['hide_past_events'], $event_options, true ) ) { + $query->set( + 'meta_query', + array( + array( + 'key' => 'se_event_date_end', + 'value' => wp_date( 'U' ), + 'compare' => '>=', + ), + ) + ); + } + } + } + + /** + * Restrict access to event single page. + * + * @return void + */ + public static function handle_expired_events() { + global $wp_query; + + if ( $wp_query->is_singular( self::$post_type ) ) { + $options = get_option( 'se_options' ); + + // Values for which passed events should be shown on Single View. + $event_options = array( '', 'hide_events_on_feed' ); + + if ( ! isset( $options['hide_past_events'] ) || in_array( $options['hide_past_events'], $event_options, true ) ) { + return; + } + + $event = $wp_query->get_queried_object(); + + if ( ! empty( $event ) && se_event_is_expired( $event->ID ) ) { + $wp_query->set_404(); + status_header( 404 ); + } + } + } + + /** + * Remove "Archive:" from archive title. + * + * @param string $title Archive title. + * + * @return string + */ + public static function the_archive_title( $title ) { + if ( is_post_type_archive( self::$post_type ) ) { + return post_type_archive_title( '', false ); + } + + return $title; + } + + /** + * Remove rewrite rules and then recreate rewrite rules. + * + * @return void + */ + public static function flush_rewrite_rules() { + self::register_post_type(); + flush_rewrite_rules(); + } + + /** + * Deletes event dates if no event info block is present. + * + * @param integer $event_id Event ID. + * + * @return void + */ + public static function delete_event_dates_if_no_event_info_block( $event_id ) { + if ( wp_is_post_revision( $event_id ) || get_post_type( $event_id ) !== 'se-event' ) { + return; + } + + $event = get_post( $event_id ); + $blocks = parse_blocks( $event->post_content ); + + $is_event_info_block_present = false; + + foreach ( $blocks as $block ) { + if ( 'simple-events/event-info' === $block['blockName'] ) { + $is_event_info_block_present = true; + break; + } + } + + if ( ! $is_event_info_block_present ) { + delete_post_meta( $event_id, 'se_event_dates' ); + } + } +} + +SE_Event_Post_Type::init(); diff --git a/OLD/src/classes/class-se-event-query-dates.php b/OLD/src/classes/class-se-event-query-dates.php new file mode 100644 index 0000000..f87c16f --- /dev/null +++ b/OLD/src/classes/class-se-event-query-dates.php @@ -0,0 +1,157 @@ + SE_Event_Post_Type::$post_type, + 'posts_per_page' => -1, + 'meta_query' => array( + array( + 'key' => 'se_event_date_start', + 'value' => array( + SE_Calendar::get_instance()->create_date_time( 'now' )->modify( '-' . $range . ' seconds' )->format( 'U' ), + SE_Calendar::get_instance()->create_date_time( 'now' )->format( 'U' ), + ), + 'compare' => 'BETWEEN', + ), + ), + ) + ); + + // if we have dates, process them. + if ( $events->have_posts() ) { + // Loop through the events and update the dates. + while ( $events->have_posts() ) { + $events->the_post(); + // Check if event should be updated. + if ( (bool) apply_filters( 'se_event_update_query_dates_skip', false, get_the_ID() ) ) { + continue; + } + se_event_update_event_query_dates( get_the_ID() ); + + do_action( 'se_event_updated_query_dates', get_the_ID() ); + } + } + + // Reset the post data. + wp_reset_postdata(); + + // Add the hooks back. + add_action( 'pre_get_posts', array( SE_Event_Post_Type::class, 'pre_get_posts' ) ); + } +} + +// Self initialization. +SE_Event_Dates::init(); diff --git a/OLD/src/classes/class-se-rest-ticket-products.php b/OLD/src/classes/class-se-rest-ticket-products.php new file mode 100644 index 0000000..6c497c2 --- /dev/null +++ b/OLD/src/classes/class-se-rest-ticket-products.php @@ -0,0 +1,245 @@ +namespace, + '/' . $this->rest_base, + array( + array( + 'methods' => 'GET', + 'callback' => array( $this, 'get_items' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), + 'args' => $this->get_collection_params(), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + } + + /** + * Check if a given request has access to read items. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return WP_Error|boolean + */ + public function get_items_permissions_check( $request ) { + if ( ! current_user_can( 'edit_posts' ) ) { + return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot list resources.', 'simple-events' ), array( 'status' => \rest_authorization_required_code() ) ); + } + + return true; + } + + /** + * Check if a given request has access to read an item. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return WP_Error|boolean + */ + public function get_item_permissions_check( $request ) { + if ( ! current_user_can( 'edit_posts' ) ) { + return new WP_Error( 'woocommerce_rest_cannot_view', __( 'Sorry, you cannot view this resource.', 'simple-events' ), array( 'status' => \rest_authorization_required_code() ) ); + } + + return true; + } + + /** + * Change REST API permissions so that authors have access to this API. + * + * This code only runs for methods of this class. @see Products::get_items below. + * + * @param boolean $permission Does the current user have access to the API. + * + * @return boolean + */ + public function force_edit_posts_permission( $permission ) { + // If user has access already, we can bypass additonal checks. + if ( $permission ) { + return $permission; + } + + return current_user_can( 'edit_posts' ); + } + + /** + * Get a collection of posts. + * + * @param WP_REST_Request $request Full details about the request. + * + * @return WP_Error|WP_REST_Response + */ + public function get_items( $request ) { + add_filter( 'woocommerce_rest_check_permissions', array( $this, 'force_edit_posts_permission' ) ); + $response = parent::get_items( $request ); + remove_filter( 'woocommerce_rest_check_permissions', array( $this, 'force_edit_posts_permission' ) ); + + return $response; + } + + /** + * Make extra product orderby features supported by WooCommerce available to the WC API. + * This includes 'price', 'popularity', and 'rating'. + * + * @param WP_REST_Request $request Request data. + * + * @return array + */ + protected function prepare_objects_query( $request ) { + $args = parent::prepare_objects_query( $request ); + + $args['meta_query'][] = array( + 'key' => '_ticket', + 'value' => 'yes', + 'compare' => '=', + ); + + return $args; + } + + /** + * Get product data. + * + * @param \WC_Product|\WC_Product_Variation $product Product instance. + * @param string $context Request context. Options: 'view' and 'edit'. + * + * @return array + */ + protected function get_product_data( $product, $context = 'view' ) { + return array( + 'id' => $product->get_id(), + 'name' => $product->get_title(), + 'variation' => $product->is_type( 'variation' ) ? wc_get_formatted_variation( $product, true, true, false ) : '', + 'permalink' => $product->get_permalink(), + 'sku' => $product->get_sku(), + 'description' => apply_filters( 'woocommerce_short_description', $product->get_short_description() ? $product->get_short_description() : wc_trim_string( $product->get_description(), 400 ) ), // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound + 'onsale' => $product->is_on_sale(), + 'price' => $product->get_price(), + 'price_html' => $product->get_price_html(), + 'has_options' => $product->has_options(), + 'is_purchasable' => $product->is_purchasable(), + 'is_in_stock' => $product->is_in_stock(), + ); + } + + /** + * Get the Product's schema, conforming to JSON Schema. + * + * @return array + */ + public function get_item_schema() { + $schema = array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'title' => 'simple_events_ticket_products', + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => __( 'Unique identifier for the resource.', 'simple-events' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit', 'embed' ), + 'readonly' => true, + ), + 'name' => array( + 'description' => __( 'Product name.', 'simple-events' ), + 'type' => 'string', + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'variation' => array( + 'description' => __( 'Product variation attributes, if applicable.', 'simple-events' ), + 'type' => 'string', + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'permalink' => array( + 'description' => __( 'Product URL.', 'simple-events' ), + 'type' => 'string', + 'format' => 'uri', + 'context' => array( 'view', 'edit', 'embed' ), + 'readonly' => true, + ), + 'sku' => array( + 'description' => __( 'Unique identifier.', 'simple-events' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'onsale' => array( + 'description' => __( 'Is the product on sale?', 'simple-events' ), + 'type' => 'boolean', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'description' => array( + 'description' => __( 'Short description or excerpt from description.', 'simple-events' ), + 'type' => 'string', + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'price' => array( + 'description' => __( 'Current product price.', 'simple-events' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + ), + 'price_html' => array( + 'description' => __( 'Price formatted in HTML.', 'simple-events' ), + 'type' => 'string', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'has_options' => array( + 'description' => __( 'Does the product have options?', 'simple-events' ), + 'type' => 'boolean', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'is_purchasable' => array( + 'description' => __( 'Is the product purchasable?', 'simple-events' ), + 'type' => 'boolean', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + 'is_in_stock' => array( + 'description' => __( 'Is the product in stock?', 'simple-events' ), + 'type' => 'boolean', + 'context' => array( 'view', 'edit' ), + 'readonly' => true, + ), + ), + ); + + return $this->add_additional_fields_schema( $schema ); + } +} diff --git a/OLD/src/classes/class-se-settings.php b/OLD/src/classes/class-se-settings.php new file mode 100644 index 0000000..f142c7d --- /dev/null +++ b/OLD/src/classes/class-se-settings.php @@ -0,0 +1,608 @@ +Enable this option if you are creating free events only.' ), + ), + array( __CLASS__, 'field_cb' ), + 'simple_events', + 'se_section_editor', + array( + 'label_for' => 'remove_event_tickets_block', + 'description' => esc_html__( 'Select this setting if you are creating free events only.', 'simple-events' ), + ) + ); + + // Register an "Archives" section in the `simple_events` option group. + add_settings_section( + 'se_section_archives', + esc_html__( 'Archives', 'simple-events' ), + array( __CLASS__, 'section_cb_archives' ), + 'simple_events' + ); + + // Register a "Past Events" field in the `se_section_archives` section. + add_settings_field( + 'hide_past_events', + esc_html__( 'Hide Past Events ( Feed & Single )', 'simple-events' ), + array( __CLASS__, 'radio_cb' ), + 'simple_events', + 'se_section_archives', + array( + 'label_for' => 'hide_past_events', + ) + ); + + // Register a "Past Event Notice" text field in the `se_section_archives` section. + add_settings_field( + 'past_event_notice', + esc_html__( 'Past Event Notice', 'simple-events' ), + array( __CLASS__, 'text_cb' ), + 'simple_events', + 'se_section_archives', + array( + 'label_for' => 'past_event_notice', + ) + ); + + // Register a "Update Start and End Dates" field in the `se_section_archives` section. + add_settings_field( + 'update_start_end_dates', + sprintf( + // translators: %s is a HTML break tag. + __( 'Update Query Dates%s', 'simple-events' ), + wp_kses_post( '
    Will update the start date used for queries to the next available starting date.' ), + ), + array( __CLASS__, 'field_cb' ), + 'simple_events', + 'se_section_archives', + array( + 'label_for' => 'update_start_end_dates', + ) + ); + + // Register a "reverse order" field in the `se_section_archives` section. + add_settings_field( + 'reverse_events_order', + esc_html__( 'Reverse events order in post feed.', 'simple-events' ), + array( __CLASS__, 'field_cb' ), + 'simple_events', + 'se_section_archives', + array( + 'label_for' => 'reverse_events_order', + ) + ); + + // Show next/previous links on event singles. + add_settings_field( + 'show_next_prev_links', + __( 'Show next/previous links on event singles.', 'simple-events' ), + array( __CLASS__, 'field_cb' ), + 'simple_events', + 'se_section_archives', + array( + 'label_for' => 'show_next_prev_links', + ) + ); + + // Select link for the caledar page. + add_settings_field( + 'calendar_page', + __( 'Select the page for the calendar.', 'simple-events' ), + array( __CLASS__, 'calendar_page_cb' ), + 'simple_events', + 'se_section_archives', + array( + 'label_for' => 'calendar_page', + ) + ); + + // Show next and previous link above content. + add_settings_field( + 'show_links_above_content', + __( 'Next/Previous link placement.', 'simple-events' ), + array( __CLASS__, 'link_position_cb' ), + 'simple_events', + 'se_section_archives', + array( + 'label_for' => 'show_links_above_content', + ) + ); + + add_settings_section( + 'se_section_woocommerce', + esc_html__( 'WooCommerce', 'simple-events' ), + array( __CLASS__, 'section_cb_woocommerce' ), + 'simple_events' + ); + + // Skip cart for tickets and redirect to checkout. + add_settings_field( + 'skip_cart_for_ticket', + __( 'Skip cart for tickets and redirect to checkout', 'simple-events' ), + array( __CLASS__, 'field_cb' ), + 'simple_events', + 'se_section_woocommerce', + array( + 'label_for' => 'skip_cart', + ) + ); + + // Empty cart before adding tickets. + add_settings_field( + 'empty_cart_before_adding_tickets', + sprintf( + // translators: %s is a HTML break tag. + __( 'Empty cart before a ticket is added%s', 'simple-events' ), + wp_kses_post( '
    Clears the cart before a ticket is added to the cart.' ), + ), + array( __CLASS__, 'field_cb' ), + 'simple_events', + 'se_section_woocommerce', + array( + 'label_for' => 'empty_cart_before_adding_tickets', + ) + ); + + add_settings_field( + 'autocomplete_ticket_order', + sprintf( + // translators: %s is a HTML break tag. + __( 'Set Ticket Order Status to Completed.%s', 'simple-events' ), + wp_kses_post( '
    Orders that exclusively contain tickets will be automatically marked as completed. This applys to orders placed after this feature is enabled.' ), + ), + array( __CLASS__, 'field_cb' ), + 'simple_events', + 'se_section_woocommerce', + array( + 'label_for' => 'autocomplete_ticket_order', + ) + ); + + add_settings_field( + 'mark_existing_orders_as_completed', + sprintf( + // translators: %s is a HTML break tag. + __( 'Set existing ticket orders as completed.%s', 'simple-events' ), + wp_kses_post( '
    Customer emails are disabled during the bulk update.' ), + ), + array( __CLASS__, 'ajax_cb' ), + 'simple_events', + 'se_section_woocommerce', + array( + 'action' => 'se_mark_existing_orders_as_completed', + 'btn_text' => __( 'Perform bulk status updates', 'simple-events' ), + ) + ); + + // Register an "Calendar" section in the `simple_events` option group. + add_settings_section( + 'se_section_calendar', + esc_html__( 'Calendar', 'simple-events' ), + array( __CLASS__, 'section_cb_calendar' ), + 'simple_events' + ); + + // Register a "Custom Endpoint" field in the `se_section_calendar` section. + add_settings_field( + 'cal_download_endpoint', + esc_html__( 'Custom Endpoint for Downloading Calendar', 'simple-events' ), + array( __CLASS__, 'cal_download_cb' ), + 'simple_events', + 'se_section_calendar', + array( + 'label_for' => 'cal_download_endpoint', + ) + ); + + // Register a "Download Calendar" field in the `se_section_calendar` section. + add_settings_field( + 'disable_download_calendar', + esc_html__( 'Disable Calendar Download Endpoint', 'simple-events' ), + array( __CLASS__, 'field_cb' ), + 'simple_events', + 'se_section_calendar', + array( + 'label_for' => 'disable_download_calendar', + ) + ); + } + + /** + * Displays the "Editor" section. + * + * @return void + */ + public static function section_cb_editor() { + ?> +

    + +

    + +

    + +

    + 'Show Both', // Shows old events in feed and single view. Empty string used due to it being default value if se_options not set previously. + 'hide_events_on_both' => 'Hide Both', // Hides old events on both feed and single view. + 'hide_events_on_feed' => 'Hide on Feed, Show on Single', // Hides old events on both feed only. + ); + $value = isset( $options[ $args['label_for'] ] ) ? $options[ $args['label_for'] ] : ''; + + foreach ( $radio_labels as $key => $label ) { + ?> + +
    '; + } + } + } + + /** + * Displays the "Past Events" field. + * + * @param array $args Display arguments. + * + * @return void + */ + public static function field_cb( $args ) { + $options = get_option( 'se_options' ); + ?> + + > + + +
    + + + + + + + + + + + +

    + %1$s', 'simple-events' ), + esc_url( get_post_type_archive_link( SE_Event_Post_Type::$post_type ) . $value ), + ) + ); + ?> +

    + +
    + +

    + +
    + + + +
    + +
    + -1, + 'orderby' => 'date', + 'order' => 'DESC', + 'return' => 'ids', + ) + ); + + // Disable email notifications + add_filter( 'woocommerce_defer_transactional_emails', '__return_true' ); + + $updated_orders = 0; + + foreach ( $orders as $order ) { + $order = wc_get_order( $order ); + $order_status = $order->get_status(); + + // Skip if order is already completed or isn't being processed. + if ( 'completed' === $order_status || 'processing' !== $order_status ) { + continue; + } + + $items = $order->get_items(); + $should_autocomplete = true; + + // Check if order contains only tickets. + foreach ( $items as $item ) { + if ( ! wc_box_office_is_product_ticket( $item['product_id'] ) ) { + $should_autocomplete = false; + } + } + + // Mark order as completed if it contains only tickets. + if ( $should_autocomplete ) { + $order->update_status( 'completed' ); + ++$updated_orders; + } + } + + // Enable email notifications again + remove_filter( 'woocommerce_defer_transactional_emails', '__return_true' ); + + // translators: %d is the number of orders updated. + wp_send_json_success( sprintf( __( '%d orders updated successfully', 'simple-events' ), $updated_orders ) ); + } +} + +SE_Settings::init(); diff --git a/OLD/src/classes/class-se-template-loader.php b/OLD/src/classes/class-se-template-loader.php new file mode 100644 index 0000000..040388d --- /dev/null +++ b/OLD/src/classes/class-se-template-loader.php @@ -0,0 +1,153 @@ +post_name ) . '.php', + 'single-se-event.php', + ); + + // If a custom page template has been assigned to the event, add it to the front of the list. + if ( '' !== $event->page_template ) { + array_unshift( $theme_templates, $event->page_template ); + } + + // Determine if any of these templates is available in the theme. + $single_event_template = get_query_template( 'singular', $theme_templates ); + + if ( $single_event_template ) { + return $single_event_template; + } + + $fallback_template = 'single.php'; + } + + // Determine if standard se-event archive templates are available in the theme + // before replacing with the custom template in this plugin. + if ( is_archive( 'se-event' ) ) { + $theme_templates = array( + 'archive-se-event.php', + ); + + // Determine if any of these templates is available in the theme. + $archive_event_template = get_query_template( 'archive', $theme_templates ); + + if ( $archive_event_template ) { + return $archive_event_template; + } + + $fallback_template = 'archive.php'; + } + + // Retrieve the full path of the fallback template in this plugin. + $fallback_template = self::locate_template( array( $fallback_template ) ); + + if ( '' !== $fallback_template ) { + return $fallback_template; + } + + return $template; + } + + /** + * Load a template. + * + * @param array $template_names Template file(s) to search for, in order. + * @param boolean $load If true the template file will be loaded if it is found. + * @param boolean $once Whether to require_once or require. Default true. Has no effect if $load is false. + * @param array $args Arguments. + * @param boolean $return_html Return generated HTML. + * + * @return string + */ + public static function locate_template( $template_names, $load = false, $once = true, $args = array(), $return_html = false ) { + $located = ''; + + foreach ( (array) $template_names as $template_name ) { + if ( ! $template_name ) { + continue; + } + + if ( file_exists( SE_TEMPLATE_PATH . '/' . $template_name ) ) { + $located = SE_TEMPLATE_PATH . '/' . $template_name; + break; + } + } + + if ( $load && '' !== $located ) { + if ( $return_html ) { + ob_start(); + load_template( $located, $once, $args ); + $output = ob_get_contents(); + ob_end_clean(); + return $output; + } + load_template( $located, $once, $args ); + } + + return $located; + } + + /** + * Loads a template part into a template. + * + * @param string $slug The slug name for the generic template. + * @param string $name The name of the specialised template. + * @param boolean $load If true the template file will be loaded if it is found. + * @param array $args Arguments. + * @param boolean $return_html Return generated HTML. + * + * @return string + */ + public static function get_template_part( $slug, $name = null, $load = true, $args = array(), $return_html = false ) { + $templates = array(); + + if ( isset( $name ) ) { + $templates[] = $slug . '-' . $name . '.php'; + } + + $templates[] = $slug . '.php'; + + return self::locate_template( $templates, $load, false, $args, $return_html ); + } +} + +SE_Template_Loader::init(); diff --git a/OLD/src/event-functions.php b/OLD/src/event-functions.php new file mode 100644 index 0000000..a089f12 --- /dev/null +++ b/OLD/src/event-functions.php @@ -0,0 +1,530 @@ +post_content ); + + foreach ( $blocks as $block ) { + if ( 'simple-events/event-tickets' === $block['blockName'] ) { + if ( ! empty( $block['attrs'] ) && ! empty( $block['attrs']['selected'] ) ) { + $products = $block['attrs']['selected']; + break; + } + } + } + + // Validate ids. + foreach ( $products as $key => $product ) { + if ( ! wc_box_office_is_product_ticket( $product ) ) { + unset( $products[ $key ] ); + } + } + + return $products; +} + +/** + * Get tickets attached to event. + * + * @param integer $event_id Event id. + * + * @return mixed + */ +function se_event_get_ticket_prices( $event_id ) { + $prices = array(); + + $tickets = se_event_get_tickets( $event_id ); + + if ( ! empty( $tickets ) ) { + // Get prices. + foreach ( $tickets as $ticket ) { + $ticket = wc_get_product( $ticket ); + + if ( ! $ticket ) { + continue; + } + + $prices[] = $ticket->get_price(); + } + } + + // Sort prices. + sort( $prices ); + + if ( ! empty( $prices ) ) { + return $prices; + } + + return false; +} + +/** + * Get ticket stock for an event. + * + * @param integer $event_id Event id. + * + * @return mixed + */ +function se_event_get_tickets_stock( $event_id ) { + $stock_total = 0; + + // Get ticket products. + $tickets = se_event_get_tickets( $event_id ); + + if ( ! empty( $tickets ) ) { + foreach ( $tickets as $ticket ) { + $ticket = wc_get_product( $ticket ); + + if ( ! $ticket ) { + continue; + } + + $stock = ( $ticket->managing_stock() ? $ticket->get_stock_quantity() : false ); + + if ( $stock && $stock > 0 ) { + $stock_total += $stock; + } + } + } + + if ( $stock_total < 1 ) { + return false; + } + + return $stock_total; +} + +/** + * Get event dates. + * + * @param integer $event_id Event id. + * @param array $event_dates Event dates. + * + * @return mixed + */ +function se_event_get_dates( $event_id, $event_dates = null ) { + if ( is_null( $event_dates ) ) { + $event_dates = get_post_meta( $event_id, 'se_event_dates', true ); + } + + if ( empty( $event_dates ) ) { + return apply_filters( 'se_event_dates', false, $event_id ); + } + + // Sort dates. + if ( count( $event_dates ) > 1 ) { + array_multisort( + array_column( $event_dates, 'datetime_start' ), + SORT_ASC, + $event_dates + ); + } + + return apply_filters( 'se_event_dates', $event_dates, $event_id ); +} + +/** + * Gets only the future event dates in a formatted string. + * + * @param integer $event_id Event id. + * @param boolean $date_only Whether to return only the date. + * @param boolean $time_only Whether to return only the time. + * @param array $event_dates Event dates. + * + * @return string + */ +function se_event_get_future_dates( $event_id, $date_only = false, $time_only = false, $event_dates = null ) { + // Get required post meta. + $event_dates = se_event_get_dates( $event_id, $event_dates ); + $event_timezone = get_post_meta( $event_id, 'se_event_timezone', true ); + $hide_end_time = get_post_meta( $event_id, 'se_event_hide_end_time', true ); + $hide_start_time = get_post_meta( $event_id, 'se_event_hide_start_time', true ); + $display_timezone = (bool) get_post_meta( $event_id, 'se_event_display_timezone', true ); + $now = SE_Calendar::get_instance()->create_date_time( 'now' )->format( 'U' ); + + if ( ! $event_dates ) { + return ''; + } + + // Iterate over all the events and remove any where the start and end has passed. + foreach ( $event_dates as $key => $date ) { + if ( $date['datetime_start'] < $now && $date['datetime_end'] < $now ) { + unset( $event_dates[ $key ] ); + } + } + if ( empty( $event_dates ) ) { + return ''; + } + + return se_event_format_dates( + $event_dates, + $event_timezone, + $hide_end_time, + $hide_start_time, + $display_timezone, + false, + false + ); +} +/** + * Get the event dates in a formatted string. + * + * @param integer $event_id Event id. + * @param boolean $date_only Whether to return only the date. + * @param boolean $time_only Whether to return only the time. + * @param array $event_dates Event dates. + * + * @return string + */ +function se_event_get_formatted_dates( $event_id, $date_only = false, $time_only = false, $event_dates = null ) { + + // Get required post meta. + $event_dates = se_event_get_dates( $event_id, $event_dates ); + $event_timezone = get_post_meta( $event_id, 'se_event_timezone', true ); + $hide_end_time = get_post_meta( $event_id, 'se_event_hide_end_time', true ); + $hide_start_time = get_post_meta( $event_id, 'se_event_hide_start_time', true ); + $display_timezone = (bool) get_post_meta( $event_id, 'se_event_display_timezone', true ); + + if ( ! $event_dates ) { + return ''; + } + + return se_event_format_dates( + $event_dates, + $event_timezone, + $hide_end_time, + $hide_start_time, + $display_timezone, + $date_only, + $time_only + ); +} + +/** + * Formats the dates for the event. + * + * @param array $event_dates Event dates. + * @param string $timezone Timezone. + * @param mixed $hide_end_time If we should hide the end time. + * @param mixed $hide_start_time If we should hide the start time. + * @param mixed $display_timezone If we should display the timezone. + * @param mixed $date_only If we should only show the date. + * @param mixed $time_only If we should only show the time. + * + * @return string + */ +function se_event_format_dates( $event_dates, $timezone, $hide_end_time, $hide_start_time, $display_timezone, $date_only, $time_only ) { + $dates_count = is_array( $event_dates ) ? count( $event_dates ) : 1; + + if ( ! empty( $event_timezone ) ) { + $timezone = new DateTimeZone( $event_timezone ); + } else { + $timezone = wp_timezone(); + } + + $timezone_date = new DateTime( '', $timezone ); + $timezone_abbr = $timezone_date->format( 'T' ); + + // Begin output as a list if the count is more than 1. + $dates_output = ( $dates_count > 1 ) ? '