Development

จัดการ Content ด้วย pagecms opensource สุดคูล

แนะนำเครื่องมือสำหรับการจัดการ content สำหรับเว็บไซต์ประเภท static site

Introduction

เว็บไซต์นี้พัฒนาโดยใช้ Nuxt ร่วมกับ NuxtContent ซึ่งการจะเป็นการนำเอา Content ในรูปแบบของ Markdown มาสร้างเป็น Web Application โดยเป็นไปตามที่มีการตั้งค่าเอาไว้ ซึ่งวิธีนี้จะทำให้สามารถ Custom ตัวเว็บไซต์ได้เกือบ 100% เลย

ผมเก็บ source code ของ website ไว้ที่ github และ deploy ไปยัง cloudflare page โดยใช้ CICD ของ cloudflare page ครับ ซึ่งวิธีการนี้ทำให้มีค่าใช้จ่ายของเว็บไซต์นี้เกือบจะเป็น 0 บาทต่อเดือนเลยครับ เพราะทุกอย่างใช้จบได้ภายใน Free Tier

แต่ความยากอย่างนึงที่ผมเจอก็คือการที่ต้องจัดการ content ซึ่งอยู่ในรูปแบบของ markdown ช่วงแรก ๆ ก็จะใช้งานผ่าน vscode เอาเลย แต่ช่วงหลังก็เปลี่ยนมาใช้ obsidian โดยปรับแต่งให้สามารถจัดการ content ได้ แต่ก็ยังรู้สึกไม่ค่อยสะดวกเท่าไหร่

จนผมมาเจอเครื่องมือ opensource ตัวนึงชื่อว่า pagecms ซึ่งสามารถแก้ไขปัญหาตรงนี้ให้ผมได้และสะดวกมากขึ้นเยอะเลยครับ

What is pagecms?

pagecms คือ Content Management System สำหรับ Website ที่เป็นประเภท Static Site เช่น Jekyll, Next.js, VuePress, Hugo หรือประเภทใดก็ตามที่มีการเก็บ content ในลักษณะของ File Markdown

ซึ่งตัวเครื่องมือนี้สามารถใช้งานได้แบบง่าย ๆ โดยการเข้าใช้งานที่ https://app.pagescms.org/ จากนั้นทำการเชื่อมต่อกับ Github และเลือก Repo ที่ต้องการได้เลย

สามารถกำหนดการตั้งค่าต่าง ๆ ได้ผ่านตัวเว็บไซต์เลยครับ กำหนด config ให้ตรงกับ project structure โดยดูเพิ่มเติมได้จาก https://pagescms.org/docs/configuration/

สิ่งที่ pagecms สามารถทำได้

  • เพิ่ม/ลบ/แก้ไข content ของ website ได้ โดยจะเป็นการ commit เพื่อแก้ไข repo บน github โดยตรง
  • สามารถเพิ่ม/ลบ จัดการ media ภายใน website หรือ repo ได้
  • สลับ branch ในการจัดการได้
  • สามารถ invite คนอื่นเข้ามาร่วมแก้ไขได้ด้วย โดยอันนี้จะเป็นการ invite เข้า repo บน github เลยนะครับ

ซึ่งทั้งหมดจะทำงานบน github อีกทีนึง ตัว pagecms จะเป็นแค่หน้ากากทำให้ใช้งานได้ง่ายยิ่งขึ้นครับ

คำแนะนำ

จากที่ลองใช้งานมารู้สึกโอเคนะครับ แต่ตอนนี้ project กำลังอยู่ในช่วงพัฒนาคิดว่าจะมีฟีเจอร์มาให้ใช้งานอีกเพียบ สามารถติดตามได้ที่ https://github.com/hunvreus/pagescms

แนะนำให้สร้าง branch แยกกับ branch ที่มีการเปิด CICD เอาไว้นะครับ เพราะว่าทุกครั้งที่มีการ Upload File ในช่อง "Media" มันจะเป็นการสร้าง commit ใหม่ ซึ่งจะ trigger CICD เลยครับ แนะนำว่าให้สร้าง branch ใหม่แล้วถ้าต้องการ update ค่อย merge เข้าไปใน branch หลักอีกที

สำหรับผมมองว่าเป็นแค่ Add-on ที่เพิ่มเข้ามา ถ้าวันนึงมันไม่ work แล้วก็สามารถนำออกไปได้เลยครับ

อัปเดต 2026

โพสต์นี้เขียนไว้ตั้งแต่ปี 2025 พอกลับมารื้อ config ใหม่อีกรอบ ก็เจอว่า Pages CMS ขยับไปไกลกว่าที่คิด ของบางอย่างที่เคยเขียนไว้ข้างบนใช้ไม่ได้แล้วครับ

creatable ใน select หายไปแล้ว เดิมผมใส่ creatable: true ไว้ที่ field tags เพื่อจะได้พิมพ์แท็กใหม่จากในหน้าเว็บได้เลย ตอนนี้ไม่มีโค้ดส่วนไหนอ่านคีย์นี้แล้ว select เหลือแค่ค่าที่ประกาศไว้ล่วงหน้าอย่างเดียว อยากเพิ่มแท็กใหม่ก็ต้องมาแก้ที่ values เอง

