Files
ladill-woo-manager/app/Services/Woo/ProductIngestService.php
T
isaaccladandCursor 085645fd0f
Deploy Ladill Woo Manager / deploy (push) Successful in 24s
Add WooCommerce-style featured image and product gallery flow.
Sync full image sets through the plugin, with upload/URL support in the product editor and thumbnails in the list.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 00:27:11 +00:00

100 lines
3.6 KiB
PHP

<?php
namespace App\Services\Woo;
use App\Models\WooProduct;
use App\Models\WooStore;
use Carbon\Carbon;
class ProductIngestService
{
/** @param array<string, mixed> $payload */
public function ingest(WooStore $store, array $payload): WooProduct
{
$externalId = (int) ($payload['id'] ?? 0);
if ($externalId === 0) {
throw new \InvalidArgumentException('WooCommerce product id missing.');
}
$regular = $this->priceMinor($payload['regular_price'] ?? null);
$sale = $this->priceMinor($payload['sale_price'] ?? null);
$images = collect((array) ($payload['images'] ?? []))
->map(fn (array $image, int $index) => [
'id' => (int) ($image['id'] ?? 0),
'src' => (string) ($image['src'] ?? ''),
'alt' => (string) ($image['alt'] ?? ''),
'position' => (int) ($image['position'] ?? $index),
])
->filter(fn (array $image) => $image['src'] !== '' || $image['id'] > 0)
->sortBy('position')
->values()
->all();
$categoryIds = collect((array) ($payload['categories'] ?? []))
->map(fn (array $category) => (int) ($category['id'] ?? 0))
->filter(fn (int $id) => $id > 0)
->values()
->all();
return WooProduct::query()->updateOrCreate(
[
'woo_store_id' => $store->id,
'external_id' => $externalId,
],
[
'name' => (string) ($payload['name'] ?? 'Product'),
'slug' => (string) ($payload['slug'] ?? 'product-'.$externalId),
'sku' => $this->nullableString($payload['sku'] ?? null),
'status' => (string) ($payload['status'] ?? WooProduct::STATUS_DRAFT),
'type' => (string) ($payload['type'] ?? 'simple'),
'regular_price_minor' => $regular,
'sale_price_minor' => $sale,
'stock_quantity' => isset($payload['stock_quantity']) ? (int) $payload['stock_quantity'] : null,
'manage_stock' => (bool) ($payload['manage_stock'] ?? false),
'category_external_ids' => $categoryIds,
'images' => $images,
'short_description' => $this->nullableString($payload['short_description'] ?? null),
'description' => $this->nullableString($payload['description'] ?? null),
'wc_updated_at' => $this->updatedAt($payload),
'metadata' => [
'permalink' => $payload['permalink'] ?? null,
'featured' => (bool) ($payload['featured'] ?? false),
],
],
);
}
public function delete(WooStore $store, int $externalId): void
{
WooProduct::query()
->where('woo_store_id', $store->id)
->where('external_id', $externalId)
->delete();
}
private function priceMinor(mixed $value): ?int
{
if ($value === null || $value === '') {
return null;
}
return (int) round(((float) $value) * 100);
}
/** @param array<string, mixed> $payload */
private function updatedAt(array $payload): ?Carbon
{
$raw = $payload['date_modified_gmt'] ?? $payload['date_modified'] ?? null;
return is_string($raw) && $raw !== '' ? Carbon::parse($raw) : null;
}
private function nullableString(mixed $value): ?string
{
$text = trim(strip_tags((string) $value));
return $text === '' ? null : $text;
}
}