Subscriptions Batch Table Implementation
Overview
The subscriptions batch table is implemented using the DataTables library to provide a dynamic, server-side processed table for managing shipping batches. This implementation includes features like inline editing, reshipping capabilities, and real-time data updates.
Table Structure
Frontend Template
The table is rendered using a PHP template that defines the basic structure:
<table id='table-batch' class='display' data-batch-id='<?php echo $batch_id?>'>
<thead>
<tr>
<?php foreach ($columns as $key => $column) {
printf('<th>%1$s</th>', $column);
} ?>
</tr>
</thead>
<tfoot>
<tr>
<?php foreach ($columns as $key => $column) {
printf('<th>%1$s</th>', $column);
} ?>
</tr>
</tfoot>
</table>
Column Definitions
The table includes the following columns:
$columns = array(
'_actions' => __('Actions', 'tsj-subscriptions'),
'_subscription_id' => __('Sub #', 'tsj-subscriptions'),
'_quantity' => __('Quantity', 'tsj-subscriptions'),
'_first_name' => __('First Name', 'tsj-subscriptions'),
'_last_name' => __('Last Name', 'tsj-subscriptions'),
'_company' => __('Company', 'tsj-subscriptions'),
'_address_1' => __('Address 1', 'tsj-subscriptions'),
'_address_2' => __('Address 2', 'tsj-subscriptions'),
'_city' => __('City', 'tsj-subscriptions'),
'_state' => __('State', 'tsj-subscriptions'),
'_postcode' => __('Postcode', 'tsj-subscriptions'),
'_country' => __('Country', 'tsj-subscriptions'),
'_country_name' => __('Country Name', 'tsj-subscriptions'),
'_reship' => __('Reship', 'tsj-subscriptions'),
'_reship_reason' => __('Reship Reason', 'tsj-subscriptions'),
'_sku' => __('SKU', 'tsj-subscriptions'),
'_first_issue' => __('First Issue', 'tsj_subscriptions'),
'_last_issue' => __('Last Issue', 'tsj-subscriptions'),
'_gifted' => __('Gifted', 'tsj-subscriptions'),
'_comp' => __('Comp', 'tsj-subscriptions'),
'_special' => __('Special', 'tsj-subscriptions'),
'_premium' => __('Premium', 'tsj-subscriptions'),
'_concierge' => __('Concierge', 'tsj-subscriptions'),
'_concierge_notes' => __('Concierge Notes', 'tsj-subscriptions'),
'_customer_note' => __('Customer Note', 'tsj-subscriptions'),
);
JavaScript Implementation
The table is initialized with the following configuration:
var table = $('#table-batch').DataTable({
columns: [
{data: '_actions'},
{data: '_subscription_id'},
{data: '_quantity'},
// ... other columns
],
serverSide: true,
scrollX: true,
searchDelay: 1000,
ordering: false,
ajax: {
url: tsj_subscriptions_public.ajaxurl,
data: function(d) {
d.action = 'tsj_subscriptions_batch_get_data';
d.shipping_batch_id = $('#table-batch').data('batch-id');
}
}
});
Inline Editing
The table supports inline editing using DataTables Editor:
var editor = new $.fn.dataTable.Editor({
table: '#table-batch',
idSrc: "id",
ajax: {
url: tsj_subscriptions_public.ajaxurl,
data: function(d) {
d.action = 'tsj_subscriptions_batch_get_data';
d.shipping_batch_id = $('#table-batch').data('batch-id');
}
}
});
$('#table-batch').on('click', 'tbody td:not(:first-child)', function(e) {
editor.inline(this);
});
Reshipping Functionality
The table includes a reshipping feature:
$.fn.dataTable.ext.buttons.reship = {
text: 'Reship',
extend: 'selectedSingle',
action: function(e, dt, node, config) {
var data = table.row('.selected').data();
reshipDialog.foundation('open');
}
};
Server-Side Processing
Data Retrieval
The server-side processing is handled by the TSJ_Subscriptions_Batch_Table
class:
public function get_data() {
$draw = intval($_GET['draw']);
$per_page = intval($_GET['length']);
$offset = intval($_GET['start']);
$this->batch_id = intval($_GET['shipping_batch_id']);
$shipping_batch = new TSJ_Shipping_Batch($this->batch_id);
$this->issue_id = $shipping_batch->get_issue_id();
$this->editable = $shipping_batch->get_batch_status() != 'shipped';
$this->reshippable = (($shipping_batch->get_batch_status() == 'shipped'));
$data = array();
$search_term = isset($_GET['search']['value']) ? $_GET['search']['value'] : '';
$batch_subscriptions = tsj_get_shipping_list(
$this->batch_id,
$offset,
$per_page,
'all',
$search_term
);
// Process and format data
foreach ($batch_subscriptions as $batch_subscription) {
$item = array();
foreach ($this->columns as $key => $column) {
if ($key == '_actions') continue;
$func = 'get' . $key;
$item[$key] = $batch_subscription->{$func}();
}
$actions = $this->get_actions(
$batch_subscription->get_id(),
$batch_subscription->get_subscription_id()
);
$item['_actions'] = $actions;
$item['_country_name'] = $batch_subscription->get_country_name();
$item['id'] = $batch_subscription->get_id();
$data[] = $item;
}
$total = tsj_get_shipping_list_count($this->batch_id);
return array(
'draw' => $draw,
'recordsTotal' => $total,
'recordsFiltered' => $total,
'data' => $data
);
}
Action Handling
The table supports various actions through the get_actions
method:
protected function get_actions($batch_subscription_id, $subscription_id) {
$actions = '';
if ($this->editable) {
$remove_link = add_query_arg(array(
'batch_subscription_action' => 'remove',
'batch_subscription_id' => $batch_subscription_id,
), $this->batch_subscription_url);
$edit_link = add_query_arg(array(
'batch_subscription_action' => 'edit',
'batch_subscription_id' => $batch_subscription_id,
), $this->batch_subscription_url);
$actions .= sprintf('<a href="%s">Edit</a>', $edit_link);
$actions .= sprintf('<a href="%s">Remove</a>', $remove_link);
}
if ($this->reshippable) {
$reship_link = add_query_arg(array(
'reship_action' => 'create',
'issue_id' => $this->issue_id,
'subscription_id' => $subscription_id,
'batch_id' => $this->batch_id
), $this->reship_url);
$actions .= sprintf('<a href="%s">Reship</a>', $reship_link);
$actions = sprintf('<span class="actions">%s</span>', $actions);
}
return $actions;
}
Best Practices
Performance Optimization
- Server-side processing for large datasets
- Search delay implementation to reduce server load
- Proper indexing on database tables
User Experience
- Inline editing for quick updates
- Clear action buttons with appropriate permissions
- Responsive design with horizontal scrolling
Data Integrity
- Validation of input data
- Proper error handling
- Status-based action availability
Security
- Nonce verification for actions
- Permission checks for editing
- Input sanitization
Usage Example
To implement a similar table:
- Include required scripts and styles:
wp_enqueue_script('datatables');
wp_enqueue_style('datatables');
wp_enqueue_script('journal-batch-table');
- Initialize the table class:
$table = TSJ_Subscriptions_Batch_Table::get_instance();
- Create the table HTML structure:
<table id='table-batch' class='display' data-batch-id='<?php echo $batch_id?>'>
<!-- Table structure -->
</table>
- The JavaScript will automatically initialize the DataTable with the configured options.