$p !== '')); foreach (explode('/', $relativePath) as $segment) { if ($segment === '..') { array_pop($base); } elseif ($segment !== '.' && $segment !== '') { $base[] = $segment; } } $result = '/' . implode('/', $base); return rtrim($result, '/'); }; $apiPath = '../rw/elements/com.elementsplatform.cms/api'; $wantsRSS = 'false' === 'true'; $wantsSitemap = 'false' === 'true'; // Use pre-parsed WAF-safe paths from hooks.js $collectionPathClean = 'groaning-room-items' !== '' ? 'groaning-room-items' : 'examples/content/blog'; $collectionPathDepth = (int) '1'; $_currentPageDir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/'); $pagePath = $resolveToAbsoluteWebPath($_currentPageDir, '../groaning-room-items/groaning-room-item-template/'); $prettyUrls = 'true' === 'true'; // Static RSS file path if ($wantsRSS) { $rssFolder = ''; $rssFilename = 'feed.xml' !== '' ? 'feed.xml' : 'feed.xml'; // Get the current script's directory as base for relative paths $currentScriptDir = dirname($_SERVER['SCRIPT_FILENAME']); // If no folder selected, use current page directory if (empty($rssFolder)) { $absoluteRssDir = $currentScriptDir; } else { // Resolve relative path (e.g., "../") from current script directory $absoluteRssDir = realpath($currentScriptDir . '/' . $rssFolder); if ($absoluteRssDir === false) { // Directory doesn't exist yet, construct the path manually $absoluteRssDir = $currentScriptDir . '/' . $rssFolder; } } $absoluteRssPath = rtrim($absoluteRssDir, '/') . '/' . $rssFilename; // Calculate the web-accessible path from document root $rssFilePath = str_replace($_SERVER['DOCUMENT_ROOT'], '', $absoluteRssPath); echo ''; } // Static Sitemap file path if ($wantsSitemap) { $sitemapFolder = ''; $sitemapFilename = 'sitemap.xml' !== '' ? 'sitemap.xml' : 'sitemap.xml'; // Get the current script's directory as base for relative paths $currentScriptDir = dirname($_SERVER['SCRIPT_FILENAME']); // If no folder selected, use current page directory if (empty($sitemapFolder)) { $absoluteSitemapDir = $currentScriptDir; } else { // Resolve relative path (e.g., "../") from current script directory $absoluteSitemapDir = realpath($currentScriptDir . '/' . $sitemapFolder); if ($absoluteSitemapDir === false) { // Directory doesn't exist yet, construct the path manually $absoluteSitemapDir = $currentScriptDir . '/' . $sitemapFolder; } } $absoluteSitemapPath = rtrim($absoluteSitemapDir, '/') . '/' . $sitemapFilename; // Calculate the web-accessible path from document root $sitemapFilePath = str_replace($_SERVER['DOCUMENT_ROOT'], '', $absoluteSitemapPath); echo ''; } })(); ?>

the groaning room

twelve situations. all recognisable. if you're in one of them, folc. can help. team@folc.studio

