SEO: fix head placement, add sitemap/robots, update title to The Radical Party

- Move canonical, robots, JSON-LD, sitemap link inside <head> (were incorrectly
  placed after </head>, causing Google to ignore them)
- Title changed to "The Radical Party | Direct Democracy for Australia" so the
  party name shows up in search results
- Description now leads with "The Radical Party" for brand recognition
- Keywords updated to include "The Radical Party", "radical party australia", CIR
- JSON-LD updated to dual WebSite + Organization schema with richer data
- Added /robots.txt endpoint (was 404) pointing crawlers to sitemap
- Added /sitemap.xml endpoint (was 404) with homepage + top 50 proposals

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
King Omar 2026-07-12 13:44:44 +10:00
parent 966bfa9a9e
commit 786a23667d
2 changed files with 125 additions and 34 deletions

View file

@ -3,25 +3,25 @@
<head>
<meta charset="UTF-8">
<!-- Title -->
<title>RADICAL - The Underground Parliament</title>
<meta name="title" content="RADICAL - The Underground Parliament">
<meta property="og:title" content="RADICAL - The Underground Parliament">
<meta name="twitter:title" content="RADICAL - The Underground Parliament">
<meta itemprop="name" content="RADICAL - The Underground Parliament">
<meta property="og:site_name" content="RADICAL">
<meta name="application-name" content="RADICAL">
<meta name="twitter:domain" content="RADICAL">
<title>The Radical Party | Direct Democracy for Australia</title>
<meta name="title" content="The Radical Party | Direct Democracy for Australia">
<meta property="og:title" content="The Radical Party | Direct Democracy for Australia">
<meta name="twitter:title" content="The Radical Party | Direct Democracy for Australia">
<meta itemprop="name" content="The Radical Party">
<meta property="og:site_name" content="The Radical Party">
<meta name="application-name" content="The Radical Party">
<meta name="twitter:domain" content="theradicalparty.com">
<!-- Description -->
<meta property="og:description"
content="Australia's direct democracy movement. Share policy ideas, vote on proposals, take back control. Vibe, Vote, Veto.">
<meta name="description" content="Australia's direct democracy movement. Share policy ideas, vote on proposals, take back control. Vibe, Vote, Veto.">
content="The Radical Party: Australia's direct democracy movement. One policy — 100,000 signatures forces a binding referendum. Post ideas, build movements, take back control.">
<meta name="description" content="The Radical Party: Australia's direct democracy movement. One policy — 100,000 signatures forces a binding referendum. Post ideas, build movements, take back control.">
<meta name="twitter:description"
content="Australia's direct democracy movement. Share policy ideas, vote on proposals, take back control. Vibe, Vote, Veto.">
content="The Radical Party: Australia's direct democracy movement. One policy — 100,000 signatures forces a binding referendum. Post ideas, build movements, take back control.">
<meta name="abstract"
content="Australia's direct democracy movement. Share policy ideas, vote on proposals, take back control. Vibe, Vote, Veto.">
content="The Radical Party is an Australian political party promoting direct democracy through Citizens Initiated Referendums.">
<meta itemprop="description"
content="Australia's direct democracy movement. Share policy ideas, vote on proposals, take back control. Vibe, Vote, Veto.">
content="The Radical Party: Australia's direct democracy movement. One policy — 100,000 signatures forces a binding referendum. Post ideas, build movements, take back control.">
<!-- Icon -->
<meta name="twitter:image"
@ -251,7 +251,6 @@
/* ── Inline milestone strip on proposal cards ── */
.card-milestone{margin-top:8px}
</style>
</head>
<!-- Crawling -->
<link rel="sitemap" href="https://theradicalparty.com/sitemap.xml" type="application/xml">
@ -278,7 +277,7 @@
<meta property="og:type" content="website">
<meta name="twitter:card" content="summary">
<meta name="keywords"
content="radical, democracy, direct democracy, petitions, australia, policy, activism, movement, underground parliament">
content="The Radical Party, radical party australia, direct democracy australia, citizens initiated referendum, CIR australia, radical, democracy, petitions, policy, activism">
<meta name="rating" content="general">
<meta name="theme-color"
content="#ff0099">
@ -287,29 +286,53 @@
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "RADICAL",
"description": "Australia's direct democracy movement. Share policy ideas, vote on proposals, take back control. Vibe, Vote, Veto.",
"image": "https://theradicalparty.com/memes/mickeymeta.PNG",
"url": "https://theradicalparty.com",
"author": {
"@type": "Organization",
"name": "RADICAL Party"
},
"sameAs": [
"https://twitter.com/RadicalAustralia"
],
"potentialAction": {
"@type": "SearchAction",
"target": {
"@type": "EntryPoint",
"urlTemplate": "https://theradicalparty.com/search?q={search_term_string}"
"@graph": [
{
"@type": "WebSite",
"name": "The Radical Party",
"alternateName": "RADICAL",
"description": "The Radical Party is Australia's direct democracy movement. One policy: if 100,000 Australians sign a petition, the government must hold a binding referendum. Vibe, Vote, Veto.",
"url": "https://theradicalparty.com",
"image": "https://theradicalparty.com/memes/mickeymeta.PNG",
"potentialAction": {
"@type": "SearchAction",
"target": {
"@type": "EntryPoint",
"urlTemplate": "https://theradicalparty.com/search?q={search_term_string}"
},
"query-input": "required name=search_term_string"
}
},
"query-input": "required name=search_term_string"
}
{
"@type": "Organization",
"name": "The Radical Party",
"alternateName": ["RADICAL", "RAD"],
"description": "Australian political party promoting direct democracy through Citizens Initiated Referendums. One law: 100,000 signatures compels a binding national vote.",
"url": "https://theradicalparty.com",
"logo": "https://theradicalparty.com/memes/favicon.jpg",
"image": "https://theradicalparty.com/memes/mickeymeta.PNG",
"foundingLocation": {
"@type": "Country",
"name": "Australia"
},
"areaServed": {
"@type": "Country",
"name": "Australia"
},
"contactPoint": {
"@type": "ContactPoint",
"email": "contact@theradicalparty.com",
"contactType": "general"
},
"sameAs": [
"https://twitter.com/RadicalAustralia"
]
}
]
}
</script>
</head>
<body>
<div class="container">
<header>

