⚠️ This plugin is currently in Beta. It is designed to run on WordPress VIP. This beta release is not intended for use on a production environment.
The WordPress VIP Workflow Plugin allows you to control your editorial workflow. You can set up custom statuses for every phase of your workflow, and transitions between statuses generate actions, like notifications.
This plugin is currently developed for use on WordPress sites hosted on WordPress VIP.
Try out the VIP Workflow plugin in your browser with WordPress Playground:
The latest version of the plugin is available in the default trunk
branch of this repository.
We recommend installing the latest plugin version via git subtree
within your site's repository:
# Enter your project's root directory:
cd my-site-repo/
# Add a subtree for the trunk branch:
git subtree add --prefix plugins/vip-workflow-plugin [email protected]:Automattic/vip-workflow-plugin.git trunk --squash
To deploy the plugin to a remote branch, git push
the committed subtree.
The trunk
branch will stay up to date with the latest version of the plugin. Use this command to pull the latest trunk
branch changes:
git subtree pull --prefix plugins/vip-workflow-plugin [email protected]:Automattic/vip-workflow-plugin.git trunk --squash
Ensure that the plugin is up-to-date by pulling changes often.
Note: We do not recommend using git submodule
. Submodules on WPVIP that require authentication will fail to deploy.
The latest version of the plugin can be downloaded from the repository's Releases page. Unzip the downloaded plugin and add it to the plugins/
directory of your site's GitHub repository.
We recommend activating plugins with code.
Once the plugin is activated, go to the VIP Workflow
menu in wp-admin
to configure your workflow.
By default, the following post statuses are created:
- Pitch
- Assigned
- In Progress
- Draft
- Pending Review
Note that, these statuses are also available in the quick edit experience on the posts page alongside the core post statuses.
The plugin doesn't expect any specific configuration, so your first step is to set up statuses that reflect your workflow. You may notice that the steps are listed in a linear order. The plugin assumes a linear workflow where content is moving from creation to publish.
You can also specify which types of content use custom statuses. If a post does not use custom statuses, it will use the standard WordPress publishing flow.
VIP Workflow has the ability to send email and/or webhook notifications when a post's status changes. By default, these are off as no email address or webhook is provided out of the box. You set up webhook and/or email notifications under Admin -> VIP Workflow -> Settings.
Additional filters are available here to customize the notifications that are sent.
By default, VIP Workflow prevents publishing a post or page (the supported post types are configurable within settings) unless it has reached the last status on your list. This feature can be turned off under settings under the Publish Guard
option in Admin -> VIP Workflow -> Settings.
VIP Workflow adds an editor button to move posts between custom post statuses:
While editing a post with a custom status, click the "Move to ..." button to advance to the next state. When Publish Guard is enabled, the regular "Publish" button will be hidden until a post reaches the final custom status state.
Custom statuses can also be modified by using the "Extended Post Status" row "Edit" button in the post sidebar.
VIP Workflow adds a "Preview" section to the post sidebar, which allows sharing previews of pre-published content:
Anybody with a preview link (including not logged-in users) will be able to view a post with a preview link. Preview links can expire in three ways:
- Via expiration. Preview links are generated with an expiration (1 hour, 8 hours, or 1 day by default). When this time has passed, the token URL will no longer be valid.
- Via one-time usage. If the "One-time use" checkbox is selected, the preview URL will only work a single time, and then the token will become invalid. If this box is not selected, a preview URL can be used any number of times before expiration.
- Via post status changes. If a post moves out of VIP Workflow's set of extended post statuses, tokens will no longer be valid. For example, a post moved to "Publish" will no longer have valid preview tokens.
VIP Workflow adds a "Editorial Metadata" section to the post sidebar, which allows for additional data to be included with the post such as "Needs Legal Review". This can be managed under the plugin's settings, to get a visual for all of the configured editorial metadata fields.
When a post changes status, configured notifications are sent. You can use this filter to prevent notifications when a post transitions into specific statuses. By default, the plugin already filters the built-in inherit
and auto-draft
statuses.
/**
* Filter the statuses that should be ignored when sending notifications
*
* @param array $ignored_statuses Array of statuses that should be ignored when sending notifications
* @param string $post_type The post type of the post
*/
apply_filters( 'vw_notification_ignored_statuses', [ $old_status, 'inherit', 'auto-draft' ], $post->post_type );
For example, this filter can be used to add assigned
to the ignored statuses for a post of post_type
page, so no notifications are sent for such posts:
add_filter( 'vw_notification_ignored_statuses', function ( $ignored_statuses, $post_type ) {
if ( $post_type === 'page' ) {
$ignored_statuses[] = 'assigned';
}
return $ignored_statuses;
}, 10, 2 );
Change the recipients that receive an email notification, when the status of a post changes. By default, it is set to the configured email address under Admin -> VIP Workflow -> Settings.
/**
* Filter the email recipients
*
* @param array $email_recipients Array of email recipients
* @param string $action Action being taken, eg. status-change
* @param WP_Post $post Post object
*/
apply_filters( 'vw_notification_email_recipients', $email_recipients, $action, $post );
For example, this filter can be used to send email notifications to more than just 1 recipients especially for special statuses:
add_filter( 'vw_notification_email_recipients', function ( $email_recipients, $action, $post ) {
if ( $post->post_status === 'legal-review' ) {
$email_recipients[] = '[email protected]';
}
return $email_recipients;
}, 10, 2 );
Change the subject of the email that recipients receive, when the status of a post changes.
/**
* Filter the email subject
*
* @param string $subject Subject of the email
* @param string $action Action being taken, eg. status-change
* @param WP_Post $post Post object
*/
apply_filters( 'vw_notification_email_subject', $subject, $action, $post );
For example, this filter can be used to set a standardized subject regardless of what the status is:
add_filter( 'vw_notification_email_subject', function ( $subject, $action, $post ) {
return __( 'Content Status Update' );
}, 10, 2 );
Change the message of the email that recipients receive, when the status of a post changes.
/**
* Filter the email message
*
* @param string $message Body of the email
* @param string $action Action being taken, eg. status-change
* @param WP_Post $post Post object
*/
apply_filters( 'vw_notification_email_message', $message, $action, $post );
For example, this filter can be used to replace the signature that the plugin adds to the footer of the email with a company one instead:
add_filter( 'vw_notification_email_message', function ( $message, $action, $post ) {
return str_replace( 'You are receiving this email because a notification was configured via the VIP Workflow Plugin.', 'You are receiving this email as part of ACME Corp.', $message);
}, 10, 2 );
Change the headers used for the email that recipients receive, when the status of a post changes. By default, they are the standard headers set by wp_mail.
/**
* Filter the email recipients
*
* @param array $message_headers Message headers
* @param string $action Action being taken, eg. status-change
* @param WP_Post $post Post object
*/
apply_filters( 'vw_notification_email_headers', $message_headers, $post );
For example, this filter can be used to send HTML formatted email notifications instead of the default plain text formatted email notifications:
add_filter( 'vw_notification_email_headers', function ( $message_headers, $action, $post ) {
return [ 'Content-Type: text/html; charset=UTF-8' ];
}, 10, 2 );
Change the payload sent to the webhook, when the status of a post changes. By default, it is as follows:
{
"type": "plugin:vip-workflow:post-update",
"timestamp": "2024-07-22 00:03:19",
"data": "*vipgo* changed the status of *Post #85 - <http://test-site.vipdev.lndo.site/wp-admin/post.php?post=85&action=edit|hello>* from *In Progress* to *Draft*"
}
/**
* Filter the payload before sending it to the webhook
*
* @param array $payload Payload to be sent to the webhook
*/
apply_filters( 'vw_notification_send_to_webhook_payload', $payload );
For example, this filter can be used to customize the payload so that it's compatible with Slack's incoming webhooks:
add_filter( 'vw_notification_send_to_webhook_payload', function ( $payload ) {
return [
'text' => $payload['data'],
];
}, 10, 1 );
Change the default expiration options available in the preview URL feature.
/**
* Filter the expiration options available in the preview modal dropdown.
*
* @param array $expiration_options Array of expiration options. Each option uses keys:
* 'label': The visible label for the option, e.g. "1 hour"
* 'value': The value to be sent to the API, e.g. "1h". This value should be unique.
* 'second_count': The number of seconds the this expiration should be valid for, e.g. 3600
* 'default': Optional. Whether this option should be selected by default.
*/
return apply_filters( 'vw_preview_expiration_options', [ /* ... */ ]);
Here is an example using a shorter set of expiration lengths:
add_filter( 'vw_preview_expiration_options', function () {
return [
[
'label' => '5 minutes',
'value' => '5m',
'second_count' => 5 * 60,
'default' => true,
],
[
'label' => '15 minutes',
'value' => '15m',
'second_count' => 15 * 60,
],
[
'label' => '1 hour',
'value' => '1h',
'second_count' => 60 * 60,
],
];
} );
This generates these custom expiration values in the preiew link dialog:
This plugin uses wp-env
for development, and wp-env
to run the tests written for the plugin. wp-env
requires Docker so please ensure you have that installed on your system first.
To install wp-env
, use the following command:
npm -g i @wordpress/env
Read more about wp-env
here.
Optionally, it's also possible to use vip dev-env
instead for development. Installation instructions for the VIP cli can be found here, and instructions on how to setup vip dev-env
can be found here.
This plugin also uses Composer to manage PHP dependencies. Composer can be downloaded here.
- Install PHP dependencies:
composer install
- Install NPM dependencies:
npm install
- Start dev environment:
wp-env start
React hot reloading is supported. A few configuration steps are required for the setup:
-
Set
define( 'SCRIPT_DEBUG', true );
in yourwp-config.php
orvip-config.php
. At the time of writing, this is awp-scripts
limitation. -
Run
npm run dev:hot
. If you're running WordPress on a non-localhost hostname, e.g. onvip dev-env
, you may also need to specify the hostname:HOST=mysite.vipdev.lndo.site npm run dev:hot
This can also be specified using a
.env
configuration file:HOST=mysite.vipdev.lndo.site
If you use
wp-env
, you should be able to skip specifyingHOST
manually. -
If HMR is not working and you're developing out of a new component tree, you may also need to opt-in to hot module reloading via
module.hot.accept()
We are currently in the process of writing unit tests to ensure thorough code coverage of the plugin. At the moment, these are just PHP tests which can be run locally using the following:
wp-env start
composer install
composer run test
This plugin has been based on the wonderful EditFlow plugin developed by Daniel Bachhuber, Scott Bressler, Mohammad Jangda, and others.