Plugin Development Guide

# FearlessCMS Plugin Development Guide FearlessCMS features a powerful plugin system that allows you to extend the functionality of your website. This guide will walk you through creating your own plugins. ## Table of Contents 1. [Plugin Structure](#plugin-structure) 2. [Basic Plugin Example](#basic-plugin-example) 3. [Plugin Configuration](#plugin-configuration) 4. [Admin Interface Integration](#admin-interface-integration) 5. [Hooks and Filters](#hooks-and-filters) 6. [Route Handling](#route-handling) 7. [Content Processing](#content-processing) 8. [Database Integration](#database-integration) 9. [Security Considerations](#security-considerations) 10. [Testing Your Plugin](#testing-your-plugin) 11. [Distribution](#distribution) ## Plugin Structure A FearlessCMS plugin consists of the following structure: ``` plugins/ └── your-plugin-name/ ├── plugin.json # Plugin metadata ├── your-plugin-name.php # Main plugin file ├── includes/ # Additional PHP files ├── templates/ # HTML templates ├── assets/ # CSS, JS, images └── README.md # Documentation ``` ### Required Files #### plugin.json This file contains metadata about your plugin: ```json { "name": "Your Plugin Name", "description": "A brief description of what your plugin does", "version": "1.0.0", "author": "Your Name", "main": "your-plugin-name.php", "features": [ "Feature 1", "Feature 2" ] } ``` #### Main Plugin File The main PHP file should follow this naming convention: `your-plugin-name.php` (where `your-plugin-name` matches the directory name). ## Basic Plugin Example Here's a simple plugin that adds a custom function: ```php 'Example Plugin', 'menu_order' => 50, 'parent' => 'plugins', 'render_callback' => 'example_admin_page' ]); // Register hooks fcms_add_hook('content', 'example_process_content'); } // Admin page callback function example_admin_page() { ob_start(); ?>

Example Plugin Settings

This is your plugin's admin interface.

