Building a Custom Plugin for PolyCMS — Scaffold Guide

Last updated on May 15, 2026 11:20 PM

Overview

PolyCMS uses a WordPress-inspired plugin architecture that lets you add features without touching core module code. Each plugin is self-contained in its own directory with a standardized structure.

This guide walks you through building a plugin from scratch. By the end, you'll have a complete, working plugin scaffold that you can customize for any purpose.

Prerequisites: Familiarity with PHP, CodeIgniter basics, and the PolyCMS hooks system.

Plugin Directory Structure

All plugins live in modules/polycms/plugins/. Each plugin has this structure:

modules/polycms/plugins/
└── my-custom-plugin/
    ├── plugin.json          # Plugin manifest (required)
    ├── my-custom-plugin.php # Main entry file (required)
    ├── assets/
    │   ├── css/
    │   │   └── style.css    # Plugin CSS
    │   └── js/
    │       └── script.js    # Plugin JS
    ├── language/
    │   └── english/
    │       └── my_custom_plugin_lang.php
    └── views/
        └── settings.php     # Settings page view

Step 1: Create plugin.json

The plugin.json manifest defines your plugin metadata. This file is required.

{
    "name": "My Custom Plugin",
    "slug": "my-custom-plugin",
    "description": "A custom plugin that demonstrates the PolyCMS plugin architecture.",
    "version": "1.0.0",
    "author": "Your Name",
    "author_url": "https://your-website.com",
    "requires_polycms": "1.0.0",
    "main_file": "my-custom-plugin.php"
}
FieldRequiredDescription
nameYesDisplay name shown in admin
slugYesUnique identifier (must match folder name)
descriptionYesShort description for admin UI
versionYesSemantic version number
authorNoAuthor name
author_urlNoAuthor website
requires_polycmsNoMinimum PolyCMS version
main_fileYesEntry point PHP file

Step 2: Create the Main Plugin File

The main file is loaded when the plugin is activated. This is where you register your hooks and filters.

my-custom-plugin.php

<?php
defined('BASEPATH') or exit('No direct script access allowed');

/**
 * My Custom Plugin for PolyCMS
 *
 * @version 1.0.0
 * @author  Your Name
 */

// =============================================
// HOOKS REGISTRATION
// =============================================

// Add custom content after every post
polycms_add_filter('polycms_post_content', 'mcp_append_author_box', 20, 1);

// Inject CSS in frontend <head>
polycms_add_action('polycms_head', 'mcp_inject_styles');

// Hook into post save for custom processing
polycms_add_action('polycms_post_saved', 'mcp_on_post_saved', 10, 1);

// =============================================
// CALLBACK FUNCTIONS
// =============================================

/**
 * Append an author bio box after post content
 */
function mcp_append_author_box($content)
{
    $CI = &get_instance();
    $post = $CI->load->get_var('post');

    if (!$post) {
        return $content;
    }

    // Get plugin setting
    $show_bio = polycms_get_plugin_option('my-custom-plugin', 'show_author_bio', 'yes');
    if ($show_bio !== 'yes') {
        return $content;
    }

    $author_name = $post->author_name ?? 'Admin';
    $bio_html = '<div class="mcp-author-box">';
    $bio_html .= '<h4>About the Author</h4>';
    $bio_html .= '<p>Written by <strong>' . htmlspecialchars($author_name) . '</strong></p>';
    $bio_html .= '</div>';

    return $content . $bio_html;
}

/**
 * Inject plugin CSS in the frontend head
 */
function mcp_inject_styles()
{
    $plugin_url = polycms_plugin_url('my-custom-plugin');
    echo '<link rel="stylesheet" href="' . $plugin_url . '/assets/css/style.css">';
}

/**
 * Custom processing when a post is saved
 */
function mcp_on_post_saved($post)
{
    // Example: Log post saves
    log_activity('PolyCMS post saved: ' . $post->title . ' (ID: ' . $post->id . ')');
}

// =============================================
// SETTINGS PAGE (optional)
// =============================================

/**
 * Register a settings page for this plugin
 * This is called by PolyCMS when the admin visits the plugin settings
 */
