PHPackages                             tombroucke/wp-sync-posts - 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. tombroucke/wp-sync-posts

ActiveLibrary

tombroucke/wp-sync-posts
========================

Sync external posts and products to WordPress &amp; WooCommerce

2.4.3(1y ago)3854↓100%12MITPHP

Since Oct 19Pushed 6mo ago2 watchersCompare

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

READMEChangelogDependencies (3)Versions (13)Used By (2)

WP Sync Posts
=============

[](#wp-sync-posts)

Synchronise posts between an external provider (API, .csv, ...) and WordPress.

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

[](#installation)

```
composer require tombroucke/wp-sync-posts

```

Usage
-----

[](#usage)

### Basic usage

[](#basic-usage)

```
$syncer = new \Otomaties\WpSyncPosts\Syncer('post');

$externalPosts = [
	[
		'title' => 'API post 1 title',
		'id' => 'api-post-1',
	],
	[
		'title' => 'API post 2 title',
		'id' => 'api-post-2',
	],
];

foreach ($externalPosts as $externalPost) {
	$args = [
		'post_title' => $externalPost['title'],
		'meta_input' => [
			'external_id' => $externalPost['id'],
		],
	];

	$existingPostQuery = [
		'by' => 'meta_value',
		'key' => 'external_id',
		'value' => $externalPost['id'],
	];

	$syncer->addPost($args, $existingPostQuery);
}

$syncer->execute();
```

### Advanced usage

[](#advanced-usage)

#### Media

[](#media)

This library can import external media to the media library

```
$args = [
	'post_title' => $externalPost['title'],
	'meta_input' => [
		'external_id' => $externalPost['id'],
	],
	'media' => [
		[
			'url' => $externalPost['thumbnail']['url'],
			'featured' => true,
            'date_modified' => gmdate('Y-m-d H:i:s', $externalPost['thumbnail']['date_modified']), // If this field changes, the old media gets deleted and the new one is downloaded
		],
		[
			'url' => $externalPost['floor_plan']['url'],
            'date_modified' => gmdate('Y-m-d H:i:s', $externalPost['floor_plan']['date_modified']),
			'key' => 'floor_plan', // You can get this media using get_post_meta($postId, 'floor_plan', true);
			'group' => 'documents' // You can fetch all media for this post in this group using get_post_meta($postId, 'documents', true); Defaults to 'synced_images'
		],
	],
]
```

#### Meta

[](#meta)

You can add additional post meta in the meta\_input field

```
$args = [
	'post_title' => $externalPost['title'],
	'meta_input' => [
		'external_id' => $externalPost['id'],
		'key' => 'value'
	],
]
```

#### Taxonomy

[](#taxonomy)

You can assign posts to taxonomies using the tax\_input field

```
$args = [
	'post_title' => $externalPost['title'],
	'meta_input' => [
		'external_id' => $externalPost['id'],
	],
	'tax_input' => [
		'custom_taxonomy' => [16, 57],
	],
]
```

#### Callbacks

[](#callbacks)

You can use callbacks in post arguments.

```
$args = [
	'post_title' => $externalPost['title'],
	'post_status' => fn (\Otomaties\WpSyncPosts\Post $post) => $post->id() ? 'publish' : 'draft', // publish if post exists, draft if it doesn't
	'meta_input' => [
		'external_id' => $externalPost['id'],
	],
]
```

#### WPML support

[](#wpml-support)

```
$args = [
	'post_title' => $externalPost['title'],
	'meta_input' => [
		'external_id' => $externalPost['id'],
	],
	'lang'                          => $externalPost['language'],
	'wpml_reference'                => $externalPost['id'] . '_' . $externalPost['language'],
	'wpml_original_post_reference'  => $externalPost['id'] . '_' . 'en',
];
```

#### WooCommerce Products

[](#woocommerce-products)

```
use \Otomaties\WpSyncPosts\Syncer;

$syncer = new Syncer('product');

$externalPosts = [
	[
		'title' => 'API post 1 title',
		'id' => 'api-post-1',
		'product_type' => 'simple',
		'sku' => 'API-POST-1-SKU',
	],
	[
		'title' => 'API post 2 title',
		'id' => 'api-post-2',
		'product_type' => 'variable',
		'available_attributes' => ['color', 'size'],
		'sku' => 'API-POST-2-SKU',
		'variations' => [
			[
				'attributes' => [
					'color' => 'Blellow',
					'size' => 'M',
				],
				'price' => 29.99,
				'sku' => 'API-POST-2-RED-M',
				'stockQuantity' => 10,
				'weight' => 0.5,
				'length' => 10,
				'width' => 5,
				'height' => 2,
				'description' => 'Red Medium variation',
				'backorders' => 'no',
				'thumbnail' => [
					'url' => 'https://via.placeholder.com/800x600.png?text=Variation+1',
					'date_modified' => time(),
				],
			],
			[
				'attributes' => [
					'color' => 'Black',
					'size' => 'L',
				],
				'price' => 34.99,
				'sku' => 'API-POST-2-BLUE-L',
				'stockQuantity' => 5,
				'weight' => 0.6,
				'length' => 12,
				'width' => 6,
				'height' => 3,
				'description' => 'Blue Large variation',
				'backorders' => 'yes',
				'thumbnail' => [
					'url' => 'https://via.placeholder.com/800x600.png?text=Variation+2',
					'date_modified' => time(),
				],
			],
		],
	],
];

foreach ($externalPosts as $externalPost) {
	$existingVariationQuery = [];

	$args = [
		'post_title' => $externalPost['title'],
		'meta_input' => [
			'test' => 'value2',
			'external_id' => $externalPost['id'],
		],
		'woocommerce' => [
			'product_type' => $externalPost['product_type'], // string: 'variable', 'simple', ...
			'meta_input' => [
				'_sku' => $externalPost['sku'],
			],
		],
	];

	if ($externalPost['product_type'] === 'variable') {

		$args['woocommerce']['available_attributes'] = $externalPost['available_attributes'];
		$args['woocommerce']['variations'] = [];

		foreach(($externalPost['variations'] ?? []) as $variation) {
			$args['woocommerce']['variations'][] = [
				'woocommerce' => [
					'attributes' => [
						'color' => $variation['attributes']['color'], // string
						'size' => $variation['attributes']['size'], // string
					],
					'meta_input' => [
						'_regular_price' => $variation['price'], // float
						'_sku' => $variation['sku'], // string
						'_stock' => $variation['stockQuantity'], // int
						'_weight' => $variation['weight'], // float
						'_length' => $variation['length'], // float
						'_width' => $variation['width'], // float
						'_height' => $variation['height'], // float
						'_variation_description' => $variation['description'],
						'_backorders' => $variation['backorders'], // 'yes' or 'no'
					]
				],
				'media' => [
					[
						'key'           => false,
						'featured'      => true,
						'url'           => $variation['thumbnail']['url'], // String e.g. 'https://via.placeholder.com/800x600.png?text=Variation+4'
						'date_modified' => gmdate('Y-m-d H:i:s', $variation['thumbnail']['date_modified']),
					],
				],
			];
		}

		$existingVariationQuery = [
			'by' => 'sku',
		];
	}

	$existingPostQuery = [
		'by'    => 'meta_value', // id, meta_value, sku
		'key'   => 'external_id', // Only if 'by' => 'meta_value'
		'value' => $externalPost['id'], // Unique value to identify this post
	];
	$syncer->addProduct($args, $existingPostQuery, $existingVariationQuery);
}

$syncer->execute();
```

###  Health Score

41

—

FairBetter than 88% of packages

Maintenance58

Moderate activity, may be stable

Popularity21

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity60

Established project with proven stability

 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.

###  Release Activity

Cadence

Every ~136 days

Recently: every ~60 days

Total

12

Last Release

523d ago

Major Versions

1.0.1 → 2.0.02022-08-25

### Community

Maintainers

![](https://www.gravatar.com/avatar/4178291ccf36e3530aa8a8845124c3af1b24c064739ad98ded5b9679a4316033?d=identicon)[tombroucke](/maintainers/tombroucke)

---

Top Contributors

[![tombroucke](https://avatars.githubusercontent.com/u/24292260?v=4)](https://github.com/tombroucke "tombroucke (34 commits)")

###  Code Quality

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/tombroucke-wp-sync-posts/health.svg)

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

###  Alternatives

[league/flysystem

File storage abstraction for PHP

13.6k639.1M2.1k](/packages/league-flysystem)[livewire/livewire

A front-end framework for Laravel.

23.5k75.5M1.8k](/packages/livewire-livewire)[league/flysystem-aws-s3-v3

AWS S3 filesystem adapter for Flysystem.

1.6k263.6M782](/packages/league-flysystem-aws-s3-v3)[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[league/flysystem-local

Local filesystem adapter for Flysystem.

226231.8M39](/packages/league-flysystem-local)[league/flysystem-sftp-v3

SFTP filesystem adapter for Flysystem.

6129.6M91](/packages/league-flysystem-sftp-v3)

PHPackages © 2026

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