How to extend the Kapost Module

The purpose of this document is to outline the various techniques that can be employed in order to extend and build upon the base functionality provided by the Kapost module.

Extending the module requires custom code that lives as a "separate module" which has to be written and maintained by you.

Before you consider embarking on this journey, please ensure that the functionality you are looking for isn't provided by the Kapost module as-is.

To confirm this, please contact Kapost.

WARNING: Kapost cannot debug any potential issues that can arise in your custom code, which can prevent Kapost from being able to successfully push content to your Drupal instance.

In addition, everything outlined below assumes that you are familiar with basic Drupal concepts like hooks.

Drupal 7

Before you get started, please make sure that you have version 2.1.5 or newer of the Kapost module.

In order to "interact" with the Kapost module you have 3 hooks at your disposal.

  1. kapost_byline_node_presave
  2. kapost_byline_node_create
  3. kapost_byline_node_edit

The one that you'll use in 99% of the cases is kapost_byline_node_presave.

This hook is fired:

  1. Before the Kapost module processes any of the fields
  2. Before the node is actually persisted via node_save()

With that in mind, it's the perfect place to:

  1. Unset any fields you don't want Kapost module to process
  2. Set any fields that Kapost module doesn't care about or doesn't support on its own

Let's take a look at a real life example to understand this better.

The Kapost module will not "create" taxonomy, node or user references if they do not exist before setting them on a field. If they don't exist, they will just be ignored and not be set.

To circumvent this and auto-create these "terms" or "references", we can write a simple extension to solve this issue for us.

function custom_extension_kapost_byline_node_presave_alter($context)
{
  global $user;

  $node = $context->node;
  $content = $context->content;

  $custom_fields = $content['custom_fields'];

  if(isset($custom_fields['my_terms_field']))
  {
      $values = explode(',', $custom_fields['my_terms_field']);
      foreach($values as $value)
      {
        // if we are working with "taxonomy terms" then we
        // can just look them up by "name" and create the
        // ones that do not exist
        // we don't have to alter the node, because the
        // Kapost module will do that for us

        // if we do not want the Kapost module to handle
        // this field at all and we want to set the field
        // on the node ourselves, then we can unset this
        // custom field by using
        // unset($custom_fields['my_terms_field']);
      }
  }
}

So, let us analyze what happened in the code snippet above.

First of all, we can "access" the currently "logged" in user who is performing the operation by using the global $user variable.

The $context parameter is mutable, meaning that we can set and unset anything we desire in both $context->node and $context->content.

$context->node is the actual representation of the node as it will be inserted into the database.

Since this hook is fired for both 'create' and 'edit', we can distinguish between the two by looking at the node itself.

$node = $context->node;

if(!isset($node->nid) || !empty($node->nid))
{
  // this is a new node
}
else
{
  // this is an existing node
}

You should never call node_save(), just set the fields on the $node and they will be persisted for you.

$context->content contains the raw parameters sent by Kapost. This includes title, description, custom_fields, categories, mt_keywords (tags) and state (1 = published as live, 0 = published as draft).

You can set, unset and alter these values and the Kapost module will respect and use the changes.

If you must use node_save() because it is necessary to set some field after all the changes to the node have been persisted then it is possible to register a Drupal shutdown function like illustrated below.

if(!isset($GLOBALS['KAPOST_BYLINE_PREVIEW']) && function_exists('workbench_moderation_set_state_action'))
{
  $context->user = $GLOBALS['user'];
  drupal_register_shutdown_function('custom_extension_kapost_byline_set_moderation_state', $context);
}

It is possible to use the KAPOT_BYLINE_PREVIEW global variable to tell whether the current action is a result of a preview or regular publishing.

In our example, we wanted to execute our piece code only when not in preview mode. Also, we store the current user in the context since we will be needing it later when our registered shutdown function is called.

The other two hooks, namely kapost_byline_node_create and kapost_byline_node_edit are executed before any validations have happened. They both receieve the same $context as kapost_byline_node_presave which can be altered and interacted with in much the same way.

These are the best spots to set any required fields that would otherwise be missing and cause validation errors.