Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Release Notes for Shopify

## Unreleased

- Added `craft\shopify\records\ShopifyData::$position`.
- Fixed a bug where product images, variants, and metafields were synced in reverse order. ([#161](https://github.com/craftcms/shopify/issues/161))

## 8.2.0 - 2026-10-08

- Improved the memory usage of bulk operation processing.
Expand Down Expand Up @@ -95,6 +100,11 @@ See [Upgrading](https://github.com/craftcms/shopify/blob/8.x/README.md#upgrading
- Fixed a bug where validation errors for the “Context Pricing Countries” setting weren’t displaying correctly.
- Fixed a bug where `inventory_levels/update` webhooks weren’t triggering a product sync.

## 7.3.1 - 2026-10-19

- Added `craft\shopify\records\ShopifyData::$position`.
- Fixed a bug where product images, variants, and metafields were synced in reverse order. ([#161](https://github.com/craftcms/shopify/issues/161))

## 7.3.0 - 2026-10-08

- Improved the memory usage of bulk operation processing.
Expand Down
2 changes: 1 addition & 1 deletion src/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class Plugin extends BasePlugin
/**
* @var string
*/
public string $schemaVersion = '8.1.0';
public string $schemaVersion = '8.2.1.0';

/**
* @inheritdoc
Expand Down
1 change: 1 addition & 0 deletions src/jobs/ProcessBulkOperationData.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ protected function processItem(mixed $item): void
$record->type = $type;
$record->data = $item;
$record->parentId = $item['__parentId'] ?? null;
$record->position = $this->objectCount > 0 ? $this->objectCount - 1 - $this->itemOffset : null;
$record->save();

// Process the data based on the type
Expand Down
1 change: 1 addition & 0 deletions src/migrations/Install.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ public function createTables(): void
'type' => $this->string(),
'data' => $this->json(),
'parentId' => $this->string(),
'position' => $this->integer(),
'dateCreated' => $this->dateTime()->notNull(),
'dateUpdated' => $this->dateTime()->notNull(),
'uid' => $this->uid(),
Expand Down
33 changes: 33 additions & 0 deletions src/migrations/m261016_090000_add_position_to_data_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace craft\shopify\migrations;

use craft\db\Migration;
use craft\shopify\db\Table;

/**
* m261016_090000_add_position_to_data_table migration.
*/
class m261016_090000_add_position_to_data_table extends Migration
{
/**
* @inheritdoc
*/
public function safeUp(): bool
{
if (!$this->db->columnExists(Table::DATA, 'position')) {
$this->addColumn(Table::DATA, 'position', $this->integer()->after('parentId'));
}

return true;
}

/**
* @inheritdoc
*/
public function safeDown(): bool
{
echo "m261016_090000_add_position_to_data_table cannot be reverted.\n";
return false;
}
}
1 change: 1 addition & 0 deletions src/records/ShopifyData.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* @property string $type
* @property string|array $data
* @property string $parentId
* @property int|null $position The line index of the item in its bulk operation file (since 7.3.1)
* @property string $dateCreated
* @property string $dateUpdated
* @property string $uid
Expand Down
2 changes: 1 addition & 1 deletion src/services/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ public function getShopifyDataByType(string $type, array|string|null|false $pare

$data = ShopifyData::find()
->where($criteria)
->orderBy(['id' => SORT_ASC])
->orderBy(['position' => SORT_ASC, 'id' => SORT_ASC])
->collect();

// The caller can request the raw database rows, instead of just the `data` JSON column:
Expand Down
24 changes: 24 additions & 0 deletions tests/unit/jobs/ProcessBulkOperationDataTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,30 @@ public function testExecuteProcessesEveryLineOnceAcrossBatches(): void
self::assertEquals(58, ShopifyData::find()->where(['parentId' => $productGid])->count());
}

public function testExecuteStoresChildrenInTheOrderTheyAppearInTheFile(): void
{
$productGid = 'gid://shopify/Product/order-test-001';
$imageGids = [];
$lines = [json_encode(['id' => $productGid])];
foreach (range(1, 5) as $i) {
$imageGids[] = "gid://shopify/MediaImage/order-test-$i";
$lines[] = json_encode(['id' => end($imageGids), '__parentId' => $productGid]);
}

$filePath = Assets::tempFilePath('jsonl');
file_put_contents($filePath, implode("\n", $lines) . "\n");

Plugin::getInstance()->set('products', $this->makeEmpty(Products::class, [
'createOrUpdateProduct' => true,
]));

$this->_runJob($this->_makeExecutableJob($filePath, count($lines), 'all', batchSize: 2));

$images = Plugin::getInstance()->getApi()->getShopifyDataByType('MediaImage', $productGid);

self::assertSame($imageGids, $images->pluck('id')->all());
}

/**
* A TTR of zero makes every batch stop after its first item, leaving the rest of its slice unprocessed.
*/
Expand Down
Loading