test
This commit is contained in:
parent
d184a33ff0
commit
9bf0056520
4
admin/.htaccess
Normal file
4
admin/.htaccess
Normal file
@ -0,0 +1,4 @@
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)$ index.php?path=$1 [L,QSA]
|
||||
21
admin/delete_post.php
Normal file
21
admin/delete_post.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
// Check if user is logged in
|
||||
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!isset($_GET['id'])) {
|
||||
die('Post ID not specified.');
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('DELETE FROM posts WHERE id = ?');
|
||||
$stmt->execute([$_GET['id']]);
|
||||
|
||||
header('Location: posts.php?status=deleted');
|
||||
exit;
|
||||
?>
|
||||
21
admin/delete_product.php
Normal file
21
admin/delete_product.php
Normal file
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
// Check if user is logged in
|
||||
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!isset($_GET['id'])) {
|
||||
die('Product ID not specified.');
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('DELETE FROM products WHERE id = ?');
|
||||
$stmt->execute([$_GET['id']]);
|
||||
|
||||
header('Location: products.php?status=deleted');
|
||||
exit;
|
||||
?>
|
||||
109
admin/edit_post.php
Normal file
109
admin/edit_post.php
Normal file
@ -0,0 +1,109 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
// Check if user is logged in
|
||||
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
$post = [
|
||||
'id' => '',
|
||||
'title' => '',
|
||||
'slug' => '',
|
||||
'content' => '',
|
||||
'author' => '',
|
||||
'image_url' => '',
|
||||
'seo_title' => '',
|
||||
'seo_meta_description' => ''
|
||||
];
|
||||
|
||||
// Check if it's an edit request
|
||||
if (isset($_GET['id'])) {
|
||||
$stmt = $pdo->prepare('SELECT * FROM posts WHERE id = ?');
|
||||
$stmt->execute([$_GET['id']]);
|
||||
$post = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$post) {
|
||||
die('Post not found.');
|
||||
}
|
||||
}
|
||||
|
||||
// Handle form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$id = $_POST['id'] ?? null;
|
||||
$title = $_POST['title'];
|
||||
$slug = $_POST['slug'];
|
||||
$content = $_POST['content'];
|
||||
$author = $_POST['author'];
|
||||
$image_url = $_POST['image_url'];
|
||||
$seo_title = $_POST['seo_title'];
|
||||
$seo_meta_description = $_POST['seo_meta_description'];
|
||||
|
||||
if ($id) { // Update
|
||||
$sql = "UPDATE posts SET title = ?, slug = ?, content = ?, author = ?, image_url = ?, seo_title = ?, seo_meta_description = ? WHERE id = ?";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$title, $slug, $content, $author, $image_url, $seo_title, $seo_meta_description, $id]);
|
||||
} else { // Insert
|
||||
$sql = "INSERT INTO posts (title, slug, content, author, image_url, seo_title, seo_meta_description) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute([$title, $slug, $content, $author, $image_url, $seo_title, $seo_meta_description]);
|
||||
}
|
||||
|
||||
header('Location: posts.php?status=success');
|
||||
exit;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../includes/header.php';
|
||||
?>
|
||||
<div class="container">
|
||||
<h1 class="mt-5"><?php echo isset($post['id']) && $post['id'] ? 'Edit' : 'Add'; ?> Post</h1>
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="id" value="<?php echo $post['id']; ?>">
|
||||
<div class="form-group">
|
||||
<label for="title">Title</label>
|
||||
<input type="text" name="title" id="title" class="form-control" value="<?php echo htmlspecialchars($post['title']); ?>" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="slug">URL Slug</label>
|
||||
<input type="text" name="slug" id="slug" class="form-control" value="<?php echo htmlspecialchars($post['slug']); ?>" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="content">Content</label>
|
||||
<textarea name="content" id="content" class="form-control" rows="10" required><?php echo htmlspecialchars($post['content']); ?></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="author">Author</label>
|
||||
<input type="text" name="author" id="author" class="form-control" value="<?php echo htmlspecialchars($post['author']); ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="image_url">Image URL</label>
|
||||
<input type="text" name="image_url" id="image_url" class="form-control" value="<?php echo htmlspecialchars($post['image_url']); ?>">
|
||||
</div>
|
||||
<h2 class="mt-4">SEO Settings</h2>
|
||||
<div class="form-group">
|
||||
<label for="seo_title">SEO Title</label>
|
||||
<input type="text" name="seo_title" id="seo_title" class="form-control" value="<?php echo htmlspecialchars($post['seo_title']); ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="seo_meta_description">SEO Meta Description</label>
|
||||
<textarea name="seo_meta_description" id="seo_meta_description" class="form-control" rows="3"><?php echo htmlspecialchars($post['seo_meta_description']); ?></textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save Post</button>
|
||||
<a href="posts.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
<script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/7/tinymce.min.js" referrerpolicy="origin"></script>
|
||||
<script>
|
||||
tinymce.init({
|
||||
selector: 'textarea#content',
|
||||
plugins: 'code table lists',
|
||||
toolbar: 'undo redo | blocks | bold italic | alignleft aligncenter alignright | indent outdent | bullist numlist | code | table'
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
include __DIR__ . '/../includes/footer.php';
|
||||
?>
|
||||
150
admin/edit_product.php
Normal file
150
admin/edit_product.php
Normal file
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
// Check if user is logged in
|
||||
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
$product = [
|
||||
'id' => '',
|
||||
'name' => '',
|
||||
'description' => '',
|
||||
'images' => '',
|
||||
'material' => '',
|
||||
'application' => '',
|
||||
'url_slug' => '',
|
||||
'seo_title' => '',
|
||||
'seo_meta_description' => '',
|
||||
'canonical_url' => '',
|
||||
'og_title' => '',
|
||||
'og_description' => '',
|
||||
'og_image' => '',
|
||||
'schema_type' => 'Product'
|
||||
];
|
||||
|
||||
if (isset($_GET['id'])) {
|
||||
$stmt = $pdo->prepare('SELECT * FROM products WHERE id = ?');
|
||||
$stmt->execute([$_GET['id']]);
|
||||
$product = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$product) {
|
||||
die('Product not found.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$id = $_POST['id'] ?? null;
|
||||
$name = $_POST['name'];
|
||||
$description = $_POST['description'];
|
||||
$images = $_POST['images'];
|
||||
$material = $_POST['material'];
|
||||
$application = $_POST['application'];
|
||||
$url_slug = $_POST['url_slug'];
|
||||
$seo_title = $_POST['seo_title'];
|
||||
$seo_meta_description = $_POST['seo_meta_description'];
|
||||
$canonical_url = $_POST['canonical_url'];
|
||||
$og_title = $_POST['og_title'];
|
||||
$og_description = $_POST['og_description'];
|
||||
$og_image = $_POST['og_image'];
|
||||
$schema_type = $_POST['schema_type'];
|
||||
|
||||
if ($id) { // Update
|
||||
$sql = "UPDATE products SET name=?, description=?, images=?, material=?, application=?, url_slug=?, seo_title=?, seo_meta_description=?, canonical_url=?, og_title=?, og_description=?, og_image=?, schema_type=? WHERE id=?";
|
||||
$params = [$name, $description, $images, $material, $application, $url_slug, $seo_title, $seo_meta_description, $canonical_url, $og_title, $og_description, $og_image, $schema_type, $id];
|
||||
} else { // Insert
|
||||
$sql = "INSERT INTO products (name, description, images, material, application, url_slug, seo_title, seo_meta_description, canonical_url, og_title, og_description, og_image, schema_type) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
$params = [$name, $description, $images, $material, $application, $url_slug, $seo_title, $seo_meta_description, $canonical_url, $og_title, $og_description, $og_image, $schema_type];
|
||||
}
|
||||
$stmt = $pdo->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
|
||||
header('Location: products.php?status=success');
|
||||
exit;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../includes/header.php';
|
||||
?>
|
||||
<div class="container">
|
||||
<h1 class="mt-5"><?php echo isset($product['id']) && $product['id'] ? 'Edit' : 'Add'; ?> Product</h1>
|
||||
|
||||
<form method="post">
|
||||
<input type="hidden" name="id" value="<?php echo $product['id']; ?>">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="name">Product Name</label>
|
||||
<input type="text" name="name" id="name" class="form-control" value="<?php echo htmlspecialchars($product['name']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="url_slug">URL Slug</label>
|
||||
<input type="text" name="url_slug" id="url_slug" class="form-control" value="<?php echo htmlspecialchars($product['url_slug']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="description">Description</label>
|
||||
<textarea name="description" id="description" class="form-control" rows="5" required><?php echo htmlspecialchars($product['description']); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="images">Images (comma-separated URLs)</label>
|
||||
<input type="text" name="images" id="images" class="form-control" value="<?php echo htmlspecialchars($product['images']); ?>">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="material">Material</label>
|
||||
<input type="text" name="material" id="material" class="form-control" value="<?php echo htmlspecialchars($product['material']); ?>">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="application">Application</label>
|
||||
<input type="text" name="application" id="application" class="form-control" value="<?php echo htmlspecialchars($product['application']); ?>">
|
||||
</div>
|
||||
|
||||
<h2 class="mt-4">SEO & Open Graph</h2>
|
||||
<div class="form-group">
|
||||
<label for="seo_title">SEO Title</label>
|
||||
<input type="text" name="seo_title" id="seo_title" class="form-control" value="<?php echo htmlspecialchars($product['seo_title']); ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="seo_meta_description">SEO Meta Description</label>
|
||||
<textarea name="seo_meta_description" id="seo_meta_description" class="form-control" rows="3"><?php echo htmlspecialchars($product['seo_meta_description']); ?></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="canonical_url">Canonical URL</label>
|
||||
<input type="text" name="canonical_url" id="canonical_url" class="form-control" value="<?php echo htmlspecialchars($product['canonical_url']); ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="og_title">Open Graph Title</label>
|
||||
<input type="text" name="og_title" id="og_title" class="form-control" value="<?php echo htmlspecialchars($product['og_title']); ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="og_description">Open Graph Description</label>
|
||||
<textarea name="og_description" id="og_description" class="form-control" rows="3"><?php echo htmlspecialchars($product['og_description']); ?></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="og_image">Open Graph Image URL</label>
|
||||
<input type="text" name="og_image" id="og_image" class="form-control" value="<?php echo htmlspecialchars($product['og_image']); ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="schema_type">Schema.org Type</label>
|
||||
<input type="text" name="schema_type" id="schema_type" class="form-control" value="<?php echo htmlspecialchars($product['schema_type']); ?>">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">Save Product</button>
|
||||
<a href="products.php" class="btn btn-secondary">Cancel</a>
|
||||
</form>
|
||||
</div>
|
||||
<script src="https://cdn.tiny.cloud/1/no-api-key/tinymce/7/tinymce.min.js" referrerpolicy="origin"></script>
|
||||
<script>
|
||||
tinymce.init({
|
||||
selector: 'textarea#description',
|
||||
plugins: 'code table lists',
|
||||
toolbar: 'undo redo | blocks | bold italic | alignleft aligncenter alignright | indent outdent | bullist numlist | code | table'
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
include __DIR__ . '/../includes/footer.php';
|
||||
?>
|
||||
57
admin/index.php
Normal file
57
admin/index.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// Temporary, hardcoded password.
|
||||
define('ADMIN_PASSWORD', 'password');
|
||||
|
||||
// Login check
|
||||
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
|
||||
// If not logged in, show the login form.
|
||||
if (isset($_POST['password']) && $_POST['password'] === ADMIN_PASSWORD) {
|
||||
$_SESSION['loggedin'] = true;
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Display login page
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
<div class="container">
|
||||
<h1 class="mt-5">Admin Login</h1>
|
||||
<form method="post" class="mt-3">
|
||||
<div class="form-group">
|
||||
<label for="password">Password</label>
|
||||
<input type="password" name="password" id="password" class="form-control" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
include '../includes/footer.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
// Logout
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'logout') {
|
||||
$_SESSION = [];
|
||||
session_destroy();
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Admin Dashboard
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
<div class="container">
|
||||
<h1 class="mt-5">Admin Panel</h1>
|
||||
<p>Welcome to the admin panel. Here you can manage your products and blog posts.</p>
|
||||
<a href="?action=logout" class="btn btn-danger">Logout</a>
|
||||
|
||||
<h2 class="mt-5">Manage Content</h2>
|
||||
<ul>
|
||||
<li><a href="products.php">Manage Products</a></li>
|
||||
<li><a href="posts.php">Manage Blog Posts</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<?php
|
||||
include '../includes/footer.php';
|
||||
52
admin/posts.php
Normal file
52
admin/posts.php
Normal file
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
// Check if user is logged in
|
||||
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query('SELECT * FROM posts ORDER BY published_at DESC');
|
||||
$posts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
include __DIR__ . '/../includes/header.php';
|
||||
?>
|
||||
<div class="container">
|
||||
<h1 class="mt-5">Manage Blog Posts</h1>
|
||||
<a href="edit_post.php" class="btn btn-primary mb-3">Add New Post</a>
|
||||
|
||||
<?php if (isset($_GET['status']) && $_GET['status'] === 'success'): ?>
|
||||
<div class="alert alert-success">Post saved successfully.</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Title</th>
|
||||
<th>Author</th>
|
||||
<th>Published On</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($posts as $post): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($post['title']); ?></td>
|
||||
<td><?php echo htmlspecialchars($post['author']); ?></td>
|
||||
<td><?php echo date('F j, Y', strtotime($post['published_at'])); ?></td>
|
||||
<td>
|
||||
<a href="edit_post.php?id=<?php echo $post['id']; ?>" class="btn btn-sm btn-info">Edit</a>
|
||||
<a href="delete_post.php?id=<?php echo $post['id']; ?>" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure you want to delete this post?');">Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="index.php">Back to Admin Panel</a>
|
||||
</div>
|
||||
<?php
|
||||
include __DIR__ . '/../includes/footer.php';
|
||||
?>
|
||||
54
admin/products.php
Normal file
54
admin/products.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
// Check if user is logged in
|
||||
if (!isset($_SESSION['loggedin']) || $_SESSION['loggedin'] !== true) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query('SELECT id, name, url_slug, material, application FROM products ORDER BY created_at DESC');
|
||||
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
include __DIR__ . '/../includes/header.php';
|
||||
?>
|
||||
<div class="container">
|
||||
<h1 class="mt-5">Manage Products</h1>
|
||||
<a href="edit_product.php" class="btn btn-primary mb-3">Add New Product</a>
|
||||
|
||||
<?php if (isset($_GET['status']) && $_GET['status'] === 'success'): ?>
|
||||
<div class="alert alert-success">Product saved successfully.</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>URL Slug</th>
|
||||
<th>Material</th>
|
||||
<th>Application</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($products as $product): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars($product['name']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['url_slug']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['material']); ?></td>
|
||||
<td><?php echo htmlspecialchars($product['application']); ?></td>
|
||||
<td>
|
||||
<a href="edit_product.php?id=<?php echo $product['id']; ?>" class="btn btn-sm btn-info">Edit</a>
|
||||
<a href="delete_product.php?id=<?php echo $product['id']; ?>" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure you want to delete this product?');">Delete</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="index.php">Back to Admin Panel</a>
|
||||
</div>
|
||||
<?php
|
||||
include __DIR__ . '/../includes/footer.php';
|
||||
?>
|
||||
33
assets/css/custom.css
Normal file
33
assets/css/custom.css
Normal file
@ -0,0 +1,33 @@
|
||||
body {
|
||||
background-color: #F8F6F4 !important;
|
||||
font-family: 'Helvetica Neue', Arial, sans-serif;
|
||||
color: #38404B;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
color: #A68A64 !important;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Georgia', serif;
|
||||
color: #38404B;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #A68A64;
|
||||
border-color: #A68A64;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background-color: #8b7355;
|
||||
border-color: #8b7355;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #E0CDB8;
|
||||
box-shadow: 0 0 0 0.25rem rgba(166, 138, 100, 0.25);
|
||||
}
|
||||
|
||||
.bg-gradient-light {
|
||||
background: linear-gradient(180deg, #F8F6F4 0%, #FFFFFF 100%);
|
||||
}
|
||||
0
assets/images/blog1.jpg
Normal file
0
assets/images/blog1.jpg
Normal file
0
assets/images/blog2.jpg
Normal file
0
assets/images/blog2.jpg
Normal file
50
blog.php
Normal file
50
blog.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
$pageTitle = "Our Blog";
|
||||
$pageDescription = "Latest news, articles, and insights from the world of luxury carpets and interior design.";
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
// Fetch all posts from the database
|
||||
$posts = [];
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query("SELECT id, title, slug, content, author, image_url, published_at FROM posts ORDER BY published_at DESC");
|
||||
$posts = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
error_log('Failed to fetch posts: ' . $e->getMessage());
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<main class="container mt-5">
|
||||
<div class="row">
|
||||
<div class="col-12 text-center mb-5">
|
||||
<h1 class="display-4">From the Journal</h1>
|
||||
<p class="lead">Design insights, company news, and the art of craftsmanship.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<?php if (empty($posts)): ?>
|
||||
<div class="col-12">
|
||||
<p class="text-center">No articles have been published yet. Please check back soon.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($posts as $post): ?>
|
||||
<div class="col-md-6 mb-4">
|
||||
<div class="card h-100 shadow-sm blog-card">
|
||||
<img src="<?php echo htmlspecialchars($post['image_url'] ?? 'https://picsum.photos/800/600'); ?>" class="card-img-top" alt="<?php echo htmlspecialchars($post['title']); ?>">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h5 class="card-title"><?php echo htmlspecialchars($post['title']); ?></h5>
|
||||
<p class="card-text text-muted">By <?php echo htmlspecialchars($post['author']); ?> on <?php echo date("F j, Y", strtotime($post['published_at'])); ?></p>
|
||||
<p class="card-text"><?php echo substr(htmlspecialchars(strip_tags($post['content'])), 0, 120); ?>...</p>
|
||||
<a href="post.php?slug=<?php echo htmlspecialchars($post['slug']); ?>" class="btn btn-outline-primary mt-auto">Read More</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
125
contact.php
Normal file
125
contact.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
$pageTitle = 'Contact Us - Luxury Carpets';
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
require_once __DIR__ . '/mail/MailService.php';
|
||||
|
||||
$errors = [];
|
||||
$success = false;
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
$name = trim($_POST['name'] ?? '');
|
||||
$company = trim($_POST['company'] ?? '');
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
$phone = trim($_POST['phone'] ?? '');
|
||||
$message = trim($_POST['message'] ?? '');
|
||||
$source_page = $_SERVER['HTTP_REFERER'] ?? 'Direct';
|
||||
|
||||
if (empty($name)) {
|
||||
$errors['name'] = 'Name is required.';
|
||||
}
|
||||
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$errors['email'] = 'A valid email is required.';
|
||||
}
|
||||
if (empty($message)) {
|
||||
$errors['message'] = 'Message is required.';
|
||||
}
|
||||
|
||||
if (empty($errors)) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare(
|
||||
"INSERT INTO inquiries (name, company, email, phone, message, source_page) VALUES (?, ?, ?, ?, ?, ?)"
|
||||
);
|
||||
$stmt->execute([$name, $company, $email, $phone, $message, $source_page]);
|
||||
|
||||
// Send email notification
|
||||
$admin_email = getenv('MAIL_TO') ?: 'admin@example.com'; // Fallback
|
||||
$subject = "New Inquiry from " . htmlspecialchars($name);
|
||||
$body_html = "<h1>New Inquiry</h1>
|
||||
<p><strong>Name:</strong> " . htmlspecialchars($name) . "</p>
|
||||
<p><strong>Company:</strong> " . htmlspecialchars($company) . "</p>
|
||||
<p><strong>Email:</strong> " . htmlspecialchars($email) . "</p>
|
||||
<p><strong>Phone:</strong> " . htmlspecialchars($phone) . "</p>
|
||||
<p><strong>Message:</strong></p>
|
||||
<p>" . nl2br(htmlspecialchars($message)) . "</p>
|
||||
<p><strong>Source:</strong> " . htmlspecialchars($source_page) . "</p>";
|
||||
$body_text = "New Inquiry\n\nName: " . $name . "\nCompany: " . $company . "\nEmail: " . $email . "\nPhone: " . $phone . "\nMessage: " . $message . "\nSource: " . $source_page;
|
||||
|
||||
// Using MailService
|
||||
MailService::sendMail($admin_email, $subject, $body_html, $body_text, ['reply_to' => $email]);
|
||||
|
||||
$success = true;
|
||||
} catch (PDOException $e) {
|
||||
$errors['db'] = 'There was a problem saving your inquiry. Please try again later.';
|
||||
error_log('Inquiry Error: ' . $e->getMessage());
|
||||
} catch (Exception $e) {
|
||||
$errors['mail'] = 'There was a problem sending the notification. Your inquiry was saved.';
|
||||
error_log('Mail Error: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
include __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
|
||||
<main class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card border-0 shadow-sm">
|
||||
<div class="card-body p-5">
|
||||
<h1 class="text-center mb-4">Contact Us</h1>
|
||||
<p class="text-center text-muted mb-5">We would love to hear from you. Please fill out this form and we will get in touch with you shortly.</p>
|
||||
|
||||
<?php if ($success): ?>
|
||||
<div class="alert alert-success" role="alert">
|
||||
<strong>Thank you!</strong> Your inquiry has been sent successfully.
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php if (!empty($errors['db']) || !empty($errors['mail'])): ?>
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<?php echo htmlspecialchars($errors['db'] ?? $errors['mail']); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form action="contact.php" method="POST" novalidate>
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label">Full Name</label>
|
||||
<input type="text" class="form-control <?php echo isset($errors['name']) ? 'is-invalid' : ''; ?>" id="name" name="name" value="<?php echo htmlspecialchars($_POST['name'] ?? ''); ?>" required>
|
||||
<?php if (isset($errors['name'])): ?>
|
||||
<div class="invalid-feedback"><?php echo $errors['name']; ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="company" class="form-label">Company Name</label>
|
||||
<input type="text" class="form-control" id="company" name="company" value="<?php echo htmlspecialchars($_POST['company'] ?? ''); ?>">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">Email Address</label>
|
||||
<input type="email" class="form-control <?php echo isset($errors['email']) ? 'is-invalid' : ''; ?>" id="email" name="email" value="<?php echo htmlspecialchars($_POST['email'] ?? ''); ?>" required>
|
||||
<?php if (isset($errors['email'])): ?>
|
||||
<div class="invalid-feedback"><?php echo $errors['email']; ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="phone" class="form-label">Phone Number (Optional)</label>
|
||||
<input type="tel" class="form-control" id="phone" name="phone" value="<?php echo htmlspecialchars($_POST['phone'] ?? ''); ?>">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="message" class="form-label">Message</label>
|
||||
<textarea class="form-control <?php echo isset($errors['message']) ? 'is-invalid' : ''; ?>" id="message" name="message" rows="5" required><?php echo htmlspecialchars($_POST['message'] ?? ''); ?></textarea>
|
||||
<?php if (isset($errors['message'])): ?>
|
||||
<div class="invalid-feedback"><?php echo $errors['message']; ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary btn-lg">Send Inquiry</button>
|
||||
</div>
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php include __DIR__ . '/includes/footer.php'; ?>
|
||||
1
db/.migration_done
Normal file
1
db/.migration_done
Normal file
@ -0,0 +1 @@
|
||||
done
|
||||
65
db/seed.php
Normal file
65
db/seed.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$products = [
|
||||
[
|
||||
'name' => 'Royal Kashan Carpet',
|
||||
'description' => 'A masterpiece of Persian art, this Royal Kashan carpet features a dense, floral pattern with a central medallion. Hand-knotted from pure silk, it offers a luxurious feel and timeless elegance.',
|
||||
'images' => json_encode(['https://picsum.photos/seed/kashan/800/600', 'https://picsum.photos/seed/kashan2/800/600']),
|
||||
'material' => 'Silk',
|
||||
'application' => 'Living Room, Bedroom',
|
||||
'url_slug' => 'royal-kashan-carpet',
|
||||
'seo_title' => 'Royal Kashan Silk Carpet | Luxury Persian Rugs',
|
||||
'seo_meta_description' => 'Discover the exquisite beauty of our hand-knotted Royal Kashan silk carpet. A timeless piece of art for your luxury interior.',
|
||||
'canonical_url' => '/product/royal-kashan-carpet',
|
||||
'og_title' => 'Royal Kashan Silk Carpet',
|
||||
'og_description' => 'A masterpiece of Persian art, this Royal Kashan carpet features a dense, floral pattern with a central medallion.',
|
||||
'og_image' => 'https://picsum.photos/seed/kashan/1200/630',
|
||||
],
|
||||
[
|
||||
'name' => 'Modern Gabbeh Rug',
|
||||
'description' => 'This modern Gabbeh rug is characterized by its minimalist design and thick, plush pile. Made from hand-spun wool and natural dyes, it brings warmth and contemporary style to any space.',
|
||||
'images' => json_encode(['https://picsum.photos/seed/gabbeh/800/600', 'https://picsum.photos/seed/gabbeh2/800/600']),
|
||||
'material' => 'Wool',
|
||||
'application' => 'Office, Study',
|
||||
'url_slug' => 'modern-gabbeh-rug',
|
||||
'seo_title' => 'Modern Gabbeh Wool Rug | Contemporary Rugs',
|
||||
'seo_meta_description' => 'Add a touch of contemporary elegance with our hand-woven Modern Gabbeh wool rug. Perfect for modern and minimalist interiors.',
|
||||
'canonical_url' => '/product/modern-gabbeh-rug',
|
||||
'og_title' => 'Modern Gabbeh Wool Rug',
|
||||
'og_description' => 'Characterized by its minimalist design and thick, plush pile, this rug brings warmth and contemporary style.',
|
||||
'og_image' => 'https://picsum.photos/seed/gabbeh/1200/630',
|
||||
],
|
||||
[
|
||||
'name' => 'Vintage Turkish Kilim',
|
||||
'description' => 'A beautiful vintage Turkish Kilim, featuring geometric patterns and a rich color palette. This flat-woven rug is a versatile piece that adds a bohemian and historic touch to your home.',
|
||||
'images' => json_encode(['https://picsum.photos/seed/kilim/800/600', 'https://picsum.photos/seed/kilim2/800/600']),
|
||||
'material' => 'Wool and Cotton',
|
||||
'application' => 'Hallway, Kitchen',
|
||||
'url_slug' => 'vintage-turkish-kilim',
|
||||
'seo_title' => 'Vintage Turkish Kilim Rug | Bohemian Flat-Weave Rugs',
|
||||
'seo_meta_description' => 'Explore our collection of vintage Turkish Kilim rugs. Each piece is unique and tells a story of its own, perfect for a bohemian decor.',
|
||||
'canonical_url' => '/product/vintage-turkish-kilim',
|
||||
'og_title' => 'Vintage Turkish Kilim Rug',
|
||||
'og_description' => 'Featuring geometric patterns and a rich color palette, this flat-woven rug is a versatile piece.',
|
||||
'og_image' => 'https://picsum.photos/seed/kilim/1200/630',
|
||||
]
|
||||
];
|
||||
|
||||
$stmt = $pdo->prepare(
|
||||
'INSERT INTO products (name, description, images, material, application, url_slug, seo_title, seo_meta_description, canonical_url, og_title, og_description, og_image) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE name=name'
|
||||
);
|
||||
|
||||
foreach ($products as $product) {
|
||||
$stmt->execute(array_values($product));
|
||||
}
|
||||
|
||||
echo "Database seeded successfully!\n";
|
||||
|
||||
} catch (PDOException $e) {
|
||||
die("Database seeding failed: " . $e->getMessage() . "\n");
|
||||
}
|
||||
43
db/seed_posts.php
Normal file
43
db/seed_posts.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
try {
|
||||
$pdo = db();
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$posts = [
|
||||
[
|
||||
'title' => 'The Timeless Elegance of Hand-Knotted Carpets',
|
||||
'slug' => 'timeless-elegance-hand-knotted-carpets',
|
||||
'content' => 'Hand-knotted carpets are more than just floor coverings; they are works of art, imbued with history and craftsmanship. In this post, we explore the intricate process of creating these masterpieces and why they remain a symbol of luxury and timeless elegance in any interior.',
|
||||
'author' => 'Jane Doe',
|
||||
'image_url' => '/assets/images/blog1.jpg',
|
||||
'seo_title' => 'The Timeless Elegance of Hand-Knotted Carpets',
|
||||
'seo_meta_description' => 'Discover the art and history behind hand-knotted luxury carpets and why they are a timeless addition to any home.'
|
||||
],
|
||||
[
|
||||
'title' => 'How to Choose the Perfect Carpet for Your Space',
|
||||
'slug' => 'how-to-choose-perfect-carpet',
|
||||
'content' => 'Choosing the right carpet can transform a room. This guide provides expert tips on selecting the perfect carpet based on material, color, and foot traffic to match your lifestyle and decor. From plush wool to durable synthetics, find the ideal fit for your home.',
|
||||
'author' => 'John Smith',
|
||||
'image_url' => '/assets/images/blog2.jpg',
|
||||
'seo_title' => 'A Guide to Choosing the Perfect Luxury Carpet',
|
||||
'seo_meta_description' => 'Our expert guide helps you select the perfect luxury carpet for your home, considering material, color, and use.'
|
||||
]
|
||||
];
|
||||
|
||||
$stmt = $pdo->prepare(
|
||||
"INSERT INTO posts (title, slug, content, author, image_url, seo_title, seo_meta_description, published_at)
|
||||
VALUES (:title, :slug, :content, :author, :image_url, :seo_title, :seo_meta_description, NOW())
|
||||
ON DUPLICATE KEY UPDATE title=VALUES(title), content=VALUES(content)"
|
||||
);
|
||||
|
||||
foreach ($posts as $post) {
|
||||
$stmt->execute($post);
|
||||
}
|
||||
|
||||
echo "Successfully seeded the posts table with " . count($posts) . " articles.\n";
|
||||
|
||||
} catch (PDOException $e) {
|
||||
die("Seeding failed: " . $e->getMessage() . "\n");
|
||||
}
|
||||
72
db/setup.php
Normal file
72
db/setup.php
Normal file
@ -0,0 +1,72 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/config.php';
|
||||
|
||||
function run_migrations() {
|
||||
try {
|
||||
$pdo = db();
|
||||
// Enable error reporting
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `inquiries` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`company` VARCHAR(255) NULL,
|
||||
`email` VARCHAR(255) NOT NULL,
|
||||
`phone` VARCHAR(50) NULL,
|
||||
`message` TEXT NOT NULL,
|
||||
`source_page` VARCHAR(255) NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);";
|
||||
$pdo->exec($sql);
|
||||
|
||||
$sql_products = "
|
||||
CREATE TABLE IF NOT EXISTS `products` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`description` TEXT NOT NULL,
|
||||
`images` TEXT,
|
||||
`material` VARCHAR(255),
|
||||
`application` VARCHAR(255),
|
||||
`url_slug` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`seo_title` VARCHAR(255),
|
||||
`seo_meta_description` TEXT,
|
||||
`canonical_url` VARCHAR(255),
|
||||
`og_title` VARCHAR(255),
|
||||
`og_description` TEXT,
|
||||
`og_image` VARCHAR(255),
|
||||
`schema_type` VARCHAR(255) DEFAULT 'Product',
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
);";
|
||||
$pdo->exec($sql_products);
|
||||
|
||||
$sql_posts = "
|
||||
CREATE TABLE IF NOT EXISTS `posts` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`title` VARCHAR(255) NOT NULL,
|
||||
`slug` VARCHAR(255) NOT NULL UNIQUE,
|
||||
`content` TEXT NOT NULL,
|
||||
`author` VARCHAR(255),
|
||||
`image_url` VARCHAR(255),
|
||||
`published_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`seo_title` VARCHAR(255),
|
||||
`seo_meta_description` TEXT,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
);";
|
||||
$pdo->exec($sql_posts);
|
||||
|
||||
} catch (PDOException $e) {
|
||||
error_log("DB setup failed: " . $e->getMessage());
|
||||
// Do not die, just log the error. The page should still render.
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a flag file exists to prevent running this on every page load
|
||||
$migration_flag = __DIR__ . '/.migration_done';
|
||||
if (!file_exists($migration_flag)) {
|
||||
run_migrations();
|
||||
// Create the flag file
|
||||
file_put_contents($migration_flag, 'done');
|
||||
}
|
||||
10
includes/footer.php
Normal file
10
includes/footer.php
Normal file
@ -0,0 +1,10 @@
|
||||
<footer class="text-center mt-5 py-3 bg-white shadow-sm">
|
||||
<div class="container">
|
||||
<p class="mb-0">© <?php echo date('Y'); ?> Luxury Carpets. All Rights Reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<!-- Bootstrap JS -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
70
includes/header.php
Normal file
70
includes/header.php
Normal file
@ -0,0 +1,70 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo htmlspecialchars($seo_title ?? 'Luxury Carpet B2B'); ?></title>
|
||||
<meta name="description" content="<?php echo htmlspecialchars($seo_meta_description ?? 'High-end carpets for B2B clients.'); ?>">
|
||||
|
||||
<!-- SEO Meta Tags -->
|
||||
<?php if (!empty($canonical_url)): ?>
|
||||
<link rel="canonical" href="<?php echo htmlspecialchars($canonical_url); ?>" />
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($no_index)): ?>
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="<?php echo htmlspecialchars($og_type ?? 'website'); ?>">
|
||||
<meta property="og:title" content="<?php echo htmlspecialchars($og_title ?? $seo_title ?? 'Luxury Carpet B2B'); ?>">
|
||||
<meta property="og:description" content="<?php echo htmlspecialchars($og_description ?? $seo_meta_description ?? 'High-end carpets for B2B clients.'); ?>">
|
||||
<meta property="og:image" content="<?php echo htmlspecialchars($og_image ?? $_SERVER['PROJECT_IMAGE_URL'] ?? ''); ?>">
|
||||
<?php if (!empty($canonical_url)): ?>
|
||||
<meta property="og:url" content="<?php echo htmlspecialchars($canonical_url); ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Twitter -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="<?php echo htmlspecialchars($og_title ?? $seo_title ?? 'Luxury Carpet B2B'); ?>">
|
||||
<meta name="twitter:description" content="<?php echo htmlspecialchars($og_description ?? $seo_meta_description ?? 'High-end carpets for B2B clients.'); ?>">
|
||||
<meta name="twitter:image" content="<?php echo htmlspecialchars($og_image ?? $_SERVER['PROJECT_IMAGE_URL'] ?? ''); ?>">
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
|
||||
<!-- JSON-LD Schema -->
|
||||
<?php if (!empty($schema)): ?>
|
||||
<script type="application/ld+json">
|
||||
<?php echo json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT); ?>
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="index.php" style="font-family: Georgia, serif; font-weight: bold;">Luxury Carpets</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav ms-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="products.php">Products</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="blog.php">Blog</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="contact.php">Contact</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
179
index.php
179
index.php
@ -1,150 +1,37 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
@ini_set('display_errors', '1');
|
||||
@error_reporting(E_ALL);
|
||||
@date_default_timezone_set('UTC');
|
||||
// Run DB setup once
|
||||
require_once __DIR__ . '/db/setup.php';
|
||||
|
||||
$phpVersion = PHP_VERSION;
|
||||
$now = date('Y-m-d H:i:s');
|
||||
$pageTitle = 'Luxury Carpets B2B - High-End Solutions';
|
||||
|
||||
include __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>New Style</title>
|
||||
<?php
|
||||
// Read project preview data from environment
|
||||
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? '';
|
||||
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';
|
||||
?>
|
||||
<?php if ($projectDescription): ?>
|
||||
<!-- Meta description -->
|
||||
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
|
||||
<!-- Open Graph meta tags -->
|
||||
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<!-- Twitter meta tags -->
|
||||
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" />
|
||||
<?php endif; ?>
|
||||
<?php if ($projectImageUrl): ?>
|
||||
<!-- Open Graph image -->
|
||||
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<!-- Twitter image -->
|
||||
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
|
||||
<?php endif; ?>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg-color-start: #6a11cb;
|
||||
--bg-color-end: #2575fc;
|
||||
--text-color: #ffffff;
|
||||
--card-bg-color: rgba(255, 255, 255, 0.01);
|
||||
--card-border-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
|
||||
color: var(--text-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
|
||||
animation: bg-pan 20s linear infinite;
|
||||
z-index: -1;
|
||||
}
|
||||
@keyframes bg-pan {
|
||||
0% { background-position: 0% 0%; }
|
||||
100% { background-position: 100% 100%; }
|
||||
}
|
||||
main {
|
||||
padding: 2rem;
|
||||
}
|
||||
.card {
|
||||
background: var(--card-bg-color);
|
||||
border: 1px solid var(--card-border-color);
|
||||
border-radius: 16px;
|
||||
padding: 2rem;
|
||||
backdrop-filter: blur(20px);
|
||||
-webkit-backdrop-filter: blur(20px);
|
||||
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.loader {
|
||||
margin: 1.25rem auto 1.25rem;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.25);
|
||||
border-top-color: #fff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
.hint {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px; height: 1px;
|
||||
padding: 0; margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap; border: 0;
|
||||
}
|
||||
h1 {
|
||||
font-size: 3rem;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1rem;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
p {
|
||||
margin: 0.5rem 0;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
code {
|
||||
background: rgba(0,0,0,0.2);
|
||||
padding: 2px 6px;
|
||||
border-radius: 4px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
}
|
||||
footer {
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
font-size: 0.8rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="card">
|
||||
<h1>Analyzing your requirements and generating your website…</h1>
|
||||
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes">
|
||||
<span class="sr-only">Loading…</span>
|
||||
</div>
|
||||
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p>
|
||||
<p class="hint">This page will update automatically as the plan is implemented.</p>
|
||||
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p>
|
||||
|
||||
<main>
|
||||
<!-- Hero Section -->
|
||||
<div class="container-fluid p-0">
|
||||
<div style="background: url('<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? 'https://images.pexels.com/photos/1643384/pexels-photo-1643384.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'); ?>') no-repeat center center; background-size: cover; height: 60vh;">
|
||||
<div class="d-flex justify-content-center align-items-center h-100" style="background-color: rgba(0, 0, 0, 0.4);">
|
||||
<div class="text-white text-center">
|
||||
<h1 class="display-3" style="font-family: 'Georgia', serif;">Exquisite Carpets for Discerning Businesses</h1>
|
||||
<p class="lead">Discover unparalleled quality and bespoke designs for your luxury projects.</p>
|
||||
<a href="contact.php" class="btn btn-primary btn-lg mt-3">Request a Consultation</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<footer>
|
||||
Page updated: <?= htmlspecialchars($now) ?> (UTC)
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!-- Intro Section -->
|
||||
<div class="container my-5 py-5 text-center">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<h2>The Foundation of Luxury</h2>
|
||||
<p class="lead text-muted">
|
||||
At Luxury Carpets, we provide more than just flooring; we deliver a statement of elegance and craftsmanship. Our B2B services cater to architects, interior designers, and contractors who demand the very best for their clients.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php include __DIR__ . '/includes/footer.php'; ?>
|
||||
57
post.php
Normal file
57
post.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
$post = null;
|
||||
$slug = $_GET['slug'] ?? null;
|
||||
|
||||
if ($slug) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('SELECT * FROM posts WHERE slug = ?');
|
||||
$stmt->execute([$slug]);
|
||||
$post = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
error_log('Failed to fetch post: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (!$post) {
|
||||
http_response_code(404);
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
echo '<div class="container text-center my-5"><h1 class="display-1">404</h1><p class="lead">Article not found.</p><a href="blog.php" class="btn btn-primary">Back to Blog</a></div>';
|
||||
require_once __DIR__ . '/includes/footer.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
// SEO & Page Variables
|
||||
$pageTitle = $post['seo_title'] ?? $post['title'];
|
||||
$pageDescription = $post['seo_meta_description'] ?? substr(strip_tags($post['content']), 0, 160);
|
||||
$og_image = $post['image_url']; // Assuming this is a full URL
|
||||
$og_type = 'article';
|
||||
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
|
||||
<main class="container my-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
<article>
|
||||
<header class="mb-4">
|
||||
<h1 class="fw-bolder mb-1"><?php echo htmlspecialchars($post['title']); ?></h1>
|
||||
<div class="text-muted fst-italic mb-2">
|
||||
Posted on <?php echo date("F j, Y", strtotime($post['published_at'])); ?> by <?php echo htmlspecialchars($post['author']); ?>
|
||||
</div>
|
||||
</header>
|
||||
<figure class="mb-4">
|
||||
<img class="img-fluid rounded" src="<?php echo htmlspecialchars($post['image_url'] ?? 'https://picsum.photos/900/400'); ?>" alt="<?php echo htmlspecialchars($post['title']); ?>" />
|
||||
</figure>
|
||||
<section class="mb-5 fs-5">
|
||||
<?php echo nl2br(htmlspecialchars($post['content'])); // Using nl2br and htmlspecialchars for basic formatting and security. For full HTML, a sanitizer would be needed. ?>
|
||||
</section>
|
||||
</article>
|
||||
<a href="blog.php" class="btn btn-outline-primary">← Back to all articles</a>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
87
product.php
Normal file
87
product.php
Normal file
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
$product = null;
|
||||
$slug = $_GET['slug'] ?? null;
|
||||
|
||||
if ($slug) {
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->prepare('SELECT * FROM products WHERE url_slug = ?');
|
||||
$stmt->execute([$slug]);
|
||||
$product = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
error_log('Failed to fetch product: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// If no product is found, send a 404 response
|
||||
if (!$product) {
|
||||
http_response_code(404);
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
echo '<div class="container text-center my-5"><h1 class="display-1">404</h1><p class="lead">Product not found.</p><a href="products.php" class="btn btn-primary">Back to Catalog</a></div>';
|
||||
require_once __DIR__ . '/includes/footer.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
// --- SEO & Page Variables ---
|
||||
$seo_title = $product['seo_title'];
|
||||
$seo_meta_description = $product['seo_meta_description'];
|
||||
$canonical_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://{$_SERVER['HTTP_HOST']}" . $product['canonical_url'];
|
||||
$og_title = $product['og_title'];
|
||||
$og_description = $product['og_description'];
|
||||
$og_image = $product['og_image']; // Assuming this is a full URL
|
||||
$og_type = 'product';
|
||||
|
||||
$images = json_decode($product['images'], true);
|
||||
|
||||
// JSON-LD Schema for Product
|
||||
$schema = [
|
||||
'@context' => 'https://schema.org',
|
||||
'@type' => 'Product',
|
||||
'name' => $product['name'],
|
||||
'description' => $product['description'],
|
||||
'image' => $images, // Array of image URLs
|
||||
'offers' => [
|
||||
'@type' => 'Offer',
|
||||
'priceCurrency' => 'USD', // Change as needed
|
||||
'price' => '0', // Add a price column if you have one
|
||||
'availability' => 'https://schema.org/InStock'
|
||||
]
|
||||
];
|
||||
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
?>
|
||||
|
||||
<main class="container mt-5">
|
||||
<div class="row">
|
||||
<!-- Product Image Gallery -->
|
||||
<div class="col-md-6 mb-4">
|
||||
<?php if (!empty($images)): ?>
|
||||
<img src="<?php echo htmlspecialchars($images[0]); ?>" class="img-fluid rounded shadow-sm mb-3" alt="<?php echo htmlspecialchars($product['name']); ?>">
|
||||
<div class="row">
|
||||
<?php foreach (array_slice($images, 1) as $image): ?>
|
||||
<div class="col-4">
|
||||
<img src="<?php echo htmlspecialchars($image); ?>" class="img-fluid rounded shadow-sm" alt="<?php echo htmlspecialchars($product['name']); ?> thumbnail">
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Product Details -->
|
||||
<div class="col-md-6">
|
||||
<h1 class="display-5"><?php echo htmlspecialchars($product['name']); ?></h1>
|
||||
<p class="lead text-muted"><?php echo htmlspecialchars($product['material']); ?></p>
|
||||
<hr>
|
||||
<p><?php echo nl2br(htmlspecialchars($product['description'])); ?></p>
|
||||
<h5 class="mt-4">Application</h5>
|
||||
<p><?php echo htmlspecialchars($product['application']); ?></p>
|
||||
<div class="mt-4">
|
||||
<a href="/contact.php" class="btn btn-primary btn-lg">Inquire Now</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
50
products.php
Normal file
50
products.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/includes/header.php';
|
||||
require_once __DIR__ . '/db/config.php';
|
||||
|
||||
// Fetch all products from the database
|
||||
$products = [];
|
||||
try {
|
||||
$pdo = db();
|
||||
$stmt = $pdo->query('SELECT id, name, description, images, url_slug, material, application FROM products ORDER BY created_at DESC');
|
||||
$products = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
} catch (PDOException $e) {
|
||||
error_log('Failed to fetch products: ' . $e->getMessage());
|
||||
// You could display a friendly error message to the user
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<main class="container mt-5">
|
||||
<div class="row">
|
||||
<div class="col-12 text-center mb-5">
|
||||
<h1 class="display-4">Our Luxury Carpets</h1>
|
||||
<p class="lead">Discover our exclusive collection of hand-crafted carpets and rugs.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<?php if (empty($products)): ?>
|
||||
<div class="col-12">
|
||||
<p class="text-center">No products found. Please check back later.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($products as $product): ?>
|
||||
<?php $images = json_decode($product['images'], true); ?>
|
||||
<div class="col-md-4 mb-4">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<img src="<?php echo htmlspecialchars($images[0] ?? 'https://picsum.photos/800/600'); ?>" class="card-img-top" alt="<?php echo htmlspecialchars($product['name']); ?>">
|
||||
<div class="card-body d-flex flex-column">
|
||||
<h5 class="card-title"><?php echo htmlspecialchars($product['name']); ?></h5>
|
||||
<p class="card-text text-muted"><?php echo htmlspecialchars($product['material']); ?> | <?php echo htmlspecialchars($product['application']); ?></p>
|
||||
<p class="card-text"><?php echo substr(htmlspecialchars($product['description']), 0, 100); ?>...</p>
|
||||
<a href="product.php?slug=<?php echo htmlspecialchars($product['url_slug']); ?>" class="btn btn-primary mt-auto">View Details</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
Loading…
x
Reference in New Issue
Block a user