<?php if (!defined('DASHBOARD_ROOT')) { define('DASHBOARD_ROOT', dirname(__DIR__, 2)); require_once DASHBOARD_ROOT . '/core/bootstrap.php'; } header('Content-Type: application/json'); if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); exit(json_encode(['ok' => false, 'error' => 'Method not allowed'])); } CSRF::enforce(); RBAC::enforce('create.content'); $raw = file_get_contents('php://input'); $input = json_decode($raw, true); if (!$input || empty($input['slots'])) { http_response_code(400); exit(json_encode(['ok' => false, 'error' => 'Invalid payload'])); } $storeId = (int)($input['store_id'] ?? 0); $slots = $input['slots'] ?? []; $columns = max(1, min(4, count($slots))); $productCount = 0; $contentCount = 0; foreach ($slots as $s) { if (($s['type'] ?? 'product') === 'product') $productCount++; else $contentCount++; } $usedByProducts = $productCount; $remainingCols = max(1, 4 - $usedByProducts); $contentSlotSize = $contentCount > 0 ? max(1, (int)floor($remainingCols / $contentCount)) : 1; $contentLeftover = $contentCount > 0 ? $remainingCols - ($contentSlotSize * $contentCount) : 0; $contentBlockIndex = 0; require_once DASHBOARD_ROOT . '/core/action_chain.php'; $aid = $_SESSION['admin_id'] ?? 0; $created = []; $currentMax = 0; try { $currentMax = (int)Database::scalar( "SELECT COALESCE(MAX(display_order), 0) FROM storefront_blocks WHERE store_id = :s", [':s' => $storeId] ); $currentCatMax = (int)Database::scalar( "SELECT COALESCE(MAX(display_order), 0) FROM categories WHERE store_id = :s", [':s' => $storeId] ); } catch (\Throwable $e) {} $nextCatOrder = ($currentCatMax ?? 0) + 1; $nextBlkOrder = ($currentMax ?? 0) + 1; $totalSlotSize = 0; foreach ($slots as $slot) { $totalSlotSize += (int)($slot['slot_size'] ?? 1); } $rowComplete = ($totalSlotSize % 4 === 0); $statusCode = $rowComplete ? 6002 : 6001; $categoryId = null; $productSlots = array_filter($slots, fn($s) => ($s['type'] ?? '') === 'product'); $categoryName = trim($input['category_name'] ?? ''); if (!empty($productSlots) && $categoryName !== '') { $catResult = ActionChain::execute('product_categories', 0, [ 'store_id' => $storeId, 'name' => $categoryName, 'nickname' => $categoryName, 'slug' => preg_replace('/[^a-z0-9]+/', '-', strtolower($categoryName)), 'display_order' => $nextCatOrder, 'is_active' => 1, ], ['name'], $aid, 'category.created'); $categoryId = $catResult['id'] ?? null; } foreach ($slots as $i => $slot) { $type = $slot['type'] ?? 'content'; $slotSize = (int)($slot['slot_size'] ?? 1); if ($type === 'product') { $created[] = ['type' => 'product', 'category_id' => $categoryId, 'slot' => $i + 1]; continue; } $isLastContent = ($contentBlockIndex === $contentCount - 1); $thisSlotSize = $contentSlotSize + ($isLastContent ? $contentLeftover : 0); $contentBlockIndex++; $rowSpan = $thisSlotSize >= 4 ? 1 : 2; $existingConfig = json_decode($slot['config_json'] ?? '{}', true) ?: []; $mergedConfig = array_merge($existingConfig, [ 'row_span' => $slot['row_span'] ?? $rowSpan, 'cta' => $slot['cta'] ?? '', 'cta_link' => $slot['cta_link'] ?? '', ]); $data = [ 'store_id' => $storeId, 'category_id' => $categoryId, 'title' => trim($slot['title'] ?? 'Content Block'), 'body' => trim($slot['body'] ?? ''), 'block_type' => $slot['block_type'] ?? 'text', 'slot_size' => $thisSlotSize, 'display_order' => $nextBlkOrder + $i, 'bg_color' => $slot['bg_color'] ?? '#2D6A4F', 'text_color' => $slot['text_color'] ?? '#FFFFFF', 'config_json' => json_encode($mergedConfig), 'status_code' => $statusCode, 'mobile_display'=> 'hidden', 'image_url' => null, ]; $result = ActionChain::execute('storefront_blocks', 0, $data, ['title', 'block_type'], $aid, 'block.created'); $created[] = ['type' => 'content', 'id' => $result['id'] ?? null, 'slot' => $i + 1]; } echo json_encode([ 'ok' => true, 'created' => $created, 'category_id' => $categoryId, 'published' => $rowComplete, ]); 