How to Create a Custom Addon for wpDataTables
Overview
wpDataTables is a powerful WordPress table plugin that allows users to create dynamic tables and charts. Creating a custom addon for wpDataTables can extend its functionality. This guide uses a starter addon to create a new addon named “Key table Addon for wpDataTables”.
Description
This documentation will guide you through creating a custom addon for wpDataTables. For this example, we will integrate Key Table Extension from the Datatable library into wpDatatables. First of all, you have to download our wpdatatables-starter-addon from GitHub.
Addon Structure
The structure of a wpDataTables addon is crucial for its functionality. Below is the recommended structure for the addon:
wpdatatables-key-table-addon/ ├── assets/ │ ├── css │ │ └── wpdatatables-key-table-addon.css │ └── js │ ├── wpdatatables-key-table-addon-backend.js │ └── wpdatatables-key-table-addon-frontend.js ├── languages/ ├── templates/ │ ├── wpdatatables-key-table-addon-settings-tab.inc.php │ └── wpdatatables-key-table-addon-settings-tabpanel.inc.php ├── includes/ │ └── plugin.php ├── wpdatatables-key-table-addon.php ├── README.txt └── LICENSE.txt
Download the Starter Addon
First of all, you have to download our wpdatatables-starter-addon from GitHub and extract it to your WordPress plugins directory (wp-content/plugins/).
Modifying the Starter Addon
- Rename the Folder
- Rename the main PHP file
- Plugin Header
- Constants Definition
- Plugin Load function
- This is how wpdatatables-key-table-addon.php should look like after modification. If it is not replace the main PHP file content from the code below or adopt it for your custom addon.
Rename the extracted folder name wpdatatables-starter-addon-master to wpdatatables-key-table-addon.
Rename the main PHP file name wpdatatables-starter-addon.php to wpdatatables-key-table-addon.php.
Here is the image of what should be changed in addon structure and in the main file of the addon
The plugin header contains metadata about the plugin, such as the name, description, version, author, and text domain.
/** * @package Key table Addon for wpDataTables * @version 1.0.0 * * Plugin Name: Key Table Addon for wpDataTables * Plugin URI: https://wpdatatables.com/ * Description: Key Table adds keyboard navigation to wpDataTables, operating in exactly the same way as traditional spreadsheet applications * Version: 1.0.0 * Author: TMS-Plugins * Author URI: https://www.tmsproducts.io/ * Text Domain: wpdatatables * * Requires Plugins: wpdatatables * wpDataTables Lite tested up to: 3.4.2.* * wpDataTables Premium tested up to: 6.5 */ ...
Define necessary constants for paths and URLs used in the addon.
... if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } define('WPDATATABLES_KEY_TABLE_ADDON__FILE__', __FILE__ ); // Full path to the Key Table Addon root directory define('WPDATATABLES_KEY_TABLE_ADDON_ROOT_PATH', plugin_dir_path(WPDATATABLES_KEY_TABLE_ADDON__FILE__)); // URL of Key Table Addon define('WPDATATABLES_KEY_TABLE_ADDON_ROOT_URL', plugin_dir_url(WPDATATABLES_KEY_TABLE_ADDON__FILE__)); // Basename of Key Table Addon define('WPDATATABLES_KEY_TABLE_ADDON_BASENAME', plugin_basename(WPDATATABLES_KEY_TABLE_ADDON__FILE__)); // Path to Key Table Addon templates define('WPDATATABLES_KEY_TABLE_ADDON_TEMPLATE_PATH', WPDATATABLES_KEY_TABLE_ADDON_ROOT_PATH . 'templates/'); ...
This function is responsible for initializing and running the Key Table Addon for wpDataTables
... function wpDataTableKeyTableAddonLoad() { // Load plugin file require_once( __DIR__ . '/includes/plugin.php' ); // Run the plugin \WPDataTableKeyTableAddon\Plugin::instance(); } // Action hook that fires after all active plugins have been loaded. // This is an appropriate hook for initializing your plugin because it ensures that all dependencies (such as wpDataTables) are available. add_action( 'plugins_loaded', 'wpDataTableKeyTableAddonLoad' );
/** * @package Key table Addon for wpDataTables * @version 1.0.0 * * Plugin Name: Key Table Addon for wpDataTables * Plugin URI: https://wpdatatables.com/ * Description: Key Table adds keyboard navigation to wpDataTables, operating in exactly the same way as traditional spreadsheet applications * Version: 1.0.0 * Author: TMS-Plugins * Author URI: https://www.tmsproducts.io/ * Text Domain: wpdatatables * * Requires Plugins: wpdatatables * wpDataTables Lite tested up to: 3.4.2.* * wpDataTables Premium tested up to: 6.5 */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } define('WPDATATABLES_KEY_TABLE_ADDON__FILE__', __FILE__ ); // Full path to the Key Table Addon root directory define('WPDATATABLES_KEY_TABLE_ADDON_ROOT_PATH', plugin_dir_path(WPDATATABLES_KEY_TABLE_ADDON__FILE__)); // URL of Key Table Addon define('WPDATATABLES_KEY_TABLE_ADDON_ROOT_URL', plugin_dir_url(WPDATATABLES_KEY_TABLE_ADDON__FILE__)); // Basename of Key Table Addon define('WPDATATABLES_KEY_TABLE_ADDON_BASENAME', plugin_basename(WPDATATABLES_KEY_TABLE_ADDON__FILE__)); // Path to Key Table Addon templates define('WPDATATABLES_KEY_TABLE_ADDON_TEMPLATE_PATH', WPDATATABLES_KEY_TABLE_ADDON_ROOT_PATH . 'templates/'); function wpDataTableKeyTableAddonLoad() { // Load plugin file require_once( __DIR__ . '/includes/plugin.php' ); // Run the plugin \WPDataTableKeyTableAddon\Plugin::instance(); } add_action( 'plugins_loaded', 'wpDataTableKeyTableAddonLoad' );
Implementing Key Table Feature
This tutorial provides a detailed guide on creating the main file for the wpDataTables Key Table Addon. This addon extends the functionality of wpDataTables by integrating the Key Table extension from the DataTables JS library, which adds keyboard navigation capabilities similar to traditional spreadsheet applications. The core logic is located in the plugin.php file in includes directory. Here we will explain section by section.
Set a unique namespace, create a class Plugin, and add constants specific like addon version,wpDataTables installed, and minimum PHP version for your addon:
<?php namespace WPDataTableKeyTableAddon; if (!defined('ABSPATH')) { exit; // Exit if accessed directly. } use stdClass; use WPDataTable; /** * Plugin class. * * The main class that initiates and runs the addon. * * @since 1.0.0 */ final class Plugin { /** * Addon Version * * @since 1.0.0 * @var string The addon version. */ const VERSION = '1.0.0'; /** * Minimum wpdatatables Version * * @since 1.0.0 * @var string Minimum wpdatatables version required to run the addon. */ const MINIMUM_WPDATATABLES_VERSION = '3.4.2'; /** * Minimum PHP Version * * @since 1.0.0 * @var string Minimum PHP version required to run the addon. */ const MINIMUM_PHP_VERSION = '7.4'; ... //plugin.php
Create instance (Ensures only one instance of the class is loaded or can be loaded).
... /** * Instance * * @since 1.0.0 * @access private * @static * @var \WPDataTableKeyTableAddon\Plugin The single instance of the class. */ private static ?Plugin $_instance = null; /** * Instance * * Ensures only one instance of the class is loaded or can be loaded. * * @return \WPDataTableKeyTableAddon\Plugin An instance of the class. * @since 1.0.0 * @access public * @static */ public static function instance(): ?Plugin { if (is_null(self::$_instance)) { self::$_instance = new self(); } return self::$_instance; } ... //plugin.php
Perform some compatibility checks to make sure basic requirements are met.
... /** * Constructor * * Perform some compatibility checks to make sure basic requirements are meet. * If all compatibility checks pass, initialize the functionality. * * @since 1.0.0 * @access public */ public function __construct() { if ($this->isCompatible()) { $this->registerActions(); $this->loadAddonTextdomain(); $this->initHooks(); } } ... //plugin.php
Check whether the site meets the addon requirement and settings admin notice messages if they are not met.
... /** * Compatibility Checks * * Checks whether the site meets the addon requirement. * * @since 1.0.0 * @access public */ public function isCompatible(): bool { include_once ABSPATH . 'wp-admin/includes/plugin.php'; // Check if wpDataTables is installed and activated if (!defined('WDT_ROOT_PATH')) { add_action('admin_notices', [$this, 'adminNoticeMissingMainPlugin']); deactivate_plugins(WPDATATABLES_KEY_TABLE_ADDON_BASENAME); return false; } // Check for required wpDataTables version if (!version_compare(WDT_CURRENT_VERSION, self::MINIMUM_WPDATATABLES_VERSION, '>=')) { add_action('admin_notices', [$this, 'adminNoticeMinimumWPDataTablesVersion']); deactivate_plugins(WPDATATABLES_KEY_TABLE_ADDON_BASENAME); return false; } // Check for required PHP version if (version_compare(PHP_VERSION, self::MINIMUM_PHP_VERSION, '')) { add_action('admin_notices', [$this, 'adminNoticeMinimumPHPVersion']); deactivate_plugins(WPDATATABLES_KEY_TABLE_ADDON_BASENAME); return false; } return true; } /** * Admin notice * * Warning when the site doesn't have wpdatatables installed or activated. * * @since 1.0.0 * @access public */ public function adminNoticeMissingMainPlugin() { $message = sprintf( esc_html__( '"%1$s" requires "%2$s" to be installed and activated.', 'wpdatatable-key-table-addon' ), '' . esc_html__( 'Key Table Addon for wpDataTables', 'wpdatatable-key-table-addon' ) . '', '' . esc_html__( 'wpDataTables', 'wpdatatable-key-table-addon' ) . '' ); printf( '', $message ); } /** * Admin notice * * Warning when the site doesn't have a minimum required wpdatatables version. * * @since 1.0.0 * @access public */ public function adminNoticeMinimumWPDataTablesVersion() { $message = sprintf( esc_html__( '"%1$s" requires "%2$s" version %3$s or greater.', 'wpdatatable-key-table-addon' ), '' . esc_html__( 'Key Table Addon for wpDataTables', 'wpdatatable-key-table-addon' ) . '', '' . esc_html__( 'wpDataTables', 'wpdatatable-key-table-addon' ) . '', self::MINIMUM_WPDATATABLES_VERSION ); printf( '%1$s
', $message ); } /** * Admin notice * * Warning when the site doesn't have a minimum required PHP version. * * @since 1.0.0 * @access public */ public function adminNoticeMinimumPHPVersion() { $message = sprintf( esc_html__( '"%1$s" requires "%2$s" version %3$s or greater.', 'wpdatatable-key-table-addon' ), '' . esc_html__( 'Key Table Addon for wpDataTables', 'wpdatatable-key-table-addon' ) . '', '' . esc_html__( 'PHP', 'wpdatatable-key-table-addon' ) . '', self::MINIMUM_PHP_VERSION ); printf( '%1$s
', $message ); } ... //plugin.php%1$s
Register actions for activation and deactivation of addon.
... /** * Register actions for activation and deactivation of addon * @return void * * @since 1.0.0 * @access public */ public function registerActions() { register_activation_hook(__FILE__, [$this,'activatePlugin']); register_deactivation_hook(__FILE__, [$this,'deactivatePlugin']); } /** * Activate plugin * * @since 1.0.0 * @access public */ public function activatePlugin() { // Add custom logic after activation // for example database manipulation } /** * Deactivate plugin * * @since 1.0.0 * @access public */ public function deactivatePlugin() { // Add custom logic after deactivation // for example database manipulation } ... //plugin.php
Use hooks provided by wpDataTables to extend its functionality with the Key Table extension.
... /** * Init all hooks necessary for Key Table addon * * @since 1.0.0 * @access public */ public function initHooks() { // Add JS and CSS for tables edit page on back-end add_action('wpdatatables_enqueue_on_edit_page', [$this, 'enqueueScriptsBackend']); // Add JS and CSS for tables on front-end add_action('wpdatatables_enqueue_on_frontend', [$this, 'enqueueScriptsFrontend']); // Add "Key Table" tab on table configuration page add_action('wpdatatables_add_table_configuration_tab', [$this, 'addKeyTableSettingsTab']); // Add tab panel for "Key table" tab on table configuration page add_action('wpdatatables_add_table_configuration_tabpanel', [$this, 'addKeyTableSettingsTabPanel']); // Extend table config before saving table to DB add_filter('wpdatatables_filter_insert_table_array', [$this, 'extendTableConfig'], 10, 1); // Extend WPDataTable Object with new properties add_action('wpdatatables_extend_wpdatatable_object', [$this, 'extendTableObject'], 10, 2); // Extend table description before returning it to the front-end add_filter('wpdatatables_filter_table_description', [$this, 'extendJSONDescription'], 10, 3); // Add Key table class to main table element add_filter('wpdatatables_add_class_to_table_html_element', [$this, 'addKeyTableClass'], 10, 2); } ... //plugin.php
Enqueue the necessary CSS and JS files for the addon on the back-end and front-end as well. Besides addon files, also it includes files for Key Table functionality from Datatable CDN.
... /** * Enqueue files * * Enqueue Key table add-on files on back-end * * @since 1.0.0 * @access public */ public function enqueueScriptsBackend() { wp_enqueue_style( 'wpdatatables-key-table-addon-css', WPDATATABLES_KEY_TABLE_ADDON_ROOT_URL . 'assets/css/wpdatatables-key-table-addon.css', array(), self::VERSION ); wp_enqueue_script( 'wpdatatables-key-table-addon-backend', WPDATATABLES_KEY_TABLE_ADDON_ROOT_URL . 'assets/js/wpdatatables-key-table-addon-backend.js', array(), self::VERSION, true ); wp_enqueue_script( 'wpdatatables-key-table-addon-frontend', WPDATATABLES_KEY_TABLE_ADDON_ROOT_URL . 'assets/js/wpdatatables-key-table-addon-frontend.js', array(), self::VERSION, true ); wp_enqueue_script( 'wpdatatables-datatable-key-table-addon', 'https://cdn.datatables.net/keytable/2.12.0/js/dataTables.keyTable.js', array(), self::VERSION, true ); wp_enqueue_script( 'wpdatatables-key-table-addon-datatable', 'https://cdn.datatables.net/keytable/2.12.0/js/keyTable.dataTables.js', array(), self::VERSION, true ); } /** * Enqueue files * * Enqueue Key table add-on files on front-end * * @since 1.0.0 * @access public */ public function enqueueScriptsFrontend($wpDataTable) { if ($wpDataTable->keyTable) { wp_enqueue_script( 'wpdatatables-key-table-addon-frontend', WPDATATABLES_KEY_TABLE_ADDON_ROOT_URL . 'assets/js/wpdatatables-key-table-addon-frontend.js', array(), self::VERSION, true ); wp_enqueue_script( 'wpdatatables-datatable-key-table-addon', 'https://cdn.datatables.net/keytable/2.12.0/js/dataTables.keyTable.js', array(), self::VERSION, true ); wp_enqueue_script( 'wpdatatables-key-table-addon-datatable', 'https://cdn.datatables.net/keytable/2.12.0/js/keyTable.dataTables.js', array(), self::VERSION, true ); wp_enqueue_style( 'wpdatatables-key-table-addon-css', WPDATATABLES_KEY_TABLE_ADDON_ROOT_URL . 'assets/css/wpdatatables-key-table-addon.css', array(), self::VERSION ); } } ... //plugin.php
Function that extends table config before saving table to the database.
... /** * * Function that extends table config before saving table to the database * * @param $tableConfig - array that contains table configuration * @return mixed * * @since 1.0.0 * @access public */ public function extendTableConfig($tableConfig) { $table = json_decode(stripslashes_deep($_POST['table'])); $advancedSettings = json_decode($tableConfig['advanced_settings']); if (isset($table->keyTable)) $advancedSettings->keyTable = $table->keyTable; $tableConfig['advanced_settings'] = json_encode($advancedSettings); return $tableConfig; } ... //plugin.php
Function that extends $wpDataTable object with new properties.
... /** * * Function that extends $wpDataTable object with new properties * * @param $wpDataTable WPDataTable * @param $tableData stdClass * * @since 1.0.0 * @access public */ public function extendTableObject(WPDataTable $wpDataTable, stdClass $tableData) { if (!empty($tableData->advanced_settings)) { $advancedSettings = json_decode($tableData->advanced_settings); if (isset($advancedSettings->keyTable)) { $wpDataTable->keyTable = $advancedSettings->keyTable; } } } ... //plugin.php
Function that extends table description with params for Key Table functionality before returning it to the front-end.
... /** * * Function that extends table description before returning it to the front-end * * @param $tableDescription stdClass * @param int $tableId * @param $wpDataTable WPDataTable * @return stdClass * * @since 1.0.0 * @access public */ public function extendJSONDescription(stdClass $tableDescription, int $tableId, WPDataTable $wpDataTable): stdClass { if ($wpDataTable->keyTable) { $tableDescription->keyTable = $wpDataTable->keyTable; $tableDescription->keys = $wpDataTable->keyTable == 1; $tableDescription->dataTableParams->keys = [ 'className' => 'keyCellFocus' ]; } return $tableDescription; } ... //plugin.php
Function that extends table CSS class. In our case, we added wdtKeyTable so we can easily find it over CSS.
... /** * Function that extends table CSS class * * @param $classes string * @param $tableId int * @return string * * @since 1.0.0 * @access public */ public function addKeyTableClass(string $classes, int $tableId): string { $classes .= ' wdtKeyTable '; return $classes; } ... //plugin.php
Function that adds tab panel for Key Table Settings tab on the table configuration page.
... /** * Add tab panel for Key Table Settings tab on table configuration page * * @since 1.0.0 * @access public */ public function addKeyTableSettingsTabPanel() { ob_start(); include WPDATATABLES_KEY_TABLE_ADDON_ROOT_PATH . 'templates/wpdatatables-key-table-addon-settings-tabpanel.inc.php'; $keyTableSettingsTabPanel = ob_get_contents(); ob_end_clean(); echo $keyTableSettingsTabPanel; } ... //plugin.php
Function that adds Key Table Settings tab on the table configuration page.
... /** * Add Key Table Settings tab on table configuration page * * @since 1.0.0 * @access public */ public function addKeyTableSettingsTab() { ob_start(); include WPDATATABLES_KEY_TABLE_ADDON_ROOT_PATH . 'templates/wpdatatables-key-table-addon-settings-tab.inc.php'; $keyTableSettingsTab = ob_get_contents(); ob_end_clean(); echo $keyTableSettingsTab; } //plugin.php
Create template files.
In directory templates, files should be renamed. Rename the template PHP file wpdatatables-starter-addon-settings-tab.inc.php to wpdatatables-key-table-addon-settings-tab.inc.php and also template PHP file wpdatatables-starter-addon-settings-tabpanel.inc.php to wpdatatables-key-table-addon-settings-tabpanel.inc.php.
Content for extending new tab settings in wpDataTables settings should look like this:
<?php defined('ABSPATH') or die('Access denied.'); ?>
Content for extending new tab panel settings in wpDataTables settings should look like this:
<?php defined('ABSPATH') or die('Access denied.'); ?>//wpdatatables-key-table-addon-settings-tabpanel.inc.php<h4 class="c-title-color m-b-4 m-t-0"> <?php esc_html_e('Key Table option', 'wpdatatable-key-table-addon'); ?> </h4>
Create assets files
In directory assets are sub-directories css and js. Files should be renamed in both cases. Rename the CSS file wpdatatables-starter-addon.css to wpdatatables-key-table-addon.css. In js directory should be renamed file wpdatatables-starter-addon-backend.js to wpdatatables-key-table-addon-backend.js and also file wpdatatables-starter-addon-frontend.js to wpdatatables-key-table-addon-frontend.js.
Content for the CSS file is below and contains CSS rules for selected cells in tables with custom border color:
.wpdt-c table.wpDataTable.wdtKeyTable tbody th.keyCellFocus, .wpdt-c table.wpDataTable.wdtKeyTable tbody td.keyCellFocus { outline: 2px solid #3366ff !important; outline-offset: -2px !important; } .wpdt-c table.wpDataTable.wdtKeyTable tbody tr.selected th.keyCellFocus, .wpdt-c table.wpDataTable.wdtKeyTable tbody tr.selected td.keyCellFocus { outline-color: #0033cc !important; } div.dtk-focus-alt table.wpDataTable.wdtKeyTable tbody th.keyCellFocus, div.dtk-focus-alt table.wpDataTable.wdtKeyTable tbody td.keyCellFocus { outline: 2px solid #ff8b33 !important; outline-offset: -2px !important; } html.dark table.wpDataTable.wdtKeyTable tbody th.keyCellFocus, html.dark table.wpDataTable.wdtKeyTable tbody td.keyCellFocus { outline-color: rgb(13, 110, 253); } html.dark table.wpDataTable.wdtKeyTable tbody tr.selected th.keyCellFocus, html.dark table.wpDataTable.wdtKeyTable tbody tr.selected td.keyCellFocus { outline-color: #0143a3; } html.dark div.dtk-focus-alt table.wpDataTable.wdtKeyTable tbody th.keyCellFocus, html.dark div.dtk-focus-alt table.wpDataTable.wdtKeyTable tbody td.keyCellFocus { outline-color: #ff8b33; } /* wpdatatables-key-table-addon.css */
Content for the backend js file wpdatatables-key-table-addon-backend.js is below and shows how can be extended table settings.
(function ($) { $(function () { /** * Extend wpdatatable_config object with new properties and methods */ $.extend(wpdatatable_config, { keyTable: 0, setKeyTable: function (keyTable) { wpdatatable_config.keyTable = keyTable; $('#wpdatatables-key-table-addon-toggle').prop('checked', keyTable); } }); /** * Load the table for editing settings */ if (typeof wpdatatable_init_config !== 'undefined' && wpdatatable_init_config.advanced_settings !== '') { var wdtAdvancedSettings = JSON.parse(wpdatatable_init_config.advanced_settings); if (wdtAdvancedSettings !== null) { var keyTable = wdtAdvancedSettings.keyTable; if (typeof keyTable !== 'undefined') { wpdatatable_config.setKeyTable(keyTable); } } } /** * Toggle "Key Table" option */ $('#wpdatatables-key-table-addon-toggle').on('change', function () { wpdatatable_config.setKeyTable($(this).is(':checked') ? 1 : 0); }); }); })(jQuery); //wpdatatables-key-table-addon-backend.js
Content for frontend js file wpdatatables-key-table-addon-frontend.js is below and shows how KeyTable will automatically focus on a table cell when the table is loaded for server-side and non server-side datatables.
(function ($) { $(function () { $('table.wpDataTable:not(.wpdtSimpleTable)').each(function () { // Get each table description var tempTableDescription = JSON.parse($('#' + $(this).data('described-by')).val()); if (tempTableDescription.keyTable){ // By default, KeyTable will not automatically focus on a table cell when the table is loaded, // but rather it acts like a normal form element. // It will receive focus when clicked on or when tabbing through the document's form elements. // With this code it will be focused on first cell for non server-side tables $.each(tempTableDescription.dataTableParams.columnDefs, function (index) { if (tempTableDescription.dataTableParams.columnDefs[index].bVisible){ wpDataTables[tempTableDescription.tableId].api().cell(':eq(' + index + ')').focus(); return false; } }); // With this code it will be focused on first cell for server-side tables if (tempTableDescription.serverSide) { wpDataTables[tempTableDescription.tableId].fnSettings().aoDrawCallback.push({ sName: 'keyTableFocus', fn: function (oSettings) { $.each(oSettings.aoColumns, function (index) { if (oSettings.aoColumns[index].bVisible){ wpDataTables[tempTableDescription.tableId].api().cell(':eq(' + index + ')').focus(); return false; } }); } }); } } }); }) })(jQuery); //wpdatatables-key-table-addon-frontend.js
Conclusion
This documentation guide provides a detailed breakdown of each file for the wpDataTables Key Table Addon. By following the provided code samples and explanations, you can create a custom addon that extends wpDataTables functionality with the Key Table extension from the DataTables JS library or any other functionality or integration.