Skip to content

Commit 17e3e13

Browse files
authored
Merge pull request #479 from Codeinwp/feat/onboarding-tone-down-banners
feat(onboarding): tone down starter-sites listing banners
2 parents 1ff09fd + 7f00186 commit 17e3e13

10 files changed

Lines changed: 187 additions & 340 deletions

File tree

e2e-tests/specs/onboarding.spec.js

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -62,41 +62,6 @@ test.describe('Onboarding', () => {
6262
await expect(firstListedSiteCard.locator('.ss-title')).not.toBeEmpty();
6363
});
6464

65-
test('Onboarding promo notice can be dismissed and stays hidden after reload', async ({ page, admin }) => {
66-
await admin.visitAdminPage(ONBOARDING_URL);
67-
68-
const promoNotice = page.locator('.ob-onboarding-promo');
69-
await expect(promoNotice).toBeVisible();
70-
71-
// The client sends the dismiss action via FormData, which fetch encodes as
72-
// multipart/form-data. Inspect the raw body bytes so the predicate works
73-
// regardless of whether the encoding is multipart or url-encoded.
74-
const isDismissCall = (request) =>
75-
request.url().includes('admin-ajax.php') &&
76-
request.method() === 'POST' &&
77-
(request.postDataBuffer()?.toString('utf8') ?? '').includes(
78-
'dismiss_onboarding_promo_notice'
79-
);
80-
81-
const dismissRequest = page.waitForRequest(isDismissCall);
82-
const dismissResponse = page.waitForResponse((response) =>
83-
isDismissCall(response.request())
84-
);
85-
86-
await promoNotice.getByRole('button', { name: 'Dismiss notice' }).click();
87-
88-
const request = await dismissRequest;
89-
const response = await dismissResponse;
90-
expect(request.postDataBuffer()?.toString('utf8')).toContain(
91-
'dismiss_onboarding_promo_notice'
92-
);
93-
expect(response.ok()).toBeTruthy();
94-
95-
await expect(promoNotice).toBeHidden();
96-
await page.reload();
97-
await expect(promoNotice).toBeHidden();
98-
});
99-
10065
test('Site Import Customization Rendering', async ({ page, admin }) => {
10166
await admin.visitAdminPage(ONBOARDING_URL);
10267
await openFirstSiteAndWaitForData( page );

includes/Admin.php

Lines changed: 3 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,9 @@ class Admin {
2424
const IMPORTED_TEMPLATES_COUNT_OPT = 'tiob_premade_imported';
2525
const FEEDBACK_DISMISSED_OPT = 'tiob_feedback_dismiss';
2626

27-
const TC_REMOVED_KEY = 'tiob_tc_removed';
28-
const TC_NEW_NOTICE_DISMISSED = 'tiob_new_tc_notice_dismissed';
29-
const ONBOARDING_PROMO_NOTICE_DISMISSED = 'tiob_onboarding_promo_notice_dismissed';
30-
const VISITED_LIBRARY_OPT = 'tiob_library_visited';
27+
const TC_REMOVED_KEY = 'tiob_tc_removed';
28+
const TC_NEW_NOTICE_DISMISSED = 'tiob_new_tc_notice_dismissed';
29+
const VISITED_LIBRARY_OPT = 'tiob_library_visited';
3130

3231
/**
3332
* Admin page slug
@@ -89,7 +88,6 @@ public function init() {
8988
add_action( 'wp_ajax_tpc_get_logs', array( $this, 'external_get_logs' ) );
9089

9190
add_action( 'wp_ajax_dismiss_new_tc_notice', array( $this, 'dismiss_new_tc_notice' ) );
92-
add_action( 'wp_ajax_dismiss_onboarding_promo_notice', array( $this, 'dismiss_onboarding_promo_notice' ) );
9391

9492
$this->register_feedback_settings();
9593

@@ -163,52 +161,6 @@ public function dismiss_new_tc_notice() {
163161
$this->ensure_ajax_response( $response );
164162
}
165163

166-
/**
167-
* Dismiss onboarding promo notice.
168-
*
169-
* @return void
170-
*/
171-
public function dismiss_onboarding_promo_notice() {
172-
$response = array(
173-
'success' => false,
174-
'code' => 'ti__ob_not_allowed',
175-
'message' => 'Not allowed!',
176-
);
177-
178-
if ( ! isset( $_REQUEST['nonce'] ) ) {
179-
$this->ensure_ajax_response( $response );
180-
return;
181-
}
182-
183-
$nonce = sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) );
184-
185-
if ( ! wp_verify_nonce( $nonce, 'dismiss_onboarding_promo_notice' ) ) {
186-
$this->ensure_ajax_response( $response );
187-
return;
188-
}
189-
190-
if ( ! current_user_can( 'install_plugins' ) ) {
191-
$this->ensure_ajax_response( $response );
192-
return;
193-
}
194-
195-
$response['success'] = true;
196-
unset( $response['code'] );
197-
unset( $response['message'] );
198-
199-
update_option( self::ONBOARDING_PROMO_NOTICE_DISMISSED, 'yes' );
200-
$this->ensure_ajax_response( $response );
201-
}
202-
203-
/**
204-
* Decide if the onboarding promo notice should be shown.
205-
*
206-
* @return bool
207-
*/
208-
private function should_show_onboarding_promo_notice() {
209-
return get_option( self::ONBOARDING_PROMO_NOTICE_DISMISSED, 'no' ) !== 'yes';
210-
}
211-
212164
/**
213165
* Decide if the business/agency variant of the onboarding promo text should be shown.
214166
*
@@ -937,11 +889,6 @@ private function get_localization() {
937889
'ajaxURL' => esc_url( admin_url( 'admin-ajax.php' ) ),
938890
'nonce' => wp_create_nonce( 'dismiss_new_tc_notice' ),
939891
),
940-
'onboardingPromoNotice' => array(
941-
'show' => $this->should_show_onboarding_promo_notice(),
942-
'ajaxURL' => esc_url( admin_url( 'admin-ajax.php' ) ),
943-
'nonce' => wp_create_nonce( 'dismiss_onboarding_promo_notice' ),
944-
),
945892
'onboardingPluginCompatibility' => array(
946893
'hyve-lite' => is_php_version_compatible( '8.1' ),
947894
),

onboarding/src/Components/OnboardingPromoNotice.js

Lines changed: 0 additions & 96 deletions
This file was deleted.

onboarding/src/Components/Steps/SiteList.js

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import Toast from '../Toast';
1111
import Filters from '../Filters';
1212
import Sites from '../Sites';
1313
import EditorSelector from '../EditorSelector';
14-
import OnboardingPromoNotice from '../OnboardingPromoNotice';
1514
import SVG from '../../utils/svg';
1615
import { get, track } from '../../utils/rest';
1716

@@ -41,18 +40,16 @@ const SiteList = ( {
4140

4241
const toastMessage = createInterpolateElement(
4342
__(
44-
'Unlock Access to all premium templates with Neve Business plan. <a></a>.',
43+
'Included with Neve Business. <a>See plans</a>',
4544
'templates-patterns-collection'
4645
),
4746
{
4847
a: (
4948
<a
5049
href={ tiobDash.onboardingUpsell.upgradeToast }
5150
target="_blank"
52-
rel="external noreferrer noopener"
53-
>
54-
{ __( 'Get Started', 'templates-patterns-collection' ) }
55-
</a>
51+
rel="noopener noreferrer"
52+
/>
5653
),
5754
}
5855
);
@@ -211,13 +208,30 @@ const SiteList = ( {
211208
<div className="ob-container">
212209
<div className="ob-container-inner">
213210
<div className="ob-title-wrap">
214-
<h1>
215-
{ __( 'Choose a design', 'templates-patterns-collection' ) }
216-
</h1>
211+
<div className="ob-title-text">
212+
<h1>
213+
{ __(
214+
'Choose a design',
215+
'templates-patterns-collection'
216+
) }
217+
</h1>
218+
<p className="ob-subtitle">
219+
{ createInterpolateElement(
220+
__(
221+
'<count>Nearly 200 starter sites</count> across every niche, with dozens added recently.',
222+
'templates-patterns-collection'
223+
),
224+
{
225+
count: (
226+
<span className="ob-subtitle__count" />
227+
),
228+
}
229+
) }
230+
</p>
231+
</div>
217232
<EditorSelector />
218233
</div>
219234
<Filters />
220-
<OnboardingPromoNotice />
221235
{ ( personalizing || searching ) && (
222236
<div
223237
className="ob-ranking-loader"
@@ -248,6 +262,10 @@ const SiteList = ( {
248262
setShowToast={ setShowToast }
249263
svgIcon={ SVG.logo }
250264
className={ showToast === true ? 'show' : '' }
265+
heading={ __(
266+
'Unlock every premium template',
267+
'templates-patterns-collection'
268+
) }
251269
message={ toastMessage }
252270
/>
253271
) }

onboarding/src/Components/Toast.js

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
import classnames from 'classnames';
2+
import { __ } from '@wordpress/i18n';
23

3-
const Toast = ( { svgIcon, message, className, setShowToast } ) => {
4+
const Toast = ( { svgIcon, heading, message, className, setShowToast } ) => {
45
const handleClose = () => {
56
setShowToast( 'dismissed' );
67
};
78

89
return (
9-
<div className={ classnames( 'ob-toast', className ) }>
10+
<div
11+
className={ classnames( 'ob-toast', className ) }
12+
role="status"
13+
aria-live="polite"
14+
>
15+
{ svgIcon && (
16+
<span className="ob-toast-icon" aria-hidden="true">
17+
{ svgIcon }
18+
</span>
19+
) }
1020
<div className="ob-toast-content">
11-
{ svgIcon && <div className="ob-toast-icon">{ svgIcon }</div> }
12-
{ message && <p>{ message }</p> }
21+
{ heading && <p className="ob-toast-heading">{ heading }</p> }
22+
{ message && <p className="ob-toast-message">{ message }</p> }
1323
</div>
14-
<button className="ob-toast-close" onClick={ handleClose }>
15-
&times;
24+
<button
25+
type="button"
26+
className="ob-toast-close"
27+
onClick={ handleClose }
28+
aria-label={ __( 'Dismiss', 'templates-patterns-collection' ) }
29+
>
30+
<span aria-hidden="true">&times;</span>
1631
</button>
1732
</div>
1833
);

onboarding/src/scss/_general.scss

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,41 @@ iframe {
135135
display: flex;
136136
align-items: center;
137137
justify-content: space-between;
138+
gap: 16px;
139+
}
140+
141+
.ob-title-text {
142+
display: flex;
143+
flex-direction: column;
144+
gap: 4px;
145+
146+
h1 {
147+
margin: 0;
148+
}
149+
}
150+
151+
.ob-subtitle {
152+
margin: 6px 0 0;
153+
max-width: 56ch;
154+
// ~#6E6D6D on white ≈ 4.6:1 → passes WCAG AA while staying clearly secondary to the near-black h1.
155+
color: mix($main-text, $inverted-text, 56%);
156+
font-size: 14px;
157+
line-height: 20px;
158+
font-weight: 400;
159+
letter-spacing: 0.1px;
160+
161+
// Subtle emphasis on the catalog claim — weight only, no brand color (would read promotional).
162+
.ob-subtitle__count {
163+
font-weight: 600;
164+
color: $main-text;
165+
}
166+
}
167+
168+
@media (max-width: #{$tablet}) {
169+
.ob-subtitle {
170+
font-size: 13px;
171+
line-height: 19px;
172+
}
138173
}
139174

140175
/**

0 commit comments

Comments
 (0)