SiamCafe.net Blog
Technology

WordPress Headless Citizen Developer

wordpress headless citizen developer
WordPress Headless Citizen Developer | SiamCafe Blog
2026-05-21· อ. บอม — SiamCafe.net· 10,018 คำ

WP Headless

WordPress Headless Citizen Developer WP REST API WPGraphQL Next.js Nuxt.js Astro Content Modeling ACF Custom Post Type Deployment CDN Production

ApproachFrontendData FetchingPerformanceComplexityเหมาะกับ
Traditional WPPHP ThemeDirect DBปานกลางง่ายSimple blog
Headless + Next.jsReact SSR/SSGREST/GraphQLดีมากปานกลางDynamic site
Headless + AstroStatic HTMLREST at buildดีมากที่สุดง่ายContent site
Headless + NuxtVue SSR/SSGREST/GraphQLดีมากปานกลางVue team
Headless + GatsbyReact StaticGraphQLดีมากสูงLarge static

WP REST API

# === WordPress REST API Usage ===

# Endpoints
# GET /wp-json/wp/v2/posts          — List posts
# GET /wp-json/wp/v2/posts/123      — Single post
# GET /wp-json/wp/v2/pages          — List pages
# GET /wp-json/wp/v2/categories     — List categories
# GET /wp-json/wp/v2/tags           — List tags
# GET /wp-json/wp/v2/media          — List media
# GET /wp-json/wp/v2/users          — List users

# Query Parameters
# ?per_page=10&page=1               — Pagination
# ?search=keyword                    — Search
# ?categories=5                      — Filter by category
# ?orderby=date&order=desc          — Sort
# ?_embed                           — Include related data
# ?slug=my-post-slug                — Find by slug
# ?status=publish                    — Published only

# Next.js Data Fetching
# // pages/blog/[slug].js
# export async function getStaticPaths() {
#   const res = await fetch('https://wp.example.com/wp-json/wp/v2/posts?per_page=100');
#   const posts = await res.json();
#   return {
#     paths: posts.map(post => ({ params: { slug: post.slug } })),
#     fallback: 'blocking',
#   };
# }
#
# export async function getStaticProps({ params }) {
#   const res = await fetch(
#     `https://wp.example.com/wp-json/wp/v2/posts?slug=&_embed`
#   );
#   const [post] = await res.json();
#   return { props: { post }, revalidate: 60 };
# }

from dataclasses import dataclass

@dataclass
class APIEndpoint:
    method: str
    path: str
    auth: bool
    description: str
    example: str

endpoints = [
    APIEndpoint("GET", "/wp/v2/posts", False, "List all posts", "?per_page=10&_embed"),
    APIEndpoint("GET", "/wp/v2/posts?slug=xxx", False, "Get post by slug", "?slug=my-post&_embed"),
    APIEndpoint("POST", "/wp/v2/posts", True, "Create new post", '{"title":"New","content":"...","status":"publish"}'),
    APIEndpoint("PUT", "/wp/v2/posts/123", True, "Update post", '{"title":"Updated Title"}'),
    APIEndpoint("DELETE", "/wp/v2/posts/123", True, "Delete post", "?force=true"),
    APIEndpoint("GET", "/wp/v2/media", False, "List media files", "?per_page=20&media_type=image"),
]

print("=== WP REST API Endpoints ===")
for e in endpoints:
    auth = "Auth Required" if e.auth else "Public"
    print(f"  [{e.method}] {e.path} ({auth})")
    print(f"    {e.description}")
    print(f"    Example: {e.example}")

Content Modeling

# === Content Modeling with ACF ===

# ACF (Advanced Custom Fields) Plugin
# Create Custom Post Type: "Products"
# functions.php:
# register_post_type('product', [
#   'label' => 'Products',
#   'public' => true,
#   'show_in_rest' => true,  // Enable REST API
#   'supports' => ['title', 'editor', 'thumbnail', 'custom-fields'],
# ]);

# ACF Field Groups:
# Product Details:
#   - price (Number)
#   - sku (Text)
#   - stock (Number)
#   - gallery (Gallery)
#   - specifications (Repeater)
#     - spec_name (Text)
#     - spec_value (Text)

# REST API with ACF:
# GET /wp-json/wp/v2/product?_embed
# Response includes acf: { price: 999, sku: "SKU-001", ... }

# WPGraphQL + ACF:
# query {
#   products(first: 10) {
#     nodes {
#       title
#       productDetails {
#         price
#         sku
#         stock
#       }
#     }
#   }
# }

@dataclass
class ContentModel:
    post_type: str
    fields: str
    rest_endpoint: str
    use_case: str

