รายงานการอัปเดต SEO — PNA Digital
รายงานการ deploy การปรับ SEO ของเว็บ
pna.co.th
ครอบคลุม Audit Round 1 (11 fixes) Visual
ของเว็บไม่เปลี่ยน
ภาพรวม
ทุกการแก้ผ่านขอบเขต SEO-only ไม่แตะ visual, Tailwind, Studio editor, partner views, หรือ designed service views — หน้าตาเว็บเหมือนเดิม 100%
src/assets/style.css,
<style scoped> เดิม, inline style,
Tailwind class, Studio component (src/components/Studio/**), partner views, service views หรือ DB schema หน้าตาเว็บหลัง
deploy จะเหมือนเดิม 100%
-
ตั้ง
PUBLIC_SITE_URLบน production - สร้าง OG images 8+10 ไฟล์ — ดูที่ งานเพิ่มเติม
สิ่งที่แก้ทั้งหมด — แยกตาม 6 รอบงาน
เว็บไซต์เปรียบเหมือน ร้านค้าออนไลน์ที่ Google เป็นคนพาลูกค้าเข้ามา ก่อนหน้านี้ Google มองเว็บ PNA ไม่ออกว่าแต่ละหน้าคืออะไร เพราะมีปัญหา SEO หลายข้อ รอบนี้รีวิว + แก้ครบ 36 จุดใน 6 รอบงาน ตั้งแต่ bug หลัก ไปจนถึง rich snippet และ infrastructure (PWA, RSS, www→non-www) เพื่อให้ Google เข้าใจเว็บมากขึ้น และคนเจอเว็บง่ายขึ้นเวลาค้นหา
รอบ 1 — Core fixes (12 จุด)
Bug หลัก: og:type article, fallback origin, SearchAction ปลอม, image fallback, sitemap lastmod, dedupe
[Critical] Blog post emit og:type=website แทน
article ทุกหน้า
Critical ·R1 #12
src/views/BlogDetailView.vue
เดิม BlogDetail ส่ง
openGraph: { type: 'article' } เป็น nested object แต่
normalizeSeoConfig() เจอ flat shape → rebuild
openGraph จาก flat ทั้งก้อน
ทิ้ง type: 'article' → blog
ทุกหน้าโดน emit og:type=website
og_type: 'article' → normalize
หยิบเข้า openGraph.type ถูก · social preview ของ blog ครบทุก meta
Fallback origin → pna.co.th ทุกชั้น
Critical ·R1 #1, #5, #7, #8
useSeo.js · index.php · robots.php · sitemap.php
เดิม fallback ของหลายไฟล์ยังชี้ไป
new.pnadigital.dev (staging) — ถ้า env ไม่ตั้งใน
build / localhost dev → canonical, og:url, sitemap URL ทั้งหมดผิด
domain
useSeo.js— client fallbackindex.php— SSRpna_base_url()-
robots.php— เพิ่มpna_robot_load_env()(เดิมไม่ load env เลย) -
sitemap.php— honorPUBLIC_SITE_URL+ localhost guard
pna.co.th สม่ำเสมอ
ลบ SearchAction ปลอมออกจาก WebSite JSON-LD
Critical ·R1 #6, #11
index.php · HomeView.vue
pna_ensure_site_jsonld และ HomeView เดิมส่ง
potentialAction: SearchAction ทั้งที่เว็บ
ไม่มี search endpoint แบบ URL ?q= —
ส่ง signal ปลอม = false promise ต่อ Google
Image fallback chain (og → twitter → featured)
High ·R1 #2, #3, #4 src/composables/useSeo.js
PHP-side มี chain
og_image → twitter_image → featured_image อยู่แล้ว
แต่ client เดิมใช้แค่ input.og_image → blog post
ที่มีแค่ featured_image โดน client hydrate
ลบรูป OG ทิ้ง เปลี่ยนเป็น default
featured_image ของบทความ
ไม่ใช่ default · เพิ่ม og:locale/theme-color/site_name defaults
ให้ตรงกับ SSR
Sitemap lastmod ใช้ filemtime() + dedupe เก็บ
lastmod ใหม่สุด
High ·R1 #9, #10
public/sitemap.php
เดิม lastmod = gmdate('Y-m-d') (today ทุก crawl) →
Google เดาว่าเว็บ "อัปเดตทุกวัน" →
ignore lastmod signal ทั้งหมด · dedupe เดิม skip
URL ซ้ำ → ตอนนี้เปรียบเทียบ lastmod เก็บค่าใหม่กว่า
รอบ 2 — Additional bugs found (6 จุด)
Bug เพิ่ม: logo.png ไม่มีจริง, llms env, JSON-LD URL inconsistency, NotFound og:url
[BUG] logo.png ไม่มีจริงในระบบ → fix 3 views
Critical ·R2 #13-15
HomeView · AboutView · ContactView
ใน public/assets/img/ มีแค่
logo-192x192.png, logo-32x32.png,
logo-text.png —
ไม่มี logo.png plain ทั้งที่ JSON-LD
ของ Organization ใน 3 view ชี้ logo.png
logo-192x192.png ครบ 3 views
JSON-LD URL absolute + llms.php env + NotFound og:url
High ·R2 #16-18 BlogView · llms.php · NotFoundView
3 fix ย่อย: BlogView JSON-LD /blog, /,
logo path จาก relative → absolute
https://pna.co.th/... · llms.php เพิ่ม
env load + localhost guard (ตาม sitemap.php) · NotFoundView เพิ่ม
url: '/404' ใน openGraph
รอบ 3 — Deeper audit findings (5 จุด)
Category canonical bug, coming-soon noindex, NavBar alt, SuccessStories schema[Critical] AllServicesView fallback canonical bug
Critical ·R3 #19 src/views/AllServicesView.vue
ถ้า user ลงที่ /services/ai แต่
services.json ไม่มี entry นั้น → fall back ใช้ SEO
ของ /services/all ซึ่งมี
canonical: '/services/all' →
ทุก category page emit canonical=/services/all
→ Google de-dupe หลุด category ออกจาก index
Fix: เพิ่ม seoForRoute(path) helper
ที่ override canonical และ og.url ตาม
route ปัจจุบันเสมอ แม้ใช้ fallback config
หน้า /coming-soon →
noindex,follow ทั้ง 2 ชั้น
High ·R3 #20, #21
ServiceComingSoonView · index.php SSR sync
หน้า placeholder ของ service ที่ยังไม่พร้อม — ไม่ควรติด search
result + เสี่ยงโดน mark thin content ลด E-E-A-T · client noindex
อย่างเดียวไม่พอ — Googlebot อ่าน raw HTML รอบแรก ถ้า SSR ส่ง
index,follow
ก็ติด index ก่อน JS ทำงาน
/services/{cat}/{svc}/coming-soon →
force noindex,follow + canonical/og:url ตาม path ·
client ก็ sync เช่นกัน
NavBar alt sync + SuccessStories BreadcrumbList
Medium ·R3 #22, #23 NavBar.vue · SuccessStoriesView.vue
NavBar alt เดิม "PNA" →
"PNA Digital" (ทั้ง main nav + drawer) sync กับ
footer · SuccessStoriesView เดิมมีแค่ meta tags
ไม่มี structuredData เลย → เพิ่ม BreadcrumbList
JSON-LD
รอบ 4 — Deeper signals (4 จุด)
Internal search noindex, OG image dimensions conditional, Content-Language header
Internal search + deep pagination →
noindex,follow
High ·R4 #24, #25
index.php (SSR) + BlogView.vue (client sync)
Google guideline แนะนำให้ noindex internal search results และ deep pagination เพราะเป็น thin / duplicate content — ปล่อยให้ index จะกินส่วนแบ่ง crawl budget และเสี่ยง Panda demotion
Fix 2 ชั้น:
SSR detect /blog?q=... หรือ ?page>1 →
force noindex · client robotsForQuery() helper +
watch(route.query) update meta tag in-place
OG image dimensions conditional +
Content-Language: th header
Medium ·R4 #26, #27
public/index.php
OG width/height: เดิม hardcode
1200x630 เสมอ — แต่ blog
featured_image / service og_image ใน DB
มีขนาดต่างกันจริง → Facebook/Twitter fetch แล้วเจอขนาดไม่ตรง →
render ผิด layout, แสดง warning ใน sharing debugger ·
Fix: emit เฉพาะตอนรู้ขนาดจริง (default OG +
caller ส่งมา)
Content-Language: th HTTP header — signal
ที่แรงกว่า <html lang="th"> สำหรับ
international SEO · Googlebot ใช้ทั้งคู่แต่ header มาก่อน HTML
parse
รอบ 5 — Rich snippet / entity enrichment (4 จุด)
Organization (address/tel/email/sameAs), LocalBusiness, FAQPage, article OG tagsOrganization schema enrich ครบ (address/tel/sameAs/email)
High ·R5 #28, #29 HomeView · AboutView
ใช้ข้อมูลบริษัทจริงจาก useContact.js (ที่อยู่จริง,
เบอร์โทรจริง, social handles จริง) เพิ่มฟิลด์:
-
legalName= 'บริษัท พีเอ็นเอ ดิจิตอล จำกัด' +foundingDate: '2018' -
email+telephoneE.164 (+66-2-279-5488) -
address(PostalAddress: street/locality/region/postal/country) contactPoint× 2 (sales + customer service)-
sameAs— Facebook, Instagram, TikTok, LINE URLs -
AboutView เพิ่ม
FAQPageJSON-LD จากfaqsarray (5 ข้อ)
ContactView → LocalBusiness + article OG tags ใน blog SSR
High ·R5 #30, #31 ContactView · index.php (blog SSR)
ContactView: เปลี่ยน
@type: Organization →
LocalBusiness พร้อม priceRange: '฿฿',
hasMap (Google Maps URL), @id stable ID
· Article OG: blog SSR emit
article:published_time,
article:modified_time, article:author,
article:section (ISO 8601 จาก
published_at/updated_at)
รอบ 6 — Infrastructure / discovery (5 จุด)
PWA manifest, www → non-www 301, entity @id linking, RSS feed
301 redirect www.pna.co.th →
pna.co.th
Critical ·R6 #32
public/.htaccess
ทั้ง www.pna.co.th และ pna.co.th
resolve ได้ → Google เห็นเป็น 2 เว็บแยก →
signal split + duplicate content จริง
RewriteCond %{HTTP_HOST} ^www\.pna\.co\.th$ [NC]
RewriteRule ^(.*)$ https://pna.co.th/$1 [R=301,L]
PUBLIC_SITE_URL ใน
.env · signal รวมศูนย์
PWA site.webmanifest + RSS /feed.xml
High ·R6 #33, #35
site.webmanifest · feed.php · .htaccess · index.html
PWA manifest (ไฟล์ใหม่) มี name,
short_name, theme_color: #ef4235,
display: standalone, icons (32+192),
lang: th · index.html เพิ่ม
<link rel="manifest">
+ apple/ms tags ·
RSS feed (feed.php) emit RSS 2.0 ของ 50 blog
ล่าสุด พร้อม <atom:link rel="self">,
<enclosure>
สำหรับ featured_image, 30-min cache
Entity @id linking — Organization ตัวเดียวข้าม 3
views
Medium ·R6 #34, #36
HomeView · AboutView · ContactView
ทุก view ใช้
@id: 'https://pna.co.th/#organization' ตรงกัน
(Home/About เป็น @type: Organization, Contact เป็น
@type: LocalBusiness แต่ @id เดียวกัน) · Schema.org
@id เป็น URI identifier ที่บอก Google ว่า entity ใน
JSON-LD ของหลายหน้าคือสิ่งเดียวกัน
Bonus — Google tracking & Keyword integration
GSC + GA4 setup + keyword ของลูกค้าจาก SEO TAG_rec_PNA.xlsxติดตั้ง Google Search Console + Google Analytics 4
Bonus index.php + robots.php + verification HTML
ติดตั้ง 3 อย่าง: (1)
<meta google-site-verification> + ไฟล์
google641cc4fa446fdec2.html เพื่อ verify ใน GSC · (2)
GA4 gtag.js (G-HG0GTV3GJM) · (3) เปิดให้ AI crawlers
(GPTBot, ChatGPT-User, PerplexityBot) crawl ผ่าน
robots.php
ฝัง keyword ของลูกค้าตามไฟล์ SEO TAG_rec_PNA.xlsx
Bonus
5 views + DB SQL × 18 services + 10 blog drafts
ฝัง keyword (Top 30 + Pain-point + Tool/Service intent + AI trend) ลงใน:
-
5 หน้าหลัก (
/,/about,/contact,/services,/services/all) - 5 service detail ผ่าน SQL UPDATE (DB-first ไม่แตะ Vue)
- blueprint blog 10 หัวข้อ จาก Pain-point keyword (ทีม SeoPrime เขียนเอง — ดู Phase 4 blueprint ใน SQL section)
-
เพิ่ม category
marketing+ 3 services (seo, ads, content) → coming-soon
Keyword mapping — ใส่คำไหนลงหน้าไหน
กระจาย keyword จาก SEO TAG_rec_PNA.xlsx
ลงหน้าตามความตรงของ intent (ข้อมูลเต็มอยู่ใน
seo set up/keyword_mapping.xlsx ใน folder source)
| หน้า | Keyword หลัก | KD | Volume | Phase |
|---|---|---|---|---|
| / | รับทำการตลาดออนไลน์ครบวงจร | 75 | 1,000–5,000 | Phase 2 |
| /about | บริษัทรับทําการตลาดออนไลน์ | 45 | 2,000–5,000 | Phase 2 |
| /services | บริการการตลาดดิจิทัล | 45 | 1,000–2,000 | Phase 2 |
| /services/all | โปรแกรมจัดการธุรกิจ | 50 | 500–1,500 | Phase 2 |
| /contact | ติดต่อบริษัทรับทำเว็บไซต์ | — | — | Phase 2 |
| /services/ai/ai-chatbot | รับทำ AI Chatbot Line OA AI Chatbot | 45 | 300–500 | Phase 3 (SQL) |
| /services/ai/ai-voiceover-generation | บริการพากย์เสียง AI เครื่องมือทำคอนเทนต์ AI | 35 | 800–1,000 | Phase 3 (SQL) |
| /services/ai/slip-verification-api | ระบบตรวจสลิปอัตโนมัติ | — | — | Phase 3 (SQL) |
| /services/technology/hotel-booking-system | ระบบจองห้องพักออนไลน์ รับวางระบบ IT ธุรกิจ | 50 | 500–1,000 | Phase 3 (SQL) |
| /services/technology/online-queue-system | ระบบจัดคิวออนไลน์ ระบบ POS ออนไลน์ ระบบจัดการสต็อกสินค้า | 80 | 2,000–5,000 | Phase 3 (SQL) |
| /services/marketing/seo | รับทำ SEO ติดหน้าแรก Google | 45 | 500–1,000 | Phase 5 (SQL) |
| /services/marketing/ads | รับยิงโฆษณา Facebook Google Ads agency Thailand | 43 | 200–300 | Phase 5 (SQL) |
| /services/marketing/content | บริการคอนเทนต์การตลาด รับทำ Content Marketing | 45 | 2,000–5,000 | Phase 5 (SQL) |
| /blog/online-pos-comparison | ระบบ POS ออนไลน์ | 80 | 2,000–5,000 | Phase 4 (blueprint) |
| /blog/in-house-vs-agency-marketing | รับทำการตลาดออนไลน์ครบวงจร | 75 | 1,000–5,000 | Phase 4 (blueprint) |
| /blog/online-shop-management-system | ระบบจัดการร้านค้าออนไลน์ | 65 | 3,000–4,000 | Phase 4 (blueprint) |
= priority สูง (KD/volume ดี) · = priority สูงสุดของชุด
รายการไฟล์ทั้งหมด
ค้นไฟล์ตาม path หรือ note · กรองตาม phase ที่ทำ
| Status | Path / Note | Size | Download |
|---|
หมายเหตุ:
ทุกไฟล์ download ได้แบบเดี่ยวจากปุ่ม
Download
หรือกดปุ่มใหญ่ด้านบนเพื่อดาวน์โหลด
.zip รวม 24 ไฟล์ ไฟล์
public/api/.env ไม่อยู่ในชุดนี้
(gitignored, secret) — ต้องตั้งเองบน production
SQL — ผลกับ URL + ข้อมูล blog ที่ทีม SeoPrime จะสร้างเอง
PHASE4_BLOG_POSTS.sql เป็น
เอกสารวางแผนเนื้อหาทีม SeoPrime เขียน blog
หัวข้อใด, slug ใด, target keyword คืออะไร, title/description
ที่แนะนำ, JSON-LD ที่ต้องการ
ไม่ต้องรัน SQL บน DB จริง
/services/technology/online-queue-system
Service
Detail
PHASE3_SERVICES_SEO.sql · UPDATE 1 row
เริ่มต้น: หน้านี้ใช้ template ของ
OnlineQueueSystemView.vue — มี title/description
hardcoded แบบ generic ไม่มี keyword "ระบบ POS ออนไลน์" ที่มี KD 80
(top keyword ของ Top 30)
หลังรัน SQL row นี้ DB จะมี:
-
seo_title= "ระบบจัดคิวออนไลน์ + POS + จัดการสต็อก สำหรับร้านค้าและคลินิก | PNA" -
seo_description= "ระบบจัดคิวออนไลน์ของ PNA Digital เชื่อม POS ระบบจัดการสต็อกสินค้าและร้านค้าออนไลน์..." -
seo_keywords= ระบบจัดคิวออนไลน์, ระบบ POS ออนไลน์ (KD80), ระบบจัดการสต็อกสินค้า, ระบบจัดการร้านค้าออนไลน์, รับทำระบบหลังบ้าน -
schema_json=Service+FAQPage(3 Q&A) +BreadcrumbList -
og_title,og_description,twitter_*ตรงกับ title/description
public/index.php เรียก
pna_meta_from_service() → อ่าน DB row → render
<title>, <meta>, JSON-LD ออก
HTML ทันที → Bot index ด้วย keyword "ระบบ POS ออนไลน์" /
"จัดการสต็อก" พร้อม rich result (FAQ + Breadcrumb)
/blog/online-pos-comparison
Blog ·
Highest Priority
PHASE4_BLOG_POSTS.sql · blueprint สำหรับทีม SeoPrime
เริ่มต้น: URL นี้ ยังไม่มี ในเว็บ — Google เปิด URL จะได้ 404 · ทีม SeoPrime จะสร้าง blog นี้เองผ่าน partner UI โดยใช้ข้อมูลด้านล่างเป็น blueprint
ข้อมูลที่คาดว่าจะอยู่ใน blog (ทีม SeoPrime ใช้เป็น blueprint):
slug=online-pos-comparison-
title= "ระบบ POS ออนไลน์ — เปรียบเทียบ 5 ระบบยอดนิยมและการเลือกให้เหมาะกับร้าน" -
target keyword= "ระบบ POS ออนไลน์" (KD 80, vol 2-5K — top priority ของ Top 30) - เนื้อหาที่ blueprint แนะนำ: intro POS ออนไลน์ · เปรียบเทียบ 5 ระบบ (Loyverse, Foodstory, Wongnai POS, Storehub, Lightspeed) · ฟีเจอร์เปรียบเทียบ · ราคา · use case · สรุป recommend ระบบที่เหมาะกับร้านแต่ละขนาด
-
internal link แนะนำ: ลิงก์ไป
/services/technology/online-queue-systemเพื่อส่งทราฟฟิกไปหน้า service -
SEO ครบทุก field:
seo_title,seo_description,seo_keywords,og_*,twitter_*,breadcrumb_json— ใส่ใน partner UI ตอนสร้าง blog -
JSON-LD
BlogPostingauto-inject จากpna_meta_from_blog_post()— ไม่ต้องเขียนเอง
PHASE4_BLOG_POSTS.sql เพื่อรู้ title, slug, keyword,
JSON-LD ที่แนะนำ · (2) login partner UI →
/partner/blog/new · (3) เขียน body content ตาม
blueprint + ใส่ internal link · (4) Publish → sitemap.xml
auto-pickup · (5) Google index ภายใน 3-7 วัน
/services/technology/online-queue-system
ส่งทราฟฟิกไป service detail ที่แก้ใน Phase 3 ด้วย
/blog/in-house-vs-agency-marketing
Blog
PHASE4_BLOG_POSTS.sql · blueprint สำหรับทีม SeoPrime
เริ่มต้น: URL ไม่มี — Google ได้ 404 · ทีม SeoPrime จะสร้าง blog นี้เองตาม blueprint
ข้อมูลที่คาดว่าจะอยู่ใน blog:
-
slug=in-house-vs-agency-marketing -
title= "รับทำการตลาดออนไลน์ครบวงจร — ทำเองดีหรือจ้างเอเจนซี่?" -
seo_focus_keyword= "รับทำการตลาดออนไลน์ครบวงจร" (KD75, top-1 ของ Top 30) - เนื้อหาที่ blueprint แนะนำ: เปรียบเทียบ in-house team กับ marketing agency · ค่าใช้จ่ายเฉลี่ย · ข้อดีข้อเสียของแต่ละแบบ · use case ของธุรกิจขนาดต่างกัน · checklist ตัดสินใจ
-
internal link แนะนำ:
/services+/contact
/services ส่ง traffic หา service hub
/blog/online-shop-management-system
Blog
PHASE4_BLOG_POSTS.sql · blueprint สำหรับทีม SeoPrime
เริ่มต้น: URL ไม่มี — Google ได้ 404 · ทีม SeoPrime จะสร้าง blog นี้เองตาม blueprint
ข้อมูลที่คาดว่าจะอยู่ใน blog:
-
slug=online-shop-management-system -
title= "ระบบจัดการร้านค้าออนไลน์ — แนะนำ POS + Stock + CRM ใช้งานจริง" -
target keyword= "ระบบจัดการร้านค้าออนไลน์" (KD 65, vol 3-4K) - เนื้อหาที่ blueprint แนะนำ: ความสำคัญของระบบจัดการ e-commerce · 3 องค์ประกอบหลัก (POS + Stock + CRM) · tools recommend สำหรับร้านเล็ก/กลาง/ใหญ่ · case study ของลูกค้า PNA
-
internal link แนะนำ:
/services/technology/online-queue-system(เสริมพลังกับ Impact card #1 + #2 ของ POS cluster)
/services/technology/online-queue-system
(เสริมพลังกับ Impact card #1 + #2)
online-queue-system +
online-pos-comparison +
online-shop-management-system) ทำงานเป็น
topic cluster เดียวกัน — ทุก URL link หากันผ่าน
internal link → Google จะมอง PNA Digital เป็น "authority" ในเรื่อง
POS/Queue/Shop management → ranking ของทั้ง 3 หน้าจะดีขึ้นพร้อมกัน
ดาวน์โหลด SQL files
ทั้ง 3 ไฟล์ SQL พร้อมรันบน pnaall_db · มี
verification queries ท้ายไฟล์เพื่อตรวจหลังรันเสร็จ
· อ่าน comment ใน header ของแต่ละไฟล์ เพื่อดู "HOW
TO RUN" + warnings
UPDATE × 5 designed services
(ai-chatbot, ai-voiceover, slip-verification, hotel-booking,
online-queue ⭐)
23.3 KB · 5 rows affected
ดาวน์โหลด
เอกสารวางแผน blog 10 หัวข้อ —
ทีม SeoPrime เขียนเอง ผ่าน partner UI
(ไม่ต้องรัน SQL จริง)
รวมหัวข้อ priority: online-pos-comparison, in-house-vs-agency,
online-shop-management
36.8 KB · blueprint × 10 หัวข้อ
ดาวน์โหลด
INSERT category marketing + 3 services
(seo, ads, content) — auto coming-soon
18.5 KB · 1+3 rows · ⚠️ ต้องตั้ง @admin_partner_id
ดาวน์โหลดหมายเหตุ: วิธีรัน SQL บน DB (phpMyAdmin / CLI / SSH tunnel) + backup + verification queries อยู่ใน header comment ของแต่ละไฟล์ เปิดดูใน text editor ก่อนรัน
งานเพิ่มเติม
1. Production environment
-
SSH เข้า
pnaserver.com→ แก้~/httpdocs/api/.envให้มีบรรทัดเหล่านี้อยู่ครบ (ไม่ลบของเดิม — JWT/DB/SMTP):APP_ENV=production API_DEBUG=true PUBLIC_SITE_URL=https://pna.co.th
PUBLIC_SITE_URLทำให้pna_base_url()ในpublic/index.phpreturnhttps://pna.co.thเลย ไม่ต้อง fallback ไปHTTP_HOSTหรือ hardcodednew.pnadigital.dev→ canonical / og:url ทุกหน้าชี้ production domain ถูก -
ยืนยัน DNS ของ
pna.co.thชี้pnaserver.com+ SSL cert ใช้งานได้ -
Set build env ก่อน
npm run buildบนเครื่อง dev (PowerShell):$env:VITE_PUBLIC_SITE_URL = "https://pna.co.th" npm run build
VITE_*prefix จำเป็น เพื่อให้ Vite expose ไปที่useSeo.jsฝั่ง client (import.meta.env.VITE_PUBLIC_SITE_URL)
2. OG images (1200×630) — 8 ไฟล์ใหม่ที่ต้อง upload
public/assets/img/og-ai-chatbot.pngpublic/assets/img/og-ai-voiceover.pngpublic/assets/img/og-slip-verification.pngpublic/assets/img/og-hotel-booking.pngpublic/assets/img/og-online-queue.pngpublic/assets/img/og-seo-service.pngpublic/assets/img/og-ads-service.pngpublic/assets/img/og-content-service.png-
public/assets/img/blog/{slug}.png× 10 (จาก Phase 4)
หาก image ไม่มี —
pna_social_image() fallback ไปใช้
/assets/img/og-default.png แทน social
preview จะ generic แต่ไม่ break