add SEO enhancements: OG images, meta robots, FAQ block, image sitemap
All checks were successful
deploy / deploy (push) Successful in 4m59s
All checks were successful
deploy / deploy (push) Successful in 4m59s
- Per-page SEO controls: meta robots directives, focus keyword, OG image - Site-wide default OG image in admin settings - FAQ block type with FAQPage JSON-LD schema - Enhanced Organization JSON-LD with business info, contact, address - Image sitemap with product images - SEO preview panel with Google/social card mockups - SEO checklist with real-time scoring - Business info section in site editor - GSC integration scaffolding (OAuth, client, cache) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,7 @@ defmodule BerrypodWeb.SiteEditorState do
|
||||
state = SiteEditorState.revert(state)
|
||||
"""
|
||||
|
||||
alias Berrypod.Site
|
||||
alias Berrypod.{Settings, Site}
|
||||
alias Berrypod.Site.{NavItem, SocialLink}
|
||||
|
||||
defstruct [
|
||||
@@ -37,6 +37,8 @@ defmodule BerrypodWeb.SiteEditorState do
|
||||
:footer_about,
|
||||
:footer_copyright,
|
||||
:show_newsletter,
|
||||
# Business info (stored in Settings as JSON)
|
||||
:business_info,
|
||||
# List fields (separate tables)
|
||||
:header_nav,
|
||||
:footer_nav,
|
||||
@@ -52,6 +54,7 @@ defmodule BerrypodWeb.SiteEditorState do
|
||||
footer_about: String.t(),
|
||||
footer_copyright: String.t(),
|
||||
show_newsletter: boolean(),
|
||||
business_info: map(),
|
||||
header_nav: [NavItem.t()],
|
||||
footer_nav: [NavItem.t()],
|
||||
social_links: [SocialLink.t()],
|
||||
@@ -67,6 +70,7 @@ defmodule BerrypodWeb.SiteEditorState do
|
||||
header_nav = Site.list_nav_items(:header)
|
||||
footer_nav = Site.list_nav_items(:footer)
|
||||
social_links = Site.list_social_links()
|
||||
business_info = Settings.get_business_info()
|
||||
|
||||
state = %__MODULE__{
|
||||
announcement_text: settings.announcement_text,
|
||||
@@ -75,6 +79,7 @@ defmodule BerrypodWeb.SiteEditorState do
|
||||
footer_about: settings.footer_about,
|
||||
footer_copyright: settings.footer_copyright,
|
||||
show_newsletter: settings.show_newsletter,
|
||||
business_info: business_info,
|
||||
header_nav: header_nav,
|
||||
footer_nav: footer_nav,
|
||||
social_links: social_links
|
||||
@@ -102,6 +107,14 @@ defmodule BerrypodWeb.SiteEditorState do
|
||||
Map.put(state, field, value)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Update a business info field. Returns updated state.
|
||||
"""
|
||||
@spec put_business_info(t(), String.t(), any()) :: t()
|
||||
def put_business_info(%__MODULE__{business_info: info} = state, key, value) do
|
||||
%{state | business_info: Map.put(info, key, value)}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Add a new social link. Returns updated state.
|
||||
"""
|
||||
@@ -255,6 +268,11 @@ defmodule BerrypodWeb.SiteEditorState do
|
||||
state.show_newsletter
|
||||
)
|
||||
|
||||
# Save business info if changed
|
||||
if state.business_info != state._original.business_info do
|
||||
Settings.put_business_info(state.business_info)
|
||||
end
|
||||
|
||||
# Sync nav items and social links
|
||||
header_nav = sync_nav_items(state.header_nav, state._original.header_nav)
|
||||
footer_nav = sync_nav_items(state.footer_nav, state._original.footer_nav)
|
||||
@@ -278,6 +296,7 @@ defmodule BerrypodWeb.SiteEditorState do
|
||||
footer_about: original.footer_about,
|
||||
footer_copyright: original.footer_copyright,
|
||||
show_newsletter: original.show_newsletter,
|
||||
business_info: original.business_info,
|
||||
header_nav: original.header_nav,
|
||||
footer_nav: original.footer_nav,
|
||||
social_links: original.social_links
|
||||
@@ -301,6 +320,7 @@ defmodule BerrypodWeb.SiteEditorState do
|
||||
footer_about: state.footer_about,
|
||||
footer_copyright: state.footer_copyright,
|
||||
show_newsletter: state.show_newsletter,
|
||||
business_info: state.business_info,
|
||||
header_nav: Enum.map(state.header_nav, &nav_item_snapshot/1),
|
||||
footer_nav: Enum.map(state.footer_nav, &nav_item_snapshot/1),
|
||||
social_links: Enum.map(state.social_links, &social_link_snapshot/1)
|
||||
|
||||
Reference in New Issue
Block a user