$p !== '')); foreach (explode('/', $relativePath) as $segment) { if ($segment === '..') { array_pop($base); } elseif ($segment !== '.' && $segment !== '') { $base[] = $segment; } } $result = '/' . implode('/', $base); return rtrim($result, '/'); } } // Collection configuration and data fetching $collectionPath = '../groaning-room-items' !== '' ? '../groaning-room-items' : '../rw/elements/com.elementsplatform.cms/api/examples/content/blog'; // WAF-safe parsed paths (pre-parsed in hooks.js to avoid "../" in API requests) $collectionPathClean = 'groaning-room-items'; $collectionPathDepth = (int) '1'; $resourcesPathClean = 'resources'; $resourcesPathDepth = (int) '1'; $_currentPageDir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/'); $pagePath = resolveToAbsoluteWebPath($_currentPageDir, '../groaning-room-items/groaning-room-item-template/'); $tagPagePath = resolveToAbsoluteWebPath($_currentPageDir, ''); $authorPagePath = resolveToAbsoluteWebPath($_currentPageDir, ''); $prettyUrls = 'true' === 'true'; // Collection configuration $itemsPerPage = (int) "10"; $paginationOffset = (int) "0"; $currentPage = (int) ($_GET['page'] ?? 1); // Build filters from template settings and URL parameters $filters = []; // Tag filtering $filterTags = "all"; if ($filterTags !== 'all') { $tags = match ($filterTags) { 'url' => is_array($_GET['tags'] ?? '') ? $_GET['tags'] : array_filter(array_map('trim', explode(',', $_GET['tags'] ?? ''))), default => array_filter(array_map('trim', explode(',', ''))) }; if (!empty($tags)) { $filters['tags'] = implode(',', $tags); } } // Author filtering $filterAuthor = "all"; if ($filterAuthor !== 'all') { $author = match ($filterAuthor) { 'url' => is_array($_GET['author'] ?? '') ? $_GET['author'] : array_filter(array_map('trim', explode(',', $_GET['author'] ?? ''))), default => array_filter(array_map('trim', explode(',', ''))) }; if (!empty($author)) { $filters['author'] = implode(',', $author); } } // Featured filtering $filterFeatured = "all"; if ($filterFeatured !== 'all') { $filters['featured'] = $filterFeatured === 'true' ? 'true' : 'false'; } // Status filtering $filterStatus = "published"; if ($filterStatus !== 'all') { $filters['status'] = $filterStatus; } else { $filters['status'] = 'published'; // Default to published only } // Date filtering - handled via API query parameters $filterDate = "past"; if ($filterDate === 'past') { $filters['date_before'] = date('Y-m-d H:i:s'); } elseif ($filterDate === 'future') { $filters['date_after'] = date('Y-m-d H:i:s'); } $orderBy = "date"; $orderDirection = "desc"; // Build collection query using fluent API with URL configuration $ECMS_options = [ 'resources' => [ 'path' => '../resources' ] ]; $query = cms($ECMS_options)->collection($collectionPath) ->pagePath($pagePath) ->tagPagePath('') ->authorPagePath('') ->prettyUrls($prettyUrls) ->orderBy($orderBy, $orderDirection) ->offset($paginationOffset); // Generate static RSS file if enabled $rssURL = null; $sitemapURL = null; if ('false' === 'true') { $rssFolder = ''; $rssFilename = 'feed.xml' !== '' ? 'feed.xml' : 'feed.xml'; // Get the current script's directory as base for relative paths $currentScriptDir = dirname($_SERVER['SCRIPT_FILENAME']); // If no folder selected, use current page directory if (empty($rssFolder)) { $absoluteRssDir = $currentScriptDir; } else { // Resolve relative path (e.g., "../") from current script directory $absoluteRssDir = realpath($currentScriptDir . '/' . $rssFolder); if ($absoluteRssDir === false) { // Directory doesn't exist yet, construct the path manually $absoluteRssDir = $currentScriptDir . '/' . $rssFolder; } } $absoluteRssPath = rtrim($absoluteRssDir, '/') . '/' . $rssFilename; // Calculate the web-accessible relative path from document root $rssRelativePath = str_replace($_SERVER['DOCUMENT_ROOT'], '', $absoluteRssPath); // Time-based cache expiration (24 hours = 86400 seconds) $rssCacheMaxAge = 86400; $needsRegeneration = false; // Force regeneration via query param: ?regenerate_rss=1 $forceRegenerate = isset($_GET['regenerate_rss']); if ($forceRegenerate) { $needsRegeneration = true; } elseif (!file_exists($absoluteRssPath)) { $needsRegeneration = true; } else { // Check if file is older than max age $fileAge = time() - filemtime($absoluteRssPath); if ($fileAge > $rssCacheMaxAge) { $needsRegeneration = true; } } if ($needsRegeneration) { // Generate RSS content using the query builder $rssContent = $query->limit(20)->rss( 'folc.studio - groaning-room-items', 'RSS feed for groaning-room-items', 'https://folc.studio' ); // Ensure directory exists $rssDir = dirname($absoluteRssPath); if (!is_dir($rssDir)) { mkdir($rssDir, 0755, true); } file_put_contents($absoluteRssPath, $rssContent); } $rssURL = $rssRelativePath; } if ('false' === 'true') { $sitemapFolder = ''; $sitemapFilename = 'sitemap.xml' !== '' ? 'sitemap.xml' : 'sitemap.xml'; // Get the current script's directory as base for relative paths $currentScriptDir = dirname($_SERVER['SCRIPT_FILENAME']); // If no folder selected, use current page directory if (empty($sitemapFolder)) { $absoluteSitemapDir = $currentScriptDir; } else { // Resolve relative path (e.g., "../") from current script directory $absoluteSitemapDir = realpath($currentScriptDir . '/' . $sitemapFolder); if ($absoluteSitemapDir === false) { // Directory doesn't exist yet, construct the path manually $absoluteSitemapDir = $currentScriptDir . '/' . $sitemapFolder; } } $absoluteSitemapPath = rtrim($absoluteSitemapDir, '/') . '/' . $sitemapFilename; // Calculate the web-accessible relative path from document root $sitemapRelativePath = str_replace($_SERVER['DOCUMENT_ROOT'], '', $absoluteSitemapPath); // Time-based cache expiration (24 hours = 86400 seconds) $sitemapCacheMaxAge = 86400; $needsSitemapRegeneration = false; // Force regeneration via query param: ?regenerate_sitemap=1 $forceSitemapRegenerate = isset($_GET['regenerate_sitemap']); if ($forceSitemapRegenerate) { $needsSitemapRegeneration = true; } elseif (!file_exists($absoluteSitemapPath)) { $needsSitemapRegeneration = true; } else { // Check if file is older than max age $sitemapFileAge = time() - filemtime($absoluteSitemapPath); if ($sitemapFileAge > $sitemapCacheMaxAge) { $needsSitemapRegeneration = true; } } if ($needsSitemapRegeneration) { // Generate sitemap content using the query builder $sitemapContent = $query->limit(1000)->sitemap('https://folc.studio'); // Ensure directory exists $sitemapDir = dirname($absoluteSitemapPath); if (!is_dir($sitemapDir)) { mkdir($sitemapDir, 0755, true); } file_put_contents($absoluteSitemapPath, $sitemapContent); } $sitemapURL = $sitemapRelativePath; } // Apply all filters foreach ($filters as $key => $value) { switch ($key) { case 'tags': $query = $query->tags($value); break; case 'author': $query = $query->author($value); break; case 'featured': $query = $query->featured($value === 'true'); break; case 'status': $query = $query->status($value); break; case 'date_before': $query = $query->before($value); break; case 'date_after': $query = $query->after($value); break; } } // Execute query with pagination try { $collection = $query ->paginate($currentPage, $itemsPerPage) ->get(); $items = $collection->items; $pagination = $collection->pagination; } catch (Exception $e) { $items = []; $pagination = (object) [ 'current_page' => 1, 'total_pages' => 1, 'total_items' => 0, 'items_per_page' => $itemsPerPage, 'has_prev' => false, 'has_next' => false ]; } // Create collection-like object for backward compatibility $collectionObj = new class($items, $pagination, $rssURL, $sitemapURL) { public $items; public $pagination; public $rssURL; public $sitemapURL; public function __construct($items, $pagination, $rssURL, $sitemapURL) { $this->items = $items; $this->pagination = $pagination; $this->rssURL = $rssURL; $this->sitemapURL = $sitemapURL; } public function each($callback) { foreach ($this->items as $item) { $callback($item); } } }; // Collection data is now available in template scope $collection = $collectionObj; ?> $collection->pagination, 'items' => $collection->items, 'collection' => $collection, 'filters' => $filters, 'orderBy' => $orderBy, 'orderDirection' => $orderDirection, 'collectionPath' => $collectionPath, 'pagePath' => $pagePath, 'itemsPerPage' => $itemsPerPage, 'paginationOffset' => $paginationOffset, 'prettyUrls' => $prettyUrls, 'collectionItemTemplateId' => $collectionItemTemplateId ?? null ]); ?>
each(function ($item) use ($collection, $collectionItemTemplate, $filters, $orderBy, $orderDirection, $collectionPath, $pagePath, $itemsPerPage, $paginationOffset, $prettyUrls, $collectionItemTemplateId) { echo renderTemplate($collectionItemTemplate, [ 'item' => $item, 'collection' => $collection, 'filters' => $filters, 'orderBy' => $orderBy, 'orderDirection' => $orderDirection, 'collectionPath' => $collectionPath, 'pagePath' => $pagePath, 'itemsPerPage' => $itemsPerPage, 'paginationOffset' => $paginationOffset, 'prettyUrls' => $prettyUrls, 'collectionItemTemplateId' => $collectionItemTemplateId ]); }); // Output the template for use in frontend Alpine components echo ''; ?>
$collection->pagination, 'items' => $collection->items, 'collection' => $collection, 'filters' => $filters, 'orderBy' => $orderBy, 'orderDirection' => $orderDirection, 'collectionPath' => $collectionPath, 'pagePath' => $pagePath, 'itemsPerPage' => $itemsPerPage, 'paginationOffset' => $paginationOffset, 'prettyUrls' => $prettyUrls, 'collectionItemTemplateId' => $collectionItemTemplateId ]); ?>

folc. studio services limited · company no. 17056089 · team@folc.studio · folc.studio · production people. no hand-holding · website terms · privacy notice