PolyCMS Hooks & Filters — Complete Reference

Last updated on May 16, 2026 2:04 AM

Overview

PolyCMS provides a WordPress-inspired hook and filter system that allows developers to extend functionality without modifying core module files. This is the foundation for building custom plugins and themes.

There are two types of hooks:

  • Actions — Execute custom code at specific points (e.g., after a post is saved).
  • Filters — Modify data before it's used (e.g., alter post content before display).

Core API Functions

Registering an Action

polycms_add_action(string $hook, callable $callback, int $priority = 10, int $args = 1);

Parameters:

  • $hook — Name of the action hook.
  • $callback — Function or method to execute.
  • $priority — Execution order (lower = earlier). Default: 10.
  • $args — Number of arguments passed to the callback. Default: 1.

Example:

// Send a Slack notification when a post is published
polycms_add_action('polycms_post_published', function($post) {
    $message = "New post published: {$post->title}";
    send_slack_notification($message);
}, 10, 1);

Registering a Filter

polycms_add_filter(string $hook, callable $callback, int $priority = 10, int $args = 1);

Filters must return the modified value.

Example:

// Add a disclaimer to every post content
polycms_add_filter('polycms_post_content', function($content) {
    return $content . '<p class="disclaimer"><em>Views expressed are the author\'s own.</em></p>';
}, 20, 1);

Triggering Hooks

// Trigger an action
polycms_do_action(string $hook, ...$args);

// Apply a filter
$value = polycms_apply_filters(string $hook, $value, ...$args);

Complete Hook Reference

Post Lifecycle Actions

HookFired WhenParameters
polycms_post_saveBefore a post is saved to DB$data (array)
polycms_post_savedAfter a post is saved$post (object)
polycms_post_publishedWhen a post status changes to published$post (object)
polycms_post_deleteBefore a post is deleted$post_id (int)
polycms_post_deletedAfter a post is deleted$post_id (int)
polycms_post_status_changedWhen post status changes$post, $old_status, $new_status

Page Lifecycle Actions

HookFired WhenParameters
polycms_page_savedAfter a page is saved$page (object)
polycms_page_deletedAfter a page is deleted$page_id (int)

Comment Actions

HookFired WhenParameters
polycms_comment_submittedWhen a new comment is submitted$comment (object)
polycms_comment_approvedWhen a comment is approved$comment (object)
polycms_comment_deletedWhen a comment is deleted$comment_id (int)

Frontend Rendering Actions

HookFired WhenParameters
polycms_headInside tag of frontend
polycms_footerBefore of frontend
polycms_frontend_initWhen frontend controller initializes
polycms_before_render_postBefore a single post is rendered$post (object)
polycms_after_render_postAfter a single post is rendered$post, $output
polycms_after_render_homepageAfter homepage renders$output
polycms_admin_bar_actionsCustom buttons in the admin bar

Content Filters

FilterApplied ToInputExpected Return
polycms_post_contentPost body HTML before display$content (string)Modified content
polycms_post_titlePost title before display$title (string)Modified title
polycms_post_excerptPost excerpt before display$excerpt (string)Modified excerpt
polycms_page_contentPage body HTML before display$content (string)Modified content
polycms_post_metaPost meta data$meta (array)Modified meta

SEO Filters

FilterApplied ToInput
polycms_meta_titleFinal meta title tag$title (string)
polycms_meta_descriptionMeta description$description (string)
polycms_og_tagsOpen Graph tag array$tags (array)
polycms_twitter_tagsTwitter Card tag array$tags (array)

Plugin & Theme Actions

HookFired WhenParameters
polycms_plugin_activatedWhen a plugin is activated$plugin_slug
polycms_plugin_deactivatedWhen a plugin is deactivated$plugin_slug
polycms_theme_switchedWhen active theme changes$new_theme, $old_theme

Practical Examples

Example 1: Auto-Generate Excerpt

polycms_add_filter('polycms_post_excerpt', function($excerpt) {
    if (empty($excerpt)) {
        $CI = &get_instance();
        $content = $CI->load->get_var('post')->content ?? '';
        return mb_substr(strip_tags($content), 0, 160) . '...';
    }
    return $excerpt;
});

Example 2: Inject Google Tag Manager

polycms_add_action('polycms_head', function() {
    $gtm_id = get_option('polycms_gtm_id');
    if ($gtm_id) {
        echo "<script>(function(w,d,s,l,i){...})(window,document,'script','dataLayer','{$gtm_id}');</script>";
    }
});

Example 3: Restrict Post Content to Logged-in Users

polycms_add_filter('polycms_post_content', function($content) {
    $CI = &get_instance();
    $post = $CI->load->get_var('post');
    
    if ($post->visibility === 'private' && !is_staff_logged_in()) {
        return '<div class="restricted"><p>This content is available to registered members only.</p></div>';
    }
    return $content;
});

Best Practices

  1. Always use priority numbers to control execution order. Default is 10.
  2. Filters must return a value — forgetting to return will break the data chain.
  3. Use unique function names or closures to avoid conflicts between plugins.
  4. Don't modify global state inside filters — only transform and return the input data.
  5. Test with a single plugin first before combining multiple hooks to isolate issues.

Related Documentation