Add publish_date and expiry_date support
This commit is contained in:
parent
a22281c896
commit
4448798bf5
6 changed files with 148 additions and 3 deletions
|
|
@ -120,7 +120,10 @@ function buildNavigation(Context $ctx): array {
|
||||||
|
|
||||||
$itemPath = "{$ctx->contentDir}/$item";
|
$itemPath = "{$ctx->contentDir}/$item";
|
||||||
$metadata = loadMetadata($itemPath);
|
$metadata = loadMetadata($itemPath);
|
||||||
|
|
||||||
|
// Skip invisible content (future publish or expired)
|
||||||
|
if (!isVisible($metadata)) continue;
|
||||||
|
|
||||||
// Only include if explicitly marked as menu item
|
// Only include if explicitly marked as menu item
|
||||||
// parse_ini_file returns boolean true as 1, false as empty string, and "true"/"false" as strings
|
// parse_ini_file returns boolean true as 1, false as empty string, and "true"/"false" as strings
|
||||||
if (!$metadata || !isset($metadata['menu']) || !$metadata['menu']) {
|
if (!$metadata || !isset($metadata['menu']) || !$metadata['menu']) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,15 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
// Check if content is visible based on publish_date and expiry_date
|
||||||
|
// No metadata or absent fields = always visible
|
||||||
|
function isVisible(?array $metadata): bool {
|
||||||
|
if (!$metadata) return true;
|
||||||
|
$today = gmdate('Y-m-d');
|
||||||
|
if (isset($metadata['publish_date']) && $today < $metadata['publish_date']) return false;
|
||||||
|
if (isset($metadata['expiry_date']) && $today > $metadata['expiry_date']) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function resolveTemplate(string $templateName): string {
|
function resolveTemplate(string $templateName): string {
|
||||||
$customTemplate = dirname(__DIR__) . "/custom/templates/$templateName.php";
|
$customTemplate = dirname(__DIR__) . "/custom/templates/$templateName.php";
|
||||||
$defaultTemplate = __DIR__ . "/default/templates/$templateName.php";
|
$defaultTemplate = __DIR__ . "/default/templates/$templateName.php";
|
||||||
|
|
@ -39,6 +49,9 @@ function buildListItems(string $dir, Context $ctx, ?array $parentMetadata): arra
|
||||||
$items = array_filter(array_map(function($item) use ($dir, $ctx) {
|
$items = array_filter(array_map(function($item) use ($dir, $ctx) {
|
||||||
$itemPath = "$dir/$item";
|
$itemPath = "$dir/$item";
|
||||||
$metadata = loadMetadata($itemPath);
|
$metadata = loadMetadata($itemPath);
|
||||||
|
|
||||||
|
if (!isVisible($metadata)) return null;
|
||||||
|
|
||||||
$coverImage = findCoverImage($itemPath);
|
$coverImage = findCoverImage($itemPath);
|
||||||
$pdfFile = findPdfFile($itemPath);
|
$pdfFile = findPdfFile($itemPath);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,13 @@ switch ($parsedPath['type']) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$metadata = loadMetadata($dir);
|
||||||
|
if (!isVisible($metadata)) {
|
||||||
|
http_response_code(404);
|
||||||
|
renderTemplate($ctx, "<h1>404 - Page Not Found</h1><p>The requested page could not be found.</p>", 404);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
$contentFiles = findAllContentFiles($dir);
|
$contentFiles = findAllContentFiles($dir);
|
||||||
if (!empty($contentFiles)) {
|
if (!empty($contentFiles)) {
|
||||||
renderMultipleFiles($ctx, $contentFiles, $dir);
|
renderMultipleFiles($ctx, $contentFiles, $dir);
|
||||||
|
|
@ -218,7 +225,13 @@ switch ($parsedPath['type']) {
|
||||||
|
|
||||||
// Load metadata for this directory
|
// Load metadata for this directory
|
||||||
$metadata = loadMetadata($dir);
|
$metadata = loadMetadata($dir);
|
||||||
|
|
||||||
|
if (!isVisible($metadata)) {
|
||||||
|
http_response_code(404);
|
||||||
|
renderTemplate($ctx, "<h1>404 - Page Not Found</h1><p>The requested page could not be found.</p>", 404);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if hide_list is enabled - if so, treat as page
|
// Check if hide_list is enabled - if so, treat as page
|
||||||
if (isset($metadata['hide_list']) && $metadata['hide_list']) {
|
if (isset($metadata['hide_list']) && $metadata['hide_list']) {
|
||||||
if (!empty($contentFiles)) {
|
if (!empty($contentFiles)) {
|
||||||
|
|
|
||||||
21
devel/tests/helpers/is_visible.phpt
Normal file
21
devel/tests/helpers/is_visible.phpt
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
--TEST--
|
||||||
|
isVisible: returns true when metadata is null or date fields absent
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
require '/var/www/app/hooks.php';
|
||||||
|
require '/var/www/app/context.php';
|
||||||
|
require '/var/www/app/helpers.php';
|
||||||
|
|
||||||
|
// Null metadata = always visible
|
||||||
|
echo isVisible(null) ? "true\n" : "false\n";
|
||||||
|
|
||||||
|
// Empty array = always visible
|
||||||
|
echo isVisible([]) ? "true\n" : "false\n";
|
||||||
|
|
||||||
|
// Metadata without date fields = always visible
|
||||||
|
echo isVisible(['title' => 'Hello']) ? "true\n" : "false\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
true
|
||||||
|
true
|
||||||
|
true
|
||||||
60
devel/tests/helpers/is_visible_dates.phpt
Normal file
60
devel/tests/helpers/is_visible_dates.phpt
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
--TEST--
|
||||||
|
isVisible: enforces publish_date and expiry_date boundaries
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
require '/var/www/app/hooks.php';
|
||||||
|
require '/var/www/app/context.php';
|
||||||
|
require '/var/www/app/helpers.php';
|
||||||
|
|
||||||
|
$today = gmdate('Y-m-d');
|
||||||
|
|
||||||
|
// Helper to create tomorrow/yesterday dates
|
||||||
|
$tomorrow = gmdate('Y-m-d', strtotime('+1 day'));
|
||||||
|
$yesterday = gmdate('Y-m-d', strtotime('-1 day'));
|
||||||
|
|
||||||
|
// Future publish_date = hidden
|
||||||
|
echo isVisible(['publish_date' => $tomorrow]) ? "visible\n" : "hidden\n";
|
||||||
|
|
||||||
|
// Past publish_date = visible
|
||||||
|
echo isVisible(['publish_date' => $yesterday]) ? "visible\n" : "hidden\n";
|
||||||
|
|
||||||
|
// Publish date = today = visible (inclusive)
|
||||||
|
echo isVisible(['publish_date' => $today]) ? "visible\n" : "hidden\n";
|
||||||
|
|
||||||
|
// Past expiry_date = hidden
|
||||||
|
echo isVisible(['expiry_date' => $yesterday]) ? "visible\n" : "hidden\n";
|
||||||
|
|
||||||
|
// Future expiry_date = visible
|
||||||
|
echo isVisible(['expiry_date' => $tomorrow]) ? "visible\n" : "hidden\n";
|
||||||
|
|
||||||
|
// Expiry date = today = visible (inclusive)
|
||||||
|
echo isVisible(['expiry_date' => $today]) ? "visible\n" : "hidden\n";
|
||||||
|
|
||||||
|
// Both set, today in range = visible
|
||||||
|
echo isVisible([
|
||||||
|
'publish_date' => $yesterday,
|
||||||
|
'expiry_date' => $tomorrow,
|
||||||
|
]) ? "visible\n" : "hidden\n";
|
||||||
|
|
||||||
|
// Both set, today before range = hidden
|
||||||
|
echo isVisible([
|
||||||
|
'publish_date' => $tomorrow,
|
||||||
|
'expiry_date' => gmdate('Y-m-d', strtotime('+2 days')),
|
||||||
|
]) ? "visible\n" : "hidden\n";
|
||||||
|
|
||||||
|
// Both set, today after range = hidden
|
||||||
|
echo isVisible([
|
||||||
|
'publish_date' => gmdate('Y-m-d', strtotime('-3 days')),
|
||||||
|
'expiry_date' => $yesterday,
|
||||||
|
]) ? "visible\n" : "hidden\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
hidden
|
||||||
|
visible
|
||||||
|
visible
|
||||||
|
hidden
|
||||||
|
visible
|
||||||
|
visible
|
||||||
|
visible
|
||||||
|
hidden
|
||||||
|
hidden
|
||||||
|
|
@ -55,9 +55,44 @@ Returns flat key-value array with a special `_raw` key containing the full parse
|
||||||
| `redirect` | string | — | External URL (list items can redirect) |
|
| `redirect` | string | — | External URL (list items can redirect) |
|
||||||
| `feed` | bool | `false` | Enable Atom feed on list pages (`feed.xml`) |
|
| `feed` | bool | `false` | Enable Atom feed on list pages (`feed.xml`) |
|
||||||
| `author` | string | title | Atom feed author name (falls back to page title) |
|
| `author` | string | title | Atom feed author name (falls back to page title) |
|
||||||
|
| `publish_date` | string (YYYY-MM-DD) | — | Earliest date content is visible |
|
||||||
|
| `expiry_date` | string (YYYY-MM-DD) | — | Last date content is visible (inclusive) |
|
||||||
| `plugins` | string | — | Comma-separated page-level plugin names |
|
| `plugins` | string | — | Comma-separated page-level plugin names |
|
||||||
|
|
||||||
### Settings Section
|
## Visibility (Scheduling)
|
||||||
|
|
||||||
|
Content can be scheduled using `publish_date` and `expiry_date`. Both fields are optional — when absent, content is always visible.
|
||||||
|
|
||||||
|
When set:
|
||||||
|
- **`publish_date`** — Content becomes visible on this date (inclusive). Before this date it is treated as non-existent.
|
||||||
|
- **`expiry_date`** — Content remains visible through this date (inclusive). After this date it is treated as non-existent.
|
||||||
|
|
||||||
|
Invisible content is:
|
||||||
|
- Hidden from list views (`buildListItems()`)
|
||||||
|
- Excluded from navigation (`buildNavigation()`)
|
||||||
|
- Returns 404 on direct access (page and list cases in `router.php`)
|
||||||
|
- Omitted from Atom feeds automatically (feeds use the filtered items array)
|
||||||
|
|
||||||
|
The check uses UTC (`gmdate('Y-m-d')`) so behavior is consistent regardless of server timezone.
|
||||||
|
|
||||||
|
These fields can be overridden per-language in `[en]` sections via the language plugin:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
title = "Event"
|
||||||
|
publish_date = "2025-10-01"
|
||||||
|
expiry_date = "2025-10-07"
|
||||||
|
|
||||||
|
[no]
|
||||||
|
title = "Arrangement"
|
||||||
|
publish_date = "2025-10-01"
|
||||||
|
expiry_date = "2025-10-08"
|
||||||
|
```
|
||||||
|
|
||||||
|
### `isVisible(?array $metadata): bool`
|
||||||
|
|
||||||
|
Pure function in `helpers.php`. Returns `true` when content should be visible, `false` otherwise. Accepts nullable metadata — returns `true` for `null` (no metadata file = always visible).
|
||||||
|
|
||||||
|
## Settings Section
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
[settings]
|
[settings]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue