Building a Custom Plugin for PolyCMS — Scaffold Guide
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"
}
| Field | Required | Description |
|---|---|---|
name | Yes | Display name shown in admin |
slug | Yes | Unique identifier (must match folder name) |
description | Yes | Short description for admin UI |
version | Yes | Semantic version number |
author | No | Author name |
author_url | No | Author website |
requires_polycms | No | Minimum PolyCMS version |
main_file | Yes | Entry 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:
| Function | Description |
|---|---|
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
- Create the
my-custom-plugin/folder inmodules/polycms/plugins/. - Add all files as described above.
- Go to Blog → Plugins in Perfex CRM.
- Find "My Custom Plugin" and click Activate.
- Configure settings via the plugin's Settings page.
Best Practices
- Prefix all functions with your plugin abbreviation (e.g.,
mcp_) to avoid naming conflicts. - Always check
BASEPATHat the top of every PHP file. - Use plugin options instead of raw database queries for settings storage.
- Keep assets minimal — only load CSS/JS when needed.
- Support multiple languages by using the language file convention.
- 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
- Hooks & Filters Reference — Complete list of available hooks.
- Building a Custom Theme — Theme development scaffold.
- Creating Custom Shortcodes — Register shortcodes from your plugin.
- Architecture Overview — Understand the system structure.