From 568f10761e96c0eb110403300a7350aa28101aa1 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Oct 2025 14:20:46 +0200 Subject: [PATCH] Add comprehensive SEO optimization with dynamic meta tags and social sharing support (#23) * Initial plan * Add SEO optimization with dynamic meta tags for all pages Co-authored-by: mroxso <24775431+mroxso@users.noreply.github.com> * Fix SEO meta tags to use useSeoMeta correctly without useEffect Co-authored-by: mroxso <24775431+mroxso@users.noreply.github.com> * Add SEO verification documentation Co-authored-by: mroxso <24775431+mroxso@users.noreply.github.com> * Add comprehensive SEO examples documentation Co-authored-by: mroxso <24775431+mroxso@users.noreply.github.com> * Refactor routing to use HomePage component and update blog post fetching limit --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: mroxso <24775431+mroxso@users.noreply.github.com> Co-authored-by: highperfocused --- SEO_EXAMPLES.md | 253 +++++++++++++++++++ SEO_VERIFICATION.md | 152 +++++++++++ index.html | 17 +- src/AppRouter.tsx | 5 +- src/components/LatestInHashtag.tsx | 6 +- src/hooks/useBlogPostsByHashtag.ts | 4 +- src/hooks/useSearch.ts | 4 +- src/pages/ArticlePage.tsx | 55 ++++ src/pages/BookmarksPage.tsx | 7 + src/pages/CreatePostPage.tsx | 7 + src/pages/EditPostPage.tsx | 7 + src/pages/EventPage.tsx | 33 +++ src/pages/FollowingPage.tsx | 7 + src/pages/{BlogHomePage.tsx => HomePage.tsx} | 26 +- src/pages/Index.tsx | 15 +- src/pages/NotePage.tsx | 31 +++ src/pages/ProfilePage.tsx | 46 ++++ src/pages/SearchResultsPage.tsx | 19 ++ 18 files changed, 676 insertions(+), 18 deletions(-) create mode 100644 SEO_EXAMPLES.md create mode 100644 SEO_VERIFICATION.md rename src/pages/{BlogHomePage.tsx => HomePage.tsx} (51%) diff --git a/SEO_EXAMPLES.md b/SEO_EXAMPLES.md new file mode 100644 index 0000000..7d9af53 --- /dev/null +++ b/SEO_EXAMPLES.md @@ -0,0 +1,253 @@ +# SEO Implementation Examples + +This document shows concrete examples of how the SEO meta tags appear on different pages of zelo.news. + +## Example 1: Article Page + +When viewing an article titled "The Future of Decentralized Social Media" by Alice: + +### What Gets Rendered: +```html + + The Future of Decentralized Social Media - Alice - zelo.news + + + + + + + + + + + + + + + + + + + + + + +``` + +### What This Looks Like When Shared: + +**WhatsApp Preview:** +``` +┌─────────────────────────────────────────┐ +│ [Article Image] │ +├─────────────────────────────────────────┤ +│ The Future of Decentralized Social │ +│ Media │ +│ Exploring how Nostr and other │ +│ decentralized protocols are reshaping │ +│ social media... │ +│ zelo.news │ +└─────────────────────────────────────────┘ +``` + +**Twitter/X Preview:** +``` +┌─────────────────────────────────────────┐ +│ [Large Article Image] │ +├─────────────────────────────────────────┤ +│ The Future of Decentralized Social │ +│ Media │ +│ Exploring how Nostr and other │ +│ decentralized protocols... │ +│ 🔗 zelo.news │ +└─────────────────────────────────────────┘ +``` + +## Example 2: Profile Page + +When viewing Bob's profile who has published 15 articles: + +### What Gets Rendered: +```html + + Bob - Profile - zelo.news + + + + + + + + + + + + + + + + + + + +``` + +### What This Looks Like When Shared: + +**Facebook/LinkedIn Preview:** +``` +┌─────────────────────────────────────────┐ +│ [Bob's Profile Banner or Avatar] │ +├─────────────────────────────────────────┤ +│ Bob on zelo.news │ +│ Bitcoin enthusiast and writer exploring │ +│ decentralized systems. • 15 articles │ +│ published │ +│ 🔗 ZELO.NEWS │ +└─────────────────────────────────────────┘ +``` + +## Example 3: Home Page + +When viewing the home page: + +### What Gets Rendered: +```html + + zelo.news - Decentralized News on Nostr + + + + + + + + + + + + + + + + + + + +``` + +## Example 4: Search Results Page + +When searching for "bitcoin": + +### What Gets Rendered: +```html + + Search: bitcoin - zelo.news + + + + +``` + +## Example 5: Note Page (Short Post) + +When viewing a short text note from Charlie: + +### What Gets Rendered: +```html + + Charlie's note - zelo.news + + + + + + + + + + + + + + + + + + +``` + +## Benefits of This Implementation + +### 1. Better Search Engine Rankings +- Unique titles for every page +- Descriptive meta descriptions +- Proper semantic HTML structure +- Keywords in meta tags + +### 2. Rich Social Media Previews +When users share links on: +- **WhatsApp**: Shows article image, title, and description +- **Facebook**: Rich preview with image, title, and description +- **Twitter/X**: Large image card with content preview +- **LinkedIn**: Professional preview with article details +- **Discord**: Embedded preview with image and text +- **Slack**: Link unfurling with full preview +- **Telegram**: Rich message preview + +### 3. Dynamic Content Handling +- Meta tags update automatically when content loads +- Fallback values ensure something always displays +- Social media crawlers execute JavaScript and see updated tags + +### 4. Professional Appearance +- Consistent branding across all social platforms +- Author attribution on all content +- Timestamp information for articles +- Category tags for better discovery + +## Testing Your Implementation + +### Quick Test with Twitter +1. Copy any article URL from your deployed site +2. Paste it into a new tweet +3. Twitter will show a preview - you should see the article image, title, and description + +### Full Test with Facebook Debugger +1. Go to https://developers.facebook.com/tools/debug/ +2. Enter any page URL from your deployed site +3. Click "Scrape Again" +4. Review the preview - should show all meta tags and image + +### Verify in Browser +1. Open any page +2. Right-click → Inspect +3. Go to Elements tab +4. Look at `` section +5. Should see all meta tags listed above + +## Common Issues and Solutions + +### Issue: Social preview not updating +**Solution**: Use the social media debuggers to force a re-scrape +- Facebook: https://developers.facebook.com/tools/debug/ +- Twitter: https://cards-dev.twitter.com/validator +- LinkedIn: https://www.linkedin.com/post-inspector/ + +### Issue: Image not showing in preview +**Solution**: Ensure images use absolute URLs (https://...) not relative (/image.jpg) + +### Issue: Old title/description showing +**Solution**: Clear browser cache or test in incognito mode + +## Conclusion + +The SEO implementation provides: +✅ Professional social media previews on all platforms +✅ Better search engine visibility +✅ Dynamic updates for Nostr content +✅ Proper handling of images and descriptions +✅ Consistent branding across the web + +All without requiring server-side rendering - it works entirely in the browser with the @unhead library! diff --git a/SEO_VERIFICATION.md b/SEO_VERIFICATION.md new file mode 100644 index 0000000..26cc9b1 --- /dev/null +++ b/SEO_VERIFICATION.md @@ -0,0 +1,152 @@ +# SEO Optimization Verification + +This document describes the SEO optimizations implemented in zelo.news and how to verify they work correctly. + +## What Was Implemented + +### 1. Dynamic Page Titles +Each page now has a unique, descriptive title that updates based on content: +- **Article Pages**: `[Article Title] - [Author Name] - zelo.news` +- **Profile Pages**: `[Username] - Profile - zelo.news` +- **Home Page**: `zelo.news - Decentralized News on Nostr` +- **Search Pages**: `Search: [query] - zelo.news` or `Articles tagged #[tag] - zelo.news` +- **Other Pages**: Descriptive titles for bookmarks, following, etc. + +### 2. Meta Descriptions +Every page includes a relevant description: +- **Articles**: Uses the article summary, or first 160 characters of content +- **Profiles**: Uses the user's "about" text, or a default description +- **Notes/Events**: Uses the first 160 characters of the content +- **Search**: Includes result count and search term + +### 3. Open Graph Tags (for Facebook, LinkedIn, WhatsApp, etc.) +All pages include Open Graph meta tags: +- `og:title` - Page/content title +- `og:description` - Page/content description +- `og:type` - "article" for content pages, "website" for home +- `og:url` - Current page URL +- `og:image` - Article image, profile picture, or default icon +- `og:site_name` - "zelo.news" + +Article pages also include: +- `article:published_time` - Publication timestamp +- `article:author` - Author name +- `article:tag` - Article hashtags + +### 4. Twitter Card Tags +All pages include Twitter Card meta tags for Twitter/X sharing: +- `twitter:card` - "summary_large_image" for articles, "summary" for others +- `twitter:title` - Page/content title +- `twitter:description` - Page/content description +- `twitter:image` - Article image, profile picture, or default icon +- `twitter:site` - "@zelo_news" + +### 5. Additional SEO Features +- Keywords meta tag in base HTML +- Author meta tag in base HTML +- `robots: noindex` for personal pages (bookmarks, following, search results, editor) +- Proper semantic HTML structure + +## How to Verify + +### Method 1: Browser DevTools +1. Open the application in a browser +2. Open DevTools (F12) +3. Go to the Elements/Inspector tab +4. Look at the `` section +5. You should see dynamically injected meta tags from @unhead + +### Method 2: View Page Source +1. Right-click on any page and select "View Page Source" +2. Look for `` tags in the `` +3. Default tags will be visible in the static HTML +4. Dynamic tags are injected by JavaScript after page load + +### Method 3: Social Media Sharing Debuggers +These tools show what social media platforms will see: + +**Facebook/Open Graph Debugger:** +- Visit: https://developers.facebook.com/tools/debug/ +- Enter a page URL from your deployed site +- Click "Scrape Again" to see the latest meta tags +- Should show article title, description, and image + +**Twitter Card Validator:** +- Visit: https://cards-dev.twitter.com/validator +- Enter a page URL from your deployed site +- Should show a preview of how the link will appear on Twitter + +**LinkedIn Post Inspector:** +- Visit: https://www.linkedin.com/post-inspector/ +- Enter a page URL from your deployed site +- Should show how the link will appear on LinkedIn + +### Method 4: Browser Extensions +Install a meta tag viewer extension: +- **SEO Meta in 1 Click** (Chrome/Edge) +- **META SEO inspector** (Firefox) +- These will show all meta tags on the current page + +## Example: Article Page Meta Tags + +When viewing an article page, the following meta tags should be present: + +```html +[Article Title] - [Author Name] - zelo.news + + + + + + + + + + + + + + + + + + + + + +``` + +## Testing Dynamic Content Loading + +The SEO implementation handles dynamically loaded content: + +1. **Initial Load**: Default meta tags from `index.html` are visible +2. **After Data Loads**: Meta tags are updated with actual content +3. **Social Media Crawlers**: They execute JavaScript and will see the updated tags + +To verify this works: +1. Open a page (e.g., an article page) +2. Open DevTools > Network tab +3. Reload the page +4. Watch the meta tags in the Elements tab - they should update as data loads + +## Notes + +- **Server-Side Rendering**: Currently not implemented. Social media crawlers execute JavaScript, so they will see the dynamically set meta tags. +- **@unhead Library**: This library is SSR-compatible and properly manages meta tags. +- **Image URLs**: Uses absolute URLs so social media platforms can fetch images. +- **Default Fallbacks**: All pages have sensible defaults if content is not available. + +## Files Modified + +- `index.html` - Updated default meta tags +- `src/pages/ArticlePage.tsx` - Added article-specific SEO +- `src/pages/ProfilePage.tsx` - Added profile-specific SEO +- `src/pages/BlogHomePage.tsx` - Added home page SEO +- `src/pages/SearchResultsPage.tsx` - Added search page SEO (noindex) +- `src/pages/BookmarksPage.tsx` - Added bookmarks page SEO (noindex) +- `src/pages/FollowingPage.tsx` - Added following page SEO (noindex) +- `src/pages/CreatePostPage.tsx` - Added create page SEO (noindex) +- `src/pages/EditPostPage.tsx` - Added edit page SEO (noindex) +- `src/pages/NotePage.tsx` - Added note page SEO +- `src/pages/EventPage.tsx` - Added event page SEO diff --git a/index.html b/index.html index 53f6696..b2d803f 100644 --- a/index.html +++ b/index.html @@ -3,8 +3,10 @@ - zelo.news - Your Source for Decentralized News - + zelo.news - Decentralized News on Nostr + + + @@ -17,8 +19,15 @@ - - + + + + + + + + + diff --git a/src/AppRouter.tsx b/src/AppRouter.tsx index 5b5b084..17c36a5 100644 --- a/src/AppRouter.tsx +++ b/src/AppRouter.tsx @@ -1,8 +1,6 @@ import { BrowserRouter, Route, Routes } from "react-router-dom"; import { ScrollToTop } from "./components/ScrollToTop"; import { BlogLayout } from "./components/BlogLayout"; - -import BlogHomePage from "./pages/BlogHomePage"; import CreatePostPage from "./pages/CreatePostPage"; import EditPostPage from "./pages/EditPostPage"; import SearchResultsPage from "./pages/SearchResultsPage"; @@ -12,6 +10,7 @@ import Nip05ProfilePage from "./pages/Nip05ProfilePage"; import ArticleByDTagPage from "./pages/ArticleByDTagPage"; import { NIP19Page } from "./pages/NIP19Page"; import NotFound from "./pages/NotFound"; +import HomePage from "./pages/HomePage"; export function AppRouter() { return ( @@ -19,7 +18,7 @@ export function AppRouter() { - } /> + } /> } /> } /> } /> diff --git a/src/components/LatestInHashtag.tsx b/src/components/LatestInHashtag.tsx index 1a7a4a6..aecf584 100644 --- a/src/components/LatestInHashtag.tsx +++ b/src/components/LatestInHashtag.tsx @@ -15,7 +15,7 @@ const INITIAL_POSTS_COUNT = 3; export function LatestInHashtag({ hashtag, icon }: LatestInHashtagProps) { const navigate = useNavigate(); - const { data: posts, isLoading } = useBlogPostsByHashtag(hashtag); + const { data: posts, isLoading } = useBlogPostsByHashtag(hashtag, 4); // Loading state if (isLoading) { @@ -60,9 +60,9 @@ export function LatestInHashtag({ hashtag, icon }: LatestInHashtagProps) {

Latest in #{hashtag}

-

+ {/*

{posts.length} {posts.length === 1 ? 'article' : 'articles'} in this category -

+

*/} {hasMore && (