รายงานการอัปเดต SEO — PNA Digital

รายงานการ deploy การปรับ SEO ของเว็บ pna.co.th ครอบคลุม Audit Round 1 (11 fixes) Visual ของเว็บไม่เปลี่ยน

ดาวน์โหลดทั้งหมด (.zip) รวม 24 ไฟล์ · ~127 KB · พร้อมแตก zip วางทับ repo เดิม (โครงต้นทาง: public/, src/views/, src/components/, src/composables/, scripts/,
Repo: pna_backup (Vue 3 SPA + PHP backend) Branch: seo รายงาน: 15-05-2026 Scope: SEO only — visual ไม่เปลี่ยน Domain: pna.co.th

ภาพรวม

ทุกการแก้ผ่านขอบเขต SEO-only ไม่แตะ visual, Tailwind, Studio editor, partner views, หรือ designed service views — หน้าตาเว็บเหมือนเดิม 100%

36
SEO fixes ทั้งหมด
6
รอบงาน (Round 1–6)
17
ไฟล์ที่ modified
5
ไฟล์ใหม่ (manifest/feed/SQL)
30+
Keywords ที่ฝัง
0
ผลกระทบ visual
Scope check ผ่าน 100% ไม่มีไฟล์ใดที่แก้แล้วกระทบ src/assets/style.css, <style scoped> เดิม, inline style, Tailwind class, Studio component (src/components/Studio/**), partner views, service views หรือ DB schema หน้าตาเว็บหลัง deploy จะเหมือนเดิม 100%
มี action ต้องทำต่อฝั่ง user งานในรายงานนี้คือ "ทำ code/SQL พร้อมแล้ว" แต่ยังเหลือ:

สิ่งที่แก้ทั้งหมด — แยกตาม 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
12 fixes
1

[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

เปรียบเหมือน... บอก Facebook ว่าบทความ blog ของคุณคือ "เว็บไซต์ทั่วไป" ไม่ใช่ "บทความ" → Facebook/LinkedIn ไม่แสดง publish date, author, section ใน preview card
ผลที่คาด: Fix เป็น flat key og_type: 'article' → normalize หยิบเข้า openGraph.type ถูก · social preview ของ blog ครบทุก meta
2

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 fallback
  • index.php — SSR pna_base_url()
  • robots.php — เพิ่ม pna_robot_load_env() (เดิมไม่ load env เลย)
  • sitemap.php — honor PUBLIC_SITE_URL + localhost guard
ผลที่คาด: canonical/og:url/sitemap ทุกที่ชี้ pna.co.th สม่ำเสมอ
3

ลบ 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

ผลที่คาด: เก็บ WebSite identity ไว้ ลบ potentialAction ทิ้ง → Google ไม่เจอ inconsistent signal
4

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

ผลที่คาด: Social preview ของ blog ใช้ featured_image ของบทความ ไม่ใช่ default · เพิ่ม og:locale/theme-color/site_name defaults ให้ตรงกับ SSR
5

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 เก็บค่าใหม่กว่า

ผลที่คาด: Google เชื่อ lastmod ของเรา → re-crawl เฉพาะหน้าที่ จริงๆ มีการเปลี่ยนแปลง (save crawl budget)

รอบ 2 — Additional bugs found (6 จุด)

Bug เพิ่ม: logo.png ไม่มีจริง, llms env, JSON-LD URL inconsistency, NotFound og:url
6 fixes
6

[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

ผลที่คาด: Google Rich Results Test เคยแจ้ง "missing image" → fix เปลี่ยนเป็น logo-192x192.png ครบ 3 views
7

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

ผลที่คาด: JSON-LD ของทุก view ใช้ absolute URL สม่ำเสมอ · llms.txt URL ชี้ถูก domain · 404 page มี og:url

รอบ 3 — Deeper audit findings (5 จุด)

Category canonical bug, coming-soon noindex, NavBar alt, SuccessStories schema
5 fixes
8

[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

ผลที่คาด: ทุก category route emit canonical ของ ตัวเอง · Google index แยกแต่ละหมวด ไม่ de-dupe หลุด
9

หน้า /coming-soonnoindex,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 ทำงาน

ผลที่คาด: SSR detect path /services/{cat}/{svc}/coming-soon → force noindex,follow + canonical/og:url ตาม path · client ก็ sync เช่นกัน
10

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

ผลที่คาด: brand recognition สม่ำเสมอ ทั้ง a11y + image search · SuccessStories มี breadcrumb signal ใน SERP

รอบ 4 — Deeper signals (4 จุด)

Internal search noindex, OG image dimensions conditional, Content-Language header
4 fixes
11

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

ผลที่คาด: Google crawl budget โฟกัสที่หน้าสำคัญ · ไม่ติด Panda demotion จาก thin content
12

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

ผลที่คาด: Facebook/Twitter sharing preview ถูกขนาด · International SEO signal ชัดเจน

รอบ 5 — Rich snippet / entity enrichment (4 จุด)

Organization (address/tel/email/sameAs), LocalBusiness, FAQPage, article OG tags
4 fixes
13

Organization schema enrich ครบ (address/tel/sameAs/email)

High ·R5 #28, #29 HomeView · AboutView

ใช้ข้อมูลบริษัทจริงจาก useContact.js (ที่อยู่จริง, เบอร์โทรจริง, social handles จริง) เพิ่มฟิลด์:

  • legalName = 'บริษัท พีเอ็นเอ ดิจิตอล จำกัด' + foundingDate: '2018'
  • email + telephone E.164 (+66-2-279-5488)
  • address (PostalAddress: street/locality/region/postal/country)
  • contactPoint × 2 (sales + customer service)
  • sameAs — Facebook, Instagram, TikTok, LINE URLs
  • AboutView เพิ่ม FAQPage JSON-LD จาก faqs array (5 ข้อ)
ผลที่คาด: Google Knowledge Graph สร้าง entity card ในผล search · FAQPage rich snippet ใน Bing/AI/voice
14

ContactView → LocalBusiness + article OG tags ใน blog SSR

High ·R5 #30, #31 ContactView · index.php (blog SSR)

ContactView: เปลี่ยน @type: OrganizationLocalBusiness พร้อม 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)

ผลที่คาด: Google Maps preview "Open now" reviews อนาคต · Facebook/LinkedIn share preview ของ blog มีวันที่/หมวด

รอบ 6 — Infrastructure / discovery (5 จุด)

PWA manifest, www → non-www 301, entity @id linking, RSS feed
5 fixes
15

301 redirect www.pna.co.thpna.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]
ผลที่คาด: ใช้ non-www เป็น primary ตาม PUBLIC_SITE_URL ใน .env · signal รวมศูนย์
16

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

ผลที่คาด: Lighthouse PWA section: 0 → installable · "Add to Home Screen" บนมือถือ · AI crawlers (ChatGPT, Claude, Perplexity) ดึง RSS ก่อน full page → discovery เร็ว
17

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 ของหลายหน้าคือสิ่งเดียวกัน

ผลที่คาด: consolidate signal ลง Knowledge Graph แทนแยก 3 entity → entity card ใน Google search ครบข้อมูล

Bonus — Google tracking & Keyword integration

GSC + GA4 setup + keyword ของลูกค้าจาก SEO TAG_rec_PNA.xlsx
+2
18

ติดตั้ง 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

ผลที่คาด: ดู index status / keyword / traffic ผ่าน GSC + GA4 · ติดผลค้นหาของ ChatGPT, Perplexity
19

ฝัง 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
ผลที่คาด: เพิ่ม visibility สำหรับ keyword "รับทำการตลาดออนไลน์ครบวงจร", "ระบบ POS ออนไลน์", "Line OA AI Chatbot" และอีก 25+ คำ

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 จะสร้างเอง

เกี่ยวกับ Phase 4 — Blog drafts × 10 ไฟล์ 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
Flow หลัง SQL วิ่ง เมื่อ Google bot hit URL นี้ → public/index.php เรียก pna_meta_from_service() → อ่าน DB row → render <title>, <meta>, JSON-LD ออก HTML ทันที → Bot index ด้วย keyword "ระบบ POS ออนไลน์" / "จัดการสต็อก" พร้อม rich result (FAQ + Breadcrumb)
ผลที่คาด: target KW "ระบบ POS ออนไลน์" (KD80, vol 2-5K) + KW รอง 4 ตัว → ติดอันดับ + rich result ใน SERP

/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 BlogPosting auto-inject จาก pna_meta_from_blog_post() — ไม่ต้องเขียนเอง
Flow ฝั่งทีม SeoPrime (1) ดู blueprint ในไฟล์ 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 วัน
ผลที่คาด: target KW "ระบบ POS ออนไลน์" (KD80, vol 2-5K) — top priority ของชุด blog · internal link → /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
ผลที่คาด: target KW "รับทำการตลาดออนไลน์ครบวงจร" (KD75, vol 1-5K) · internal link → /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)
ผลที่คาด: target KW "ระบบจัดการร้านค้าออนไลน์" (KD65, vol 3-4K) · internal link → /services/technology/online-queue-system (เสริมพลังกับ Impact card #1 + #2)
Cluster effect 3 URL นี้ (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

A Phase 3 — Services SEO

UPDATE × 5 designed services
(ai-chatbot, ai-voiceover, slip-verification, hotel-booking, online-queue ⭐)

23.3 KB · 5 rows affected

ดาวน์โหลด
A Phase 4 — Blog Blueprint × 10

เอกสารวางแผน blog 10 หัวข้อ — ทีม SeoPrime เขียนเอง ผ่าน partner UI (ไม่ต้องรัน SQL จริง)
รวมหัวข้อ priority: online-pos-comparison, in-house-vs-agency, online-shop-management

36.8 KB · blueprint × 10 หัวข้อ

ดาวน์โหลด
A Phase 5 — Marketing Cat

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

  1. 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.php return https://pna.co.th เลย ไม่ต้อง fallback ไป HTTP_HOST หรือ hardcoded new.pnadigital.dev → canonical / og:url ทุกหน้าชี้ production domain ถูก

  2. ยืนยัน DNS ของ pna.co.th ชี้ pnaserver.com + SSL cert ใช้งานได้
  3. 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.png
  • public/assets/img/og-ai-voiceover.png
  • public/assets/img/og-slip-verification.png
  • public/assets/img/og-hotel-booking.png
  • public/assets/img/og-online-queue.png
  • public/assets/img/og-seo-service.png
  • public/assets/img/og-ads-service.png
  • public/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