Documentation πΊπΈ
sansCMS Documentation
Welcome to the complete documentation for sansCMS, a simple and lightweight content management system based on Markdown files.
π Overview
sansCMS is a lightweight, fast, database-free Content Management System. It uses Markdown files to store content and features a high-performance caching system with customizable TTLs.
Key Features
- β Database-free: Uses only Markdown files
- β‘ Smart caching system with customizable TTLs
- π Visit statistics with unique IP tracking
- π¨ Multiple themes with built-in selector
- π Private pages with password protection
- π SEO optimized (sitemap, RSS, meta tags)
- π± Responsive based on Pico CSS
- π§ Built-in contact form
- π High performance with compression and minification
Architecture
sansCMS/
βββ cache/ # System cache (protected)
β βββ markdown/ # Markdown rendering cache
β βββ pages/ # Complete pages cache
β βββ stats/ # Statistics cache
βββ config/ # Configuration files
β βββ site.json # Main configuration
βββ libs/ # Third-party libraries
β βββ Parsedown.php # Markdown parser
βββ logs/ # Logs and statistics
β βββ stats.json # Tracking data
βββ pages/ # Markdown content
β βββ 1-home.md # Homepage
β βββ 2-contact.md # Contact page
β βββ *.md # Other pages/posts
βββ src/ # PHP source code
β βββ CacheManager.php # Cache management
β βββ ConfigLoader.php # Configuration loader
β βββ ContactFormHandler.php # Contact form handler
β βββ MarkdownParser.php # Markdown parser with cache
β βββ OutputOptimizer.php # HTML output optimization
β βββ Page.php # Page class
β βββ Router.php # Request routing
β βββ sansCMS.php # Main class
β βββ StatsTracker.php # Statistics tracking
βββ themes/ # Visual themes
β βββ pico/ # Default theme
βββ index.php # Entry point
βββ .htaccess # Apache configurationInstallation
- Download the project to your web server
- Check that PHP 7.4+ is installed
- Configure the web server (Apache or Nginx)
- Create the
config/site.jsonfile (generated automatically on first run)
Server Configuration
Apache
The .htaccess file is created automatically:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L]
Options -IndexesNginx
Configuration generated in nginx-site.conf:
server {
listen 80;
server_name localhost;
root /path/to/sansCMS;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/var/run/php/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.md$ {
deny all;
return 403;
}
}Configuration (site.json)
{
"site": {
"name": "My Site",
"description": "My site description",
"contact_email": "email@example.com",
"contact_subjects": {
"general": "General inquiry",
"support": "Support request",
"business": "Business inquiry",
"bug": "Bug report",
"suggestion": "Feature suggestion"
}
},
"blog": {
"url": "blog",
"name": "Blog",
"description": "Discover our articles"
},
"theme": {
"name": "pico",
"posts_per_page": 8
},
"features": {
"cache_enabled": true,
"cache_ttl": {
"markdown": 3600, // 1 hour
"pages": 7200, // 2 hours
"stats": 300, // 5 minutes
"rss": 3600, // 1 hour
"sitemap": 86400 // 24 hours
},
"stats_enabled": true,
"stats_access_enabled": true,
"session_timeout": 1800,
"rate_limit_enabled": true
},
"performance": {
"lazy_load_pages": true,
"compress_output": true,
"minify_html": false
},
"debug": {
"enabled": false,
"level": "INFO",
"log_to_file": true,
"display_errors": false
},
"seo": {
"meta_keywords": "cms, markdown, blog",
"robots": "index, follow",
"rss_enabled": true
}
}Markdown File Format
Basic Structure
---
titre: Page Title
description: SEO description
date: 2024-01-15
auteur: Author Name
tags: tag1, tag2, tag3
permalien: my-article
---
Your page content in **Markdown**.
### Level 2 Heading
Your text with [links](https://example.com).Available Metadata
| Field | Type | Description |
|---|---|---|
titre | string | Page/post title |
description | string | SEO description |
date | date | Publication date (format: YYYY-MM-DD) |
auteur | string | Author name |
tags | string | Comma-separated tags |
permalien | string | Custom URL |
prive | string | Password hash (bcrypt) |
brouillon | boolean | Hide from publication |
cacher | boolean | Hide from navigation but accessible via URL |
Private Page
To create a private page:
---
titre: Private Page
prive: $2y$10$example_bcrypt_hash
---Generate bcrypt hash in PHP:
echo password_hash('my_password', PASSWORD_BCRYPT);Automatic Table of Contents
Insert [TOC] or [TOC:Custom Title] in your content:
[TOC:Table of Contents]
### Section 1
Content...
### Section 2
Content...Caching System
Cache Architecture
The system uses three cache levels:
- Markdown Cache: HTML renders of .md files
- Pages Cache: Complete pages with templates
- Stats Cache: Pre-calculated statistics
Customizable TTLs
Time-to-live (TTL) values are independently configurable:
"cache_ttl": {
"markdown": 3600, // Markdown rendering (1h)
"pages": 7200, // Complete pages (2h)
"stats": 300, // Statistics (5min)
"rss": 3600, // RSS feed (1h)
"sitemap": 86400 // XML sitemap (24h)
}Cache Management
// Clear all cache
CacheManager::clearAll();
// Clear only Markdown cache
CacheManager::clearMarkdownCache();
// Get cache statistics
$stats = CacheManager::getStats();
// Clean expired files
CacheManager::cleanExpired();Admin Page
Access /cache-admin (requires debug.enabled: true) to:
- View cache statistics
- Selectively clear cache
- See cached file details
Statistics System
Features
- Unique views per IP counting
- Statistics by day/hour
- Popular pages
- Weekly reports
- 5-minute cache for performance
Usage
// Get stats for last 30 days
$stats = StatsTracker::getStats(30);
// Get text report
$report = StatsTracker::getSimpleReport(7);
// Rebuild cache
StatsTracker::rebuildCache();Data Structure
[
'total_views' => 1234,
'pages_count' => 45,
'recent_days' => [
'2024-01-15' => 56,
'2024-01-14' => 42,
// ...
],
'popular_pages' => [
'/article' => [
'title' => 'My Article',
'total_views' => 234,
'type' => 'post'
]
]
]Routing
Available Routes
| Route | Description |
|---|---|
/ | Homepage |
/blog | Post list |
/blog?page=2 | Pagination |
/blog?tag=php | Filter by tag |
/blog?auteur=John | Filter by author |
/blog?q=search | Search |
/sitemap | XML sitemap |
/rss | RSS feed |
/stats | Statistics |
/cache-admin | Cache admin (debug) |
/logout | Logout private pages |
Contact Form
Configuration
The form uses the email configured in site.json:
"contact_email": "contact@example.com",
"contact_subjects": {
"general": "General inquiry",
"support": "Technical support"
}Security
- CSRF protection with tokens
- Anti-spam honeypot
- Server-side validation
- Rate limiting
Customizable Templates
themes/pico/contact/
βββ contact-form.php # Form
βββ contact-success.php # Success message
βββ contact-errors.php # Error display
βββ contact-sent.php # Send confirmation
βββ email-contact.php # HTML email templatePerformance Optimization
Output Compression
"compress_output": true // Enable gzipHTML Minification
"minify_html": true // Remove unnecessary spacesOPcache
Enable OPcache in php.ini:
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2SEO
Built-in Features
- β Automatic XML sitemap
- β Complete RSS feed
- β Open Graph meta tags
- β Twitter Cards
- β Canonical URLs
- β SEO-friendly pagination
- β Structured data
Optimization
---
titre: My SEO-optimized article
description: Unique 150-160 character description
tags: keyword1, keyword2
---Security
Folder Protection
All sensitive folders are automatically protected:
cache/β Access deniedconfig/β Access deniedlogs/β Access deniedsrc/β Access deniedpages/β .md files not accessible
Sessions
"session_timeout": 1800 // 30 minutesRate Limiting
Protection against form abuse.
Debugging
Enable Debug Mode
"debug": {
"enabled": true,
"level": "INFO",
"display_errors": true
}Displayed Metrics
- β±οΈ Execution time
- πΎ Memory used
- π Cache statistics
- π§ Active configuration
- β‘ OPcache status
API and Helpers
ConfigLoader
// Get a value
$value = ConfigLoader::get('site.name');
$value = ConfigLoader::get('missing.key', 'default');
// Check a feature
if (ConfigLoader::isFeatureEnabled('cache')) {
// Cache enabled
}
// Get specific TTL
$ttl = ConfigLoader::getCacheTTL('markdown');CacheManager
// Paths
$cache_dir = CacheManager::getCacheDir();
$md_cache = CacheManager::getMarkdownCachePath();
// Statistics
$stats = CacheManager::getStats();
$size = CacheManager::getTotalSize();
// Cleanup
CacheManager::clearAll();
CacheManager::clearMarkdownCache();
CacheManager::cleanExpired(3600);
// Protection
$checks = CacheManager::checkProtection();MarkdownParser
// Parse with cache
$result = MarkdownParser::parse($content, $source_file);
// ['metadata' => [], 'content' => '...']
// Statistics
$stats = MarkdownParser::getCacheStats();
$size = MarkdownParser::getCacheSize();
$details = MarkdownParser::getCacheDetails();
// Cleanup
MarkdownParser::clearCache();Migration and Maintenance
Backup
Files to backup regularly:
config/site.json
pages/*.md
logs/stats.jsonRestoration
- Restore files
- Cache will be regenerated automatically
Update
- Backup
config/andpages/ - Replace system files
- Check
config/site.jsonfor new options - Clear cache:
/cache-admin
Troubleshooting
Cache Not Working
- Check
cache_enabled: trueinsite.json - Check
cache/folder permissions - Check logs in debug mode
Statistics Not Displaying
- Check
stats_enabled: true - Check
logs/permissions - Check
stats_access_enabledfor/statsURL
Error 500
- Enable debug mode
- Check PHP logs
- Check folder permissions
- Check
site.jsonsyntax
Private Pages Not Working
- Verify bcrypt hash is correct
- Verify PHP sessions are working
- Check
session_timeoutin config
License
- See LICENSE file for details
Support
For support and questions, please visit the project repository or contact the development team.
Version: 1.0.0-stable
Last Updated: November 2024