Development Guidelines

Overview

ValPress follows a set of strict yet flexible development guidelines to ensure the CMS remains performant, secure, and maintainable. By adhering to these standards, developers can create plugins and themes that integrate seamlessly with the core application and other extensions.

Why It Matters

A consistent coding style and architectural approach prevent technical debt and minimize conflicts between different plugins or themes. Following these guidelines ensures that your code is:

  • Interoperable: Works well with the ValPress core and other ecosystem components.
  • Maintainable: Easy for you and other developers to understand and update.
  • Secure: Protected against common web vulnerabilities.
  • Performant: Optimized for high-traffic environments.

How It Works

ValPress leverages Laravel's modern PHP features while maintaining a WordPress-inspired hook system. The architecture promotes decoupling—where components interact through events (actions) and filters rather than direct dependencies. This allows the core to boot, load plugins, and then initialize the theme in a predictable sequence.

Usage

When developing for ValPress, you should integrate these guidelines into your daily workflow:

  1. Follow Coding Standards: Adhere to PSR-12 and Laravel-specific naming conventions.
  2. Use Localization: Wrap all user-facing strings in __() or @lang.
  3. Manage Assets Correctly: Use the ScriptManager instead of hardcoding <script> or <link> tags.
  4. Prioritize Hooks: Use actions and filters to modify behavior rather than overriding core files.
  5. Validate Updates: Implement ValidatesUpdate on src/Plugin.php or src/Theme.php when your extension has update prerequisites. See Plugin Update Validation and Repair Actions.

Code Examples

Correct Asset Enqueueing

Avoid using @push or @stack in your views if the assets should be managed globally. Instead, use the ScriptManager in your plugin or theme's functions.php.

// In your plugin's main file or theme functions.php
add_action('admin_enqueue_scripts', function () {
    // Register and enqueue a CSS file
    ScriptManager::registerStyle(
        'my-custom-admin-css', 
        asset('plugins/my-plugin/assets/css/admin.css'),
        ['version' => '1.0.0']
    );

    // Register and enqueue a JS file with dependencies
    ScriptManager::registerScript(
        'my-custom-admin-js',
        asset('plugins/my-plugin/assets/js/admin.js'),
        ['deps' => ['jquery', 'valpress-core'], 'footer' => true]
    );
});

Proper Localization

Never hardcode strings. This allows ValPress to automatically support multiple languages.

// In a Controller or Helper
return response()->json([
    'message' => __('Record updated successfully!'),
]);

// In a Blade Template
<button type="submit">
    {{ __('Save Changes') }}
</button>

Secure Data Handling

Always validate user input and sanitize output to prevent XSS and SQL injection.

// Handling a form submission in a plugin controller
public function store(Request $request)
{
    // 1. Validation (Laravel way)
    $validated = $request->validate([
        'title' => 'required|string|max:255',
        'content' => 'required|string',
    ]);

    // 2. Interaction via Eloquent (Auto-sanitization for DB)
    $post = Post::create($validated);

    // 3. Filtering output (Use Blade's {{ }} for auto-escaping)
    return view('my-plugin::admin.success', compact('post'));
}

Advanced Usage

Decoupling with Custom Hooks

If you are building a complex plugin, provide your own hooks so other developers can extend your functionality without modifying your plugin code.

// Inside your plugin's logic
$data = [
    'id' => 1,
    'status' => 'pending',
];

// Allow other plugins to modify this data before processing
$data = apply_filters('my_plugin_before_process_data', $data);

// Execute the process
MyService::process($data);

// Notify other components that processing is complete
do_action('my_plugin_after_process_data', $data);

Performance: Efficient Queries

Avoid "N+1" query problems by using Eager Loading when fetching content.

// ❌ Bad: Causes a query for every post to get the author
$posts = Post::all();
foreach ($posts as $post) {
    echo $post->author->name;
}

// ✅ Good: One query for posts, one for authors
$posts = Post::with('author')->get();

Best Practices

  • Prefix Everything: Use a unique prefix for your hooks, functions, and CSS classes (e.g., acme_) to avoid collisions.
  • Stay in the Sandbox: Keep your plugin assets inside public/plugins/{slug}/assets.
  • Use Type Hinting: Leverage PHP 8+ type hinting for better IDE support and error catching.
  • Keep it DRY: Use Laravel's Service Classes for complex logic instead of stuffing everything into plugin.php.
  • Documentation: Comment your hooks clearly using PHPDoc tags so others know what parameters are passed.

Common Mistakes

  • Modifying Core: Never edit files in app/Core or resources/views/admin. Your changes will be lost during updates.
  • Direct Database Queries: Avoid DB::statement() unless absolutely necessary. Use Eloquent or the Query Builder for better security and abstraction.
  • Ignoring CSRF: Always include @csrf in your forms. ValPress (via Laravel) will reject any POST request without a valid token.
  • Hardcoding URLs: Use route(), asset(), or valpress_get_permalink() instead of hardcoded strings like http://mysite.com/page.

Summary

Developing for ValPress means embracing the Laravel ecosystem while respecting the extensible nature of a CMS. By following PSR-12, using the built-in localization and asset management tools, and prioritizing hooks over direct modification, you ensure your contributions are professional, secure, and ready for production.