Structure
Overview
ValPress is architected to balance the familiar simplicity of a CMS with the robust, modern foundations of the Laravel framework. This section details the directory layout, the core database schema, and the internal request lifecycle that brings plugins and themes to life. Understanding this structure is essential for building scalable extensions and maintaining a healthy installation.
Why It Matters
- Consistency: Following the established directory layout ensures your code is automatically discovered and registered by the CMS.
- Data Integrity: Knowing the database schema allows for efficient querying and proper use of taxonomies and metadata.
- Extensibility: Understanding the request lifecycle—specifically when plugins and themes boot—is critical for using hooks at the correct execution point.
- Maintainability: A clear separation between core files, user uploads, and extensions prevents "hacking core" and simplifies the update process.
How It Works
Directory Layout
ValPress follows a standard Laravel directory structure with dedicated entry points for extensions.
Core Application
app/Core: The engine of ValPress. Contains thePluginManager,ThemeManager,Hooksystem, and theValPressfacade.app/Models,app/Http/Controllers: Standard Laravel entities for core functionality (e.g., Post models, Admin controllers).app/Providers: Service providers that bootstrap the CMS and its services.
Extension Points
public/plugins: Individual directories for each plugin. Each plugin must have aplugin.phpentry point or aconfig.phpmetadata file.public/themes: Individual directories for each theme. Supports parent-child theme relationships and standardfunctions.phplogic.
Resources and Assets
resources/views: Contains core admin views and default frontend templates.public/uploads: The default location for all media assets managed via the Media Library.database/migrations: Core database schema definitions.
Database Schema
ValPress uses a normalized schema designed for high-performance content retrieval.
| Table | Purpose |
|---|---|
posts |
Stores all content types (posts, pages, and custom post types). |
post_types |
Definitions and settings for each content type. |
postmeta |
Flexible key-value storage for post-specific metadata. |
options |
Global site settings and active plugin/theme lists. |
categories / tags |
Core taxonomies for content classification. |
media |
Metadata for uploaded files and their generated sizes. |
translations |
Multilingual support for core and extension strings. |
Request Lifecycle
The request lifecycle in ValPress is an extension of the standard Laravel lifecycle, injected with CMS-specific bootstrapping steps.
- Entry Point: The request hits
public/index.php. - Framework Boot: Laravel loads service providers defined in
config/app.php. - CMS Boot (
AppServiceProvider):- Plugin Initialization:
PluginManageridentifies active plugins from theoptionstable and executes theirplugin.phpfiles. - Resource Registration: Plugins use the
ValPressfacade to register routes, views, and migrations. - Theme Initialization:
ThemeManagerboots the active theme, loads itsfunctions.php, and sets up the view hierarchy (giving precedence to child themes).
- Plugin Initialization:
- Hook Execution: Core actions like
valpress_initandafter_setup_themeare fired. - Routing: Laravel matches the request to a registered route (core, plugin, or theme-defined).
- Execution & Rendering: The controller executes logic, and the view is rendered using the prioritized template hierarchy.
Usage
Navigating the Core Engine
If you need to understand how the CMS boots extensions, explore app/Core/ValPress.php. This class acts as the central registry for plugin resources:
// Registering a plugin route via the ValPress facade
ValPress::registerRoutes(__DIR__ . '/routes/web.php');
Accessing Database Tables
While you can use standard Eloquent models, ValPress provides helpers for common table operations:
// Get a global site option
$site_name = get_option('site_name');
// Get post metadata
$price = get_post_meta($post_id, 'product_price', true);
Code Examples
Plugin Resource Registration
Inside a plugin's plugin.php, resources should be registered during the boot process to ensure they are available to the framework.
<?php
/*
Plugin Name: Custom Analytics
*/
// Register view namespace so we can use view('analytics::dashboard')
ValPress::registerViews(__DIR__ . '/views', 'analytics');
// Register a migration path for plugin-specific tables
ValPress::registerMigrations(__DIR__ . '/database/migrations');
add_action('valpress_init', function() {
// Logic to run after all plugins and themes are booted
});
Theme Template Hierarchy
ValPress automatically handles template priority. A child theme can override any parent template simply by matching the filename in its views/ directory.
public/themes/
├── parent-theme/
│ └── views/
│ └── single.blade.php
└── child-theme/
└── views/
└── single.blade.php <-- This file will be loaded automatically
Best Practices
- Never Modify Core: Avoid changing files in
app/Coreorresources/views/admin. Use hooks (actions and filters) instead. - Use the
public/directory for extensions: Keep plugins and themes in their designated folders to ensure thePluginManagerandThemeManagercan handle updates and activation. - Register Resources via Facades: Use
ValPress::registerRoutes()orValPress::registerViews()instead of manual Laravel registration to ensure proper scoping and cleanup. - Prefix Database Keys: When adding entries to the
optionsorpostmetatables, use a unique prefix (e.g.,myplugin_settings) to avoid collisions with other extensions.
Common Mistakes
- Registering routes too late: If you register routes inside a hook that fires after the routing phase, they will never be matched. Always register them
directly in
plugin.phporfunctions.php. - Hardcoding paths: Always use helpers like
plugin_dir_path(__FILE__)or Laravel'spublic_path()to ensure your code works across different environments. - Missing
config.phpfor plugins: Whileplugin.phpheaders work, using aconfig.phpis recommended for complex plugins requiring detailed metadata. - Direct SQL queries: Avoid writing raw SQL for core tables. Use Eloquent models or ValPress helpers to ensure compatibility with different database drivers (MySQL vs SQLite).
Summary
The ValPress structure is designed for clarity and extensibility. By leveraging standard Laravel patterns and providing dedicated extension points in
public/plugins and public/themes, ValPress allows developers to build complex features without compromising the integrity of the core engine. Understanding
the AppServiceProvider driven lifecycle is the key to mastering the timing of your customizations.