Skip to content

Commit 7af4b0d

Browse files
authored
Hosting Dashboard: Add settings for robots and 3rd party sharing (#103661)
1 parent af2e8b0 commit 7af4b0d

File tree

7 files changed

+518
-16
lines changed

7 files changed

+518
-16
lines changed

client/dashboard/data/index.ts

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -323,39 +323,67 @@ export const updateSiteSettings = async ( siteIdOrSlug: string, data: Partial< S
323323
};
324324

325325
// eslint-disable-next-line @typescript-eslint/no-explicit-any
326-
function fromRawSiteSettings( settings: any ): SiteSettings {
327-
const blog_public = Number( settings.blog_public );
328-
const wpcom_coming_soon = Number( settings.wpcom_public_coming_soon );
329-
const wpcom_public_coming_soon = Number( settings.wpcom_public_coming_soon );
326+
function fromRawSiteSettings( rawSettings: any ): SiteSettings {
327+
// Pluck out raw settings which don't map directly to a field in SiteSettings.
328+
const {
329+
blog_public: blogPublicRaw,
330+
wpcom_coming_soon: wpcomComingSoonRaw,
331+
wpcom_public_coming_soon: wpcomPublicComingSoonRaw,
332+
wpcom_data_sharing_opt_out: wpcomDataSharingOptOutRaw,
333+
...settings
334+
} = rawSettings;
335+
336+
const blog_public = Number( blogPublicRaw );
337+
const wpcom_coming_soon = Number( wpcomComingSoonRaw );
338+
const wpcom_public_coming_soon = Number( wpcomPublicComingSoonRaw );
339+
const wpcom_data_sharing_opt_out = Boolean( wpcomDataSharingOptOutRaw );
330340

331341
if ( wpcom_coming_soon === 1 || wpcom_public_coming_soon === 1 ) {
332342
settings.wpcom_site_visibility = 'coming-soon';
343+
settings.wpcom_discourage_search_engines = false;
333344
} else if ( blog_public === -1 ) {
334345
settings.wpcom_site_visibility = 'private';
346+
settings.wpcom_discourage_search_engines = false;
335347
} else {
336348
settings.wpcom_site_visibility = 'public';
349+
settings.wpcom_discourage_search_engines = blog_public === 0;
337350
}
351+
352+
settings.wpcom_prevent_third_party_sharing = wpcom_data_sharing_opt_out;
353+
338354
return settings;
339355
}
340356

341357
// eslint-disable-next-line @typescript-eslint/no-explicit-any
342358
function toRawSiteSettings( settings: Partial< SiteSettings > ): any {
343-
const rawSettings = settings as any; // eslint-disable-line @typescript-eslint/no-explicit-any
344-
345-
const { wpcom_site_visibility } = settings;
359+
// Pluck out settings which don't map directly to a field in the raw settings.
360+
const {
361+
wpcom_site_visibility,
362+
wpcom_discourage_search_engines,
363+
wpcom_prevent_third_party_sharing,
364+
...rest
365+
} = settings;
366+
const rawSettings = rest as any; // eslint-disable-line @typescript-eslint/no-explicit-any
346367

347368
if ( wpcom_site_visibility !== undefined ) {
348369
if ( wpcom_site_visibility === 'coming-soon' ) {
349370
rawSettings.blog_public = 0;
350371
rawSettings.wpcom_public_coming_soon = 1;
372+
rawSettings.wpcom_data_sharing_opt_out = false;
351373
} else if ( wpcom_site_visibility === 'private' ) {
352374
rawSettings.blog_public = -1;
353375
rawSettings.wpcom_public_coming_soon = 0;
376+
rawSettings.wpcom_data_sharing_opt_out = false;
354377
} else {
355-
rawSettings.blog_public = 1;
378+
rawSettings.blog_public = wpcom_discourage_search_engines ? 0 : 1;
356379
rawSettings.wpcom_public_coming_soon = 0;
380+
rawSettings.wpcom_data_sharing_opt_out = wpcom_prevent_third_party_sharing;
357381
}
382+
383+
// Take opportunity, while the user is switching visibility settings, to disable the legacy coming soon setting.
384+
rawSettings.wpcom_coming_soon = 0;
358385
}
386+
359387
return rawSettings;
360388
}
361389

client/dashboard/data/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,8 @@ export interface EngagementStats {
168168

169169
export interface SiteSettings {
170170
wpcom_site_visibility?: 'coming-soon' | 'public' | 'private';
171+
wpcom_discourage_search_engines?: boolean;
172+
wpcom_prevent_third_party_sharing?: boolean;
171173
wpcom_gifting_subscription?: boolean;
172174
wpcom_performance_report_url?: string;
173175
}

client/dashboard/sites/settings-site-visibility/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import PageLayout from '../../components/page-layout';
66
import SettingsPageHeader from '../settings-page-header';
77
import { LaunchForm } from './launch-form';
88
import { PrivacyForm } from './privacy-form';
9+
import './style.scss';
910

1011
export default function SiteVisibilitySettings( { siteSlug }: { siteSlug: string } ) {
1112
const { data: site } = useQuery( siteQuery( siteSlug ) );

client/dashboard/sites/settings-site-visibility/privacy-form.tsx

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@ import {
33
__experimentalHStack as HStack,
44
__experimentalVStack as VStack,
55
Button,
6+
CheckboxControl,
7+
ExternalLink,
68
} from '@wordpress/components';
79
import { useDispatch } from '@wordpress/data';
10+
import { createInterpolateElement } from '@wordpress/element';
811
import { __ } from '@wordpress/i18n';
912
import { store as noticesStore } from '@wordpress/notices';
1013
import { useState } from 'react';
1114
import type { SiteSettings } from '../../data/types';
12-
import type { Field, SimpleFormField } from '@automattic/dataviews';
15+
import type { Field, Form } from '@automattic/dataviews';
1316
import type { UseMutationResult } from '@tanstack/react-query';
1417

1518
const fields: Field< SiteSettings >[] = [
@@ -38,12 +41,56 @@ const fields: Field< SiteSettings >[] = [
3841
},
3942
],
4043
},
44+
{
45+
id: 'wpcom_discourage_search_engines',
46+
Edit: 'checkbox',
47+
label: __( 'Discourage search engines from indexing this site' ),
48+
description: __(
49+
'This does not block access to your site — it is up to search engines to honor your request.'
50+
),
51+
isVisible: ( { wpcom_site_visibility }: SiteSettings ) => wpcom_site_visibility === 'public',
52+
},
53+
{
54+
id: 'wpcom_prevent_third_party_sharing',
55+
Edit: ( { field, onChange, data, hideLabelFromVision } ) => (
56+
<CheckboxControl
57+
__nextHasNoMarginBottom
58+
label={ hideLabelFromVision ? '' : field.label }
59+
checked={ field.getValue( { item: data } ) }
60+
disabled={ data.wpcom_discourage_search_engines }
61+
onChange={ () => {
62+
onChange( { [ field.id ]: ! field.getValue( { item: data } ) } );
63+
} }
64+
help={ createInterpolateElement(
65+
__(
66+
'This will present this site’s content from being shared with our licensed network of content and research partners, including those that train AI models. <a>Learn more</a>'
67+
),
68+
{
69+
a: (
70+
// TODO investigate whether localizeUrl() is safe to import into dashboard
71+
<ExternalLink
72+
/* eslint-disable-next-line wpcalypso/i18n-unlocalized-url */
73+
href="https://wordpress.com/support/privacy-settings/make-your-website-public/#prevent-third-party-sharing"
74+
children={ null } // ExternalLink's children prop is marked as required
75+
/>
76+
),
77+
}
78+
) }
79+
/>
80+
),
81+
label: __( 'Prevent third-party sharing for this site' ),
82+
isVisible: ( { wpcom_site_visibility }: SiteSettings ) => wpcom_site_visibility === 'public',
83+
},
4184
];
4285

4386
const form = {
44-
type: 'regular' as const,
45-
fields: [ { id: 'wpcom_site_visibility', labelPosition: 'none' } as SimpleFormField ],
46-
};
87+
type: 'regular',
88+
fields: [
89+
{ id: 'wpcom_site_visibility', labelPosition: 'none' },
90+
'wpcom_discourage_search_engines',
91+
'wpcom_prevent_third_party_sharing',
92+
],
93+
} satisfies Form;
4794

4895
export function PrivacyForm( {
4996
settings,
@@ -55,6 +102,9 @@ export function PrivacyForm( {
55102
const { createSuccessNotice, createErrorNotice } = useDispatch( noticesStore );
56103
const [ formData, setFormData ] = useState( {
57104
wpcom_site_visibility: settings.wpcom_site_visibility,
105+
wpcom_discourage_search_engines: settings.wpcom_discourage_search_engines,
106+
wpcom_prevent_third_party_sharing:
107+
settings.wpcom_discourage_search_engines || settings.wpcom_prevent_third_party_sharing,
58108
} );
59109

60110
const isDirty = Object.entries( formData ).some(
@@ -78,19 +128,38 @@ export function PrivacyForm( {
78128
};
79129

80130
return (
81-
<form onSubmit={ handleSubmit }>
131+
<form onSubmit={ handleSubmit } className="dashboard-site-settings-privacy-form">
82132
<VStack spacing={ 4 }>
83133
<DataForm< SiteSettings >
84134
data={ formData }
85135
fields={ fields }
86136
form={ form }
87137
onChange={ ( edits: Partial< SiteSettings > ) => {
88-
setFormData( ( data ) => ( { ...data, ...edits } ) );
138+
setFormData( ( data ) => {
139+
const newFormData = { ...data, ...edits };
140+
141+
if ( edits.wpcom_site_visibility !== undefined ) {
142+
// Forget any previous edits to the discoverability controls when the visibility changes.
143+
newFormData.wpcom_discourage_search_engines =
144+
settings.wpcom_discourage_search_engines;
145+
newFormData.wpcom_prevent_third_party_sharing =
146+
settings.wpcom_discourage_search_engines ||
147+
settings.wpcom_prevent_third_party_sharing;
148+
}
149+
150+
if ( edits.wpcom_discourage_search_engines === true ) {
151+
// Checking the search engine box forces the third party checkbox too.
152+
newFormData.wpcom_prevent_third_party_sharing = true;
153+
}
154+
155+
return newFormData;
156+
} );
89157
} }
90158
/>
91159
<HStack justify="flex-start">
92160
<Button
93161
variant="primary"
162+
__next40pxDefaultSize
94163
type="submit"
95164
isBusy={ isPending }
96165
disabled={ isPending || ! isDirty }
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.dashboard-site-settings-privacy-form .components-checkbox-control:has(input[type="checkbox"]:disabled:checked) {
2+
label {
3+
cursor: default;
4+
}
5+
6+
input[type="checkbox"] {
7+
background: #f0f0f0;
8+
border-color: #ddd;
9+
cursor: default;
10+
opacity: 1;
11+
}
12+
13+
svg {
14+
fill: var( --dashboard__text-color );
15+
}
16+
}

0 commit comments

Comments
 (0)