Want to take your software engineering career to the next level? Join the mailing list for career tips & advice Click here


Liveblogging done right. Using WordPress.

Subscribe to updates I use liveblog

Statistics on liveblog

Number of watchers on Github 267
Number of open issues 75
Average time to close an issue 27 days
Main language PHP
Average time to merge a PR 15 days
Open pull requests 43+
Closed pull requests 22+
Last commit over 2 years ago
Repo Created about 8 years ago
Repo Last Updated over 2 years ago
Size 22.3 MB
Homepage https://wordpress...
Organization / Authorautomattic
Latest Release1.7.1
Page Updated
Do you use liveblog? Leave a review!
View open issues (75)
View liveblog activity
View on github
Fresh, new opensource launches πŸš€πŸš€πŸš€
Software engineers: It's time to get promoted. Starting NOW! Subscribe to my mailing list and I will equip you with tools, tips and actionable advice to grow in your career.
Evaluating liveblog for your project? Score Explanation
Commits Score (?)
Issues & PR Score (?)


Build Status

Quick and simple blogging for following fast-paced events.


Your readers want your updates as quickly as possible, and we think we provide the easiest and the most flexible publishing environment to make that happen. Sometimes though, thats just not enough.

When youre covering a fast-paced event the latest Apple unveiling, an F1 Grand Prix, or the Super Bowl a full blog post for each individual update is a poor experience for your authors and your audience.

The WordPress.com VIP Liveblog Add-On was purpose-built to address these issues specifically.

Heres what makes it special:

  • Post updates right from the front-end of your site (no need to use the /wp-admin dashboard)
  • Viewers of your Liveblog get new entries served to them instantly and automatically, without needing to refresh their browser.
  • Your authors can drag-and-drop photos right into the Liveblog area, without needing to navigate to separate browser tabs or windows.
  • Theres no need for a separate site dedicated to liveblogging: every post can be a liveblog, even existing ones.

Check out our in-depth documentation.

If you'd like to check out the code and contribute, join us on github, pull requests are more than welcome.


  1. Upload the liveblog folder to your plugins directory (e.g. /wp-content/plugins/)
  2. Activate the plugin through the 'Plugins' menu in WordPress
  3. You can enable the liveblog on any post's edit page


The entry system supports #hashtags, /commands, @authors and :emoji: with an autocomplete system to help speed up the process. These extensions are filtered on save, for example a hashtag #football would be saved as <span class="liveblog-hash term-football">football</span> allowing easy styling. The container of the entry will also receive the same class term-football.

The command system has one inbuilt command:

/key: Which defines an entry to a key event, it adds the meta key to entry liveblog_key_entry. A key event can be styled using the .type-key class.

To display a key event box you can add the [liveblog_key_events] shortcode in your theme, e.g. in the sidebar, or you can use the Liveblog Key Events widget. Entries used with the key command will be inserted to both this box and the main feed. It also acts an anchor system to jump to parts of the main feed. It's not necessary to include the shortcode for the /key command to be enabled.

An example of using the key command would be an author writing the following in the New Entry box:

New iPad announced, launching next week  more info to come. /key

You can add new commands easily with a filter, the most basic command will add a class to entry, so you could do a simple /highlight which would add type-highlight to the entry container, letting you style the background color:

add_filter( 'liveblog_active_commands',  array( __CLASS__, 'add_highlight_command' ), 10 );

