<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ivan Bertotto</title>
    <description>The latest articles on DEV Community by Ivan Bertotto (@ivan_bertotto_a81eb06db85).</description>
    <link>https://dev.to/ivan_bertotto_a81eb06db85</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3877406%2F2ceba83f-772c-4952-b3a3-d4fdbef2c498.jpg</url>
      <title>DEV Community: Ivan Bertotto</title>
      <link>https://dev.to/ivan_bertotto_a81eb06db85</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ivan_bertotto_a81eb06db85"/>
    <language>en</language>
    <item>
      <title>O CMS</title>
      <dc:creator>Ivan Bertotto</dc:creator>
      <pubDate>Mon, 13 Apr 2026 21:17:55 +0000</pubDate>
      <link>https://dev.to/ivan_bertotto_a81eb06db85/o-cms-1l8e</link>
      <guid>https://dev.to/ivan_bertotto_a81eb06db85/o-cms-1l8e</guid>
      <description>&lt;h2&gt;
  
  
  The problem nobody asked me to solve
&lt;/h2&gt;

&lt;p&gt;I'm a computer science teacher in Verbania, a small town on Lake Maggiore in northern Italy. Beautiful place. &lt;/p&gt;

&lt;p&gt;Every year, some colleague asks me: "Hey Ivan, I need a simple website for my class project / department / school event. Can you help?" And every year I go through the same ritual: install WordPress on the school's 3-euro-a-month shared hosting, wait for it to crash because PHP memory is set to 64MB, install seventeen plugins to get basic functionality, then spend the next three months explaining why they shouldn't click "Update All" on a Friday afternoon.&lt;/p&gt;

&lt;p&gt;One day I thought: what if the CMS was just... files? JSON files. No MySQL. No migrations. No "Error establishing a database connection" at 8:55 AM when 200 students need to access the class materials.&lt;/p&gt;

&lt;p&gt;So I built one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What O-CMS actually is
&lt;/h2&gt;

&lt;p&gt;O-CMS is a flat-file content management system written in PHP. Every piece of content — articles, pages, users, settings, comments — is a JSON file sitting in a &lt;code&gt;data/&lt;/code&gt; folder. You want a backup? Copy the folder. You want to migrate? Upload the folder somewhere else. You want to understand how your site works? Open a JSON file in a text editor. Revolutionary, I know.&lt;/p&gt;

&lt;p&gt;The whole thing is a single PHP application with no external dependencies. No Composer. No npm. No build step. You upload it via FTP, open &lt;code&gt;install.php&lt;/code&gt; in your browser, answer six questions, and you have a working site with an admin panel.&lt;/p&gt;

&lt;p&gt;Here's the kind of tech stack I'm talking about:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;th&gt;How&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Storage&lt;/td&gt;
&lt;td&gt;JSON files (yes, really)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;PHP 8.0+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Server-rendered HTML + vanilla CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;None. Zero. Nada.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dependencies&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deploy method&lt;/td&gt;
&lt;td&gt;FTP, like it's 2005 and I'm not ashamed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  But does it actually do things?
&lt;/h2&gt;

&lt;p&gt;More than I originally planned, honestly. It started as "just a blog engine" and then feature creep happened, except I was both the developer and the client, so the arguments were very short.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CMS stuff:&lt;/strong&gt; articles, pages, categories, tags, threaded comments with moderation, media manager, visual menu builder, form builder with 10 field types, full-text search with fuzzy matching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fancy stuff:&lt;/strong&gt; a drag-and-drop layout builder with 18 module types, a theme system with a creation wizard, an extension system with hooks, a REST API, dark/light mode, built-in analytics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The teacher stuff&lt;/strong&gt; (this is where it gets personal): a lessons system where you upload HTML/PDF/video and students access them from a clean interface. An interactive quiz system with timer, randomization, and automatic grading. Galleries for class projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "I got carried away" stuff:&lt;/strong&gt; AI integration with Anthropic, OpenAI, Groq, Mistral, and Google. Five role levels (super admin → author). Backup and migration with one click. SEO tools. SMTP configuration.&lt;/p&gt;

&lt;p&gt;All of this in one PHP file of about 5,000 lines (the core engine) plus admin views and a default theme. Total project size: around 60 PHP files.&lt;/p&gt;

&lt;h2&gt;
  
  
  The installation experience
&lt;/h2&gt;

&lt;p&gt;I spent an unreasonable amount of time on the installer because I know my audience. My colleague who teaches Art History is not going to SSH into a server. She's going to upload files with FileZilla and open a URL.&lt;/p&gt;