function mcp_settings_page()
{
    $CI = &get_instance();

    if ($CI->input->post()) {
        // Save settings
        polycms_set_plugin_option('my-custom-plugin', 'show_author_bio', $CI->input->post('show_author_bio'));
        polycms_set_plugin_option('my-custom-plugin', 'bio_template', $CI->input->post('bio_template'));
        set_alert('success', 'Settings saved successfully.');
        redirect(admin_url('polycms/plugins/settings/my-custom-plugin'));
    }

    $data = [
        'show_author_bio' => polycms_get_plugin_option('my-custom-plugin', 'show_author_bio', 'yes'),
        'bio_template'    => polycms_get_plugin_option('my-custom-plugin', 'bio_template', ''),
    ];

    // Load the settings view
    $plugin_path = POLYCMS_PLUGINS_PATH . 'my-custom-plugin/';
    $CI->load->view($plugin_path . 'views/settings', $data);
}

// Register the settings page callback
polycms_register_plugin_settings('my-custom-plugin', 'mcp_settings_page');

Step 3: Create the Settings View

views/settings.php

<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>

<div class="panel_s">
    <div class="panel-heading">
        <h4 class="panel-title">My Custom Plugin Settings</h4>
    </div>
    <div class="panel-body">
        <?php echo form_open(admin_url('polycms/plugins/settings/my-custom-plugin')); ?>

        <div class="form-group">
            <label for="show_author_bio">Show Author Bio Box</label>
            <select name="show_author_bio" id="show_author_bio" class="form-control">
                <option value="yes" <?php echo $show_author_bio === 'yes' ? 'selected' : ''; ?>>Yes</option>
                <option value="no" <?php echo $show_author_bio === 'no' ? 'selected' : ''; ?>>No</option>
            </select>
        </div>

        <div class="form-group">
            <label for="bio_template">Custom Bio Template (HTML)</label>
            <textarea name="bio_template" id="bio_template" class="form-control" rows="5"><?php echo htmlspecialchars($bio_template); ?></textarea>
            <span class="help-block">Leave empty to use the default template.</span>
        </div>

        <button type="submit" class="btn btn-primary">Save Settings</button>
        <?php echo form_close(); ?>
    </div>
</div>

Step 4: Add CSS Assets

assets/css/style.css

.mcp-author-box {
    margin-top: 2rem;
    padding: 1.5rem;
    background: #f8f9fa;
    border-left: 4px solid #82b440;
    border-radius: 8px;
}

.mcp-author-box h4 {
    margin: 0 0 0.5rem 0;
    color: #333;
    font-size: 1rem;
}

Step 5: Add Language Support

language/english/my_custom_plugin_lang.php

<?php
defined('BASEPATH') or exit('No direct script access allowed');

$lang['mcp_plugin_name']      = 'My Custom Plugin';
$lang['mcp_show_author_bio']  = 'Show Author Bio Box';
$lang['mcp_bio_template']     = 'Custom Bio Template';
$lang['mcp_settings_saved']   = 'Settings saved successfully.';

Available Plugin Helper Functions

These helper functions are available for use in your plugin:

FunctionDescription
polycms_get_plugin_option($slug, $key, $default)Get a plugin setting value
polycms_set_plugin_option($slug, $key, $value)Save a plugin setting value
polycms_plugin_url($slug)Get the URL to the plugin's directory
polycms_plugin_path($slug)Get the filesystem path to the plugin directory
polycms_register_plugin_settings($slug, $callback)Register a settings page
polycms_register_widget($id, $config)Register a custom widget

Installation

  1. Create the my-custom-plugin/ folder in modules/polycms/plugins/.
  2. Add all files as described above.
  3. Go to Blog → Plugins in Perfex CRM.
  4. Find "My Custom Plugin" and click Activate.
  5. Configure settings via the plugin's Settings page.

Best Practices

  1. Prefix all functions with your plugin abbreviation (e.g., mcp_) to avoid naming conflicts.
  2. Always check BASEPATH at the top of every PHP file.
  3. Use plugin options instead of raw database queries for settings storage.
  4. Keep assets minimal — only load CSS/JS when needed.
  5. Support multiple languages by using the language file convention.
  6. Test deactivation — ensure your plugin cleans up gracefully when deactivated.

Need Help Building Your Plugin?

If you need assistance developing a custom plugin, have questions about the hooks/filters API, or want to discuss your integration ideas — feel free to reach out at any time. We provide completely free support to all PolyCMS customers.

Simply leave a comment on the PolyCMS page on CodeCanyon with your question, and our development team will respond with guidance, code samples, or troubleshooting help. Whether you're building your first plugin or working on a complex integration, we're happy to assist.

Related Documentation