public static function add_highlight_command( $commands ) {
  $commands[] = highlight;
  return $commands;

A command can have both a filter called before the entry is saved, or an action that is called after its saved:

apply_filter( "liveblog_command_{$command}_before", $arg );
do_action( "liveblog_command_{$command}_after", $arg );

Customizing Key Events Shortcode

As mentioned earlier you can add the key events section by using [liveblog_key_events]. If you wish to change the title from the default Key Events then you can add a title attribute:

 [liveblog_key_events title="My New Title"]

If want to remove the title, good example when placing the shortcode in a widget.

 [liveblog_key_events title="false"]

A key event entry can be altered in to two ways:

Template: This is how each entry will be rendered. There are two inbuilt templates: list and timeline, or you can add your own using a filter:

add_filter( 'liveblog_key_templates', 'add_template' );

function add_template( $templates ) {
  $templates['custom'] = array( 'key-events.php', 'div', 'liveblog-key-custom-css-class' );
  return $templates;

There's a few things to note here:

  • key-events.php points to liveblog folder in the current active theme directory, in this case we our loading template file liveblog/key-events.php.
  • div is where we set the element type that wraps all entries, in the case where you wanted to build a list, you would set this to ul.
  • liveblog-key-custom-css-class is a class that will be added to the wrapper element of the entry to help with styling, in this case it would look like: <div class="liveblog-key-custom-css-class">...</div>

An example of a template file is:

<div class="<?php echo esc_attr( $css_classes ); ?>" >
    <a href="#liveblog-entry-<?php echo esc_attr( $entry_id ); ?>">
        <?php echo WPCOM_Liveblog_Entry_Key_Events::get_formatted_content( $content, $post_id ); ?>

Format: This is how each entries content is filtered, there are three inbuilt formats:

  • Full - which shows content without filtering
  • First Sentence - which will return everything until it hits either .?!
  • First Linebreak - which will return everything until it hits a linebreak (Shift + Enter) or <br />.

Formats add an extra level of control to how the key events section looks. If using the timeline template with first sentence and the following is entered into the new entry box:

New iPad announced. With plan to ship next month, pre-orders starting 23rd September retailing at $499 for 16gb $599 32gb. /key

The main feed would show the full text, and the key events section would only show:

New iPad announced

You can add your own using a filter:

add_filter( 'liveblog_key_formats', 'add_format' );

function add_format( $formats ) {
  $formats['strip-tags'] = 'new_format';
  return $formats;

function new_format( $content ) {
  $content = strip_tags( $content );
  return $content;

In the example above we are adding a format Strip Tags, which removes any HTML tags from the content.

Below is the full example of adding both:

function liveblog_add_key_event_template() {

    add_filter( 'liveblog_key_templates', 'add_template' );
    add_filter( 'liveblog_key_formats',   'add_format' );

    function add_template( $templates ) {
        $templates['custom'] = array( 'key-events.php', 'div', 'liveblog-key-custom-css-class' );
        return $templates;

    function add_format( $formats ) {
        $formats['strip-tags'] = 'new_format';
        return $formats;

    function new_format( $content ) {
        $content = strip_tags( $content );
        return $content;

add_action( 'init', 'liveblog_add_key_event_template' );

Selecting which template or format to use for liveblog happens in the admin panel on the edit of page of the post:

Key Events Admin Options

Managing Hashtags

Hashtags are manageable in the admin area. Under Posts there will be a menu for Hashtags. Please note that the slug is used, not the name.


When a :emoji: is inserted into an entry it is converted into:

<img src="//s.w.org/images/core/emoji/72x72/1f44d.png" class="liveblog-emoji emoji-+1">

Extending the Admin Meta Box

If you need to extend the Admin Meta Box there are a few filters and actions to make this easier. As an example, let's add a section with a text input and a button to save. To start we need to add the fields:


add_filter( 'liveblog_admin_add_settings', array( __CLASS__, 'add_admin_options' ), 10, 2 );

public static function add_admin_options( $extra_fields, $post_id ) {
  $args = array(
    'new_label'  => __( 'My new field', 'liveblog' ),
    'new_button' => __( 'Save', 'liveblog' ),

  $extra_fields[] = WPCOM_Liveblog::get_template_part( 'template.php', $args );
  return $extra_fields;


  <label for="liveblog-new-input"><?php echo esc_html( $new_label ); ?></label>
  <input name="liveblog-new-input" type="text" value="" />
  <button type="button" class="button button-primary" value="liveblog-new-input-save"><?php echo esc_html( $new_button ); ?></button>

Next we catch when the user has clicked our new save button liveblog-new-input-save:

add_action( 'liveblog_admin_settings_update', array( __CLASS__, 'save_template_option' ), 10, 3 );

public static function save_template_option( $response, $post_id ) {
  if ( 'liveblog-new-input-save' == $response['state'] && ! empty( $response['liveblog-new-input-save'] ) ) {
      //handle your logic here

Hooking into Entries

There is five useful filters to alter entries at current stages:

Before inserting into the database

add_filter( 'liveblog_before_insert_entry', array( __CLASS__, 'filter' ), 10 );

public static function filter( $entry ) {}

Before inserting updated entry into the database

add_filter( 'liveblog_before_update_entry', array( __CLASS__, 'filter' ), 10 );

public static function filter( $entry ) {}

Before we show preview (how we convert :emoji: back to <img>)

add_filter( 'liveblog_preview_update_entry', array( __CLASS__, 'filter' ), 10 );

public static function filter( $entry ) {}

Before we allow the entry to edited (how we convert <img> back to :emoji:)

add_filter( 'liveblog_before_edit_entry', array( __CLASS__, 'filter' ), 10 );

public static function filter( $content ) {}

Before the entry JSON is sent to the frontend

add_filter( 'liveblog_entry_for_json', array( __CLASS__, 'filter' ), 10, 2 );

public static function filter( $entry, $object ) {}

Altering hashtags, commands, authors and emoji

It is possible to set your own symbol and / or change the class prefix for #hashtags, /commands, @authors and :emoji:. These are handled by filters:

add_filter( 'liveblog_{type}_prefixes', array( __CLASS__, 'filter' ) );
add_filter( 'liveblog_{type}_class', array( __CLASS__, 'filter' ) );

Lets say you decide to use ! instead of # for #hashtags, therefore you expect them to be !hashtag:

add_filter( 'liveblog_hashtags_prefixes', array( __CLASS__, 'filter' ) );

public static function filter( $prefixes ) {
  $prefixes = array( '!', '\x{21}' );
  return $prefixes;

Currently hashtags use the class prefix term-, you can change that to whatever you need - in this case lets change to hashtag-:

add_filter( 'liveblog_hashtags_class', array( __CLASS__, 'filter' ) );

public static function filter( $class_prefix ) {
  $class_prefix = 'hashtag-';
  return $class_prefix;

Shortcode Filtering

Developers have to ability to exclude shortcodes from being used within the content of a live entry. By default the in built key events widget short code is excluded, but others can be added easily enough from within the themes functions.php.

    // Added to Functions.php

    function liveblog_entry_add_restricted_shortcodes() {

        add_filter( 'liveblog_entry_restrict_shortcodes', 'add_shortcode_restriction', 10, 1 );

        function add_shortcode_restriction( $restricted_shortcodes ) {

            $restricted_shortcodes['my-shortcode'] = 'This Text Will Be Inserted Instead Of The Shortcode!';
            $restricted_shortcodes['my-other-shortcode'] = '<h1>Here is a Markup Shortcode Replacement</h1>';

            return $restricted_shortcodes;

    add_action( 'init', 'liveblog_entry_add_restricted_shortcodes' );

The functionality takes a associative array of key value pairs where the key is the shortcode to be looked up and the value is the replacement string.

So, given the example above an editor adding any of the shortcode formats:

[my-shortcode] / [my-shortcode][/my-shortcode] / [my-shortcode arg="20"][/my-shortcode]

would see This Text Will Be Inserted Instead Of The Shortcode! outputted on live entry.

By default the inbuilt [liveblog_key_events] shortcode is replaced with We Are Blogging Live! Check Out The Key Events in The Sidebar.

To override this behaviour simple redefine the array key value:

$restricted_shortcodes['liveblog_key_events'] = 'Here is my alternative output for the shortcode! <a href="/">Click Here to Find Out More!</a>';

Auto Archiving of Live Blog Posts

This feature was added at the request of the community and solves the issues where Editors will forget to archive old Live Blog's leaving them live indefinitely.

Auto archive works by setting an expiry to the Post Meta for live blog posts. This expiry is calculated using the date of the latest liveblog entry + the number of days configured.

Once the expiry date is met the live blog post will be auto archived. It is however possible to re-enable an auto archived Live Blog Post, simply click the enable button in the post Liveblog meta box and the expiry will be extended by the number of days configured from the latest liveblog entry date. The auto archiving feature will then re-archive the post at the new expiry date.

In order to configure the number of days to autoarchive after, a filter has been implemented. By default the value is NULL and as such disables the feature. To enable it simply apply a value to the filter e.g:

add_filter( 'liveblog_auto_archive_days', function( $auto_archive_days ) {
  $auto_archive_days = 50;
  return $auto_archive_days;
}, 10, 1 );

WebSocket support

By default this plugin uses AJAX polling to update the list of Liveblog entries. This means that there is a delay of a few seconds between the moment a entry is created and the moment it is displayed to the users. For a close to real-time experience, it is possible to configure Liveblog to use WebSockets instead of AJAX polling. To achieve this, Liveblog uses Socket.io, Redis and socket.io-php-emitter (responsible for sending messages from PHP to the Socket.io server via Redis).

It is important to note that, since for now the Socket.io server has no way to tell if a client is an authenticated WordPress user or not and what are its capabilities, WebSockets will be used only for public Liveblog posts.

Follow the instructions below to enable WebSocket support.


Here is a list of what needs to be installed on the server to enable WebSocket support:

Install dependencies

Connected via SSH on the server, it is necessary to run the following commands from the Liveblog plugin directory to install WebSocket support dependencies:

composer install     # to install socket.io-php-emitter and Predis (a PHP client for Redis)
cd nodeapp
npm install     # to install socket.io and the adapter socket.io-redis


Add the following constants to wp-config.php to configure Liveblog plugin to use WebSockets:

  • LIVEBLOG_USE_SOCKETIO: set this constant to true to enabled WebSocket support. Default: false.
  • LIVEBLOG_SOCKETIO_URL: URL used by the Socket.io client to connect to the Socket.io server. Default: YOUR_SITE_DOMAIN:3000.
  • LIVEBLOG_REDIS_HOST: Redis server host. Default: localhost.
  • LIVEBLOG_REDIS_PORT: Redis server port. Default: 6379.

Running the Socket.io server

To start the Socket.io server go to the plugin directory and run:

node nodeapp/app.js

This will start a Socket.io server on port 3000 listening to a Redis server running on localhost:6379. It is possible to use the parameters bellow to change the app default values:

--socketio-port [port]
--redis-host [host]
--redis-port [port]

For more information on the accepted parameters run:

node nodeapp/app.js --help

Making sure everything is working

To test that everything is working, after following the steps above, open a Liveblog post in two different browser windows and check that whenever a user changes the list of entries in one window, the list in the other window is refreshed in real-time. It is also possible to use the browser developer tools to verify that there are no AJAX requests being sent every few seconds to check for changes in the list of entries. Instead the browser is receiving changes using a single WebSocket connection whenever they occur.

Important note about private Liveblog posts

When using Liveblog with WebSocket, the plugin will create a unique key for each Liveblog post (based on the post ID and its status). This key is shared with the users with permission to see the corresponding post when the page is loaded. The key is then send by the user's browser to the Socket.io server when a connection is established. Whenever there is a new Liveblog entry (or a Liveblog entry is updated or deleted), the Socket.io server will send a message only to the clients that provided the right key. This system is enough to prevent someone without permission to see the post from receiving Liveblog entries emitted by the Socket.io server but it has an important limitation. Once a user with permission receives the post key, if he saves it somewhere, he will be able to receive messages from the Socket.io server for that particular post even if for some reason he loses access to the post (for example if the user is removed from WordPress).

If you are using private Liveblog posts to share sensitive data and it is important that, once a user loses access to the post, he is not able to receive messages emitted by the Socket.io server anymore, consider using the 'liveblog_socketio_post_key' filter to implement your own criteria to generate the post key. For example, you could generate a random post key for each post that is saved as a post meta and that can be manually invalidated by an editor whenever necessary.

Tips for debugging

If for some reason the plugin is not able to use WebSockets to refresh the list of entries, below is a list of tips that might help you debug where is the problem:

  • Use your browser developer tools network tab to check if a WebSocket connection was established or check the browser console for errors when trying to establish it.
  • Check if the Node.js app that starts the Socket.io server is running. The app won't start or will stop running if unable to connect to the Redis server.
  • The plugin will fallback to AJAX polling if unable to connect to the Redis server.
  • It is possible to see all the messages received by the Redis server using the command redis-cli MONITOR
  • To see Socket.io server debug messages start the Node.js app with the command DEBUG=socket.io* node nodeapp/app.js


The entry form is the simplest possible Writers can preview before posting New posts are highlighted Adding images is a matter of just drag-and-drop Dragged photos are automatically inserted Typical liveblog view

liveblog open issues Ask a question     (View All Issues)
  • almost 4 years Tests are broken since #270 was merged
  • almost 4 years Using deprecated function `vary_cache_on_function`
  • almost 4 years Convert front-end to React
  • almost 4 years Notification bar
  • about 4 years Is there a way to tell that a shortcode is rendered within a liveblog?
  • about 4 years Add support for AMP Live List
  • over 4 years Prefetched entries are not updated or deleted.
  • over 4 years Not possible to update entry twice at the same session.
  • over 4 years Dangerous combination of [liveblog_key_events] shortcode and /key command.
  • over 4 years Remove Key Event from Key Events Widget does not work after entry update
  • over 4 years Structured Data support
  • over 4 years Add option to the key events widget (and shortcode) to display entries for a given post
  • over 4 years Add support for pages
  • over 4 years Upgrading to Liveblog 1.5 causes PHP Fatal errors
  • over 4 years WP API
  • over 4 years Provide admin UI for editing entries
  • over 4 years Key Events: Editing existing entry doesn't add to key events list
  • almost 5 years Key Events
  • about 5 years Post to Twitter/Facebook
  • about 5 years Twitter searching and embed
  • over 5 years Keyboard Shortcuts
  • over 5 years How to scale liveblog
  • over 5 years Edited comments appear at end of liveblog after archiving
  • over 5 years Hide #liveblog-messages after some time
  • over 5 years Trigger resize_contenteditable() after an image is uploaded
  • over 5 years 1.3.1 release for fixes
  • over 5 years In WYSIWYG, add toggle for target="_blank"
  • almost 6 years Create Relation Between Comment and Attachment
  • about 6 years More specific error when updating liveblog at a preview URL
  • about 6 years Custom form fields
liveblog open pull requests (View All Pulls)
  • Add support for WebSocket
  • Add widget to display a list of key events
  • run handle_request before canonical_redirects
  • Provide wpcom_liveblog_output() for Live Blogs to be output into a theme manually.
  • Fix: Deleting updated entries doesn't work #108
  • Updating and deleting an entry should return an empty query
  • Proper error code for no liveblog entry existing
  • Remove font family and pixel font sizes
  • Create liveblog-it_IT.mo
  • Add `Upload image` link for mobile.
  • Add Italian Language
  • Retrofit the nag bar for themes with fixed headers
  • Issue 98: Comment reply to entries
  • [WIP] Feature - Adding REST API endpoints
  • Add missing equal sign to fix HTML syntax in the Liveblog metabox
  • Feature/fix post global variable
  • Auto load formatted tweets when new posts are either auto loaded at t…
  • Updated deduping logic for replaced entries to work properly with lazy loading
  • Update WPCom helper to include all modifications applied to v1.3
  • Move is_robot function to javascript
  • REST API Endpoints
  • [WIP] Better Cache Control
  • Fix for unwanted "load more" button
  • Fix WYSIWYG icons getting cropped in MAC OS
  • Fix entries not getting removed after delete
  • Initial implementation of AMP support
  • Remove old "things yet to be implemented" list
  • Remove PHP 5.2 tests from Travis config
  • Fixed twice updation issue at the same session
  • Editor Enhancements
  • Add support for other post types #223
  • Add LiveBlogPosting Schema
  • Update plugin PHP version requirements
  • Sharable Entries
  • Author Select
  • Add filter for the_content only once to prevent issues with incorrect…
  • Added liveblog support to pages.
  • Fixed showing deleted posts in 'load more' functionality
  • Gutenberg Integration
  • add ability to filter authors
  • Fix spelling of "emojis"
  • WordPress coding standards fixes
  • Display ENTRY If ID exists in the Database Else Return
liveblog questions on Stackoverflow (View All Questions)
  • Remove inline style from body element that is automatically added by WordPress Liveblog
liveblog list of languages used
liveblog latest release notes
1.8-beta1 1.8-beta1
  • Allow multiple authors for a single Liveblog entry
  • Entries can easily be shared with a unique permalink
  • New block-based editor improvements
1.7.1 1.7.1
  • Fix bug with REST endpoints in Multisite (props justnorris)
  • Fix for some failing unit tests due to core changes (props jasonagnew)
  • Fix for bug where shortcodes would be removed completely (props jasonagnew)
  • Fixed some pagination issues in relatively unique circumstances (props liam-defty)
  • Fixed a bug that failed to correctly handle avatars (props liam-defty)
  • Made sure we handle timezones in entries properly (props liam-defty)
1.7 1.7
  • New: Mobile-friendly React-based frontend UI for a better editing experience across devices. (props jagnew jrmd liam-defty)
  • Various UI bugfixes thanks to the new frontend.
  • Fix for incorrect use of defined() (props kevinfodness)
Other projects in PHP