openvibers/openvibe.network Commits

SEO-31: the network is one WebSite, with the sitelinks search set to OpenVibe.Search (#410)

OP OpenVibers committed 15 days ago · 5407f22e80 · 2 files, +13 −1

The home already carried the Organization, an ItemList and a FAQPage, but no WebSite: search
engines had nothing that said "this domain is one site" and nothing to put in a sitelinks search
box. Add the WebSite node from the shared builder with potentialAction → SearchAction targeting
https://search.openvibe.network/?q={search_term_string}, which is the network's own search.

The test parses the node and asserts the url, the target and the required query-input.

Changes

ddiff --git a/server/home/render.js b/server/home/render.js
iindex f1f8a214..71c9850f 100644
---- a/server/home/render.js
++++ b/server/home/render.js
@@@ -320,7 +320,14 @@ function render({ releaseId = '' } = {}) {
const stat = fs.statSync(SHELL);
const key = `${stat.mtimeMs}:${catalog.updated}:${catalog.tools.length}:${act.version}:${releaseId}`;
if (pageCache.key === key) return pageCache;
-- const ld = seo.jsonLdTag(seo.jsonLd.itemList(sitesHeading(), OPEN.map((site) => ({ name: siteName(site), url: `https://${site.host}/`, description: site.what })))) + seo.jsonLdTag(seo.jsonLd.faq(faqPairs()));
++ // The network as one entity (SEO-31): a WebSite whose sitelinks search is the network's own search service, so a
++ // search box in a Google result searches OpenVibe rather than the wider web. The description is true of today.
++ const ld = seo.jsonLdTag(seo.jsonLd.website({
++ name: 'OpenVibe.Network',
++ url: 'https://openvibe.network/',
++ description: `The front door to the OpenVibe network: one free account across ${OPEN.length} open sites — live streaming, tools, chat, games, a wiki, news, deals and an open developer platform.`,
++ searchUrl: 'https://search.openvibe.network/?q={q}',
++ })) + seo.jsonLdTag(seo.jsonLd.itemList(sitesHeading(), OPEN.map((site) => ({ name: siteName(site), url: `https://${site.host}/`, description: site.what })))) + seo.jsonLdTag(seo.jsonLd.faq(faqPairs()));
const card = social.url('network', 'https://openvibe.network/shared') || 'https://openvibe.network/assets/logo-512.png';
const summary = summaryOf(catalog);
const html = fs.readFileSync(SHELL, 'utf8').replace('<div id="navbar-mount"></div>', '<div id="navbar-mount"></div>' + summary.body + require('openvibe-shared/frame').noscriptNav({ name: 'OpenVibe.Network', links: [{ label: 'Sign in', href: '/login' }, { label: 'Themes', href: '/themes' }] })).replace('<!--OV:HOME-->', body(catalog, act)).replace('<!--OV:INTENTS-->', intents(catalog)).replace('<!--OV:CONSTELLATION-->', () => orbit() + numbers(catalog, act)).replaceAll('__OV_CARD__', card).replace('<!--OV:SITES-->', String(OPEN.length + 1)).replace('<!--OV:COUNT-->', catalog.tools.length ? String(catalog.tools.length) : 'free').replace('<div id="ov-footer"></div>', require('openvibe-shared/footer').ssr({ service: 'network', variant: 'full' })).replace('</head>', () => `${ld}\n${summary.head}\n${boost.meta(releaseId)}\n</head>`);
ddiff --git a/test/home-front-door.test.js b/test/home-front-door.test.js
iindex 33b82125..0f606f79 100644
---- a/test/home-front-door.test.js
++++ b/test/home-front-door.test.js
@@@ -98,6 +98,11 @@ assert.ok(!/class="home-(sec|card|grid|fams|fam|dev)\b/.test(html), 'no hand-bui
assert.strictEqual((html.match(/<h1[\s>]/g) || []).length, 1, 'one h1: the hero');
assert.match(html, /<meta name="ai-summary" content="One account for \d+ open sites \(live, /);
assert.ok(/"@type":"WebPage"/.test(html), 'the summary has its WebPage JSON-LD');
++// SEO-31: the network is one WebSite entity, and its sitelinks search is the network's own search service.
++const siteLd = JSON.parse(/<script type="application\/ld\+json">(\{"@context":"https:\/\/schema.org","@type":"WebSite"[\s\S]*?)<\/script>/.exec(html)[1]);
++assert.strictEqual(siteLd.url, 'https://openvibe.network/', 'the WebSite is the network itself');
++assert.strictEqual(siteLd.potentialAction.target.urlTemplate, 'https://search.openvibe.network/?q={search_term_string}', 'the sitelinks search is OpenVibe.Search');
++assert.strictEqual(siteLd.potentialAction['query-input'], 'required name=search_term_string');
// A tagline that already ends a sentence ("What should we eat?") gets no second period; a family of one is "1 tool".
assert.ok(!/[.?!]\. /.test(html.replace(/<[^>]+>/g, ' ')), 'no doubled sentence end after a site tagline');
assert.ok(!/\b1 tools\b/.test(html), 'one tool is "1 tool"');