มี field ชนิด reference มาแทน ชี้ไปที่ collection อื่นหรือ collection ตัวเองก็ได้ แล้วเลือกเอาจาก dropdown ผมย้าย prev / next / recommends จาก string มาเป็นอันนี้หมด ไม่ต้องพิมพ์ slug เองอีก จุดที่ต้องระวังคือค่าที่มันเขียนลงไฟล์เป็นชื่อไฟล์เต็มพร้อม .md ถ้าฝั่งเว็บเอาไปต่อเป็น URL ตรง ๆ ต้องตัดนามสกุลทิ้งก่อน

ตั้งชื่อไฟล์ให้อัตโนมัติได้ ผ่าน filename.template เขียนเป็น pattern อย่าง {year}-{month}-{day}-{ogTitle}.md แต่ token วันที่ตรงนี้คือวันที่ตอนกดสร้าง ไม่ได้ดึงจาก field date ที่กรอกไว้ ถ้าจะย้อนวันที่ก็ต้องแก้ชื่อไฟล์เองอยู่ดี

ล็อกการลบได้ ด้วย operations เปิดปิด create, rename, delete แยกกันได้ ผมปิด delete ไว้ กันมือลั่นลบโพสต์จากหน้าเว็บ

ปุ่มยิง GitHub Actions อันนี้สนุกสุด ประกาศ actions ไว้ใน config แล้ว Pages CMS จะเอาปุ่มไปแปะให้ กดแล้วมัน dispatch workflow พร้อมส่ง payload บอกว่าใครกดและกดมาจากโพสต์ไหน ผมเอามาทำปุ่มรัน typecheck, lint กับ build ก่อน publish

settings คุม commit message ที่ CMS สร้างขึ้นมา กับสั่งให้ merge field ที่ไม่ได้ประกาศไว้แทนที่จะลบทิ้ง อันหลังนี่สำคัญ ถ้าไม่เปิดไว้ field ที่มีอยู่ในไฟล์แต่ไม่มีใน config จะหายไปตอน save

แล้วนี่คือ config ที่ใช้อยู่ตอนนี้ครับ

media:
  input: public/images
  output: /images
  extensions: [jpg, jpeg, png, webp, gif, svg]

settings:
  content:
    # เก็บ field ที่ไม่ได้ประกาศข้างล่างไว้ ไม่ต้องลบทิ้งตอน save
    merge: true
  commit:
    templates:
      create: 'content(blogs): add {path}'
      update: 'content(blogs): update {path}'
      delete: 'content(blogs): remove {path}'
      rename: 'content(blogs): rename {oldPath} to {newPath}'

content:
  - name: blogs
    label: Blog Posts
    type: collection
    path: content/blogs
    filename:
      # slug ของ route คือชื่อไฟล์ ตัดนามสกุล ตัว date prefix เลยสำคัญ
      # แต่ {year}/{month}/{day} คือวันที่ตอนกดสร้าง ไม่ได้ตามค่าใน field date
      # เป็นแค่ค่าตั้งต้น field: create เปิดให้แก้เองได้
      template: '{year}-{month}-{day}-{ogTitle}.md'
      field: create
    operations:
      create: true
      rename: true
      delete: false
    actions:
      - name: run-checks
        label: Run checks
        workflow: pages-cms-checks.yml
        scope: collection
        ref: current
    view:
      fields: [title, date, tags, draft]
      primary: title
      sort: [date, title]
      search: [title, description, tags]
      default:
        sort: date
        order: desc
    fields:
      - name: title
        label: Title
        type: string
        required: true
      - name: ogTitle
        label: OG Text
        type: string
        required: true
      - name: description
        label: Description
        type: text
        required: true
      - name: date
        label: Date
        type: date
        required: true
        options:
          format: yyyy-MM-dd
      - name: tags
        label: Tags
        type: select
        options:
          multiple: true
          values: [Development, Homelab, AI, Tools, Python, Lifestyle]
      - name: draft
        label: Draft
        type: boolean
        default: true
      - name: pin
        label: Pin
        type: boolean
        default: false
      - name: prev
        label: Previous Post
        type: reference
        options:
          collection: blogs
          value: '{name}'
          label: '{primary}'
          search: 'title,description'
      - name: next
        label: Next Post
        type: reference
        options:
          collection: blogs
          value: '{name}'
          label: '{primary}'
          search: 'title,description'
      - name: recommends
        label: Recommended Posts
        type: reference
        options:
          collection: blogs
          multiple: true
          max: 3
          value: '{name}'
          label: '{primary}'
          search: 'title,description'
      - name: body
        label: Body
        type: rich-text

Related Articles

วิธีการติดตั้ง Ubuntu Version Pro แบบฟรี
Homelab

วิธีการติดตั้ง Ubuntu Version Pro แบบฟรี

วิธีขอและเปิดใช้ Ubuntu Pro ฟรีสำหรับ personal use สูงสุด 5 เครื่อง ได้อัปเดตความปลอดภัยยาว 10 ปี
Simple Paginate
Development

Simple Paginate

โค้ดตัวอย่างการทำ pagination แบบง่าย ๆ ด้วย Express + TypeScript + Mongoose พร้อมหน้าตา response
ตั้งค่าให้สามารถเชื่อมต่อ Local Network ได้ ตอนที่เชื่อม openvpn
Development

ตั้งค่าให้สามารถเชื่อมต่อ Local Network ได้ ตอนที่เชื่อม openvpn

แก้ไขไฟล์ openvpn config หากมีการ import เข้าไปใน openvpn gui แล้วสามารถค้นหาไฟล์การตั้งค่าได้ที่

Copyright © 2026