SDK Reference
Hooks API

Hooks API

The Hooks API provides a WordPress-style system for actions and filters.

Actions

Actions allow you to execute code at specific points in the CMS lifecycle.

sdk.hooks.addAction(name, callback, priority)

Register an action hook.

sdk.hooks.addAction('post.viewed', async (post) => {
  console.log('Post viewed:', post.title);
  // Track view, send notification, etc.
}, 10);

Parameters:

ParameterTypeDescription
namestringHook name
callbackfunctionFunction to execute
prioritynumberExecution order (lower = earlier, default: 10)

sdk.hooks.removeAction(name, callback)

Remove a previously registered action.

const myCallback = (post) => console.log(post.title);
sdk.hooks.addAction('post.viewed', myCallback);
 
// Later...
sdk.hooks.removeAction('post.viewed', myCallback);

sdk.hooks.doAction(name, ...args)

Trigger an action (primarily for themes).

await sdk.hooks.doAction('my_custom_action', data);

Filters

Filters allow you to modify data as it passes through the system.

sdk.hooks.addFilter(name, callback, priority)

Register a filter hook.

// Modify post title
sdk.hooks.addFilter('post.title', (title) => {
  return title.toUpperCase();
}, 10);
 
// Modify post content
sdk.hooks.addFilter('post.content', (content) => {
  // Add something to content
  return content + '<p>Thanks for reading!</p>';
}, 20);

Parameters:

ParameterTypeDescription
namestringFilter name
callbackfunctionFunction that receives and returns data
prioritynumberExecution order (lower = earlier, default: 10)

sdk.hooks.removeFilter(name, callback)

Remove a previously registered filter.

const myFilter = (title) => title.toUpperCase();
sdk.hooks.addFilter('post.title', myFilter);
 
// Later...
sdk.hooks.removeFilter('post.title', myFilter);

sdk.hooks.applyFilter(name, value, ...args)

Apply all registered filters to a value.

const filteredTitle = await sdk.hooks.applyFilter('post.title', post.title);

Available Hooks

Actions

Hook NameArgumentsDescription
init-CMS has initialized
post.viewedpostA post was viewed
post.savedpostA post was saved
post.deletedpostIdA post was deleted
category.savedcategoryA category was saved
author.savedauthorAn author was saved
plugin.activatedpluginIdA plugin was activated
plugin.deactivatedpluginIdA plugin was deactivated
theme.switchedthemeIdTheme was changed

Filters

Filter NameInputDescription
post.titletitleFilter post title
post.contentcontentFilter post HTML content
post.excerptexcerptFilter post excerpt
post.datapostFilter entire post object
page.titletitleFilter page/document title
page.metametaFilter page meta tags

Theme Hooks (for templates)

{# In your theme templates #}
{{{ hooks.do('theme_head') }}}
{{{ hooks.do('theme_body_start') }}}
{{{ hooks.do('theme_before_content') }}}
{{{ hooks.do('theme_after_content') }}}
{{{ hooks.do('theme_body_end') }}}
{{{ hooks.do('theme_after_post') }}}
{{{ hooks.do('theme_home_before') }}}
{{{ hooks.do('theme_home_after_hero') }}}

Examples

Track Post Views

module.exports = async function(sdk) {
  
  sdk.hooks.addAction('post.viewed', async (post) => {
    // Get current view count
    const stats = await sdk.storage.get('viewStats') || {};
    stats[post.id] = (stats[post.id] || 0) + 1;
    await sdk.storage.set('viewStats', stats);
  });
  
  return { activate: async () => {}, deactivate: async () => {} };
};

Auto-Link Keywords

module.exports = async function(sdk) {
  
  const keywords = {
    'FeedGen CMS': 'https://feedgen.net',
    'documentation': '/docs'
  };
  
  sdk.hooks.addFilter('post.content', (content) => {
    Object.entries(keywords).forEach(([word, url]) => {
      const regex = new RegExp(`\\b${word}\\b`, 'gi');
      content = content.replace(regex, `<a href="${url}">${word}</a>`);
    });
    return content;
  }, 20);
  
  return { activate: async () => {}, deactivate: async () => {} };
};

Add Custom Meta Tags

module.exports = async function(sdk) {
  
  sdk.hooks.addFilter('page.meta', (meta) => {
    meta.push('<meta name="author" content="My Site">');
    meta.push('<meta property="og:site_name" content="My Site">');
    return meta;
  });
  
  return { activate: async () => {}, deactivate: async () => {} };
};

Inject Content Into Theme

module.exports = async function(sdk) {
  
  // Add analytics to head
  sdk.hooks.addAction('theme_head', async () => {
    return `<script>/* Analytics code */</script>`;
  });
  
  // Add banner after content
  sdk.hooks.addAction('theme_after_content', async () => {
    return `<div class="promo-banner">Check out our deals!</div>`;
  });
  
  return { activate: async () => {}, deactivate: async () => {} };
};

Best Practices

  1. Use appropriate priorities - Lower numbers run first (10 is default)
  2. Always return filtered values - Filters must return the modified data
  3. Handle errors gracefully - Wrap async code in try/catch
  4. Keep callbacks efficient - Hooks run on every request
  5. Remove hooks on deactivate - Clean up when plugin is disabled
  6. Namespace your hooks - Prefix custom hooks with plugin name