Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Implement comprehensive newsletter settings UI with DataForm-based interface, toggle controls, and card-based design
5 changes: 5 additions & 0 deletions projects/packages/newsletter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,14 @@
"extends @wordpress/browserslist-config"
],
"dependencies": {
"@automattic/jetpack-api": "workspace:*",
"@automattic/jetpack-components": "workspace:*",
"@wordpress/components": "30.8.0",
"@wordpress/dataviews": "10.2.0",
"@wordpress/element": "6.35.0",
"@wordpress/i18n": "6.8.0",
"@wordpress/notices": "5.35.0",
"@wordpress/url": "4.35.0",
"debug": "4.4.1"
},
"devDependencies": {
Expand Down
63 changes: 63 additions & 0 deletions projects/packages/newsletter/src/class-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,69 @@
'enqueue' => true,
)
);

wp_add_inline_script(
'jetpack-newsletter',
'window.jetpackNewsletterSettings = ' . wp_json_encode( $this->get_settings_data() ) . ';',
'before'
);
}

/**
* Get the data to be passed to the newsletter settings page.
*
* @return array
*/
private function get_settings_data() {
$current_user = wp_get_current_user();
$theme = wp_get_theme();

// Get blog ID if available (for WordPress.com sites).
$blog_id = defined( 'Jetpack_Options' ) && class_exists( 'Jetpack_Options' )
? \Jetpack_Options::get_option( 'id', 0 )

Check failure on line 145 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / Static analysis

UndefError PhanUndeclaredClassMethod Call to method get_option from undeclared class \Jetpack_Options FAQ on Phan issues: pdWQjU-Jb-p2
: 0;

// Get site URL without protocol.
$site_url = get_site_url();
$site_raw_url = preg_replace( '(^https?://)', '', $site_url );

return array(
'isBlockTheme' => wp_is_block_theme(),

Check warning on line 153 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array double arrow not aligned correctly; expected 23 space(s) between "'isBlockTheme'" and double arrow, but found 6. (WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned)
'siteAdminUrl' => admin_url(),

Check warning on line 154 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array double arrow not aligned correctly; expected 23 space(s) between "'siteAdminUrl'" and double arrow, but found 6. (WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned)
'themeStylesheet' => $theme->get_stylesheet(),

Check warning on line 155 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array double arrow not aligned correctly; expected 20 space(s) between "'themeStylesheet'" and double arrow, but found 3. (WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned)
'blogID' => $blog_id,

Check warning on line 156 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array double arrow not aligned correctly; expected 29 space(s) between "'blogID'" and double arrow, but found 12. (WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned)
'siteRawUrl' => $site_raw_url,

Check warning on line 157 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array double arrow not aligned correctly; expected 25 space(s) between "'siteRawUrl'" and double arrow, but found 8. (WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned)
'email' => $current_user->user_email,

Check warning on line 158 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array double arrow not aligned correctly; expected 30 space(s) between "'email'" and double arrow, but found 13. (WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned)
'gravatar' => get_avatar_url( $current_user->ID ),

Check warning on line 159 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array double arrow not aligned correctly; expected 27 space(s) between "'gravatar'" and double arrow, but found 10. (WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned)
'displayName' => $current_user->display_name,

Check warning on line 160 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array double arrow not aligned correctly; expected 24 space(s) between "'displayName'" and double arrow, but found 7. (WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned)
'wpAdminSubscriberManagementEnabled' => apply_filters( 'jetpack_wpcom_subscriber_management_enabled', false ),
'isSubscriptionSiteEditSupported' => wp_is_block_theme(),
'setupPaymentPlansUrl' => $this->get_jetpack_cloud_url( 'monetize/payments' ),

Check warning on line 163 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array double arrow not aligned correctly; expected 15 space(s) between "'setupPaymentPlansUrl'" and double arrow, but found 1. (WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned)
'isSitePublic' => (int) get_option( 'blog_public' ) === 1,

Check warning on line 164 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / PHP Code Sniffer (non-excluded files only)

Array double arrow not aligned correctly; expected 23 space(s) between "'isSitePublic'" and double arrow, but found 6. (WordPress.Arrays.MultipleStatementAlignment.DoubleArrowNotAligned)
);
}

