CI / Coding Standards (pull_request) Successful in 51s
CI / No Debug Code (pull_request) Successful in 3s
CI / Tests (PHP 8.2) (pull_request) Successful in 50s
CI / Tests (PHP 8.3) (pull_request) Successful in 1m2s
CI / Build Plugin Zip (pull_request) Has been skipped
CI / Tests (PHP 8.1) (pull_request) Successful in 53s
CI / PHPStan (pull_request) Successful in 1m24s
The booking block gains a loginPageId attribute choosing which page its logged-out "log in to book a lesson" link points to (default remains the WordPress login screen), and the student-login block gains a bookingPageId attribute controlling the logged-in "View available lessons" link and the post-login redirect target (default remains the current page). Both blocks also gain an autoRedirect toggle, off by default, that sends the visitor straight to the target page; block rendering starts after output, so the redirect runs on template_redirect by parsing the queried page's content for the block, with a self-target guard against redirect loops. The link targets are also available to the shortcodes as login_page_id/booking_page_id. Also fixes a pre-existing fatal: WordPress passes an empty string (not an array) to shortcode callbacks when a shortcode is used without attributes, so bare [us_booking] etc. threw a TypeError against the strictly-typed render(array $atts) methods. ShortcodeRegistrar now wraps each callback to normalize non-array attribute values. Closes #51 Co-Authored-By: Claude Fable 5 <[email protected]>
152 lines
6.4 KiB
JavaScript
152 lines
6.4 KiB
JavaScript
/* global wp */
|
|
(function () {
|
|
'use strict';
|
|
|
|
const { registerBlockType } = wp.blocks;
|
|
const { createElement: el } = wp.element;
|
|
const { useBlockProps, InspectorControls } = wp.blockEditor;
|
|
const { PanelBody, SelectControl, ToggleControl } = wp.components;
|
|
const { useSelect } = wp.data;
|
|
const ServerSideRender = wp.serverSideRender;
|
|
const { __ } = wp.i18n;
|
|
|
|
/**
|
|
* Dropdown of published pages with a leading "default" choice.
|
|
* Values are page IDs; 0 means the default behaviour.
|
|
*/
|
|
function PageSelect(props) {
|
|
const pages = useSelect(
|
|
(select) => select('core').getEntityRecords('postType', 'page', {
|
|
per_page: -1,
|
|
orderby: 'title',
|
|
order: 'asc',
|
|
status: 'publish',
|
|
_fields: 'id,title',
|
|
}),
|
|
[]
|
|
);
|
|
|
|
const options = [{ label: props.defaultLabel, value: '0' }].concat(
|
|
(pages || []).map((page) => ({
|
|
label: (page.title && page.title.rendered) || __('(no title)', 'unsupervised-schedular'),
|
|
value: String(page.id),
|
|
}))
|
|
);
|
|
|
|
return el(SelectControl, {
|
|
label: props.label,
|
|
help: props.help,
|
|
value: String(props.value || 0),
|
|
options: options,
|
|
onChange: (value) => props.onChange(parseInt(value, 10) || 0),
|
|
});
|
|
}
|
|
|
|
const blocks = [
|
|
{
|
|
name: 'us-scheduler/booking',
|
|
title: __('Lesson Booking', 'unsupervised-schedular'),
|
|
description: __('Lets students browse availability and book lessons. Shows a styled preview in the editor.', 'unsupervised-schedular'),
|
|
icon: 'calendar-alt',
|
|
keywords: ['booking', 'lesson', 'schedule'],
|
|
shortcode: 'us_booking',
|
|
attributes: {
|
|
loginPageId: { type: 'number', default: 0 },
|
|
autoRedirect: { type: 'boolean', default: false },
|
|
},
|
|
inspector: (attributes, setAttributes) => el(
|
|
PanelBody,
|
|
{ title: __('Logged-out visitors', 'unsupervised-schedular') },
|
|
el(PageSelect, {
|
|
label: __('Login page', 'unsupervised-schedular'),
|
|
help: __('Where the log-in link sends visitors who are not logged in.', 'unsupervised-schedular'),
|
|
defaultLabel: __('WordPress login screen', 'unsupervised-schedular'),
|
|
value: attributes.loginPageId,
|
|
onChange: (loginPageId) => setAttributes({ loginPageId }),
|
|
}),
|
|
el(ToggleControl, {
|
|
label: __('Redirect automatically', 'unsupervised-schedular'),
|
|
help: __('Send logged-out visitors straight to the login page instead of showing a link.', 'unsupervised-schedular'),
|
|
checked: !!attributes.autoRedirect,
|
|
onChange: (autoRedirect) => setAttributes({ autoRedirect }),
|
|
})
|
|
),
|
|
},
|
|
{
|
|
name: 'us-scheduler/student-login',
|
|
title: __('Student Login', 'unsupervised-schedular'),
|
|
description: __('The front-end login form for students.', 'unsupervised-schedular'),
|
|
icon: 'admin-users',
|
|
keywords: ['login', 'student', 'sign in'],
|
|
shortcode: 'us_student_login',
|
|
attributes: {
|
|
bookingPageId: { type: 'number', default: 0 },
|
|
autoRedirect: { type: 'boolean', default: false },
|
|
},
|
|
inspector: (attributes, setAttributes) => el(
|
|
PanelBody,
|
|
{ title: __('Logged-in visitors', 'unsupervised-schedular') },
|
|
el(PageSelect, {
|
|
label: __('Booking page', 'unsupervised-schedular'),
|
|
help: __('Where students are sent after logging in, and where the link shown to already-logged-in visitors points.', 'unsupervised-schedular'),
|
|
defaultLabel: __('This page', 'unsupervised-schedular'),
|
|
value: attributes.bookingPageId,
|
|
onChange: (bookingPageId) => setAttributes({ bookingPageId }),
|
|
}),
|
|
el(ToggleControl, {
|
|
label: __('Redirect automatically', 'unsupervised-schedular'),
|
|
help: __('Send logged-in visitors straight to the booking page instead of showing a link. Requires a booking page to be chosen.', 'unsupervised-schedular'),
|
|
checked: !!attributes.autoRedirect,
|
|
onChange: (autoRedirect) => setAttributes({ autoRedirect }),
|
|
})
|
|
),
|
|
},
|
|
{
|
|
name: 'us-scheduler/student-register',
|
|
title: __('Student Registration', 'unsupervised-schedular'),
|
|
description: __('The invite-only student registration form.', 'unsupervised-schedular'),
|
|
icon: 'welcome-add-page',
|
|
keywords: ['register', 'student', 'invite'],
|
|
shortcode: 'us_student_register',
|
|
},
|
|
{
|
|
name: 'us-scheduler/group-classes',
|
|
title: __('Group Classes', 'unsupervised-schedular'),
|
|
description: __('Lets students browse and enrol in group classes. Shows a styled preview in the editor.', 'unsupervised-schedular'),
|
|
icon: 'groups',
|
|
keywords: ['group', 'class', 'enrol'],
|
|
shortcode: 'us_group_classes',
|
|
},
|
|
];
|
|
|
|
blocks.forEach((def) => {
|
|
registerBlockType(def.name, {
|
|
apiVersion: 3,
|
|
title: def.title,
|
|
description: def.description,
|
|
icon: def.icon,
|
|
category: 'widgets',
|
|
keywords: def.keywords,
|
|
supports: { html: false, multiple: false },
|
|
attributes: def.attributes || {},
|
|
example: {},
|
|
edit: function Edit(props) {
|
|
const inspector = def.inspector
|
|
? el(InspectorControls, {}, def.inspector(props.attributes, props.setAttributes))
|
|
: null;
|
|
|
|
return el(
|
|
'div',
|
|
useBlockProps(),
|
|
inspector,
|
|
el(ServerSideRender, { block: def.name, attributes: props.attributes })
|
|
);
|
|
},
|
|
save: () => null,
|
|
transforms: {
|
|
from: [{ type: 'shortcode', tag: def.shortcode }],
|
|
},
|
|
});
|
|
});
|
|
}());
|