A clean, modern batch processing library for WordPress with real-time progress tracking and a beautiful modal UI.
- π Batch Processing - Process large datasets in manageable chunks
- π Real-time Progress - Live progress bar, counters, and activity log
- π― Modal UI - Professional, non-intrusive interface
- β‘ Performance - Handles thousands of items without timeout issues
- π Auto-refresh - Optional page reload after completion
- π Activity Log - Detailed logging with timestamps
- π Copy Log - One-click clipboard export for debugging
- β Error Tracking - Live failed counter and detailed error messages
composer require arraypress/wp-batch-syncuse ArrayPress\BatchSync\Manager;
$batch_sync = new Manager( 'my_sync' );$batch_sync->register( 'sync_products', [
'callback' => [ $this, 'sync_products_callback' ],
'title' => 'Sync Products',
'description' => 'Sync products from Stripe',
'button_text' => 'Start Sync',
'singular' => 'product',
'plural' => 'products',
'limit' => 10, // Items per batch
'auto_close' => true, // Auto-close modal on success
] );// In your admin page
$batch_sync->button( 'sync_products' );public function sync_products_callback( string $starting_after, int $limit, array $options ): array {
// Fetch your items (API, database, etc.)
$products = $this->get_products( $starting_after, $limit );
$results = [
'items' => [],
'has_more' => count( $products ) === $limit,
'last_id' => end( $products )['id'] ?? '',
'estimated_total' => 100, // Optional: total items count
];
foreach ( $products as $product ) {
$item = [
'id' => $product['id'],
'name' => $product['name'],
'error' => null
];
try {
// Process the item
$this->process_product( $product );
} catch ( Exception $e ) {
$item['error'] = $e->getMessage();
}
$results['items'][] = $item;
}
return $results;
}| Option | Type | Default | Description |
|---|---|---|---|
callback |
callable | required | Function to process each batch |
title |
string | 'Sync Data' | Modal title |
description |
string | '' | Optional description shown in modal |
button_text |
string | 'Sync Now' | Button text |
singular |
string | 'item' | Singular item name |
plural |
string | 'items' | Plural item name |
limit |
int | 10 | Items per batch |
capability |
string | 'manage_options' | Required user capability |
icon |
string | 'update' | Dashicon name (without 'dashicons-') |
auto_close |
bool | false | Auto-close modal and refresh on success |
notice_target |
string | '.wrap h1' | CSS selector for success notice placement |
Your callback must return an array with:
[
'items' => [ // Array of processed items
[
'id' => '123', // Item identifier
'name' => 'Item Name', // Display name
'error' => null // Error message or null
],
// ... more items
],
'has_more' => true, // Are there more items to process?
'last_id' => '123', // Last processed ID (for pagination)
'estimated_total' => 100, // Optional: Total items (for progress bar)
]- User clicks button β Modal opens
- User starts sync β Button shows spinning icon
- First batch β Callback returns items +
estimated_total - Progress updates β UI shows: "10 / 100" (10%)
- Next batch β Uses
last_idfor pagination - Repeats β Until
has_moreis false - Completion β Shows summary, copy log button appears
PROGRESS PROCESSED FAILED
45% 45 / 100 2
Real-time updates with timestamps:
01:23:45 β Product ABC synced
01:23:46 β Product XYZ - API error
- β Success: "Sync complete! 100 products synced."
β οΈ Partial: "Sync complete! 100 products processed. 97 succeeded, 3 failed."
public function sync_stripe_products( string $starting_after, int $limit, array $options ): array {
\Stripe\Stripe::setApiKey( STRIPE_SECRET_KEY );
$params = [ 'limit' => $limit ];
if ( $starting_after ) {
$params['starting_after'] = $starting_after;
}
$products = \Stripe\Product::all( $params );
$results = [
'items' => [],
'has_more' => $products->has_more,
'last_id' => $products->data ? end( $products->data )->id : '',
'estimated_total' => 100, // Or fetch from Stripe
];
foreach ( $products->data as $product ) {
$item = [
'id' => $product->id,
'name' => $product->name,
'error' => null
];
try {
// Create/update WooCommerce product
$wc_product_id = $this->create_wc_product( $product );
update_post_meta( $wc_product_id, '_stripe_product_id', $product->id );
} catch ( Exception $e ) {
$item['error'] = $e->getMessage();
}
$results['items'][] = $item;
}
return $results;
}- API calls: 10-20 items (avoid rate limits)
- Database operations: 50-100 items
- Heavy processing: 5-10 items
try {
$this->process_item( $item );
} catch ( Exception $e ) {
// Return error in item, don't throw
$item['error'] = $e->getMessage();
}- Use
estimated_totalfor accurate progress - Add small delays for API calls:
usleep(50000)(50ms) - Process in manageable chunks
- Don't process all data at once
- Set
auto_close => truefor simple syncs - Use clear, descriptive messages
- Provide estimated totals when possible
- Test with failures to see error handling
- WordPress 5.0+
- PHP 7.4+
- jQuery (included with WordPress)
MIT
For issues and feature requests, please use GitHub issues.