models = [
    ContentModel("Posts", "title content excerpt categories tags featured_image", "/wp/v2/posts", "Blog articles"),
    ContentModel("Products", "price sku stock gallery specifications", "/wp/v2/product", "E-commerce catalog"),
    ContentModel("Events", "date location speaker capacity registration_url", "/wp/v2/event", "Event listings"),
    ContentModel("Testimonials", "author_name company rating quote photo", "/wp/v2/testimonial", "Social proof"),
    ContentModel("Portfolio", "client project_url technologies gallery", "/wp/v2/portfolio", "Work showcase"),
    ContentModel("FAQ", "question answer category order", "/wp/v2/faq", "FAQ sections"),
]

print("\n=== Content Models ===")
for m in models:
    print(f"  [{m.post_type}] Endpoint: {m.rest_endpoint}")
    print(f"    Fields: {m.fields}")
    print(f"    Use: {m.use_case}")

Deployment and Operations

# === Deployment Architecture ===

# WordPress Backend:
#   - Hosted on VPS / Managed WP (Kinsta, WP Engine)
#   - Only accessible by editors (no public frontend)
#   - Protected by .htaccess IP restriction or VPN
#   - Plugins: ACF Pro, WPGraphQL, Yoast SEO, WP Webhooks
#
# Next.js Frontend:
#   - Deployed on Vercel / Netlify / Cloudflare Pages
#   - ISR (Incremental Static Regeneration) every 60s
#   - CDN cached globally
#   - On-demand revalidation via WP Webhook
#
# Webhook Flow:
#   WP Post Published → WP Webhooks Plugin → POST to Vercel API
#   → Vercel revalidates page → Fresh content in seconds

@dataclass
class DeployComponent:
    component: str
    hosting: str
    url: str
    purpose: str
    cost: str

deploy = [
    DeployComponent("WordPress", "Kinsta / VPS", "admin.example.com", "CMS Backend API", "$30-100/mo"),
    DeployComponent("Next.js", "Vercel", "www.example.com", "Public frontend", "Free-$20/mo"),
    DeployComponent("CDN", "Cloudflare", "cdn.example.com", "Static assets cache", "Free"),
    DeployComponent("Media", "S3 + CloudFront", "media.example.com", "Image video storage", "$5-20/mo"),
    DeployComponent("Search", "Algolia", "N/A (API)", "Full-text search", "Free-$29/mo"),
    DeployComponent("Forms", "Formspree", "N/A (API)", "Contact forms", "Free-$10/mo"),
]

print("Deployment Architecture:")
for d in deploy:
    print(f"  [{d.component}] {d.hosting}")
    print(f"    URL: {d.url} | Purpose: {d.purpose}")
    print(f"    Cost: {d.cost}")

citizen_dev_tools = {
    "Content": "WordPress Admin — Gutenberg Editor, ACF Fields",
    "Design": "Elementor (backend preview) or Figma mockups",
    "Automation": "Zapier / Make.com — connect WP to email, CRM, sheets",
    "SEO": "Yoast SEO plugin — titles, meta, sitemap",
    "Analytics": "Google Analytics + Search Console",
    "Forms": "WPForms or Gravity Forms → REST API",
}

print(f"\n\nCitizen Developer Tools:")
for k, v in citizen_dev_tools.items():
    print(f"  [{k}]: {v}")

เคล็ดลับ

WordPress Headless คืออะไร

WordPress Backend CMS ไม่ใช้ Theme WP REST API WPGraphQL Frontend แยก Next.js Nuxt.js Astro Performance ดี ปลอดภัย Scale CDN

Citizen Developer คืออะไร

ไม่ใช่โปรแกรมเมอร์ สร้าง App ได้ Low-code No-code WordPress Admin ACF Elementor Gutenberg Zapier Make.com Content Backend Admin Panel

WP REST API ใช้อย่างไร

/wp-json/wp/v2/ Posts Pages Categories Tags Media GET POST PUT DELETE Authentication Application Password JWT Custom Post Type ACF

เลือก Frontend Framework อะไรดี

Next.js เหมาะสุด SSG SSR ISR React Community Nuxt.js Vue Astro Static เร็ว Gatsby GraphQL SvelteKit Svelte Team Skill WPGraphQL

สรุป

WordPress Headless Citizen Developer WP REST API WPGraphQL Next.js ACF Custom Post Type Content Modeling Webhook ISR CDN Deployment Production

📖 บทความที่เกี่ยวข้อง

WordPress Headless Post-mortem Analysisอ่านบทความ → Elixir Ecto Citizen Developerอ่านบทความ → BigQuery Scheduled Query Citizen Developerอ่านบทความ → DNSSEC Implementation Citizen Developerอ่านบทความ → WordPress Headless Agile Scrum Kanbanอ่านบทความ →

📚 ดูบทความทั้งหมด →