PHPackages                             arraypress/wp-inline-sync - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. arraypress/wp-inline-sync

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

arraypress/wp-inline-sync
=========================

Lightweight WordPress library for inline batch sync operations with progress UI. Register sync operations that run directly on existing admin screens.

08PHP

Since Mar 3Pushed 2mo agoCompare

[ Source](https://github.com/arraypress/wp-inline-sync)[ Packagist](https://packagist.org/packages/arraypress/wp-inline-sync)[ RSS](/packages/arraypress-wp-inline-sync/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependenciesVersions (1)Used By (0)

WP Inline Sync
==============

[](#wp-inline-sync)

A lightweight WordPress library for inline batch sync operations with progress UI. Register sync operations that run directly on existing admin screens — no separate pages, no stats storage, no complexity.

Features
--------

[](#features)

- **Inline progress bar** — renders above your admin table with real-time progress
- **Current item display** — shows the name of each item as it's processed
- **Auto-binding buttons** — output a trigger button, the JS handles everything
- **Single REST endpoint** — one endpoint serves all registered syncs
- **Cursor-based pagination** — works with any API that supports cursor pagination
- **Cancel support** — users can cancel mid-sync
- **Dismissable notices** — completion summary disappears on click or page refresh
- **No persistence** — nothing stored in the database, refresh and it's gone

Requirements
------------

[](#requirements)

- PHP 8.1+
- WordPress 6.0+

Installation
------------

[](#installation)

```
composer require arraypress/wp-inline-sync
```

Quick Start
-----------

[](#quick-start)

### 1. Register a sync

[](#1-register-a-sync)

```
register_sync( 'stripe_prices', [
    'hook_suffix'      => 'toplevel_page_sugarcart',
    'title'            => __( 'Sync Prices', 'my-plugin' ),
    'button_label'     => __( 'Sync from Stripe', 'my-plugin' ),
    'container'        => '.wp-list-table',
    'data_callback'    => 'MyPlugin\fetch_prices',
    'process_callback' => 'MyPlugin\process_price',
    'name_callback'    => fn( $item ) => $item->product->name ?? $item->id,
] );
```

### 2. Output the trigger button

[](#2-output-the-trigger-button)

```
// In your admin screen
render_sync_button( 'stripe_prices' );
```

That's it. The button renders with data attributes, the JS auto-binds on click, and the progress bar appears above your table.

Configuration
-------------

[](#configuration)

KeyTypeDefaultDescription`hook_suffix``string|array``''`Admin screen hook suffix(es) where assets should load.`capability``string``'manage_options'`Required user capability.`title``string``''`Display title shown in the progress bar header.`button_label``string``'Sync'`Text for the trigger button.`button_class``string``'button'`CSS class(es) for the trigger button.`container``string``'.wp-list-table'`CSS selector — progress bar inserts before this element.`data_callback``callable``null`Fetches items. Receives `(string $cursor)`.`process_callback``callable``null`Processes one item.`name_callback``callable|null``null`Extracts a display name from an item.Callbacks
---------

[](#callbacks)

### data\_callback

[](#data_callback)

Fetches a batch of items from your data source. Receives the cursor string (empty on first call). You control the batch size internally.

```
function fetch_prices( string $cursor ): array {
    $params = [
        'limit'  => 100,
        'active' => true,
    ];

    if ( $cursor ) {
        $params['starting_after'] = $cursor;
    }

    $prices = $stripe->prices->all( $params );
    $last   = end( $prices->data );

    return [
        'items'    => $prices->data,
        'has_more' => $prices->has_more,
        'cursor'   => $last ? $last->id : '',
        'total'    => null, // null if unknown
    ];
}
```

**Return format:**

KeyTypeDescription`items``array`Items to process this batch.`has_more``bool`Whether more batches remain.`cursor``string`Cursor to pass on next call.`total``int|null`Total item count if known (enables % progress).### process\_callback

[](#process_callback)

Processes a single item. Called once per item in the batch.

```
function process_price( object $item ): string|WP_Error {
    $existing = get_price_by_stripe_id( $item->id );

    if ( $existing ) {
        update_price( $existing->id, [ /* ... */ ] );
        return 'updated';
    }

    add_price( [ /* ... */ ] );
    return 'created';
}
```

**Return values:**

ValueMeaning`'created'`Item was newly created`'updated'`Item was updated`'skipped'`Item was skipped`WP_Error`Item failed### name\_callback

[](#name_callback)

Optional. Extracts a display name from an item for the progress UI. If not provided, the library guesses by checking common fields (`name`, `title`, `label`, `email`, `id`).

```
'name_callback' => fn( $item ) => $item->product->name ?? $item->id,
```

Functions
---------

[](#functions)

### register\_sync

[](#register_sync)

```
register_sync( string $id, array $config ): Sync
```

Register an inline sync operation.

### get\_sync

[](#get_sync)

```
get_sync( string $id ): ?Sync
```

Retrieve a registered sync instance.

### has\_sync

[](#has_sync)

```
has_sync( string $id ): bool
```

Check if a sync is registered.

### render\_sync\_button

[](#render_sync_button)

```
render_sync_button( string $id, array $args = [] ): void
```

Output a trigger button. Accepts optional overrides for `label`, `class`, and `container`.

### get\_sync\_button

[](#get_sync_button)

```
get_sync_button( string $id, array $args = [] ): string
```

Returns the button HTML instead of echoing it.

JavaScript API
--------------

[](#javascript-api)

The JS auto-binds to `.inline-sync-trigger` buttons. For programmatic control:

```
// Start a sync manually
InlineSync.start('stripe_prices');

// Cancel a running sync
InlineSync.cancel('stripe_prices');
```

### Events

[](#events)

Events are fired on `$(document)`:

EventArgumentsDescription`inline-sync:complete``syncId, totals`Sync finished`inline-sync:cancelled``syncId`User cancelled`inline-sync:error``syncId, message`Sync failed```
$(document).on('inline-sync:complete', function (e, syncId, totals) {
    if (syncId === 'stripe_prices') {
        // Reload the table
        location.reload();
    }
});
```

Multiple Syncs
--------------

[](#multiple-syncs)

Register each sync separately. They can target the same screen:

```
register_sync( 'stripe_prices', [
    'hook_suffix'      => 'toplevel_page_my-plugin',
    'title'            => 'Sync Prices',
    'button_label'     => 'Sync Prices',
    'data_callback'    => 'fetch_prices',
    'process_callback' => 'process_price',
] );

register_sync( 'stripe_customers', [
    'hook_suffix'      => 'my-plugin_page_customers',
    'title'            => 'Sync Customers',
    'button_label'     => 'Sync Customers',
    'data_callback'    => 'fetch_customers',
    'process_callback' => 'process_customer',
] );
```

Progress Bar Behavior
---------------------

[](#progress-bar-behavior)

**During sync:** Blue left border, progress track with fill, item count, current item name, cancel button.

**On completion:** Green left border, summary line (e.g., "120 items synced — 3 created, 115 updated, 2 skipped"), dismiss button. First 3 error messages shown inline if any items failed.

**On error/cancel:** Red left border, error message or "Sync cancelled", dismiss button.

**On dismiss or page refresh:** Gone. Nothing persisted.

License
-------

[](#license)

GPL-2.0-or-later

###  Health Score

20

—

LowBetter than 14% of packages

Maintenance56

Moderate activity, may be stable

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity12

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/cd6eb8aff0903d87eb674d1ba3c5f3653899c0d7661504eb0deb7798ed86b643?d=identicon)[arraypress](/maintainers/arraypress)

---

Top Contributors

[![arraypress](https://avatars.githubusercontent.com/u/22668877?v=4)](https://github.com/arraypress "arraypress (7 commits)")

### Embed Badge

![Health badge](/badges/arraypress-wp-inline-sync/health.svg)

```
[![Health](https://phpackages.com/badges/arraypress-wp-inline-sync/health.svg)](https://phpackages.com/packages/arraypress-wp-inline-sync)
```

###  Alternatives

[olivestudio/craft-olivemenus

A powerful menus plugin for Craft 4 built for the need of simplicity and flexibility

3918.9k1](/packages/olivestudio-craft-olivemenus)[humanmade/block-supports-extended

Block supports extension helpers

123.5k](/packages/humanmade-block-supports-extended)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
