Update framework documentation and rename project to FolderWeb
This commit is contained in:
parent
4c697122ab
commit
f2c18659dc
3 changed files with 64 additions and 321 deletions
30
CLAUDE.md
30
CLAUDE.md
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
## Philosophy
|
## Philosophy
|
||||||
|
|
||||||
**Just enough, nothing more.** This framework applies minimal PHP to enable modern conveniences while remaining maintainable for years or decades. Avoid rapidly changing components and dependencies. The code should be readable, simple, and strictly necessary.
|
**Just enough, nothing more.** This framework applies minimal PHP to enable modern conveniences while remaining maintainable for years or decades. Avoid rapidly changing components and dependencies. The code should be readable, simple, and only add what is strictly necessary.
|
||||||
|
|
||||||
## Core Principles
|
## Core Principles
|
||||||
|
|
||||||
|
|
@ -22,7 +22,6 @@
|
||||||
- Folder hierarchy dictates URL structure
|
- Folder hierarchy dictates URL structure
|
||||||
- Drop a file (`.md`, `.php`, `.html`) in a folder and it renders immediately
|
- Drop a file (`.md`, `.php`, `.html`) in a folder and it renders immediately
|
||||||
- Assets placed in content directories are automatically accessible
|
- Assets placed in content directories are automatically accessible
|
||||||
- Frontpage is handled by `/content/frontpage.php`
|
|
||||||
- Directories with subfolders trigger list views
|
- Directories with subfolders trigger list views
|
||||||
|
|
||||||
### Template System
|
### Template System
|
||||||
|
|
@ -35,9 +34,6 @@
|
||||||
### Content Conventions
|
### Content Conventions
|
||||||
|
|
||||||
#### File Naming
|
#### File Naming
|
||||||
- Page files: `page.php`, `page.html`, `page.md`
|
|
||||||
- Single/article files: `article.md`, `post.md`, `single.md` (and `.php`/`.html` variants)
|
|
||||||
- Index overrides: `index.php` in any directory takes precedence
|
|
||||||
- Cover images: `cover.jpg`, `cover.webp`, etc.
|
- Cover images: `cover.jpg`, `cover.webp`, etc.
|
||||||
|
|
||||||
#### Date Formatting
|
#### Date Formatting
|
||||||
|
|
@ -92,26 +88,6 @@
|
||||||
### Extensibility Patterns
|
### Extensibility Patterns
|
||||||
- Third-party code goes in `/app/vendor/`
|
- Third-party code goes in `/app/vendor/`
|
||||||
- Custom code goes in `/app/custom/`
|
- Custom code goes in `/app/custom/`
|
||||||
- Never modify defaults—always override
|
|
||||||
- Use fallback chains: custom → default → docs variant
|
|
||||||
|
|
||||||
## Common Patterns
|
|
||||||
|
|
||||||
### Adding Custom Styles
|
|
||||||
Place CSS in `/app/custom/styles/base.css`—it automatically overrides default styles.
|
|
||||||
|
|
||||||
### Creating Custom Templates
|
|
||||||
Place templates in `/app/custom/templates/`—they automatically override defaults.
|
|
||||||
|
|
||||||
### Adding Fonts
|
|
||||||
Place font files in `/app/custom/fonts/` and reference them in your custom CSS.
|
|
||||||
|
|
||||||
### Creating Content
|
|
||||||
1. Create a directory for your content
|
|
||||||
2. Add a content file: `page.md`, `article.md`, etc.
|
|
||||||
3. Optionally add `metadata.ini` for title, date, summary
|
|
||||||
4. Optionally add `cover.jpg` for list view thumbnails
|
|
||||||
5. Content is immediately accessible at the URL matching the directory path
|
|
||||||
|
|
||||||
### List Views
|
### List Views
|
||||||
When a directory contains subdirectories:
|
When a directory contains subdirectories:
|
||||||
|
|
@ -124,12 +100,8 @@ When a directory contains subdirectories:
|
||||||
- Not a CMS with an admin panel
|
- Not a CMS with an admin panel
|
||||||
- Not a single-page application
|
- Not a single-page application
|
||||||
- Not a JavaScript framework
|
- Not a JavaScript framework
|
||||||
- Not opinionated about design aesthetics
|
|
||||||
- Not trying to scale to millions of users
|
|
||||||
|
|
||||||
## What This Framework Is
|
## What This Framework Is
|
||||||
|
|
||||||
- A simple, intuitive way to publish content
|
- A simple, intuitive way to publish content
|
||||||
- A foundation that will work for decades
|
- A foundation that will work for decades
|
||||||
- A teaching tool for understanding web fundamentals
|
|
||||||
- A protest against complexity for complexity's sake
|
|
||||||
|
|
|
||||||
81
README.md
81
README.md
|
|
@ -1,24 +1,69 @@
|
||||||
# PNP (Plug'n Play) - A 'just enough' PHP framework for simple websites
|
# FolderWeb
|
||||||
|
|
||||||
HTML lacks native support for including repeating elements, like the site header and footer. By using PHP sparsely, we can add this feature and some other modern conviniences, while providing a nearly maintanance-free framework that will chugh along for years, possibly decades, by avoiding a bunch of rapidly changing components and dependencies. Since reasonably up-to-date PHP versions is available at the vast majority of shared hosting providers, it makes sence to combine HTML with PHP.
|
A minimal, file-based PHP framework for publishing content that will work for decades. **Just enough, nothing more.** FolderWeb applies minimal PHP to enable modern conveniences while remaining maintainable for years or decades. No frameworks, no build tools, no JavaScript—just HTML, PHP 8.3+, and CSS. This is not a CMS with an admin panel, not a single-page application.
|
||||||
|
|
||||||
The mission statement is to apply just enough PHP to make the core features work. No admin panel, just an intuitive folder-based workflow. Intuitive defaults are applied, with optional overrides and customizations.
|
## Getting Started
|
||||||
|
|
||||||
## Main features from the users perspective
|
### Requirements
|
||||||
|
|
||||||
- The user should be able to create a new folder and drop in a markdown, PHP or HTML file and have it rendered imediatly. The directory hierarchy dictate the URL, for example `/www/articles/2025/10-23-title-of-article/article.md` would translate to the following URL: `domain.tld/articles/2025/-10-23-title-of-article/`.
|
- PHP 8.3 or higher
|
||||||
- The user can drop images and files in a directory and use them as assets. If a user drops a jpeg or webp into the folder mentioned above, the image can be refferenced in the markdown, like so: `[!alt text for the image](filname.jpg). The image will be renderend inline in the text. The same goes for PDF's or other document files, only they will not be rendered, but can be linked to.
|
- A web server (Apache, Nginx, or PHP's built-in server)
|
||||||
- If a directory contains one or more subfolders, it is assumed that it is a parent folder containing multiple instances of the same type of content, for example a list of articles, blog posts and so on. A default list view will be applied showing title and date, but the view can be overriden and defined for each content type / folder.
|
|
||||||
|
|
||||||
## Main features from a developers perspective
|
### Quick Start
|
||||||
|
|
||||||
- The code is readable and adds nothing more than strictly neccessary
|
1. Clone or download this repository
|
||||||
- Only HTML, PHP and CSS is allowed – no JS!
|
2. Point your web server's document root to /content
|
||||||
- Sparsely commented, only the main sections
|
|
||||||
- Custom templates is located at /app/custom
|
## Development
|
||||||
- Third party scripts are added to /app/vendors
|
|
||||||
- Supports PHP 8.3+ and makes use of modern PHP features whenever possible
|
### Creating Content
|
||||||
- Uses a PHP to make a simple router
|
|
||||||
- Uses .htaccess to make the PHP router handle all requests.
|
1. Create a directory for your content in the document root
|
||||||
- The HTML is classles and highly compliant with best practices
|
2. Add a content file (.md, .php or .html)
|
||||||
- The CSS uses modern features to apply styles as effective and smart as possible
|
3. Optionally add `metadata.ini` for title, date, and summary
|
||||||
|
4. Optionally add `cover.jpg|webp` for list view thumbnails
|
||||||
|
|
||||||
|
Content is immediately accessible at the URL matching the directory path.
|
||||||
|
|
||||||
|
**Example structure:**
|
||||||
|
|
||||||
|
```
|
||||||
|
/content/
|
||||||
|
about/
|
||||||
|
page.md
|
||||||
|
blog/
|
||||||
|
2025-11-01-hello-world/
|
||||||
|
article.md
|
||||||
|
cover.jpg
|
||||||
|
metadata.ini
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customization
|
||||||
|
|
||||||
|
All customization lives in `custom/`:
|
||||||
|
|
||||||
|
- **Styles:** Place CSS in `custom/styles/base.css`
|
||||||
|
- **Templates:** Override defaults by placing files in `custom/templates/`
|
||||||
|
- **Fonts:** Add font files to `custom/fonts/`
|
||||||
|
- **Configuration:** Copy `app/config.ini` to `custom/config.ini` and modify
|
||||||
|
|
||||||
|
Never modify files in `/app/default/`—always override them in `custom/`.
|
||||||
|
|
||||||
|
### File-Based Routing
|
||||||
|
|
||||||
|
The folder hierarchy dictates URL structure:
|
||||||
|
|
||||||
|
- `/about/page.md` → `yoursite.com/about`
|
||||||
|
- `/blog/2025-11-01-post/article.md` → `yoursite.com/blog/2025-11-01-post`
|
||||||
|
- Dates in folder names are automatically extracted and formatted
|
||||||
|
- Directories with subdirectories automatically show list views
|
||||||
|
|
||||||
|
### Metadata
|
||||||
|
|
||||||
|
Use `metadata.ini` files for structured data:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
title = "My Page Title"
|
||||||
|
date = "2025-11-01"
|
||||||
|
summary = "A brief description of the page"
|
||||||
|
```
|
||||||
|
|
|
||||||
274
app/README.md
274
app/README.md
|
|
@ -1,274 +0,0 @@
|
||||||
# Framework Documentation
|
|
||||||
|
|
||||||
This directory contains the core framework for the file-based CMS. It provides a minimal, extensible foundation that can be customized via the `/custom/` directory.
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
The framework is a lightweight PHP-based routing system that:
|
|
||||||
- Converts URLs to filesystem paths
|
|
||||||
- Resolves language-specific content and slugs
|
|
||||||
- Applies templates to render content
|
|
||||||
- Serves static assets (styles, fonts, images)
|
|
||||||
|
|
||||||
## Directory Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
app/
|
|
||||||
├── router.php # Main routing logic
|
|
||||||
├── static.php # Static asset server for /app/* resources
|
|
||||||
├── config.ini # Default framework configuration
|
|
||||||
├── vendor/ # Third-party dependencies
|
|
||||||
│ └── Parsedown/ # Markdown parser
|
|
||||||
└── default/ # Default templates and styles (fallback)
|
|
||||||
├── templates/
|
|
||||||
│ ├── base.php # Base HTML structure
|
|
||||||
│ ├── page.php # Single page/article template
|
|
||||||
│ └── list.php # Directory listing template
|
|
||||||
└── styles/
|
|
||||||
└── base.css # Default base styles
|
|
||||||
```
|
|
||||||
|
|
||||||
## Core Components
|
|
||||||
|
|
||||||
### `router.php`
|
|
||||||
|
|
||||||
The main request router that handles all content requests. Key responsibilities:
|
|
||||||
|
|
||||||
1. **Language Detection**: Extracts language from URL path (`/no/`, `/en/`)
|
|
||||||
2. **Slug Resolution**: Converts language-specific slugs to directory names using metadata
|
|
||||||
3. **Path Resolution**: Maps URLs to filesystem paths in `/content/`
|
|
||||||
4. **Content Loading**: Reads content files (`.md`, `.html`, `.php`)
|
|
||||||
5. **Template Application**: Applies appropriate template based on content type
|
|
||||||
6. **Rendering**: Outputs final HTML with base template
|
|
||||||
|
|
||||||
**Key Functions:**
|
|
||||||
- `resolveLanguageSlugToName()` - Translates slugs to directory names
|
|
||||||
- `findContentFile()` - Locates content files with language variants
|
|
||||||
- `renderPage()` - Renders content with templates
|
|
||||||
- `parseMetadata()` - Parses INI metadata files
|
|
||||||
|
|
||||||
### `static.php`
|
|
||||||
|
|
||||||
Serves static assets from `/app/` directory. Handles requests for:
|
|
||||||
- `/app/styles/*` - Framework CSS files
|
|
||||||
- `/app/fonts/*` - Framework fonts
|
|
||||||
- `/app/default-styles/*` - Default stylesheet aliases
|
|
||||||
|
|
||||||
Includes security checks to prevent path traversal attacks.
|
|
||||||
|
|
||||||
### `config.ini`
|
|
||||||
|
|
||||||
Default configuration for the framework:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[languages]
|
|
||||||
default = "no" # Default language
|
|
||||||
available = "no,en" # Available languages
|
|
||||||
```
|
|
||||||
|
|
||||||
Can be overridden by `/custom/config.ini`.
|
|
||||||
|
|
||||||
### `vendor/`
|
|
||||||
|
|
||||||
Third-party dependencies:
|
|
||||||
- **Parsedown**: Markdown-to-HTML parser library
|
|
||||||
|
|
||||||
### `default/`
|
|
||||||
|
|
||||||
Fallback templates and styles used when custom templates are not provided.
|
|
||||||
|
|
||||||
## Request Flow
|
|
||||||
|
|
||||||
```
|
|
||||||
1. User requests URL (e.g., /no/artikler/pasientinfo)
|
|
||||||
↓
|
|
||||||
2. Apache routes to /content/index.php
|
|
||||||
↓
|
|
||||||
3. index.php includes router.php
|
|
||||||
↓
|
|
||||||
4. router.php:
|
|
||||||
- Extracts language: "no"
|
|
||||||
- Resolves slug "artikler" → "artikler" directory
|
|
||||||
- Resolves slug "pasientinfo" → "pasientinfo" directory
|
|
||||||
- Checks if path exists in /content/
|
|
||||||
- Determines content type (file or directory)
|
|
||||||
↓
|
|
||||||
5. For single article:
|
|
||||||
- Loads metadata.ini
|
|
||||||
- Loads article.no.md (or article.md)
|
|
||||||
- Applies /custom/templates/page.php (or default)
|
|
||||||
- Wraps with /custom/templates/base.php
|
|
||||||
↓
|
|
||||||
6. For directory listing:
|
|
||||||
- Scans directory for subdirectories
|
|
||||||
- Loads metadata.ini for each item
|
|
||||||
- Applies list template specified in metadata
|
|
||||||
- Wraps with base.php
|
|
||||||
↓
|
|
||||||
7. Outputs final HTML to browser
|
|
||||||
```
|
|
||||||
|
|
||||||
## Template System
|
|
||||||
|
|
||||||
Templates can be overridden by placing files in `/custom/templates/`:
|
|
||||||
|
|
||||||
### Base Template (`base.php`)
|
|
||||||
Wraps all content with HTML structure, header, footer, navigation.
|
|
||||||
|
|
||||||
**Variables available:**
|
|
||||||
- `$title` - Page title
|
|
||||||
- `$content` - Rendered page content
|
|
||||||
- `$language` - Current language code
|
|
||||||
- `$metadata` - Page metadata array
|
|
||||||
|
|
||||||
### Page Template (`page.php`)
|
|
||||||
Renders single articles/pages.
|
|
||||||
|
|
||||||
**Variables available:**
|
|
||||||
- `$contentHtml` - Parsed HTML content
|
|
||||||
- `$metadata` - Article metadata
|
|
||||||
- `$language` - Current language code
|
|
||||||
- `$parentMetadata` - Parent directory metadata
|
|
||||||
|
|
||||||
### List Templates
|
|
||||||
Render directory listings. Multiple variants:
|
|
||||||
- `list.php` - Simple list
|
|
||||||
- `list-grid.php` - Grid layout
|
|
||||||
- `list-card-grid.php` - Card grid with images
|
|
||||||
- `list-faq.php` - Expandable FAQ view
|
|
||||||
|
|
||||||
**Variables available:**
|
|
||||||
- `$items` - Array of child items with metadata
|
|
||||||
- `$metadata` - Directory metadata
|
|
||||||
- `$language` - Current language code
|
|
||||||
|
|
||||||
## Customization
|
|
||||||
|
|
||||||
The framework is designed to be minimal and extensible. All customization should happen in `/custom/`:
|
|
||||||
|
|
||||||
### Override Templates
|
|
||||||
Create files in `/custom/templates/` with the same name as default templates.
|
|
||||||
|
|
||||||
### Override Configuration
|
|
||||||
Create `/custom/config.ini` to override default settings.
|
|
||||||
|
|
||||||
### Add Custom Styles
|
|
||||||
Place CSS in `/custom/styles/` and reference in custom templates.
|
|
||||||
|
|
||||||
### Add Custom Fonts
|
|
||||||
Place font files in `/custom/fonts/` and reference in CSS.
|
|
||||||
|
|
||||||
### Add Translations
|
|
||||||
Create or edit `/custom/languages/[lang].ini` files.
|
|
||||||
|
|
||||||
## Metadata System
|
|
||||||
|
|
||||||
Content is configured via `metadata.ini` files placed in each directory.
|
|
||||||
|
|
||||||
### Common Metadata Fields
|
|
||||||
|
|
||||||
```ini
|
|
||||||
[metadata]
|
|
||||||
title[no] = "Norwegian Title"
|
|
||||||
title[en] = "English Title"
|
|
||||||
slug[no] = "norwegian-slug"
|
|
||||||
slug[en] = "english-slug"
|
|
||||||
summary[no] = "Norwegian summary"
|
|
||||||
summary[en] = "English summary"
|
|
||||||
date = "2024-10-15"
|
|
||||||
category = "Category Name"
|
|
||||||
tags = "tag1,tag2,tag3"
|
|
||||||
template = "list-card-grid" # For directories
|
|
||||||
show_in_menu = true
|
|
||||||
menu_order = 10
|
|
||||||
```
|
|
||||||
|
|
||||||
### Metadata Inheritance
|
|
||||||
Child items inherit parent metadata when not specified.
|
|
||||||
|
|
||||||
## Content File Resolution
|
|
||||||
|
|
||||||
The router looks for content files in this order:
|
|
||||||
|
|
||||||
1. `article.[language].md` (e.g., `article.no.md`)
|
|
||||||
2. `article.[language].html`
|
|
||||||
3. `article.[language].php`
|
|
||||||
4. `article.md` (fallback)
|
|
||||||
5. `article.html` (fallback)
|
|
||||||
6. `article.php` (fallback)
|
|
||||||
7. `page.[language].md` (for directory index)
|
|
||||||
8. `page.md` (fallback)
|
|
||||||
|
|
||||||
## Language System
|
|
||||||
|
|
||||||
### URL Structure
|
|
||||||
- Norwegian: `/no/artikler/pasientinfo`
|
|
||||||
- English: `/en/articles/patient-info`
|
|
||||||
|
|
||||||
### Slug Translation
|
|
||||||
Slugs are resolved using metadata:
|
|
||||||
```ini
|
|
||||||
slug[no] = "pasientinfo"
|
|
||||||
slug[en] = "patient-info"
|
|
||||||
```
|
|
||||||
|
|
||||||
The router automatically translates URLs to filesystem paths regardless of language.
|
|
||||||
|
|
||||||
### Translation Files
|
|
||||||
Located in `/custom/languages/`:
|
|
||||||
- `no.ini` - Norwegian translations
|
|
||||||
- `en.ini` - English translations
|
|
||||||
|
|
||||||
Format:
|
|
||||||
```ini
|
|
||||||
key = "Translated text"
|
|
||||||
another_key = "More text"
|
|
||||||
```
|
|
||||||
|
|
||||||
Access in templates: `$translations['key']`
|
|
||||||
|
|
||||||
## Security Considerations
|
|
||||||
|
|
||||||
- **Path Traversal Protection**: `static.php` validates paths to prevent directory traversal
|
|
||||||
- **Input Sanitization**: URLs are sanitized before filesystem operations
|
|
||||||
- **Template Isolation**: Templates run in controlled scope with specific variables
|
|
||||||
- **No Database**: File-based system eliminates SQL injection risks
|
|
||||||
|
|
||||||
## Performance
|
|
||||||
|
|
||||||
- **No Caching**: Content is rendered on each request (suitable for low-traffic sites)
|
|
||||||
- **Performance Tracking**: Page generation time is measured and displayed
|
|
||||||
- **Static Assets**: Served directly by Apache when possible
|
|
||||||
|
|
||||||
## Extending the Framework
|
|
||||||
|
|
||||||
To add new features:
|
|
||||||
|
|
||||||
1. **Custom Functions**: Add helper functions in custom templates
|
|
||||||
2. **New Template Types**: Create new template files in `/custom/templates/`
|
|
||||||
3. **Metadata Fields**: Add new fields to `metadata.ini` files
|
|
||||||
4. **Custom Routes**: Extend `router.php` (requires modifying framework)
|
|
||||||
|
|
||||||
## Debugging
|
|
||||||
|
|
||||||
Enable error reporting in `content/index.php`:
|
|
||||||
```php
|
|
||||||
ini_set('display_errors', 1);
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
```
|
|
||||||
|
|
||||||
View page generation time at bottom of each page.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- PHP 8.3 or higher
|
|
||||||
- Apache with mod_rewrite enabled
|
|
||||||
- Write permissions on content directories (for future admin features)
|
|
||||||
|
|
||||||
## Limitations
|
|
||||||
|
|
||||||
- No built-in caching (regenerates pages on each request)
|
|
||||||
- No built-in admin interface (content edited via filesystem)
|
|
||||||
- No user authentication system
|
|
||||||
- No built-in search functionality
|
|
||||||
- Performance may degrade with very large content libraries
|
|
||||||
Loading…
Add table
Reference in a new issue