&lt;p&gt;The installer is a 7-step wizard that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Checks PHP version and extensions&lt;/li&gt;
&lt;li&gt;Asks for site name and URL&lt;/li&gt;
&lt;li&gt;Creates the admin account&lt;/li&gt;
&lt;li&gt;Optionally configures SMTP&lt;/li&gt;
&lt;li&gt;Explains the installation notification (more on this below)&lt;/li&gt;
&lt;li&gt;Shows a summary&lt;/li&gt;
&lt;li&gt;Installs everything and self-destructs&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Step 7 literally deletes &lt;code&gt;install.php&lt;/code&gt; from the server via an AJAX call. Because if I don't, it will stay there for eternity. I know my users.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "why not just use Grav/Kirby/Pico" question
&lt;/h2&gt;

&lt;p&gt;Fair question. Those are excellent projects. Here's my honest take:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grav&lt;/strong&gt; is powerful but has a learning curve. It uses Markdown, Twig templates, and a plugin ecosystem that requires some technical fluency. For me, that's fine. For the colleague who just wants to publish class notes? It's another Friday afternoon phone call waiting to happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kirby&lt;/strong&gt; is beautiful but costs €99 per site for commercial use. Schools don't have that budget for internal projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pico&lt;/strong&gt; is wonderfully minimal, but it's &lt;em&gt;too&lt;/em&gt; minimal. No admin panel. You edit Markdown files. Again, my Art History colleague is not going to learn Markdown.&lt;/p&gt;

&lt;p&gt;O-CMS sits in a specific gap: &lt;strong&gt;an admin panel that non-technical people can use&lt;/strong&gt;, with &lt;strong&gt;zero server requirements beyond basic PHP hosting&lt;/strong&gt;, and &lt;strong&gt;no cost&lt;/strong&gt;. It's MIT licensed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The transparency thing
&lt;/h2&gt;

&lt;p&gt;O-CMS sends a single anonymous ping when it's installed — just the domain name, PHP version, and CMS version. One call, one time, never again. No personal data, no IP tracking, no cookies.&lt;/p&gt;

&lt;p&gt;Why? Because I want to know if anyone actually uses this. If three people install it, I'll keep it as a personal project. If three hundred do, I'll invest more time in documentation, themes, and features. It's a simple feedback loop.&lt;/p&gt;

&lt;p&gt;This ping cannot be disabled, but the installer tells you about it clearly before you proceed. I'd rather be upfront about it than hide a toggle in a config file and pretend it's not there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who is this for?
&lt;/h2&gt;

&lt;p&gt;Originally, I built it for &lt;strong&gt;teachers&lt;/strong&gt; who need a simple web presence without the overhead of a "real" CMS. But honestly, it works for anyone who:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Needs a blog or small site on cheap shared hosting&lt;/li&gt;
&lt;li&gt;Doesn't want to deal with databases&lt;/li&gt;
&lt;li&gt;Wants something they can understand by reading the files&lt;/li&gt;
&lt;li&gt;Prefers "upload and it works" over "read the docs for 45 minutes"&lt;/li&gt;
&lt;li&gt;Wants a self-hosted solution they actually control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's probably &lt;em&gt;not&lt;/em&gt; for you if you need a site with 10,000 pages, complex user permissions, or e-commerce. At some point, you do actually need a database. I'm not delusional.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;p&gt;Since we're among developers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;~5,000 lines&lt;/strong&gt; in the core engine&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;60 PHP files&lt;/strong&gt; total&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;0 external dependencies&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;7-step installer&lt;/strong&gt; that a non-technical user can complete&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;18 layout modules&lt;/strong&gt; in the drag-and-drop builder&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;10 form field types&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5 AI providers&lt;/strong&gt; supported&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 developer&lt;/strong&gt; (me, mostly on weekends)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;th&gt;Where&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GitHub repo&lt;/td&gt;
&lt;td&gt;&lt;a href="https://github.com/b84an/o-cms" rel="noopener noreferrer"&gt;&lt;strong&gt;github.com/b84an/o-cms&lt;/strong&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Project page&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ivanbertotto.it/s/o-cms" rel="noopener noreferrer"&gt;&lt;strong&gt;ivanbertotto.it/s/o-cms&lt;/strong&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;My site (runs on O-CMS)&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ivanbertotto.it/" rel="noopener noreferrer"&gt;&lt;strong&gt;ivanbertotto.it/&lt;/strong&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The code is MIT licensed. There's an Italian README too, because despite writing this post in English, I do most of my teaching in Italian and I'd feel weird not including it.&lt;/p&gt;

&lt;p&gt;If you try it, let me know what breaks. If nothing breaks, let me know that too — it would be a first.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>php</category>
      <category>html</category>
    </item>
  </channel>
</rss>