View file

@ -104,6 +104,17 @@ export default {
return serveStaticAsset(request, env);
}
if (path === '/robots.txt') {
return new Response(
'User-agent: *\nAllow: /\nSitemap: https://theradicalparty.com/sitemap.xml\n',
{ headers: { 'Content-Type': 'text/plain', 'Cache-Control': 'public, max-age=86400' } }
);
}
if (path === '/sitemap.xml') {
return serveSitemap(request, env);
}
// Handle media files
if (path.startsWith('/memes/') || path.startsWith('/audio/')) {
return serveMedia(request, env);
@ -226,6 +237,63 @@ async function serveMedia(request, env) {
}
}
async function serveSitemap(request, env) {
try {
const topProposals = await env.DB.prepare(`
SELECT p.id, p.timestamp,
(SELECT COUNT(*) FROM votes WHERE proposal_id = p.id AND vote_type = 'upvote') as upvotes
FROM proposals p
WHERE (p.hidden = 0 OR p.hidden IS NULL)
ORDER BY upvotes DESC
LIMIT 50
`).all();
const base = 'https://theradicalparty.com';
const now = new Date().toISOString().split('T')[0];
let urls = `
<url>
<loc>${base}/</loc>
<lastmod>${now}</lastmod>
<changefreq>hourly</changefreq>
<priority>1.0</priority>
</url>`;
for (const p of (topProposals.results || [])) {
const date = new Date(p.timestamp).toISOString().split('T')[0];
urls += `
<url>
<loc>${base}/?proposal=${p.id}</loc>
<lastmod>${date}</lastmod>
<changefreq>weekly</changefreq>
<priority>0.6</priority>
</url>`;
}
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">${urls}
</urlset>`;
return new Response(xml, {
headers: {
'Content-Type': 'application/xml',
'Cache-Control': 'public, max-age=3600',
},
});
} catch (error) {
console.error('Error serving sitemap:', error);
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://theradicalparty.com/</loc>
<changefreq>hourly</changefreq>
<priority>1.0</priority>
</url>
</urlset>`;
return new Response(xml, { headers: { 'Content-Type': 'application/xml' } });
}
}
// Handle static assets
async function serveStaticAsset(request, env) {
try {