Documentation

MonoCMS 3.0

MonoCMS has been published since 2016 as 'MonoCMS beta', MonoCMS 1.0. This has been the first period of development, which was finished in 2018-19  and is known as MonoCMS 1.0 even though we didn't specifically stated that all these versions are part of 1.0. Many of these versions had names like "monocms 2.0" , but they should not be confused with the subsequent versions from 2021(see a full list).

The first version of 2021 was at the moment the biggest update and is named MonoCMS 2.0. MonoCMS 2.0 dropped theme support and menu builder as basic features, supported a new simple plugin and extensions system, added some more xml based configurations and is targeted to a range of users, such as programmers, designers, students and simple users who need to build their personal website.


MonoCMS 3.0 is a more mature and complete version suitable for everyone. Plugins and Extensions are not supported anymore and categories have been upgraded with additional publishing options. A new function, print_posts() allows the users to publish multiple post feeds in addition to the standard index, posts and pages content. Designers can use this function to create content sections that could be managed through the control panel.




Login and security

session_name('MON');
session_start();
if (session_name() == 'MON')
if ( !isset($_SESSION['username'])) {
 ...
The user identification starts with the session_start() function, which initiates a new or continues an existing session. A name is used so that the system can maintain a safe single user connection. PHP always stores a corresponding cookie in the browser of the user, which includes a unique ID. Similarly, the session must be distinct from any session that might exist on the same domain or website. Sessions are saved inside 'monofiles/session'.
See also the cryptograpfy section below for more security information.


SimpleXML

Using SimpleXML is very common when working with xml files, like the example below
$monousers = new simpleXMLElement('filesinfo/log.xml',null,true);

This way we gather up all user data to a SimpleXML element and continue to user identification and data saving in the log file. If the combination of username and password given by the user, exists in the file, the user is allowed to enter the control panel. Note that while the username is stored in the session and saved in the log file, the user's password is never stored, either in session or the log file. User identification is based on password_hash function which reads the hashed password as a parameter. Hashed paswords are saved inside the 'monofiles/filesinfo/log.xml' file.


Use of functions

It is easy to use some of the system functions, to write your own code and pages. Some examples:

Load the xml file of a page and print the title$page = simplexml_object('filename','l','page');
echo $page->pageinfo->page->title;


Load the settings using getXMLSettings function

$settings = getXMLSettings();

This will load an array() with the results$settings = ['ownerid' => ...
                    'title' => ...
                    'description' => ...
                     ... => ...
                ];

Print a post titleecho getxmlpost('path_to_xmlfile_of_post')['title'];
These functions and many more can be found in monofiles/log.php file.


The print_posts() function

The print_posts function is introduced in monocms 3.0. It will publish posts based on parameters and it can be called as many times as we want. The parameters are saved inside monofiles/filesinfo/print_content.xml
Posts will be included in the final results, if these parameters are found in them, while also limiting or modifying the results.

Usage is very simple print_posts('example') where 'example' is the name of an entry inside the xml file.
Read the xml file for more details on how this function can be used.



Cryptography - User login

Password_hash is used for password encryption. The password hash is saved and compared to the hash of the password given by the user, using password_verify
password_verify($_POST['password'],$password);

Using password_needs_rehash, PHP checks whether or not password needs to be re-encrypted, which, usually, happens in two cases:
- When a different version of PHP, that has a different default encryption algorithm, has been installed.
- When set-cost.php gives us a different cost result than the previous value. The cost is a parameter of password_hash and password_needs_rehash functions and regulates the complexity of encryption by delaying the execution of these functions.

In our case the value of cost depends on the server performance. MonoCMS follows the PHP example of automatically finding a good cost. In case of a hardware upgrade or the system is transferred to another server, or even just a usual login, it is possible that the cost will change and force password_needs_rehash to re-hash the user password. This is done while the user is logging in
password_needs_rehash($password, PASSWORD_DEFAULT, ["cost" => $cost]);
In the line above, if the new value of $cost is not the same as the value of cost contained in $password, the password is going to be re-encrypted.

Re-hashing starts in set-cost.php
$phtime = 0.5; // 500 ms

for ($cost = 4; ; $cost++){

#password_hash speed test

...
Here time is set at 500 milliseconds, which is a good option for an admin panel. We test password_hash speed, starting from cost = 4. If the test is completed in less than the given time, the cost value increases by 1 and the test is repeated. If completion time is more than given time, it is terminated and we save the result.


If a password_hash test lasts more than 1 second, the cost and encrypted password, remain the same.
Below is an example of manually applying a cost
password_needs_rehash($password, PASSWORD_DEFAULT, ["cost" => 11]);


User block

A user is blocked after a few failed login attempts, by blocking the user's ip address. A blocked user is prevented from reaching the login page. You can change the values of this function by modifiyng the next lines inside data_connect.php
# Failed login attempts before blocking a user
$block = 8;
# Minutes passed to unblock a user
$unblock = 15;

log.php and saved data

Most of the control panel data is saved in /monofiles/filesinfo folder. Many of the actions performed to manage this data can be found in log.php

- Gather general information like the total number of posts, the total number of pages, the date of the last failed login attempt and the last modification date of any of the above. 

This is how to get the total number of pages
include 'log.php';
get_log('pages');


- Load personal account information. We do this by using either the username or the userID as a parameter. The userID is a unique code which is stored along with other account information
include 'log.php';
get_account($_SESSION[userID])['rights'];

In the example above, we get the user's account type, using the userID that we have previously saved in the session.
Note: Despite the fact that the userID is saved alongside the username, it is not password and it doesn't grant any access to the user.

- Update user account or log.xml info. For example, this is how we can change the total number of posts to 12

include 'log.php';
update_log(posts,12);

Update an account
include 'log.php';
update_account($id,'set');

We can also delete an account in a similar way
include 'log.php';
update_account($id,'delete');

The $id variable contains the userID.


Saving data in MonoCMS is basically done by writing to xml files.
Saving in session is also a method of storing information, mainly used for control panel needs and all of the data is deleted as soon as the user is logged out. Xml and htm files are useful when we want to store posts and pages data, like text, titles, images etc. You save most of the posts information inside xml files, except for the main body of a post, which is saved in a separate htm file. Xml is used for the majority of data storing such as user accounts info and logging activity.

User accounts

Account management allows multiple users to have access to the control panel, using their username and password. There are two differrent types of accounts: Administrator and author. The main account which is used to install the CMS is also an administrator but also has owner rights, allowed only to a single account each time. Owners cannot be deleted and other administrators cannot edit their account.

As an administrator, the user has complete access to control panel. Authors can only create their own posts and also have access to some personal account settings.

In general:

- Only administrators havw access to account manager.
- Every administrator can create or delete accounts of other administrators and authors.
- An administrator account rights can be changed to author and backwards.
- Administrators can delete their own account as well.



Backup

Most web servers are usually configured to keep your website backup, but it is really easy with MonoCMS as well. More specifically:

/monofiles/autosaves/: Contains all posts.
/monofiles/savedpages/: Contains all pages.
/monofiles/filesinfo/: Contains all user accounts, log info and system settings.

Posts are also saved inside folders using the current year as a name, like 2025, 2026 etc, in home directory.


Docs

readme.txt

Thank you for downloading MonoCMS 3.0. A content management system that stores data in XML files. Easy to install, easy to learn.

++++++++++++++++++++++
[The MonoCMS License]
 You can copy, modify and redistribute this software as a whole or each file separately, without any restriction. You don't have to include this license in your projects either.

++++++++++++++++++++++

[Requirements]
 Linux Web server with PHP installed


[Installation]
- Download MonoCMS from monocms.com/download.
- Upload and extract to your server. You can select the folder you like (Home directory is usually the public_html folder).
- Change the password and username to your prefered one. First visit 'monofiles/login' to login (username:admin,password:1234). Then you can visit the "Settings" page, to change password and the "Accounts" page to select a new username.


[Updating]
To install the latest version, update the files in 'monofiles' folder. Although the rest of the files might occasionally receive changes as well, the users should rely on those in "monofiles" in order to get the latest and most important upgrades. A full upgrade might be needed when having a general upgrade for example from version 2.0 to 3.0 but not from 3.0 to 3.1


[I forgot my password]
 If you forget your password follow the steps below:
- Download the latest version of MonoCMS.
- Open the file 'monofiles/filesinfo/log.xml and copy the contents of the 'pshs' tag.
- Paste into your own log.xml and save.
- Login using the initial password(1234).





print_posts.txt

The print_posts() function

+++++++++++++++++

The print_posts function will publish posts based on parameters. These parameters are saved inside monofiles/filesinfo/print_content.xml
Posts will be included in the results, if these parameters are found in them, while also limiting or modifying the results. We can call the function multiple times, to combine different results.

For example you can write "print_posts('example')" inside the pagep.php file, in order to load posts that match the parameters saved under the name 'example', in print_content.xml

+++++++++++++++++
Usage 

<?php

    print_posts('string'); 

?>


A string given as a parameter, is the name of an entry inside an xml file.
(see example at the end)


+++++++++++++++++

XML info/parameters:

status: optional deactivation for an entry. default:on
name: A name for an entry. This is the one parameter given to print_posts() which "identifies" the call. The function searches for it in the xml file and loads the related parameters
Categories, Tags : Posts which match at least one category (separated by comma) and all the tags given, will be included in the results. If no tags are given, there's no requirement for tags.
inc , paginc: Select in which types of pages to print results, with inc. Paginc is the same but for paginated content. default:on
inc : 5 on off values, separated with comma, following this order: home page, category index, tag index, post, page
paginc : 3 on off values separated with comma: home page, category index, tag index
sort : Sorting, chronological or alphabetical(based on the post's title). default:time
sortcat : Another sorting option. In case of multiple entries in <categories>, print results following the order they are written. default:off
reverse : Reverse sort. Note: Does not reverse sortcat. default:off
limit : Limit the number of results. default:0(show all)
title: Show or hide the post title. default:on
date: Apply a php date format or turn off. default:off
exc : Contains two values, comma separated. First is post's excerpt limit, given as an integer, where 0 means ignore any limit and show full post and off means don't show any excerpt. Second value can be 'off', meaning force no link to the post. default:panel settings->tags
unidates : Repeat or not similar dates of posts. default:off
stag,scat,sign : Show or hide post tags, category or author sign. default:off
tlinks : show tags as links or turn off to show as plain text. Unlike panel settings, setting tlinks off does NOT unpublish tag indexes. If left empty, panel value is used. default:panel settings->tags as links
label: Text to appear as label for category, tags and author sign and read more, in case they are 'on'. default: empty string
force: Publish content even when the categories are hidden default: off

+++++++++++++++++

XML values:
(note: empty values are accepted)

content status = on off
name= 'an entry name' (utf characters);
categories= 'category names'
tags= 'tag names'
inc= '','','','','' on off
paginc= '','',''  on off
sort= time  alpha
reverse= on  off
sortcat= on off
limit= int >= 0 (0 = no limit)
stag= on off
tlinks= on off
scat= on off
sign= on off
date= date() off
title= on off
exc= '',''  off 0 int>=0 , off
unidates= on off
label->cat= text
label->tag= text
label->sign= text
label->read= text
force= on off

+++++++++++++++++

Example
    
   <content status="on">
      <name>news</name>
      <categories>development</categories>
      <tags>latest,fixes</tags>
      <sort></sort>
      <reverse></reverse>
      <sortcat></sortcat>
      <limit></limit>
      <inc>on,off,off,off,off</inc>
      <paginc>off,off,off</paginc>
      <stag></stag>
      <tlinks></tlinks>
      <scat></scat>
      <sign></sign>
      <date></date>
      <title></title>
      <exc></exc>
      <unidates></unidates>
      <label>
          <cat></cat>
          <tag></tag>
          <sign></sign>
          <read></read>
      </label>
      <force>on</force>
  </content>



In this example, content will load when

        print_posts('news');
         
 is called.

Posts which belong to the category 'development' and contain the tags 'latest' and 'fixes', will be included in the results.
In <inc> first value is on and all of the rest is off, which means that content will appear on the website's home page only.
<paginc> values are all off, so this content will not appear on subpages of paginated content either.
Finally, force is on and this means content will be published, even if the category 'development' is set as hidden.

+++++++++++++++++



Last update 22 Nov, 2025