The Urlaube CMS is a flat-file content management system. It has been developed with modularity in mind. The core consists of the files contained in ./system/ while all user-provided files are located in ./user/.
Config SHALL be located in the ./user/config/config.php file.
Content SHALL be located in the ./user/content/ directory and MAY be located in subdirectories. Each content file has to end with the extension .md otherwise it is not considered to be a content file. Content files consist of header lines in the form of <Key>: <Value> which are used to provide further information about the content to handlers, plugins and themes. The actual content of the file starts after a blank line and ends at the end of the file.
An example content file might look like this:
Category: myCategory examplePages
Date: 21.05.2018
Title: Example Page
This is an example page.
The core are the minimal files that make up the CMS. The following files belong to the core:
./index.phpis the main entrypoint into the CMS, no other source file SHOULD be directly callable./router.phpis the router file that can be used to test Urlaube locally by callingphp -S localhost:8080 ./router.php./system/derived.phpcontains constants that are derived from other values./system/init.phpis the place where all core files are included./system/recommended.phpcontains constants that SHOULD be used by handlers, plugins and themes for interoperability./system/static.phpcontains constants that are static./system/system.phpconstains core functions that SHOULD NOT be used by handlers, plugins and themes./system/user.phpconstains core functions that MAY be used by handlers, plugins and themes./system/core/BaseConfig.class.phpcontains a base class with getters and setters for dynamic values./system/core/BaseHandler.class.phpcontains a standard handler implementation./system/core/BaseSingleton.class.phpcontains a simple singleton base class./system/core/Content.class.phpcontains the content class that is used to represent content files./system/core/Handler.interface.phpcontains the handler interface that SHOULD be used by all handler developers./system/core/Handlers.class.phpcontains the handler management class./system/core/Logging.class.phpcontains a simple logging class./system/core/Main.class.phpcontains the main class that controls the workflow of the core./system/core/Plugin.interface.phpcontains the plugin interface that SHOULD be used by all plugin developers./system/core/Plugins.class.phpcontains the plugin management class./system/core/Theme.interface.phpcontains the theme interface that SHOULD be used by all theme developers./system/core/Themes.class.phpcontains the theme management class./system/core/Translate.class.phpcontaints a simple translation engine class
Handlers extend the core and react on certain URLs by matching a handler's regular expression against the relative URI that has been called by the user.
Handlers can be registered in the core by calling the following method:
Handlers::register($entity, $function, $regex, $methods = [GET], $priority = 0);
The register method has the following parameters:
$entityis eithernull, a class name or an object$functionis either the name of a function (when$entityisnull) or the name of a method of$entity$regexis the regular expression that is matched against the URI relative to the configured root URI$methodsis either a string or an array of strings denoting the HTTP methods the handler shall react on$priorityis the priority value of the handler to allow it to be called earlier
The following priority values SHOULD be used for now:
FIXURLis the earliest stage when the URI has not even been normalizedADDSLASHis the stage when the URI has been normalized but the trailing slash has not been added (useful for handling URIs denoting file names)USERis the stage when most handlers run after the URI has been fully normalizedERRORis the stage before the system's error handler collects all unhandled URIs
When a handler has successfully handled a URI, it MUST return true to abort the further handling of the URI by other handlers.
At the moment the Urlaube CMS consists of the following system handlers that are located in ./system/handlers/:
fixurlnormalizes the URI to discard garbagefaviconicohandles accesses to thefavicon.icofile by returning a204 No Contentindexphphandles accesses to theindex.phpfile by redirecting to the configured root URIrobotstxthandles accesses to therobots.txtfile by generating a minimal filesitemapxmlhandles access to thesitemap.xmlfile by generating a minimal fileaddslashadds a trailing slash to the URIarchiveprovides a paginated archive feature based on the content'sDatefieldauthorprovides a paginated author feature based on the content'sAuthorfieldcategoryprovides a paginated category feature based on the content'sCategoryfieldfeedprovides an RSS feed for the archive, author, category and search featuresearchprovides a paginated search featurepagehandles access to single pages by converting the URI to the corresponding content file patherrorhandles all URIs that have not been handled by another handler
Users MAY add their own handlers by putting them in the ./user/handlers/ directory.
User handlers MAY need additional configuration. To do this the handler management class provides the following method:
Handlers::set($name, $value);
The method has the following parameters:
$nameis the name of the configuration value$valueis the contents of the configuration value
Plugins extend the core and react on certain events.
Plugins MAY be registered in the core by calling the following method:
Plugins::register($entity, $function, $event);
The register method has the following parameters:
$entityis eithernull, a class name or an object$functionis either the name of a function (when$entityisnull) or the name of a method of$entity$eventis the event name the plugin shall react on
The following core trigger events are available for now:
BEFORE_MAINis called before the core is runBEFORE_HANDLERis called before the handlers are runBEFORE_THEMEis called before the theme is runAFTER_THEMEis called after the theme has finished runningAFTER_HANDLERis called after the handlers have finished runningAFTER_MAINis called after the core has finished running
The following theme trigger events SHOULD be used for now:
BEFORE_HEADshould be called by a theme before the head is generatedAFTER_HEADshould be called by a theme after the head is generatedBEFORE_BODYshould be called by a theme before the body is generatedBEFORE_SIDEBARshould be called by a theme before the sidebar is generatedAFTER_SIDEBARshould be called by a theme after the sidebar is generatedAFTER_BODYshould be called by a theme after the body is generatedBEFORE_FOOTERshould be called by a theme before the footer is generatedAFTER_FOOTERshould be called by a theme after the footer is generated
The following core filter events are available for now:
FILTER_CONTENTis called after theON_CONTENTplugins have been called incallcontent()FILTER_HANDLERSis called after the handlers have been registeredFILTER_OUTPUTis called beforeMain::run()exitsFILTER_PAGINATEis called before pagination is applied inpaginate()FILTER_PLUGINSis called after the plugins have been registeredFILTER_THEMESis called after the themes have been registeredFILTER_WIDGETSis called after theON_WIDGETSplugins incallwidgets()
The following core content events are available for now:
ON_CONTENTis called incallcontent()ON_WIDGETSis called incallwidgets()
The following cache events are available for now:
GET_CACHEis called ingetcache()SET_CACHEis called insetcache()
- Trigger plugins just get executed and don't have to provide a certain behaviour.
- Filter plugins are provided with a content argument and SHOULD return content.
- Content plugins SHOULD return content.
At the moment the Urlaube CMS consists of the following system plugins that are located in ./system/plugins/:
cacheis used to provide a file-based caching feature that uses serialize/unserializefileis used by system handlers to load content fileshideis used to provide a feature to hide content from certain pagesmarkdownis used to provide markdown support which can be disables through thenomarkdownfieldrelocateis used to provide a relocation feature through theRelocateandRelocateTypefieldsstickyis used to provide a stickiness feature through theStickyfield
Users MAY add their own plugins by putting them in the ./user/plugins/ directory.
User plugins MAY need additional configuration. To do this the plugin management class provides the following method:
Plugins::set($name, $value);
The method has the following parameters:
$nameis the name of the configuration value$valueis the contents of the configuration value
Themes extend the core and are called by a handler.
Themes can be registered in the core by calling the following method:
Themes::register($entity, $function, $name);
The register method has the following parameters:
$entityis eithernull, a class name or an object$functionis either the name of a function (when$entityisnull) or the name of a method of$entity$nameis the name of the theme to be used in the config file
To use a theme its name SHOULD be configured in the config file located at ./user/config/config.php:
Main::set(THEMENAME, "<NAME OF THE THEME>");
Users MUST add their own theme by putting it in the ./user/themes/ directory.
User themes MAY need additional configuration. To do this the theme management class provides the following method:
Themes::set($name, $value);
The method has the following parameters:
$nameis the name of the configuration value$valueis the contents of the configuration value
The Translate class provides a translation feature based on simple JSON files.
New translations can be registered by calling the following method:
Translate::register($folder, $name = null);
The register method has the following parameters:
$folderis the path to a folder that contains files named after potential LANGUAGE values (e.g.de_de)$nameis an optional namespace for the registered translation, if no name is given, the translations are loaded into the global space
An example translation file might look like this:
{
"This" : "Das",
"is" : "ist",
"an" : "eine",
"example file" : "Testdatei",
"My name is %s." : "Mein Name ist %s."
}
To translate a basic string, the following method can be used:
Translate::get($string, $name = null)
The following parameters are allowed:
$stringis the string that shall be translated, this string is searched in the JSON files within the registered folders$nameis the namespace in which the translation shall be searched for, this is helpful to separate translations of different extensions
To translate a string containing placeholders as supported by PHP's sprintf() function the following method can be used:
Translate::format($string, $name = null, ...$values)
The following parameters are allowed:
$stringis the string that shall be translated, this string is searched in the JSON files within the registered folders$nameis the namespace in which the translation shall be searched for, this is helpful to separate translations of different extensions$valuesare one or more additional values that shall be used to replace the placeholders in the translated string
There is a shortcode function in ./system/user.php to shorten the code necessary to get a translation:
t($string, $name = null, ...$values)
The following parameters are allowed:
$stringis the string that shall be translated, this string is searched in the JSON files within the registered folders$nameis the namespace in which the translation shall be searched for, this is helpful to separate translations of different extensions$valuesif left out thenTranslate::get()is called, if at least one addition $values parameter is set, thenTranslate::format()is called
To install the Urlaube CMS you can clone the corresponding git repository:
git clone https://github.com/urlaube/urlaube
The Urlaube CMS uses a single entrypoint scheme. A .htaccess is already provided for your convenience. To use the Urlaube CMS in combination with NGINX you have to implement the single entrypoint yourself:
if (!-f $request_filename) {
rewrite ^.*$ /index.php last;
}
The configuration takes place in the configuration file located at ./user/config/config.php.
The following configuration values are currently supported:
Main::set(CACHE, false);is the activation or deactivation of the cacheMain::set(CACHEAGE, 60*60);is the number of seconds a cached value is considered to be fresh by defaultMain::set(CHARSET, "UTF-8");is the charset used by the systemMain::set(CONTENTTYPE, "text/html");is the default content type set by the systemMain::set(DEBUGMODE, false);actives printing of warning and error messages
(Important: You SHOULD set this tofalsein production.)Main::set(HOSTNAME, _getDefaultHostname());is the hostname as taken from the URL
(Important: You SHOULD configure this value as the default is considered to be insure. The default is taken from$_SERVER["SERVER_NAME"],$_SERVER["HTTP_HOST"]or$_SERVER["SERVER_ADDR"]and islocalhostas a fallback.)Main::set(LANGUAGE, "de_DE");is the language used by the systemMain::set(LOGLEVEL, Logging::NONE);is the minimum level of log entries that get printed
(Important: You SHOULD set this toLogging::NONEin production or set a filename forLOGTARGET.)Main::set(LOGTARGET, Logging::OUTPUT);is the target of log entries (eitherLogging::OUTPUTfor direct output or a filename)Main::set(METHOD, _getDefaultMethod());is the HTTP method used to call the system
(The default is derived from$_SERVER["REQUEST_METHOD"].)Main::set(PAGESIZE, 5);is the number of entries per page displayed during paginationMain::set(PORT, _getDefaultPort());is the port number as taken from the URL
(Important: You SHOULD configure this value as the default is considered to be insecure. The default is taken from$_SERVER["SERVER_PORT"].)Main::set(PROTOCOL, _getDefaultProtocol());is the protocol as taken from the URL
(Important: You SHOULD configure this value as the default is considered to be unreliable. The default is derived from$_SERVER["HTTPS"].)Main::set(RESPONSECODE, "200");is the default HTTP response code set by the systemMain::set(ROOTURI, _getDefaultRootUri());is the root URI the system is reachable at
(Important: You SHOULD configure this value as the default is considered to be unreliable. The default is derived from$_SERVER["SCRIPT_NAME"].)Main::set(THEMENAME, null);is the name of the active themeMain::set(TIMEFORMAT, "c");is the time format used for log entriesMain::set(TIMEZONE, "Europe/Berlin");is the time zones used by the systemMain::set(URI, _getDefaultUri());is the URI as taken from the URL
(The default is derived from$_SERVER["REQUEST_URI"].)
The following log levels SHALL be used:
Logging::NONE- do not logLogging::DEBUG- something might help when debuggingLogging::INFO- something might be interestingLogging::WARN- something shouldn't be doneLogging::ERROR- something went wrong
The following values are set during runtime to provide status information to plugins and themes:
Main::set(CONTENT, null);is the content provided to plugins and themesMain::set(METADATA, null);are the metadata provided to plugins and themesMain::set(PAGE, 1);is the page number that is displayed during paginationMain::set(PAGECOUNT, 1);is the maximum number of pages available during pagination