Files
orderPRO/resources/views/products/show.php
Jacek Pyziak 1cbbc76a17 feat: cache-bust assets, fix XSS and filemtime error handling, clean up users filters
- Add ?ver=<filemtime> cache-busting to CSS/JS assets in app and auth layouts
- Use ?: 0 fallback on filemtime() to prevent E_WARNING when files are missing
- Escape security_information output with $e() to fix XSS vulnerability (show.php:91)
- Wrap product image metadata in __meta container, move storage path into <details>
- Add table--details CSS class and th { white-space: nowrap } rule
- Remove redundant sort, sort_dir, per_page filter dropdowns from users list
- Add 10 as a per-page option in users list
- Clean up completed items from TODO.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-27 21:40:17 +01:00

198 lines
9.6 KiB
PHP

<section class="card">
<h1><?= $e($t('products.show.title', ['id' => (string) ($productId ?? 0)])) ?></h1>
<p class="muted"><?= $e($t('products.show.description')) ?></p>
</section>
<?php $item = is_array($product ?? null) ? $product : []; ?>
<?php $images = is_array($productImages ?? null) ? $productImages : []; ?>
<?php $variants = is_array($productVariants ?? null) ? $productVariants : []; ?>
<?php $importWarning = is_array($productImportWarning ?? null) ? $productImportWarning : null; ?>
<?php $productIdValue = (int) ($productId ?? 0); ?>
<?php if (!empty($errorMessage)): ?>
<section class="card mt-16">
<div class="alert alert--danger" role="alert">
<?= $e((string) $errorMessage) ?>
</div>
</section>
<?php endif; ?>
<?php if (!empty($successMessage)): ?>
<section class="card mt-16">
<div class="alert alert--success" role="status">
<?= $e((string) $successMessage) ?>
</div>
</section>
<?php endif; ?>
<section class="card mt-16">
<div class="product-tabs-nav">
<span class="btn btn--primary"><?= $e($t('products.tabs.details')) ?></span>
<a class="btn btn--secondary" href="/products/<?= $e((string) $productIdValue) ?>/links"><?= $e($t('products.tabs.links')) ?></a>
</div>
</section>
<section class="card mt-16">
<?php if ($importWarning !== null && !empty($importWarning['messages'])): ?>
<div class="alert alert--danger" role="alert">
<div><strong><?= $e($t('products.variants.import_warning_title')) ?></strong></div>
<?php foreach ((array) ($importWarning['messages'] ?? []) as $warning): ?>
<div><?= $e((string) $warning) ?></div>
<?php endforeach; ?>
<?php if (!empty($importWarning['created_at'])): ?>
<div class="muted mt-8"><?= $e($t('products.variants.import_warning_date')) ?>: <?= $e((string) $importWarning['created_at']) ?></div>
<?php endif; ?>
</div>
<?php endif; ?>
<h3><?= $e($t('products.show.details')) ?></h3>
<table class="table table--details mt-12">
<tbody>
<tr><th>ID</th><td><?= $e((string) ($item['id'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.name')) ?></th><td><?= $e((string) ($item['name'] ?? '')) ?></td></tr>
<tr><th>SKU</th><td><?= $e((string) ($item['sku'] ?? '')) ?></td></tr>
<tr>
<th>EAN</th>
<td>
<?php if (trim((string) ($item['ean'] ?? '')) !== ''): ?>
<?= $e((string) $item['ean']) ?>
<?php else: ?>
<span class="muted">—</span>
<form method="post" action="/products/<?= $e((string) $productIdValue) ?>/assign-ean" style="display:inline; margin-left:8px;">
<input type="hidden" name="_token" value="<?= $e((string) ($csrfToken ?? '')) ?>">
<button type="submit" class="btn btn--primary btn--sm"><?= $e($t('products.gs1.assign_ean')) ?></button>
</form>
<?php endif; ?>
</td>
</tr>
<tr><th><?= $e($t('products.fields.type')) ?></th><td><?= $e((string) ($item['type'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.status')) ?></th><td><?= $e((string) ($item['status'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.promoted')) ?></th><td><?= $e((string) ($item['promoted'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.vat')) ?></th><td><?= $e((string) ($item['vat'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.weight')) ?></th><td><?= $e((string) ($item['weight'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.quantity')) ?></th><td><?= $e((string) ($item['quantity'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.price_brutto')) ?></th><td><?= $e((string) ($item['price_brutto'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.price_netto')) ?></th><td><?= $e((string) ($item['price_netto'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.price_brutto_promo')) ?></th><td><?= $e((string) ($item['price_brutto_promo'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.price_netto_promo')) ?></th><td><?= $e((string) ($item['price_netto_promo'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.short_description')) ?></th><td><?= $e((string) ($item['short_description'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.description')) ?></th><td><?= $e((string) ($item['description'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.meta_title')) ?></th><td><?= $e((string) ($item['meta_title'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.meta_description')) ?></th><td><?= $e((string) ($item['meta_description'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.meta_keywords')) ?></th><td><?= $e((string) ($item['meta_keywords'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.seo_link')) ?></th><td><?= $e((string) ($item['seo_link'] ?? '')) ?></td></tr>
<tr><th><?= $e($t('products.fields.updated_at')) ?></th><td><?= $e((string) ($item['updated_at'] ?? '')) ?></td></tr>
<?php if (!empty($item['producer_name'])): ?>
<tr><th>Producent</th><td><?= $e((string) $item['producer_name']) ?></td></tr>
<?php endif; ?>
<?php if (!empty($item['security_information'])): ?>
<tr>
<th>GPSR — informacje o bezpieczeństwie</th>
<td><?= $e((string) ($item['security_information'] ?? '')) ?></td>
</tr>
<?php endif; ?>
<?php
$customFields = [];
if (!empty($item['custom_fields_json'])) {
$decoded = json_decode((string) $item['custom_fields_json'], true);
$customFields = is_array($decoded) ? $decoded : [];
}
?>
<?php if ($customFields !== []): ?>
<tr>
<th>Dodatkowe pola</th>
<td>
<?php foreach ($customFields as $cf): ?>
<div><?= $e((string) ($cf['name'] ?? '')) ?> (<?= $e((string) ($cf['type'] ?? '')) ?><?= (int) ($cf['is_required'] ?? 0) === 1 ? ', wymagane' : '' ?>)</div>
<?php endforeach; ?>
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</section>
<section class="card mt-16">
<h3><?= $e($t('products.variants.title')) ?></h3>
<?php if ($variants === []): ?>
<p class="muted"><?= $e($t('products.variants.empty')) ?></p>
<?php else: ?>
<div class="table-wrap mt-12">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>SKU</th>
<th>EAN</th>
<th><?= $e($t('products.fields.price_brutto')) ?></th>
<th><?= $e($t('products.fields.price_netto')) ?></th>
<th><?= $e($t('products.fields.weight')) ?></th>
<th><?= $e($t('products.fields.status')) ?></th>
<th><?= $e($t('products.variants.attributes')) ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($variants as $variant): ?>
<?php
$attributes = is_array($variant['attributes'] ?? null) ? $variant['attributes'] : [];
$attributeText = [];
foreach ($attributes as $attribute) {
$attributeName = (string) ($attribute['attribute_name'] ?? '');
$valueName = (string) ($attribute['value_name'] ?? '');
if ($attributeName === '' || $valueName === '') {
continue;
}
$attributeText[] = $attributeName . ': ' . $valueName;
}
?>
<tr>
<td><?= $e((string) ($variant['id'] ?? 0)) ?></td>
<td><?= $e((string) ($variant['sku'] ?? '')) ?></td>
<td><?= $e((string) ($variant['ean'] ?? '')) ?></td>
<td><?= $e((string) ($variant['price_brutto'] ?? '')) ?></td>
<td><?= $e((string) ($variant['price_netto'] ?? '')) ?></td>
<td><?= $e((string) ($variant['weight'] ?? '')) ?></td>
<td><?= $e(((int) ($variant['status'] ?? 0)) === 1 ? $t('products.status.active') : $t('products.status.inactive')) ?></td>
<td><?= $e($attributeText !== [] ? implode(', ', $attributeText) : '-') ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</section>
<section class="card mt-16">
<h3><?= $e($t('products.images.title')) ?></h3>
<?php if ($images === []): ?>
<p class="muted"><?= $e($t('products.images.empty')) ?></p>
<?php else: ?>
<div class="product-show-images-grid mt-12">
<?php foreach ($images as $image): ?>
<div class="product-show-image-card">
<div class="product-show-image-card__meta">
<span><strong>ID:</strong> <?= $e((string) ($image['id'] ?? 0)) ?><?= ((int) ($image['is_main'] ?? 0) === 1) ? ' | <strong>' . $e($t('products.images.main')) . '</strong>' : '' ?></span>
<?php if ((string) ($image['storage_path'] ?? '') !== ''): ?>
<details class="product-show-image-path">
<summary><?= $e($t('products.images.path')) ?></summary>
<div class="product-show-image-path__url muted"><?= $e((string) ($image['storage_path'] ?? '')) ?></div>
</details>
<?php endif; ?>
</div>
<?php if ((string) ($image['public_url'] ?? '') !== ''): ?>
<div class="mt-8">
<img src="<?= $e((string) $image['public_url']) ?>" alt="<?= $e((string) ($image['alt'] ?? '')) ?>" class="product-show-image">
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</section>
<section class="card mt-16">
<a class="btn btn--secondary" href="/products"><?= $e($t('products.actions.back')) ?></a>
<a class="btn btn--secondary" href="/products/<?= $e((string) $productIdValue) ?>/links"><?= $e($t('products.actions.links')) ?></a>
<a class="btn btn--primary" href="/products/edit?id=<?= $e((string) $productIdValue) ?>"><?= $e($t('products.actions.edit')) ?></a>
</section>