diff --git a/blocks/footer/edit.tsx b/blocks/footer/edit.tsx index 6257d89c..fa3db658 100644 --- a/blocks/footer/edit.tsx +++ b/blocks/footer/edit.tsx @@ -18,7 +18,10 @@ import { Spinner } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; import { useEffect, useState } from '@wordpress/element'; -interface FooterSettings { +interface Settings { + from_email: string, + reply_to_email: string, + from_names: string[], facebook_url: string, twitter_url: string, instagram_url: string, @@ -38,22 +41,22 @@ interface FooterSettings { */ export default function Edit() { const [isLoading, setIsLoading] = useState(false); - const [footerSettings, setFooterSettings] = useState(); + const [settings, setSettings] = useState(); - const facebookUrl = footerSettings?.facebook_url ?? ''; - const twitterUrl = footerSettings?.twitter_url ?? ''; - const instagramUrl = footerSettings?.instagram_url ?? ''; - const youtubeUrl = footerSettings?.youtube_url ?? ''; - const imageId = footerSettings?.image ?? 0; - const address = footerSettings?.address ?? ''; - const address2 = footerSettings?.address_2 ?? ''; + const facebookUrl = settings?.facebook_url ?? ''; + const twitterUrl = settings?.twitter_url ?? ''; + const instagramUrl = settings?.instagram_url ?? ''; + const youtubeUrl = settings?.youtube_url ?? ''; + const imageId = settings?.image ?? 0; + const address = settings?.address ?? ''; + const address2 = settings?.address_2 ?? ''; useEffect(() => { setIsLoading(true); - apiFetch({ path: '/wp-newsletter-builder/v1/footer_settings' }) + apiFetch({ path: '/wp-newsletter-builder/v1/settings' }) .then((response) => { - setFooterSettings(response as any as FooterSettings); + setSettings(response as any as Settings); setIsLoading(false); }); }, []); @@ -63,7 +66,7 @@ export default function Edit() { } = useSelect((select) => ({ // @ts-ignore media: imageId ? select('core').getMedia(imageId) : null, - }), [footerSettings, imageId]); + }), [settings, imageId]); const imageUrl = media ? media.source_url : ''; const imageAltText = media ? media.alt_text : ''; diff --git a/blocks/footer/render.php b/blocks/footer/render.php index b7633693..b3810c02 100644 --- a/blocks/footer/render.php +++ b/blocks/footer/render.php @@ -10,14 +10,13 @@ */ $nb_settings = get_option( 'nb_settings' ); -$nb_footer_settings = is_array( $nb_settings ) ? $nb_settings['footer_settings'] : []; -$nb_facebook_url = $nb_footer_settings['facebook_url'] ?? ''; -$nb_twitter_url = $nb_footer_settings['twitter_url'] ?? ''; -$nb_instagram_url = $nb_footer_settings['instagram_url'] ?? ''; -$nb_youtube_url = $nb_footer_settings['youtube_url'] ?? ''; -$nb_image_id = $nb_footer_settings['image'] ?? 0; -$nb_address = $nb_footer_settings['address'] ?? ''; -$nb_address_2 = $nb_footer_settings['address_2'] ?? ''; +$nb_facebook_url = $nb_settings['facebook_url'] ?? ''; +$nb_twitter_url = $nb_settings['twitter_url'] ?? ''; +$nb_instagram_url = $nb_settings['instagram_url'] ?? ''; +$nb_youtube_url = $nb_settings['youtube_url'] ?? ''; +$nb_image_id = $nb_settings['image'] ?? 0; +$nb_address = $nb_settings['address'] ?? ''; +$nb_address_2 = $nb_settings['address_2'] ?? ''; $nb_has_social_links = ! empty( $nb_facebook_url ) || ! empty( $nb_twitter_url ) || ! empty( $nb_instagram_url ) || ! empty( $nb_youtube_url ); $plugin_url = plugins_url( 'wp-newsletter-builder' ); diff --git a/components/imagePicker/index.scss b/components/imagePicker/index.scss new file mode 100644 index 00000000..4da0e979 --- /dev/null +++ b/components/imagePicker/index.scss @@ -0,0 +1,11 @@ +.image-picker { + &__button-group { + display: flex; + gap: 5px; + margin-bottom: 5px; + } + + &__preview { + max-height: 200px; + } +} \ No newline at end of file diff --git a/components/imagePicker/index.tsx b/components/imagePicker/index.tsx new file mode 100644 index 00000000..0777ab46 --- /dev/null +++ b/components/imagePicker/index.tsx @@ -0,0 +1,162 @@ +/* eslint-disable camelcase */ +import { __ } from '@wordpress/i18n'; +import { BaseControl, Button, ButtonGroup } from '@wordpress/components'; +import { useEffect, useRef, useState } from 'react'; +import apiFetch from '@wordpress/api-fetch'; +import type { WP_REST_API_Attachment } from 'wp-types'; +import './index.scss'; + +type ImagePickerProps = { + label: string; + onChange: (value: number) => void; + value: number; +}; + +type MediaLibraryOptions = { + library: { + type: string; + }; +}; + +type MediaLibrarySelection = { + id: number; + url: string; +}; + +declare global { + interface Window { + wp: { + media: (options: MediaLibraryOptions) => any; + }; + } +} + +export default function ImagePicker({ + label, + onChange, + value, +}: ImagePickerProps) { + const imagePreviewRef = useRef(null); + const imagePreview = imagePreviewRef.current as HTMLImageElement; + const [imageUrl, setImageUrl] = useState(''); + + /** + * Handle the Media Library modal logic. + * @returns Promise + */ + const openMediaLibraryModal = () => new Promise((resolve, reject) => { + // Create the Media Library object. Restrict to images only. + const mediaLibrary = window?.wp?.media({ + library: { + type: 'image', + }, + }); + + if (!mediaLibrary) { + reject(); + } + + // Set up the select event listener. On success, returns a promise with the image ID and URL. + mediaLibrary?.on('select', () => { + const selectedImage = mediaLibrary?.state()?.get('selection')?.first(); + + if (!selectedImage) { + reject(); + } + + const { + attributes: { + id = 0, + url = '', + } = {}, + } = selectedImage; + + resolve({ id, url }); + }); + + // Open the Media Library modal. + mediaLibrary?.open(); + }); + + /** + * Select an image. + */ + const selectImage = async () => { + const imageData = await openMediaLibraryModal() as MediaLibrarySelection; + + const { + id = 0, + url = '', + } = imageData; + + // Pass the selected attachment ID to the onChange event. + onChange(id); + + // Update the image URL state. + setImageUrl(url); + }; + + /** + * Clear the selected image. + */ + const clearImage = () => { + onChange(0); + setImageUrl(''); + }; + + /** + * Fetch the image URL from the REST API when the image ID changes. + */ + useEffect(() => { + if (!value) { + return; + } + + // Get the image url from the REST API and update the image preview. + apiFetch({ path: `/wp/v2/media/${value}` }) + .then((response) => { + const { source_url: url = '' } = response as WP_REST_API_Attachment; + setImageUrl(url); + }) + .catch(() => { + setImageUrl(''); + }); + }, [value]); + + /** + * Update the image preview when the image URL changes. + */ + useEffect(() => { + if (!imageUrl || !imagePreview) { + return; + } + + imagePreview.src = imageUrl; + }, [imageUrl, imagePreview]); + + return ( + + + + + + + + ); +} diff --git a/entries/admin-settings/index.js b/entries/admin-settings/index.js new file mode 100644 index 00000000..24e0c05a --- /dev/null +++ b/entries/admin-settings/index.js @@ -0,0 +1,3 @@ +import '@/scss/admin-settings/notice.scss'; +import '@/scss/admin-settings/sortable-item.scss'; +import '@/scss/admin-settings/wrapper-group.scss'; diff --git a/plugins/admin-settings/email-types/frontend.jsx b/plugins/admin-settings/email-types/frontend.jsx new file mode 100644 index 00000000..4188b76d --- /dev/null +++ b/plugins/admin-settings/email-types/frontend.jsx @@ -0,0 +1,19 @@ +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; + +// Components. +import AdminEmailTypes from './index'; + +const element = document.getElementById('wp-newsletter-builder-settings__page-email-types'); + +if (element) { + const root = createRoot(element); + + if (root) { + root.render( + + + , + ); + } +} diff --git a/plugins/admin-settings/email-types/index.jsx b/plugins/admin-settings/email-types/index.jsx new file mode 100644 index 00000000..63755608 --- /dev/null +++ b/plugins/admin-settings/email-types/index.jsx @@ -0,0 +1,164 @@ +import { useEffect, useState } from 'react'; +import { __ } from '@wordpress/i18n'; +import { + Button, SelectControl, TextControl, withNotices, +} from '@wordpress/components'; +import ImagePicker from '@/components/imagePicker'; +import { + Checkboxes, Sortable, SortableItem, useOption, +} from '@alleyinteractive/block-editor-tools'; +import apiFetch from '@wordpress/api-fetch'; +import { v4 as uuidv4 } from 'uuid'; + +const AdminEmailTypes = withNotices( + ({ noticeOperations, noticeUI }) => { + const { + value: emailTypes = {}, + isEdited = false, + isSaving = false, + onChange = () => {}, + onSave = () => {}, + } = useOption('nb_email_types'); + + const { + value: settings = {}, + } = useOption('nb_settings'); + + const { + from_names: fromNames = [], + } = settings; + + const fromNameOptions = fromNames.map( + (name) => ({ label: name, value: name }), + ); + + // Get all posts with the nb_template post type. + const [templatePosts, setTemplatePosts] = useState([]); + useEffect(() => { + apiFetch({ path: '/wp/v2/nb_template' }) + .then((response) => { + const templateOptions = response.map( + (template) => { + const { + id: value = 0, + title: { + rendered: label = '', + } = {}, + } = template; + return { label, value }; + }, + ); + setTemplatePosts(templateOptions); + }); + }, []); + + /** + * Save settings data and display a notice. + */ + const { createErrorNotice, createNotice, removeAllNotices } = noticeOperations; + const saveSettingsData = () => { + onSave().then(() => { + // Remove other notices. + removeAllNotices(); + + // Display a success notice. + createNotice({ + status: 'success', + content: __('Options updated', 'wp-newsletter-builder'), + }); + }).catch(() => { + // Remove other notices. + removeAllNotices(); + + // Display an error notice. + createErrorNotice(__('Failed to update options', 'wp-newsletter-builder')); + }); + }; + + /** + * Update settings array with new data. + * @param {number} index Index to update. + * @param {string} key Key to update. + * @param {string} value Value to update. + */ + const updateSettingsData = (index, key, value) => { + emailTypes[index][key] = value; + onChange(emailTypes); + }; + + return ( +
+
+

{__('Email Types', 'wp-newsletter-builder')}

+ { noticeUI } +
+ + {emailTypes && emailTypes.length + ? emailTypes.map((emailType, index) => ( +
+ +

{__('Email Type', 'wp-newsletter-builder')}

+
+ updateSettingsData(index, 'label', value)} + value={emailType.label} + /> +
+
+ updateSettingsData(index, 'image', value)} + value={emailType.image} + /> +
+
+ {templatePosts.length !== 0 ? ( + updateSettingsData(index, 'templates', value)} + options={templatePosts} + value={emailType.templates} + /> + ) :

{__('No templates found.', 'wp-newsletter-builder')}

} +
+
+ {fromNameOptions.length !== 0 ? ( + updateSettingsData(index, 'from_name', value)} + options={fromNameOptions} + value={emailType.from_name} + /> + ) :

{__('No from names found.', 'wp-newsletter-builder')}

} +
+
+
+ )) + : null} +
+
+ +
+
+ ); + }, +); + +export default AdminEmailTypes; diff --git a/plugins/admin-settings/general-settings/frontend.jsx b/plugins/admin-settings/general-settings/frontend.jsx new file mode 100644 index 00000000..f6aa72a5 --- /dev/null +++ b/plugins/admin-settings/general-settings/frontend.jsx @@ -0,0 +1,19 @@ +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; + +// Components. +import AdminGeneralSettings from './index'; + +const element = document.getElementById('wp-newsletter-builder-settings__page-general-settings'); + +if (element) { + const root = createRoot(element); + + if (root) { + root.render( + + + , + ); + } +} diff --git a/plugins/admin-settings/general-settings/index.jsx b/plugins/admin-settings/general-settings/index.jsx new file mode 100644 index 00000000..6b14398f --- /dev/null +++ b/plugins/admin-settings/general-settings/index.jsx @@ -0,0 +1,161 @@ +import { __ } from '@wordpress/i18n'; +import { Button, TextControl, withNotices } from '@wordpress/components'; +import ImagePicker from '@/components/imagePicker'; +import { Sortable, SortableItem, useOption } from '@alleyinteractive/block-editor-tools'; + +const AdminGeneralSettings = withNotices( + ({ noticeOperations, noticeUI }) => { + const { + value: settings = {}, + isEdited = false, + isSaving = false, + onChange = () => {}, + onSave = () => {}, + } = useOption('nb_settings'); + + const { + from_email: fromEmail = '', + reply_to_email: replyToEmail = '', + from_names: fromNames = [], + facebook_url: facebookUrl = '', + twitter_url: twitterUrl = '', + instagram_url: instagramUrl = '', + youtube_url: youtubeUrl = '', + image = 0, + address = '', + } = settings; + + /** + * Update settings array with new data. + * @param {string} key Key to update. + * @param {string} value Value to update. + */ + const updateSettingsData = (key, value) => { + onChange({ + ...settings, + [key]: value, + }); + }; + + /** + * Save settings data and display a notice. + */ + const { createErrorNotice, createNotice, removeAllNotices } = noticeOperations; + const saveSettingsData = () => { + onSave().then(() => { + // Remove other notices. + removeAllNotices(); + + // Display a success notice. + createNotice({ + status: 'success', + content: __('Options updated', 'wp-newsletter-builder'), + }); + }).catch(() => { + // Remove other notices. + removeAllNotices(); + + // Display an error notice. + createErrorNotice(__('Failed to update options', 'wp-newsletter-builder')); + }); + }; + + return ( +
+
+