/**
* Get a Jetpack Cloud URL.
*
* @param string $path The path to append to the Jetpack Cloud URL.
* @return string
*/
private function get_jetpack_cloud_url( $path = '' ) {
$site_suffix = '';
if ( defined( 'Jetpack_Options' ) && class_exists( 'Jetpack_Options' ) ) {
$blog_id = \Jetpack_Options::get_option( 'id', 0 );

Check failure on line 177 in projects/packages/newsletter/src/class-settings.php

View workflow job for this annotation

GitHub Actions / Static analysis

UndefError PhanUndeclaredClassMethod Call to method get_option from undeclared class \Jetpack_Options FAQ on Phan issues: pdWQjU-Jb-p2
if ( $blog_id ) {
$site_suffix = $blog_id;
}
}

if ( ! $site_suffix ) {
$site_url = get_site_url();
$site_suffix = preg_replace( '(^https?://)', '', $site_url );
}

return 'https://cloud.jetpack.com/' . ltrim( $path, '/' ) . '/' . $site_suffix;
}

/**
Expand Down
17 changes: 17 additions & 0 deletions projects/packages/newsletter/src/settings/components/header.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.newsletter-settings__header {
margin-bottom: 2em;

&-top {
display: flex;
align-items: center;
gap: 1em;
}
}

.newsletter-settings__title {
margin: 0;
}

.newsletter-settings__tagline {
margin: 8px 0 0;
}
34 changes: 34 additions & 0 deletions projects/packages/newsletter/src/settings/components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* External dependencies
*/
import { JetpackLogo } from '@automattic/jetpack-components';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import './header.scss';

/**
* Newsletter Settings Header Component
*
* @return {JSX.Element} The header component.
*/
export function Header(): JSX.Element {
return (
<header className="newsletter-settings__header">
<div className="newsletter-settings__header-top">
<JetpackLogo showText={ false } width={ 20 } />
<h1 className="newsletter-settings__title">
{ __( 'Newsletter Settings', 'jetpack-newsletter' ) }
</h1>
</div>
<p className="newsletter-settings__tagline">
{ __(
'Transform your blog posts into newsletters to easily reach your subscribers.',
'jetpack-newsletter'
) }
</p>
</header>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.toggle-with-link__label {
display: inline-flex;
align-items: center;
gap: 0.5em;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* External dependencies
*/
import { ExternalLink, ToggleControl } from '@wordpress/components';
import { type Field } from '@wordpress/dataviews';
import { useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { addQueryArgs } from '@wordpress/url';

/**
* Internal dependencies
*/
import './toggle-with-link.scss';

interface ToggleWithLinkProps {
data: Record< string, unknown >;
field: Field< Record< string, unknown > >;
onChange: ( updates: Record< string, unknown > ) => void;
url: string;
linkText: string;
}

/**
* Generic toggle control with an external link in the label
*
* @param {object} props - Component props
* @param {object} props.data - The data object
* @param {object} props.field - The field definition
* @param {Function} props.onChange - Change handler
* @param {string} props.url - URL for the external link
* @param {string} props.linkText - Text for the link
* @return {JSX.Element} The toggle control with link
*/
function ToggleWithLink( {
data,
field,
onChange,
url,
linkText,
}: ToggleWithLinkProps ): JSX.Element {
const handleChange = useCallback( () => {
onChange( { [ field.id ]: ! data[ field.id ] } );
}, [ data, field.id, onChange ] );

return (
<ToggleControl
checked={ !! data[ field.id ] }
onChange={ handleChange }
label={
<span className="toggle-with-link__label">
{ field.label }
<ExternalLink href={ url }>{ linkText }</ExternalLink>
</span>
}
/>
);
}

interface ToggleWithEditorLinkProps {
data: Record< string, unknown >;
field: Field< Record< string, unknown > >;
onChange: ( updates: Record< string, unknown > ) => void;
siteAdminUrl: string;
themeStylesheet: string;
postType: 'wp_template' | 'wp_template_part';
templateId: string;
}

/**
* Toggle control with a "Preview and edit" link to the site editor
*
* @param {object} props - Component props
* @param {object} props.data - The data object
* @param {object} props.field - The field definition
* @param {Function} props.onChange - Change handler
* @param {string} props.siteAdminUrl - Site admin URL
* @param {string} props.themeStylesheet - Theme stylesheet name
* @param {string} props.postType - Post type (wp_template or wp_template_part)
* @param {string} props.templateId - Template ID
* @return {JSX.Element} The toggle control with editor link
*/
export function ToggleWithEditorLink( {
data,
field,
onChange,
siteAdminUrl,
themeStylesheet,
postType,
templateId,
}: ToggleWithEditorLinkProps ): JSX.Element {
const url = addQueryArgs( `${ siteAdminUrl }site-editor.php`, {
postType,
postId: `${ themeStylesheet }//${ templateId }`,
canvas: 'edit',
} );

return (
<ToggleWithLink
data={ data }
field={ field }
onChange={ onChange }
url={ url }
linkText={ __( 'Preview and edit', 'jetpack-newsletter' ) }
/>
);
}
Loading
Loading