'default_value', 'option2' => true, 'option3' => [] ]; if (file_exists(YOUR_PLUGIN_CONFIG)) { $settings = json_decode(file_get_contents(YOUR_PLUGIN_CONFIG), true); if (is_array($settings)) { return array_merge($defaults, $settings); } } return $defaults; } function your_plugin_save_settings($settings) { return file_put_contents(YOUR_PLUGIN_CONFIG, json_encode($settings, JSON_PRETTY_PRINT)); } ``` ## Admin Interface Integration ### Registering Admin Sections ```php fcms_register_admin_section('your_plugin', [ 'label' => 'Your Plugin', 'menu_order' => 50, // Lower numbers appear first 'parent' => 'plugins', // Optional: makes it a submenu 'render_callback' => 'your_plugin_admin_page' ]); ``` ### Admin Page Implementation ```php function your_plugin_admin_page() { $success_message = ''; $error_message = ''; // Handle form submissions if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { switch ($_POST['action']) { case 'save_settings': $settings = [ 'option1' => trim($_POST['option1'] ?? ''), 'option2' => isset($_POST['option2']) ]; if (your_plugin_save_settings($settings)) { $success_message = 'Settings saved successfully!'; } else { $error_message = 'Failed to save settings.'; } break; } } // Load current settings $settings = your_plugin_get_settings(); // Start output buffer ob_start(); ?>

Your Plugin Settings

query('SELECT * FROM my_table'); $rows = $stmt->fetchAll(); } // Execute a parameterized query $stmt = fcms_do_hook('database_query', 'SELECT * FROM users WHERE id = ?', [1]); if ($stmt) { $user = $stmt->fetch(); } ``` ### Creating Database Tables ```php function my_plugin_create_tables() { $pdo = fcms_do_hook('database_connect'); if (!$pdo) return false; $sql = "CREATE TABLE IF NOT EXISTS my_plugin_data ( id INT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, content TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP )"; try { $pdo->exec($sql); return true; } catch (PDOException $e) { error_log("Failed to create table: " . $e->getMessage()); return false; } } ``` ## Security Considerations ### Input Validation Always validate and sanitize user input: ```php function my_plugin_save_data($input) { // Validate input $title = trim($input['title'] ?? ''); if (empty($title) || strlen($title) > 255) { return false; } // Sanitize content $content = htmlspecialchars($input['content'] ?? '', ENT_QUOTES, 'UTF-8'); // Save to database $pdo = fcms_do_hook('database_connect'); if ($pdo) { $stmt = $pdo->prepare('INSERT INTO my_table (title, content) VALUES (?, ?)'); return $stmt->execute([$title, $content]); } return false; } ``` ### File Upload Security If your plugin handles file uploads: ```php function my_plugin_handle_upload($file) { // Check file type $allowed_types = ['image/jpeg', 'image/png', 'image/gif']; if (!in_array($file['type'], $allowed_types)) { return false; } // Check file size (e.g., 5MB limit) if ($file['size'] > 5 * 1024 * 1024) { return false; } // Generate safe filename $extension = pathinfo($file['name'], PATHINFO_EXTENSION); $filename = uniqid() . '.' . $extension; // Move to safe location $upload_dir = YOUR_PLUGIN_DATA_DIR . '/uploads/'; if (!is_dir($upload_dir)) { mkdir($upload_dir, 0755, true); } return move_uploaded_file($file['tmp_name'], $upload_dir . $filename); } ``` ### Configuration Security Never hardcode sensitive information like database credentials: ```php // ❌ Bad - hardcoded credentials $config = [ 'host' => 'localhost', 'username' => 'myuser', 'password' => 'mypassword' ]; // ✅ Good - load from configuration $config = your_plugin_get_settings(); ``` ## Testing Your Plugin ### Development Testing 1. Enable your plugin in the admin interface 2. Test all functionality in a development environment 3. Check for PHP errors in the error log 4. Test with different CMS modes ### Error Handling Always include proper error handling: ```php function my_plugin_function() { try { // Your plugin logic here return true; } catch (Exception $e) { error_log("My Plugin Error: " . $e->getMessage()); return false; } } ``` ### Debugging Use error logging for debugging: ```php error_log("My Plugin Debug: " . print_r($data, true)); ``` ## Distribution ### Plugin Package Structure When distributing your plugin, include: ``` your-plugin-name/ ├── plugin.json ├── your-plugin-name.php ├── README.md ├── CHANGELOG.md └── LICENSE ``` ### README.md Template ```markdown # Your Plugin Name Brief description of what your plugin does. ## Installation 1. Upload the plugin to `/plugins/your-plugin-name/` 2. Enable the plugin in the admin interface 3. Configure settings in the plugin admin page ## Features - Feature 1 - Feature 2 - Feature 3 ## Configuration Describe configuration options and how to use them. ## Changelog ### 1.0.0 - Initial release - Basic functionality ## Support How users can get help or report issues. ``` ## MariaDB Connector Plugin: Database Integration The **MariaDB Connector** plugin enables FearlessCMS plugins to use a shared MariaDB/MySQL database connection, extending the flat-file CMS with robust database-backed features. ### What It Does - Provides a PDO connection to MariaDB/MySQL for all plugins - Centralizes DB credentials and connection management - Enables advanced plugins (dynamic blogs, e-commerce, analytics, etc.) - Allows hybrid flat-file and database-backed plugins to coexist ### Installation & Configuration 1. **Enable the plugin** in the admin Plugins section. 2. Go to **MariaDB Connector** under Plugins in the admin menu. 3. Enter your database credentials and save. 4. Use the 'Test Connection' button to verify connectivity. Configuration is stored in `content/mariadb-connector/config.json`. ### How Plugins Use the Database Other plugins should NOT create their own DB connections. Instead, use the provided hooks: ```php // Get a PDO connection $pdo = fcms_do_hook('database_connect'); if ($pdo) { // Use $pdo as usual $stmt = $pdo->query('SELECT * FROM my_table'); $rows = $stmt->fetchAll(); } // Execute a parameterized query $stmt = fcms_do_hook('database_query', 'SELECT * FROM users WHERE id = ?', [1]); if ($stmt) { $user = $stmt->fetch(); } ``` - `database_connect`: Returns a PDO object or null on failure - `database_query`: Executes a query with parameters, returns PDOStatement or false ### Best Practices - Always use the provided hooks for DB access - Do not hardcode credentials or create new PDO instances - Check for null/false return values to handle connection errors - Use prepared statements for all queries ### Admin Integration - The plugin adds a settings page for DB config and connection status - Only users with plugin management permissions can change DB settings ### Hybrid Content Model - Flat-file and database-backed plugins can be used together - You can migrate content types gradually or mix both approaches ## Conclusion This guide covers the essential aspects of plugin development for FearlessCMS. Remember to: - Follow security best practices - Use the hook system for extensibility - Provide clear documentation - Test thoroughly before distribution - Consider using the MariaDB Connector for database-backed features For more advanced examples, study the existing plugins in the `/plugins/` directory of your FearlessCMS installation.