{/* URL structure */}
{ __( 'URL structure', 'hatch-connect' ) } tags must stay. */
sprintf( __( 'Your frontend can find your posts. Post links look like %s.', 'hatch-connect' ), permalink.example ),
{ code: }
)
: createInterpolateElement(
__( 'WordPress is using the plain ?p=123 link format, which the frontend cannot read. Choose any other link format in Settings, Permalinks.', 'hatch-connect' ),
{ code: }
)}
last
>
0
? sprintf(
/* translators: 1: number of authors, 2: number of authors who have a bio. */
_n( '%1$d author, %2$d with a bio. Bios and avatars appear on the author pages of your frontend.', '%1$d authors, %2$d with a bio. Bios and avatars appear on the author pages of your frontend.', authors.total, 'hatch-connect' ),
authors.total,
authors.with_bio
)
: __( 'No authors yet. Anyone who publishes a post will show up here.', 'hatch-connect' )}
last
>
{/* Languages */}
{ __( 'Languages', 'hatch-connect' ) } 0 ? __( 'Multilingual site', 'hatch-connect' ) : __( 'Single-language site', 'hatch-connect' )}
desc={languages.length > 0
/* translators: %s: comma-separated list of language codes. */
? sprintf( __( 'Languages found: %s.', 'hatch-connect' ), languages.map(l => l.code).join(', ') )
: __( 'Hatch lists languages here when Polylang or WPML is installed.', 'hatch-connect' )}
last
>
0 ? 'green' : 'neutral'}>{languages.length > 0
/* translators: %d: number of languages. */
? sprintf( _n( '%d language', '%d languages', languages.length, 'hatch-connect' ), languages.length )
: __( 'Single', 'hatch-connect' )}
);
}
export default function Content({ state, onDirty, setSetting }) {
const snippets = state.snippets || {};
const content = state.content || {};
const ts = state.turnstile || {};
const coreSync = state.coreSync || null;
const onText = (path) => (e) => { setSetting(path, e.target.value); onDirty(); };
// Turnstile gating: turning Turnstile on without keys does nothing useful
// (the frontend widget never renders and the server never verifies). Refuse
// the flip, scroll to the key inputs, and flash the section so it is obvious
// where to go next.
const hasKeys = !!(ts.site_key && ts.secret_key);
const [tsNeedKeys, setTsNeedKeys] = useState(false);
const guardTurnstile = (path) => (v) => {
if (v && !hasKeys) {
setTsNeedKeys(true);
const el = document.getElementById('hatch-turnstile-keys');
if (el) {
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
el.classList.remove('hatch-flash');
// force reflow so the animation restarts on repeated clicks
void el.offsetWidth;
el.classList.add('hatch-flash');
const input = el.querySelector('input:not([type="password"])');
if (input) setTimeout(() => input.focus(), 350);
}
return; // do NOT flip the toggle, do NOT mark dirty
}
setSetting(path, v);
onDirty();
};
return (
{/* WP Core Sync sits at the top: one status view of every
WordPress-owned setting Hatch syncs. The comment toggles live
inside its Discussion section, next to WordPress's own comment
settings. */}
{/* Third-party keys and services. Google Tag Manager only: GA4,
Plausible and Pixel are managed as tags inside the GTM
container, so there are no separate fields for them. */}
{ __( 'Google Tag Manager (analytics)', 'hatch-connect' ) }
{ __( 'One pair of keys covers every place Turnstile is turned on: frontend comments, the WordPress sign-in page and the WordPress comment form.', 'hatch-connect' ) }