FlatlyPage
Version 1.0.0 • 54 files • 724.77 KB
Files
.htaccess
.last_check
admin/account.php
admin/dashboard.php
admin/easyedit.js
admin/extensions.php
admin/generate-hash.php
admin/index.php
admin/logout.php
admin/preview.php
admin/scripts.php
admin/theme-edit/builder.php
admin/theme-edit/generator.php
admin/theme-edit/index.php
admin/themes.php
assets/fonts/inter/inter.css
assets/fonts/space-grotesk/space-grotesk.css
config.php
contact-handler.php
contact.php
css/admin.css
css/contact.css
css/styles.css
css/theme.css
data/.htaccess
data/index.php
data/settings.php
data/sitemap-config.php
engine/index.php
engine/renderion.php
extensions-loader.php
extensions/privimetrics/main.php
extensions/privimetrics/manifest.xml
extensions/scroll_to_top/main.php
extensions/scroll_to_top/manifest.xml
extensions/seo_image_master/main.php
extensions/seo_image_master/manifest.xml
favicons.txt
index.php
newsletter/.htaccess
newsletter/confirm.php
newsletter/manager.php
newsletter/newsletter-form.js
newsletter/newsletter-styles.css
newsletter/newsletter-unavailable.php
newsletter/newsletter.sql
newsletter/settings.php
newsletter/subscribe.php
newsletter/unsubscribe.php
page.php
robots.txt.php
sitemap.php
updater/index.php
version.txt
page.php
<?php
error_reporting(E_ALL);
ini_set('display_errors', 0);
header("X-Powered-By: FlatlyPage CMS");
header("X-Content-Type-Options: nosniff");
header("X-Frame-Options: SAMEORIGIN");
header("X-XSS-Protection: 1; mode=block");
header("Referrer-Policy: strict-origin-when-cross-origin");
require_once __DIR__ . '/config.php';
$slug = isset($_GET['slug']) ? sanitize($_GET['slug']) : '';
define('CURRENT_PAGE', 'product');
define('CURRENT_PAGE_SLUG', $slug);
if (empty($slug)) {
header('Location: index.php');
exit;
}
$page = null;
$pages = get_all_products();
foreach ($pages as $p) {
if ($p['slug'] === $slug) {
$page = $p;
break;
}
}
$site_settings = get_site_settings();
$page_title = $page['title'] ?? 'Error 404 - Page not found';
$page_description = $page['description'] ?? '';
if ($page) {
$page_index = $page['index'] ?? 'true';
$page_follow = $page['follow'] ?? 'true';
} else {
$page_index = 'false';
$page_follow = 'false';
}
$blocks = $page['blocks'] ?? [];
$has_newsletter = false;
foreach ($blocks as $block) {
if (($block['type'] ?? '') === 'newsletter') {
$has_newsletter = true;
break;
}
}
$REGISTERED_BLOCKS = [];
$REGISTERED_BLOCKS = ext_hook('register_blocks', $REGISTERED_BLOCKS);
$nav_links = $site_settings['nav_links'] ?? [];
$nav_links = ext_hook('modify_nav_links', $nav_links);
$nav_buttons = $site_settings['nav_buttons'] ?? [];
$footer = $site_settings['footer'] ?? [];
$logo_text = $site_settings['logo_text'] ?? $site_settings['site_name'] ?? 'FlatlyPage';
$logo_image = $site_settings['logo_image'] ?? '';
$allowed_fonts = [
'Inter' => '/assets/fonts/inter/inter.css',
'Space Grotesk' => '/assets/fonts/space-grotesk/space-grotesk.css',
'Arial' => '',
'Helvetica' => '',
'Times New Roman' => '',
'Courier New' => '',
'Verdana' => '',
'Trebuchet MS' => '',
];
$website_font = $site_settings['website_font'] ?? 'Inter';
if (!isset($allowed_fonts[$website_font])) {
$website_font = 'Inter';
}
$font_url = $allowed_fonts[$website_font];
?>
<!-- Powered by FlatlyPage CMS -->
<!DOCTYPE html>
<html lang="en" data-cms="flatlypage">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= e($page_title) ?> - <?= e($site_settings['site_name']) ?></title>
<meta name="description" content="<?= e($page_description) ?>">
<meta name="generator" content="FlatlyPage CMS">
<meta name="robots" content="<?= ($page_index === 'true' ? 'index' : 'noindex') ?>, <?= ($page_follow === 'true' ? 'follow' : 'nofollow') ?>">
<?php if (!empty($site_settings['favicon'])): ?>
<link rel="icon" href="<?= e($site_settings['favicon']) ?>">
<?php endif; ?>
<link rel="preload" href="/assets/fonts/inter/inter.ttf" as="font" type="font/ttf" crossorigin>
<link rel="stylesheet" href="/assets/fonts/inter/inter.css">
<?php if (!empty($font_url)): ?>
<link href="<?= e($font_url) ?>" rel="stylesheet">
<?php endif; ?>
<link rel="stylesheet" href="/css/styles.css?v=<?= filemtime(__DIR__ . '/css/styles.css') ?>">
<?php
$themePath = __DIR__ . '/css/theme.css';
$themeUrl = '/css/theme.css';
if (is_file($themePath) && filesize($themePath) > 0) {
$handle = fopen($themePath, 'r');
$header = fread($handle, 25);
fclose($handle);
if (trim($header) !== '/* No theme active */') {
$v = filemtime($themePath);
echo '<link rel="stylesheet" href="' . htmlspecialchars($themeUrl) . '?v=' . $v . '">';
}
}
?>
<style>
body { font-family: '<?= e($website_font) ?>', -apple-system, BlinkMacSystemFont, sans-serif; }
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "<?= e($site_settings['site_name'] ?? SITE_NAME) ?>",
"url": "<?= (isset($_SERVER['HTTPS']) ? "https" : "http") . "://$_SERVER[HTTP_HOST]" ?>",
"description": "<?= e($page_description) ?>",
"publisher": {
"@type": "Organization",
"name": "<?= e($logo_text) ?>"
}
}
</script>
<?php
$ext_assets = $GLOBALS['extensions']->getFrontendAssets('frontend');
foreach ($ext_assets['css'] as $css): ?>
<link rel="stylesheet" href="<?= $css ?>">
<?php endforeach;
echo ext_hook('frontend_head', '');
?>
</head>
<body>
<?php echo ext_hook('before_header', ''); ?>
<?php $nav_links = ext_hook('modify_nav_links', $nav_links); ?>
<nav class="navbar">
<div class="container navbar-inner">
<a href="/" class="logo">
<?php if (!empty($logo_image)): ?>
<img src="<?= e($logo_image) ?>" alt="<?= e($logo_text) ?>">
<?php endif; ?>
<?= e($logo_text) ?>
</a>
<?php if (!empty($nav_links)): ?>
<div class="nav-links">
<?php foreach ($nav_links as $link): ?>
<a href="<?= e($link['url'] ?? '#') ?>"><?= e($link['label'] ?? '') ?></a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if (!empty($nav_buttons)): ?>
<div class="nav-buttons">
<?php foreach ($nav_buttons as $btn): ?>
<a href="<?= e($btn['url'] ?? '#') ?>" class="btn btn-<?= e($btn['style'] ?? 'ghost') ?>"><?= e($btn['label'] ?? '') ?></a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<button class="mobile-menu-btn" aria-label="Menu" onclick="document.querySelector('.mobile-nav').classList.toggle('active')">
<svg width="24" height="24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
</button>
</div>
</nav>
<div class="mobile-nav">
<?php if (!empty($nav_links)): ?>
<?php foreach ($nav_links as $link): ?>
<a href="<?= e($link['url'] ?? '#') ?>"><?= e($link['label'] ?? '') ?></a>
<?php endforeach; ?>
<?php endif; ?>
<?php if (!empty($nav_buttons)): ?>
<?php foreach ($nav_buttons as $btn): ?>
<a href="<?= e($btn['url'] ?? '#') ?>" class="btn btn-<?= e($btn['style'] ?? 'ghost') ?>"><?= e($btn['label'] ?? '') ?></a>
<?php endforeach; ?>
<?php endif; ?>
</div>
<?php echo ext_hook('after_header', ''); ?>
<main>
<?php echo ext_hook('before_content', ''); ?>
<?php if (!$page): ?>
<section class="hero">
<div class="hero-grid"></div>
<div class="container hero-content" style="padding: 40px 0; text-align: center;">
<h1 style="font-size: 3rem; color: var(--muted);">404</h1>
<p style="font-size: 1.5rem; margin: 16px 0;">Page not found</p>
<p style="color: var(--muted); margin-bottom: 32px;">Sorry, we couldn't find the page you're looking for.</p>
<a href="/" class="btn btn-primary">Go back home</a>
</div>
</section>
<?php else: ?>
<?php if (!empty($blocks)):
$markdown_map = [
'/\[u\](.*?)\[\/u\]/is' => '<u>$1</u>',
'/\[b\](.*?)\[\/b\]/is' => '<b>$1</b>',
'/\[i\](.*?)\[\/i\]/is' => '<i>$1</i>',
'/\[s\](.*?)\[\/s\]/is' => '<s>$1</s>',
'/\[quote\](.*?)\[\/quote\]/is' => '<blockquote>$1</blockquote>',
];
$patterns = array_keys($markdown_map);
$replacements = array_values($markdown_map);
?>
<?php foreach ($blocks as $block):
$html = render_block($block);
echo preg_replace($patterns, $replacements, $html);
endforeach; ?>
<?php endif; ?>
<?php endif; ?>
<?php echo ext_hook('after_content', ''); ?>
</main>
<?php
$footer = ext_hook('modify_footer', $footer);
echo ext_hook('before_footer', '');
?>
<footer class="footer">
<div class="container">
<div class="footer-grid">
<div class="footer-brand">
<h3>
<?php if (!empty($logo_image)): ?>
<img src="<?= e($logo_image) ?>" alt="<?= e($logo_text) ?>">
<?php endif; ?>
<?= e($logo_text) ?>
</h3>
<p><?= e($footer['brand_description'] ?? '') ?></p>
<?php if (!empty($footer['social_links'])): ?>
<div class="social-links">
<?php foreach ($footer['social_links'] as $social): ?>
<a href="<?= e($social['url'] ?? '#') ?>" aria-label="<?= e(ucfirst($social['platform'] ?? '')) ?>"><?= render_social_icon($social['platform'] ?? 'twitter') ?></a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php if (!empty($footer['columns'])): ?>
<?php foreach ($footer['columns'] as $column): ?>
<div class="footer-column">
<h4><?= e($column['title'] ?? '') ?></h4>
<?php if (!empty($column['links'])): ?>
<ul>
<?php foreach ($column['links'] as $link): ?>
<li><a href="<?= e($link['url'] ?? '#') ?>"><?= e($link['label'] ?? '') ?></a></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
<div class="footer-bottom">
<div style="flex: 1;">
<p><?= e($footer['copyright'] ?? '© ' . date('Y') . ' ' . $logo_text . '. All rights reserved.') ?></p>
<?php if (!empty($footer['bottom_links'])): ?>
<div class="footer-legal">
<?php foreach ($footer['bottom_links'] as $link): ?>
<a href="<?= e($link['url'] ?? '#') ?>"><?= e($link['label'] ?? '') ?></a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<button class="theme-toggle" aria-label="Toggle theme" title="Toggle light/dark theme">
<svg class="theme-icon-sun" viewBox="0 0 24 24" style="display: none;"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
<svg class="theme-icon-moon" viewBox="0 0 24 24" style="display: block;"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
</button>
</div>
</div>
</footer>
<script>
const themeToggle = document.querySelector('.theme-toggle');
const sunIcon = document.querySelector('.theme-icon-sun');
const moonIcon = document.querySelector('.theme-icon-moon');
const html = document.documentElement;
function initTheme() {
let theme = localStorage.getItem('theme');
if (!theme) {
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
theme = prefersDark ? 'dark' : 'light';
}
setTheme(theme);
}
function setTheme(theme) {
if (theme === 'light') {
html.setAttribute('data-theme', 'light');
sunIcon.style.display = 'block';
moonIcon.style.display = 'none';
localStorage.setItem('theme', 'light');
} else {
html.removeAttribute('data-theme');
sunIcon.style.display = 'none';
moonIcon.style.display = 'block';
localStorage.setItem('theme', 'dark');
}
}
function toggleTheme() {
const currentTheme = html.getAttribute('data-theme') || 'dark';
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
setTheme(newTheme);
}
if (themeToggle) {
themeToggle.addEventListener('click', toggleTheme);
}
initTheme();
document.querySelectorAll('.mobile-nav a').forEach(link => {
link.addEventListener('click', () => {
document.querySelector('.mobile-nav').classList.remove('active');
});
});
</script>
<?php
echo ext_hook('after_footer', '');
foreach ($ext_assets['js'] as $js): ?>
<script src="<?= $js ?>"></script>
<?php endforeach; ?>
<?php if ($has_newsletter): ?>
<script src="/newsletter/newsletter-form.js?v=<?= time() ?>"></script>
<?php endif; ?>
</body>
</html>