{__('General Settings', 'wp-newsletter-builder')}

+ { noticeUI } +
+

{__('From Email', 'wp-newsletter-builder')}

+ updateSettingsData('from_email', value)} + value={fromEmail} + /> +
+
+

{__('Reply-To Email', 'wp-newsletter-builder')}

+ updateSettingsData('reply_to_email', value)} + value={replyToEmail} + /> +
+
+

{__('From Names', 'wp-newsletter-builder')}

+ updateSettingsData('from_names', value)} + > + {fromNames && fromNames.length + ? fromNames.map((fromName, index) => ( + updateSettingsData('from_names', value)} + > + { + const updatedFromNames = [...fromNames]; + updatedFromNames[index] = value; + updateSettingsData('from_names', updatedFromNames); + }} + value={fromName} + /> + + )) : null} + +
+
+

{__('Footer Settings', 'wp-newsletter-builder')}

+ updateSettingsData('facebook_url', value)} + value={facebookUrl} + /> + updateSettingsData('twitter_url', value)} + value={twitterUrl} + /> + updateSettingsData('instagram_url', value)} + value={instagramUrl} + /> + updateSettingsData('youtube_url', value)} + value={youtubeUrl} + /> + updateSettingsData('image', value)} + value={image} + /> + updateSettingsData('address', value)} + value={address} + /> +
+ +
+
+ ); + }, +); + +export default AdminGeneralSettings; diff --git a/scss/admin-settings/notice.scss b/scss/admin-settings/notice.scss new file mode 100644 index 00000000..5ac37af0 --- /dev/null +++ b/scss/admin-settings/notice.scss @@ -0,0 +1,20 @@ +.components-notice-list { + .components-notice { + --border: 1px solid #c3c4c7; + + &.is-error, + &.is-info, + &.is-success, + &.is-warning { + background-color: #fff; + border-bottom: var(--border); + border-right: var(--border); + border-top: var(--border); + } + + &__content { + margin-bottom: 0; + margin-top: 0; + } + } +} diff --git a/scss/admin-settings/sortable-item.scss b/scss/admin-settings/sortable-item.scss new file mode 100644 index 00000000..8e9403b1 --- /dev/null +++ b/scss/admin-settings/sortable-item.scss @@ -0,0 +1,6 @@ +.wp-newsletter-builder-settings__sortable-item { + background-color: #fff; + border: 1px solid #c3c4c7; + margin-bottom: 5px; + padding: 10px 20px; +} \ No newline at end of file diff --git a/scss/admin-settings/wrapper-group.scss b/scss/admin-settings/wrapper-group.scss new file mode 100644 index 00000000..2128c1ed --- /dev/null +++ b/scss/admin-settings/wrapper-group.scss @@ -0,0 +1,3 @@ +.wp-newsletter-builder-settings__wrapper-group { + margin: 20px auto 30px; +} \ No newline at end of file diff --git a/src/class-email-types.php b/src/class-email-types.php index d9e1a706..e7d515b8 100644 --- a/src/class-email-types.php +++ b/src/class-email-types.php @@ -24,22 +24,130 @@ class Email_Types { * @return void */ public function __construct() { - add_action( 'init', [ $this, 'maybe_register_settings_page' ] ); - add_filter( 'pre_update_option_' . static::SETTINGS_KEY, [ $this, 'sort_settings_on_save' ], 10, 1 ); + // add_action( 'init', [ $this, 'maybe_register_settings_page' ] ); + // add_filter( 'pre_update_option_' . static::SETTINGS_KEY, [ $this, 'sort_settings_on_save' ], 10, 1 ); + + add_action( 'admin_init', [ $this, 'register_scripts' ] ); + add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] ); + add_action( 'admin_menu', [ $this, 'register_submenu_page' ] ); + add_action( 'admin_init', [ $this, 'register_settings' ] ); + add_action( 'rest_api_init', [ $this, 'register_settings' ] ); } /** - * Registers the submenu settings page for the Email Types. - * - * @return void + * Register scripts for the settings page. + */ + public function register_scripts() { + wp_register_script( + 'wp-newsletter-builder-admin-email-types', + get_entry_asset_url( 'wp-newsletter-builder-admin-email-types' ), + array_merge( get_asset_dependency_array( 'wp-newsletter-builder-admin-email-types' ), [ 'wp-editor' ] ), + get_asset_version( 'wp-newsletter-builder-admin-email-types' ), + true + ); + wp_set_script_translations( 'wp-newsletter-builder-admin-email-types' ); + } + + /** + * Enqueue scripts and styles for the settings page. + */ + public function enqueue_assets() { + wp_enqueue_script( 'wp-newsletter-builder-admin-email-types' ); + + // Enqueue styles for the settings page. + wp_enqueue_style( + 'wp-newsletter-builder-admin-email-types', + get_entry_asset_url( 'wp-newsletter-builder-admin-email-types', 'index.css' ), + [], + get_asset_version( 'wp-newsletter-builder-admin-email-types' ), + ); + + // Enqueue styles for all settings pages. + wp_enqueue_style( + 'wp-newsletter-builder-admin-settings', + get_entry_asset_url( 'admin-settings', 'index.css' ), + get_asset_dependency_array( 'admin-settings' ), + get_asset_version( 'admin-settings' ), + ); + + // Core component styles. + wp_enqueue_style( 'wp-components' ); + + // Media functionality for Media Library button. + wp_enqueue_media(); + } + + /** + * Register the settings submenu page. */ + public function register_submenu_page(): void { + add_submenu_page( + 'edit.php?post_type=nb_newsletter', + __( 'Email Types', 'wp-newsletter-builder' ), + __( 'Email Types', 'wp-newsletter-builder' ), + 'manage_options', + 'email-types', + [ $this, 'options_menu_callback' ], + ); + } + + /** + * Callback function for add_submenu_page. Renders react entrypoint. + */ + public function options_menu_callback(): void { + echo '
'; + } + public function maybe_register_settings_page(): void { if ( function_exists( 'fm_register_submenu_page' ) && \current_user_can( 'manage_options' ) ) { - \fm_register_submenu_page( static::SETTINGS_KEY, 'edit.php?post_type=nb_newsletter', __( 'Email Types', 'wp-newsletter-builder' ), __( 'Email Types', 'wp-newsletter-builder' ) ); - \add_action( 'fm_submenu_' . static::SETTINGS_KEY, [ $this, 'register_fields' ] ); + \fm_register_submenu_page( static::SETTINGS_KEY, 'edit.php?post_type=nb_newsletter', __( 'Email Types', 'wp-newsletter-builder' ), __( 'Email Types', 'wp-newsletter-builder' ) ); + \add_action( 'fm_submenu_' . static::SETTINGS_KEY, [ $this, 'register_fields' ] ); } } + /** + * Register the settings for the page. + */ + public function register_settings(): void { + register_setting( + 'options', + static::SETTINGS_KEY, + [ + 'type' => 'object', + 'show_in_rest' => [ + 'schema' => [ + 'type' => 'array', + 'properties' => [ + 'uuid4' => [ + 'type' => 'string', + ], + 'label' => [ + 'type' => 'string', + ], + 'image' => [ + 'type' => 'number', + ], + 'templates' => [ + 'type' => 'object', + 'properties' => [ + 'id' => [ + 'type' => 'number', + ], + 'label' => [ + 'type' => 'string', + ], + ], + ], + 'from_name' => [ + 'type' => 'string', + ], + ], + ], + ], + ], + ); + } + /** * Registers the fields on the settings page for the Campaign Monitor options. * diff --git a/src/class-rest-api-endpoints.php b/src/class-rest-api-endpoints.php index abeafd36..d3c19105 100644 --- a/src/class-rest-api-endpoints.php +++ b/src/class-rest-api-endpoints.php @@ -54,10 +54,10 @@ public function register_endpoints(): void { ); register_rest_route( 'wp-newsletter-builder/v1', - '/footer_settings/', + '/settings/', [ 'methods' => 'GET', - 'callback' => [ $this, 'get_footer_settings' ], + 'callback' => [ $this, 'get_settings' ], 'permission_callback' => function () { return current_user_can( 'edit_posts' ); }, @@ -138,6 +138,9 @@ public function get_email_types(): WP_Error|array { * Gets the settings from options. * * @return WP_Error|false|array{ + * from_email?: string, + * reply_to_email?: string, + * from_names?: array, * facebook_url?: string, * twitter_url?: string, * instagram_url?: string, @@ -147,13 +150,13 @@ public function get_email_types(): WP_Error|array { * address_2?: string, * } */ - public function get_footer_settings(): WP_Error|false|array { + public function get_settings(): WP_Error|false|array { if ( ! current_user_can( 'edit_posts' ) ) { return new WP_Error( 'rest_forbidden', esc_html__( 'You do not have permission to access this endpoint.', 'wp-newsletter-builder' ), [ 'status' => 401 ] ); } $settings = new Settings(); - return $settings->get_footer_settings(); + return $settings->get_settings(); } /** diff --git a/src/class-settings.php b/src/class-settings.php index 629b94b9..739d1cb4 100644 --- a/src/class-settings.php +++ b/src/class-settings.php @@ -24,97 +24,134 @@ class Settings { * @return void */ public function __construct() { - add_action( 'init', [ $this, 'maybe_register_settings_page' ] ); + add_action( 'admin_init', [ $this, 'register_scripts' ] ); + add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] ); + add_action( 'admin_menu', [ $this, 'register_submenu_page' ] ); + add_action( 'admin_init', [ $this, 'register_settings' ] ); + add_action( 'rest_api_init', [ $this, 'register_settings' ] ); } /** - * Registers the submenu settings page for Newsletter Builder. - * - * @return void + * Register scripts for the settings page. */ - public function maybe_register_settings_page(): void { - if ( function_exists( 'fm_register_submenu_page' ) && \current_user_can( 'manage_options' ) ) { - \fm_register_submenu_page( static::SETTINGS_KEY, 'edit.php?post_type=nb_newsletter', __( 'General Settings', 'wp-newsletter-builder' ), __( 'General Settings', 'wp-newsletter-builder' ) ); - \add_action( 'fm_submenu_' . static::SETTINGS_KEY, [ $this, 'register_fields' ] ); - } + public function register_scripts() { + wp_register_script( + 'wp-newsletter-builder-admin-general-settings', + get_entry_asset_url( 'wp-newsletter-builder-admin-general-settings' ), + array_merge( get_asset_dependency_array( 'wp-newsletter-builder-admin-general-settings' ), [ 'wp-editor' ] ), + get_asset_version( 'wp-newsletter-builder-admin-general-settings' ), + true + ); + wp_set_script_translations( 'wp-newsletter-builder-admin-general-settings' ); } /** - * Registers the fields on the settings page for Newsletter Builder. - * - * @return void + * Enqueue scripts and styles for the settings page. */ - public function register_fields(): void { - $fields = [ - 'name' => static::SETTINGS_KEY, - 'children' => [ - 'from_email' => new \Fieldmanager_TextField( __( 'From Email', 'wp-newsletter-builder' ) ), - 'reply_to_email' => new \Fieldmanager_TextField( __( 'Reply To Email', 'wp-newsletter-builder' ) ), - 'from_names' => new \Fieldmanager_TextField( - [ - 'label' => __( 'From Names', 'wp-newsletter-builder' ), - 'limit' => 0, - 'add_more_label' => __( 'Add From Name', 'wp-newsletter-builder' ), - 'one_label_per_item' => false, - ] - ), - 'footer_settings' => new \Fieldmanager_Group( - [ - 'label' => __( 'Footer Settings', 'wp-newsletter-builder' ), - 'collapsed' => true, - 'collapsible' => true, - 'children' => [ - 'facebook_url' => new \Fieldmanager_Link( - [ - 'label' => __( 'Facebook URL', 'wp-newsletter-builder' ), - ] - ), - 'twitter_url' => new \Fieldmanager_Link( - [ - 'label' => __( 'Twitter URL', 'wp-newsletter-builder' ), - ] - ), - 'instagram_url' => new \Fieldmanager_Link( - [ - 'label' => __( 'Instagram URL', 'wp-newsletter-builder' ), - ] - ), - 'youtube_url' => new \Fieldmanager_Link( - [ - 'label' => __( 'YouTube URL', 'wp-newsletter-builder' ), - ] - ), - 'image' => new \Fieldmanager_Media( - [ - 'label' => __( 'Footer Image', 'wp-newsletter-builder' ), - 'preview_size' => 'medium', - ] - ), - 'address' => new \Fieldmanager_TextField( - [ - 'label' => __( 'Company Address Line 1', 'wp-newsletter-builder' ), - ] - ), - 'address_2' => new \Fieldmanager_TextField( - [ - 'label' => __( 'Company Address Line 2', 'wp-newsletter-builder' ), - ] - ), + public function enqueue_assets() { + wp_enqueue_script( 'wp-newsletter-builder-admin-general-settings' ); + + // Enqueue styles for the settings page. + wp_enqueue_style( + 'wp-newsletter-builder-admin-general-settings', + get_entry_asset_url( 'wp-newsletter-builder-admin-general-settings', 'index.css' ), + [], + get_asset_version( 'wp-newsletter-builder-admin-general-settings' ), + ); + + // Enqueue styles for all settings pages. + wp_enqueue_style( + 'wp-newsletter-builder-admin-settings', + get_entry_asset_url( 'admin-settings', 'index.css' ), + get_asset_dependency_array( 'admin-settings' ), + get_asset_version( 'admin-settings' ), + ); + + // Core component styles. + wp_enqueue_style( 'wp-components' ); + + // Media functionality for Media Library button. + wp_enqueue_media(); + } + + /** + * Register the settings submenu page. + */ + public function register_submenu_page(): void { + add_submenu_page( + 'edit.php?post_type=nb_newsletter', + __( 'General Settings', 'wp-newsletter-builder' ), + __( 'General Settings', 'wp-newsletter-builder' ), + 'manage_options', + 'general-settings', + [ $this, 'options_menu_callback' ], + ); + } + + /** + * Callback function for add_submenu_page. Renders react entrypoint. + */ + public function options_menu_callback(): void { + echo '
'; + } + + /** + * Register the settings for the page. + */ + public function register_settings(): void { + register_setting( + 'options', + static::SETTINGS_KEY, + [ + 'type' => 'object', + 'show_in_rest' => [ + 'schema' => [ + 'type' => 'object', + 'properties' => [ + 'from_email' => [ + 'type' => 'string', + 'format' => 'email', + ], + 'reply_to_email' => [ + 'type' => 'string', + 'format' => 'email', + ], + 'from_names' => [ + 'type' => 'array', + 'items' => [ + 'type' => 'string', + ], + ], + 'facebook_url' => [ + 'type' => 'string', + 'format' => 'uri', + ], + 'twitter_url' => [ + 'type' => 'string', + 'format' => 'uri', + ], + 'instagram_url' => [ + 'type' => 'string', + 'format' => 'uri', + ], + 'youtube_url' => [ + 'type' => 'string', + 'format' => 'uri', + ], + 'image' => [ + 'type' => 'number', + ], + 'address' => [ + 'type' => 'string', + ], + 'address_2' => [ + 'type' => 'string', + ], ], - ] - ), - ], - ]; - global $newsletter_builder_email_provider; - if ( ! empty( $newsletter_builder_email_provider ) && $newsletter_builder_email_provider instanceof Email_Providers\Email_Provider ) { - if ( $newsletter_builder_email_provider->provider_manages_from_names() ) { - unset( $fields['children']['from_email'] ); - unset( $fields['children']['reply_to_email'] ); - unset( $fields['children']['from_names'] ); - } - } - $settings = new \Fieldmanager_Group( $fields ); - $settings->activate_submenu_page(); + ], + ], + ] + ); } /** @@ -154,11 +191,14 @@ public function get_lists(): mixed { } /** - * Gets footer settings. + * Gets settings. * * @TODO: Add caching that works on Pantheon and WordPress VIP. * * @return array{ + * from_email?: string, + * reply_to_email?: string, + * from_names?: array, * facebook_url?: string, * twitter_url?: string, * instagram_url?: string, @@ -168,13 +208,13 @@ public function get_lists(): mixed { * address_2?: string, * }|false The footer settings. */ - public function get_footer_settings(): array|false { + public function get_settings(): array|false { $settings = get_option( static::SETTINGS_KEY ); - if ( empty( $settings ) || ! is_array( $settings ) || empty( $settings['footer_settings'] ) || ! is_array( $settings['footer_settings'] ) ) { + if ( empty( $settings ) || ! is_array( $settings ) ) { return false; } - return $settings['footer_settings']; + return $settings; } /** diff --git a/webpack.config.js b/webpack.config.js index 0f33c61a..b8d610e9 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -35,6 +35,8 @@ module.exports = (env, { mode }) => ({ 'newsletter-status/index': './plugins/newsletter-status', 'newsletter-template-styles/index': './plugins/newsletter-template-styles', 'pre-publish-checks/index': './plugins/pre-publish-checks', + 'wp-newsletter-builder-admin-general-settings/index': './plugins/admin-settings/general-settings/frontend.jsx', + 'wp-newsletter-builder-admin-email-types/index': './plugins/admin-settings/email-types/frontend.jsx', }), }; },