Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      tRPC vs GraphQL vs REST: Choosing the right API design for modern web applications

      June 26, 2025

      Jakarta EE 11 Platform launches with modernized Test Compatibility Kit framework

      June 26, 2025

      Can Good UX Protect Older Users From Digital Scams?

      June 25, 2025

      Warp 2.0 evolves terminal experience into an Agentic Development Environment

      June 25, 2025

      Microsoft Copilot secures a spot in classrooms as a “thought partner” — with Copilot Chat backed by OpenAI’s GPT-4o

      June 26, 2025

      OpenAI started as a “countervailing force” to Google — did Elon Musk and Sam Altman torpedo DeepMind’s plans to dictate AGI?

      June 26, 2025

      Gears of War: Reloaded preorders — where to buy and everything you need to know

      June 26, 2025

      OpenAI’s Sam Altman breaks silence on Microsoft feud with Satya Nadella — citing “points of tension” amid evolution plans

      June 26, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Are Semantic Layers Sexy Again? or The Rise and Fall and Rise of Semantic Layers

      June 26, 2025
      Recent

      Are Semantic Layers Sexy Again? or The Rise and Fall and Rise of Semantic Layers

      June 26, 2025

      Salesforce Marketing Cloud Engagement vs. Oracle Eloqua

      June 26, 2025

      Exploring Lucidworks Fusion and Coveo Using Apache Solr

      June 26, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured

      Microsoft Copilot secures a spot in classrooms as a “thought partner” — with Copilot Chat backed by OpenAI’s GPT-4o

      June 26, 2025
      Recent

      Microsoft Copilot secures a spot in classrooms as a “thought partner” — with Copilot Chat backed by OpenAI’s GPT-4o

      June 26, 2025

      OpenAI started as a “countervailing force” to Google — did Elon Musk and Sam Altman torpedo DeepMind’s plans to dictate AGI?

      June 26, 2025

      Gears of War: Reloaded preorders — where to buy and everything you need to know

      June 26, 2025
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»News & Updates»Using Pages CMS for Static Site Content Management

    Using Pages CMS for Static Site Content Management

    May 12, 2025

    Friends, I’ve been on the hunt for a decent content management system for static sites for… well, about as long as we’ve all been calling them “static sites,” honestly.

    I know, I know: there are a ton of content management system options available, and while I’ve tested several, none have really been the one, y’know? Weird pricing models, difficult customization, some even end up becoming a whole ‘nother thing to manage.

    Also, I really enjoy building with site generators such as Astro or Eleventy, but pitching Markdown as the means of managing content is less-than-ideal for many “non-techie” folks.

    A few expectations for content management systems might include:

    • Easy to use: The most important feature, why you might opt to use a content management system in the first place.
    • Minimal Requirements: Look, I’m just trying to update some HTML, I don’t want to think too much about database tables.
    • Collaboration: CMS tools work best when multiple contributors work together, contributors who probably don’t know Markdown or what GitHub is.
    • Customizable: No website is the same, so we’ll need to be able to make custom fields for different types of content.

    Not a terribly long list of demands, I’d say; fairly reasonable, even. That’s why I was happy to discover Pages CMS.

    According to its own home page, Pages CMS is the “The No-Hassle CMS for Static Site Generators,” and I’ll to attest to that. Pages CMS has largely been developed by a single developer, Ronan Berder, but is open source, and accepting pull requests over on GitHub.

    Taking a lot of the “good parts” found in other CMS tools, and a single configuration file, Pages CMS combines things into a sleek user interface.

    Pages CMS includes lots of options for customization, you can upload media, make editable files, and create entire collections of content. Also, content can have all sorts of different fields, check the docs for the full list of supported types, as well as completely custom fields.

    There isn’t really a “back end” to worry about, as content is stored as flat files inside your git repository. Pages CMS provides folks the ability to manage the content within the repo, without needing to actually know how to use Git, and I think that’s neat.

    User Authentication works two ways: contributors can log in using GitHub accounts, or contributors can be invited by email, where they’ll receive a password-less, “magic-link,” login URL. This is nice, as GitHub accounts are less common outside of the dev world, shocking, I know.

    Oh, and Pages CMS has a very cheap barrier for entry, as it’s free to use.

    Pages CMS and Astro content collections

    I’ve created a repository on GitHub with Astro and Pages CMS using Astro’s default blog starter, and made it available publicly, so feel free to clone and follow along.

    I’ve been a fan of Astro for a while, and Pages CMS works well alongside Astro’s content collection feature. Content collections make globs of data easily available throughout Astro, so you can hydrate content inside Astro pages. These globs of data can be from different sources, such as third-party APIs, but commonly as directories of Markdown files. Guess what Pages CMS is really good at? Managing directories of Markdown files!

    Content collections are set up by a collections configuration file. Check out the src/content.config.ts file in the project, here we are defining a content collection named blog:

    import { glob } from 'astro/loaders';
    import { defineCollection, z } from 'astro:content';
    
    const blog = defineCollection({
    // Load Markdown in the `src/content/blog/` directory.
    loader: glob({ base: './src/content/blog', pattern: '**/*.md' }),
      // Type-check frontmatter using a schema
      schema: z.object({
        title: z.string(),
       description: z.string(),
        // Transform string to Date object
        pubDate: z.coerce.date(),
        updatedDate: z.coerce.date().optional(),
        heroImage: z.string().optional(),
      }),
    });
    
    export const collections = { blog };

    The blog content collection checks the /src/content/blog directory for files matching the **/*.md file type, the Markdown file format. The schema property is optional, however, Astro provides helpful type-checking functionality with Zod, ensuring data saved by Pages CMS works as expected in your Astro site.

    Pages CMS Configuration

    Alright, now that Astro knows where to look for blog content, let’s take a look at the Pages CMS configuration file, .pages.config.yml:

    content:
      - name: blog
        label: Blog
        path: src/content/blog
        filename: '{year}-{month}-{day}-{fields.title}.md'
        type: collection
        view:
          fields: [heroImage, title, pubDate]
        fields:
          - name: title
            label: Title
            type: string
    
          - name: description
            label: Description
            type: text
    
          - name: pubDate
            label: Publication Date
            type: date
            options:
              format: MM/dd/yyyy
    
          - name: updatedDate
            label: Last Updated Date
            type: date
            options:
              format: MM/dd/yyyy
    
          - name: heroImage
            label: Hero Image
            type: image
    
          - name: body
            label: Body
            type: rich-text
    
      - name: site-settings
        label: Site Settings
        path: src/config/site.json
        type: file
        fields:
          - name: title
            label: Website title
            type: string
    
          - name: description
            label: Website description
            type: string
            description: Will be used for any page with no description.
    
          - name: url
            label: Website URL
            type: string
            pattern: ^(https?://)?(www.)?[a-zA-Z0-9.-]+.[a-zA-Z]{2,}(/[^s]*)?$
    
          - name: cover
            label: Preview image
            type: image
            description: Image used in the social preview on social networks (e.g. Facebook, Twitter...)
    
    media:
      input: public/media
      output: /media

    There is a lot going on in there, but inside the content section, let’s zoom in on the blog object.

    - name: blog
      label: Blog
      path: src/content/blog
      filename: '{year}-{month}-{day}-{fields.title}.md'
      type: collection
      view:
        fields: [heroImage, title, pubDate]
      fields:
        - name: title
          label: Title
          type: string
    
        - name: description
          label: Description
          type: text
    
        - name: pubDate
          label: Publication Date
          type: date
          options:
            format: MM/dd/yyyy
    
        - name: updatedDate
          label: Last Updated Date
          type: date
          options:
            format: MM/dd/yyyy
    
        - name: heroImage
          label: Hero Image
          type: image
    
        - name: body
          label: Body
          type: rich-text

    We can point Pages CMS to the directory we want to save Markdown files using the path property, matching it up to the /src/content/blog/ location Astro looks for content.

    path: src/content/blog

    For the filename we can provide a pattern template to use when Pages CMS saves the file to the content collection directory. In this case, it’s using the file date’s year, month, and day, as well as the blog item’s title, by using fields.title to reference the title field. The filename can be customized in many different ways, to fit your scenario.

    filename: '{year}-{month}-{day}-{fields.title}.md'

    The type property tells Pages CMS that this is a collection of files, rather than a single editable file (we’ll get to that in a moment).

    type: collection

    In our Astro content collection configuration, we define our blog collection with the expectation that the files will contain a few bits of meta data such as: title, description, pubDate, and a few more properties.

    We can mirror those requirements in our Pages CMS blog collection as fields. Each field can be customized for the type of data you’re looking to collect. Here, I’ve matched these fields up with the default Markdown frontmatter found in the Astro blog starter.

    fields:
      - name: title
        label: Title
        type: string
    
      - name: description
        label: Description
        type: text
    
      - name: pubDate
        label: Publication Date
        type: date
        options:
          format: MM/dd/yyyy
    
      - name: updatedDate
        label: Last Updated Date
        type: date
        options:
          format: MM/dd/yyyy
    
      - name: heroImage
        label: Hero Image
        type: image
    
      - name: body
        label: Body
        type: rich-text

    Now, every time we create a new blog item in Pages CMS, we’ll be able to fill out each of these fields, matching the expected schema for Astro.

    Aside from collections of content, Pages CMS also lets you manage editable files, which is useful for a variety of things: site wide variables, feature flags, or even editable navigations.

    Take a look at the site-settings object, here we are setting the type as file, and the path includes the filename site.json.

    - name: site-settings
      label: Site Settings
      path: src/config/site.json
      type: file
      fields:
        - name: title
          label: Website title
          type: string
    
        - name: description
          label: Website description
          type: string
          description: Will be used for any page with no description.
    
        - name: url
          label: Website URL
          type: string
          pattern: ^(https?://)?(www.)?[a-zA-Z0-9.-]+.[a-zA-Z]{2,}(/[^s]*)?$
    
        - name: cover
          label: Preview image
          type: image
          description: Image used in the social preview on social networks (e.g. Facebook, Twitter...)

    The fields I’ve included are common site-wide settings, such as the site’s title, description, url, and cover image.

    Speaking of images, we can tell Pages CMS where to store media such as images and video.

    media:
      input: public/media
      output: /media

    The input property explains where to store the files, in the /public/media directory within our project.

    The output property is a helpful little feature that conveniently replaces the file path, specifically for tools that might require specific configuration. For example, Astro uses Vite under the hood, and Vite already knows about the public directory and complains if it’s included within file paths. Instead, we can set the output property so Pages CMS will only point image path locations starting at the inner /media directory instead.

    To see what I mean, check out the test post in the src/content/blog/ folder:

    ---
    title: 'Test Post'
    description: 'Here is a sample of some basic Markdown syntax that can be used when writing Markdown content in Astro.'
    pubDate: 05/03/2025
    heroImage: '/media/blog-placeholder-1.jpg'
    ---

    The heroImage now property properly points to /media/... instead of /public/media/....

    As far as configurations are concerned, Pages CMS can be as simple or as complex as necessary. You can add as many collections or editable files as needed, as well as customize the fields for each type of content. This gives you a lot of flexibility to create sites!

    Connecting to Pages CMS

    Now that we have our Astro site set up, and a .pages.config.yml file, we can connect our site to the Pages CMS online app. As the developer who controls the repository, browse to https://app.pagescms.org/ and sign in using your GitHub account.

    You should be presented with some questions about permissions, you may need to choose between giving access to all repositories or specific ones. Personally, I chose to only give access to a single repository, which in this case is my astro-pages-cms-template repo.

    granting permission to a single repository, called mrtrimble/astro-pages-cms-template

    After providing access to the repo, head on back to the Pages CMS application, where you’ll see your project listed under the “Open a Project” headline.

    text that reads "Open a project" with a list of projects, the astro pages cms template is visible at the top

    Clicking the open link will take you into the website’s dashboard, where we’ll be able to make updates to our site.

    Creating content

    Taking a look at our site’s dashboard, we’ll see a navigation on the left side, with some familiar things.

    Blog dashboard page, displaying the blog entries, there is only one at the moment, called Test Post. At the top, a button labeled "Add an entry"
    • Blog is the collection we set up inside the .pages.config.yml file, this will be where we we can add new entries to the blog.
    • Site Settings is the editable file we are using to make changes to site-wide variables.
    • Media is where our images and other content will live.
    • Settings is a spot where we’ll be able to edit our .pages.config.yml file directly.
    • Collaborators allows us to invite other folks to contribute content to the site.

    We can create a new blog post by clicking the Add Entry button in the top right

    create a new entry page, with fields for title, description publication date, last updated date, hero image, and body

    Here we can fill out all the fields for our blog content, then hit the Save button.

    After saving, Pages CMS will create the Markdown file, store the file in the proper directory, and automatically commit the changes to our repository. This is how Pages CMS helps us manage our content without needing to use git directly.

    Automatically deploying

    The only thing left to do is set up automated deployments through the service provider of your choice. Astro has integrations with providers like Netlify, Cloudflare Pages, and Vercel, but can be hosted anywhere you can run node applications.

    Astro is typically very fast to build (thanks to Vite), so while site updates won’t be instant, they will still be fairly quick to deploy. If your site is set up to use Astro’s server-side rendering capabilities, rather than a completely static site, the changes might be much faster to deploy.

    Wrapping up

    Using a template as reference, we checked out how Astro content collections work alongside Pages CMS. We also learned how to connect our project repository to the Pages CMS app, and how to make content updates through the dashboard. Finally, if you are able, don’t forget to set up an automated deployment, so content publishes quickly.


    Using Pages CMS for Static Site Content Management originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.

    Source: Read More 

    Facebook Twitter Reddit Email Copy Link
    Previous ArticleCVE-2025-22247 – VMware Tools Insecure File Handling Vulnerability
    Next Article GitHub for Beginners: Building a React App with GitHub Copilot

    Related Posts

    News & Updates

    Microsoft Copilot secures a spot in classrooms as a “thought partner” — with Copilot Chat backed by OpenAI’s GPT-4o

    June 26, 2025
    News & Updates

    OpenAI started as a “countervailing force” to Google — did Elon Musk and Sam Altman torpedo DeepMind’s plans to dictate AGI?

    June 26, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    Enterprise AI Without GPU Burn: Salesforce’s xGen-small Optimizes for Context, Cost, and Privacy

    Machine Learning

    5 things we didn’t get from the Xbox Games Showcase, because Xbox obviously hates me personally

    News & Updates

    CVE-2025-47302 – Apache HTTP Server Unvalidated User Input

    Common Vulnerabilities and Exposures (CVEs)

    How Apoidea Group enhances visual information extraction from banking documents with multimodal models using LLaMA-Factory on Amazon SageMaker HyperPod

    Machine Learning

    Highlights

    Tesla Model 3 VCSEC Vulnerability Allows Attackers to Execute Arbitrary Code

    May 1, 2025

    Tesla Model 3 VCSEC Vulnerability Allows Attackers to Execute Arbitrary Code

    A critical vulnerability in Tesla Model 3’s vehicle security systems has exposed thousands of cars to potential remote attacks, cybersecurity researchers revealed this week.
    Designated CVE-2025-2082, …
    Read more

    Published Date:
    May 01, 2025 (3 hours, 41 minutes ago)

    Vulnerabilities has been mentioned in this article.

    CVE-2025-2082

    Hugging Face Releases nanoVLM: A Pure PyTorch Library to Train a Vision-Language Model from Scratch in 750 Lines of Code

    May 8, 2025

    Microsoft April 2025 Patch Tuesday: Fixes for 134 security vulnerabilities, one exploited Zero-Day

    April 9, 2025

    CVE-2025-6218 – WinRAR Directory Traversal Remote Code Execution Vulnerability

    June 20, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.