Rebuild article system

This commit is contained in:
2025-06-09 20:59:09 -06:00
parent 2ffa1b2267
commit 6d996abe27
8 changed files with 422 additions and 40 deletions
+16
View File
@@ -0,0 +1,16 @@
{
"name": "gwhc/blog",
"description": "Simple blog management",
"type": "project",
"license": "ISC",
"authors": [
{
"name": "Bill Ross",
"email": "wnross@gwhc.net"
}
],
"require": {
"league/commonmark": "^2.7",
"symfony/yaml": "^6.0"
}
}
+43 -38
View File
@@ -1,57 +1,62 @@
<?php <?php
$debug = 5; #$debug = 5;
require '_debug.php'; require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/lib/debug.php';
require __DIR__ . '/lib/render_markdown.php';
require __DIR__ . '/lib/render_php.php';
# Pattern begins '/' followed by 1 or more characters that are not '/' or '.'
# Pattern begins '/' foloowed by 1 or more characters that are not '/' or '.'
# In particular this blocks attempts to hack into system # In particular this blocks attempts to hack into system
# #
# Example path '/article/market' will result in 'market' which we can try to # Example path '/article/market' will result in 'market' which we can try to
# match with 'market.php' or 'market.md' # match with 'market.php' or 'market.md'
if (preg_match('#/([^/.]+)#',$_SERVER['PATH_INFO'], $m) === false) { # Nullish ?? is used to set default page for article summaries
if (!preg_match('#/([^/.]+)#',$_SERVER['PATH_INFO']??'/index', $m)) {
http_response_code('400'); http_response_code('400');
echo "Request {$_SERVER['PATH_INFO']} malformed"; echo "Request Path info malformed";
exit; exit;
} }
$page = $m[1];
# Identify type of file as PHP or Markdown $page = $m[1];
if (file_exists($page . '.php')) { if ($page !== 'index') {
$file = $page . '.php'; # Identify type of file as PHP or Markdown
$type = 'php'; if (file_exists($page . '.php')) {
} else if (file_exists($page . '.md')) { $file = $page . '.php';
$file = $page . '.md'; $type = 'php';
$type = 'markdown'; $article = render_php($file);
} else if (file_exists($page . '.md')) {
$file = $page . '.md';
$type = 'markdown';
$article = render_markdown($file);
} else {
# Unknown or invalid path
http_response_code('404');
echo "File '$page' not found";
exit;
}
} else { } else {
# Unknown or invalid path $article = [
http_response_code('404'); 'meta' => [ 'title' => 'articles' ],
echo "File '$page' not found"; 'html' => <<<HTML
exit; <h1>Placeholder for article listings</h1>
HTML,
];
} }
$template = file_get_contents('template.inc');
$result = preg_replace_callback('/\[(\w+)\]/', function ($matches) use ($article) {
$key = $matches[1];
return isset($article['meta'][$key]) ? $article['meta'][$key] : $matches[0]; // fallback to original if key not found
}, $template);
$rendered= preg_replace('/\[contents?\]/', $article['html'], $result);
debug("PAGE: $page\n" debug("PAGE: $page\n"
."TYPE: $type\n" ."TYPE: $type\n"
."FILE: $file\n"
."PATH: {$_SERVER['PATH_INFO']}\n"); ."PATH: {$_SERVER['PATH_INFO']}\n");
# Load file, we do include rather than file_get_contents so PHP can be echo $rendered;
# executed if needed
ob_start();
include __DIR__ . '/' . $file;
$contents = ob_get_clean();
# Split off head matter
#
# this pattern uses the 'ms' modifier to treat multiline strings as a
# single string, and let '\s', '.' etc treat newlines as whitespace
# I match an _optional_ HTML ( '<!-- nnnn -->') comment if we want to wrap
# the headmatter in a comment.
#
# The headmatter is delimited by either '----' or '++++' as per
# Markdown/yaml standards.
# Technical note that '+' is a regex character so \+{3,} instead of ++++
if (preg_match('/^(<!--\s*)?(-{3,}|\+{3,})(.*)(-{3,}|\+{3,})(-->)?(.*)/ms',$contents, $parts) === true) {
$var_dump($parts);
}
+2 -2
View File
@@ -1,4 +1,4 @@
---- ---
# Markdown Friendly Headmatter # Markdown Friendly Headmatter
date: 2025-05-08 date: 2025-05-08
title: Why is translation important title: Why is translation important
@@ -9,7 +9,7 @@ tags:
- Multilingual websites - Multilingual websites
- Customer trust - Customer trust
- SEO optimization - SEO optimization
---- ---
In todays global marketplace, businesses of all sizes are reaching out to customers beyond their local borders. For small to medium-sized enterprises (SMEs), having a corporate website that speaks the language of potential customers is no longer just a nice-to-have; its essential. Heres why translation is important for your corporate website. In todays global marketplace, businesses of all sizes are reaching out to customers beyond their local borders. For small to medium-sized enterprises (SMEs), having a corporate website that speaks the language of potential customers is no longer just a nice-to-have; its essential. Heres why translation is important for your corporate website.
View File
+36
View File
@@ -0,0 +1,36 @@
<?php
use League\CommonMark\Environment\Environment;
use League\CommonMark\MarkdownConverter;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
use Symfony\Component\Yaml\Yaml;
function render_markdown($file) {
// Set up the environment with FrontMatter and GFM support
$environment = new Environment([]);
$environment->addExtension(new CommonMarkCoreExtension());
$environment->addExtension(new GithubFlavoredMarkdownExtension());
$environment->addExtension(new FrontMatterExtension());
$converter = new MarkdownConverter($environment);
$markdownText = file_get_contents($file);
// Convert markdown and extract front matter
/** @var RenderedContentWithFrontMatter $result */
$result = $converter->convert($markdownText);
// Parse YAML front matter
if ($result instanceof RenderedContentWithFrontMatter) {
$frontMatter = $result->getFrontMatter();
}
$html = $result->getContent();
// return result
return [
'meta' => $frontMatter,
'html' => $html,
];
}
+30
View File
@@ -0,0 +1,30 @@
<?php
use Symfony\Component\Yaml\Yaml;
function render_php($file) {
ob_start();
#include __DIR__ . '/' . $file;
include $file;
$html = ob_get_clean();
$meta = [];
# Split off head matter
#
# this pattern uses the 'ms' modifier to treat multiline strings as a
# single string, and let '\s', '.' etc treat newlines as whitespace
# I match an _optional_ HTML ( '<!-- nnnn -->') comment if we want to wrap
# the headmatter in a comment.
#
# The headmatter is delimited by either '----' or '++++' as per
# Markdown/yaml standards.
# Technical note that '+' is a regex character so \+{3,} instead of ++++
if (preg_match('/^(<!--\s*)?(-{3,}|\+{3,})\s*(.*?)(-{3,}|\+{3,})\s*(-->)?\s*(.*)/ms',$html, $parts) === 1) {
$html = $parts[6];
$meta = array_merge($meta,Yaml::parse($parts[3]));
}
return [
'html' => $html,
'meta' => $meta,
];
}
+282
View File
@@ -0,0 +1,282 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>[title]</title>
<meta name="description" content="[description]">
<meta name="keywords" content="[keywords]">
<meta property="og:type" content="website">
<meta property="og:title" content="Contact Us - Enter Chat">
<meta property="og:description" content="Get in touch with us for any inquiries, support, or feedback. We're here to help you with seamless messaging solutions.">
<meta property="og:image" content="">
<meta property="og:url" content="https://dev3.jit-tr.com/contact.php">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Contact Us - Enter Chat">
<meta name="twitter:description" content="Get in touch with us for any inquiries, support, or feedback. We're here to help you with seamless messaging solutions.">
<meta name="twitter:image" content="">
<meta name="twitter:site" content="https://dev3.jit-tr.com/contact.php">
<meta name="author" content="[author]">
<meta name="google-site-verification" content="ruoLJ__fx72vnjayjwZZ7aUVmKHCHGQWq98899JCWCA">
<meta name="google-site-verification" content="XKIBolRewxihYBCtX_IYrVMzM0L90Xb8W86zLhP8usw" data-owner="Bill">
<link rel="icon" href="/icons/favicon.ico">
<link rel="apple-touch-icon" href="/icons/apple-icon-precomposed.png">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Raleway:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap">
<!-- Vendor CSS Files -->
<link rel="stylesheet" href="/assets/bootstrap/css/bootstrap.min.css">
<link rel="stylesheet" href="/assets/bootstrap-icons/bootstrap-icons.css">
<link rel="stylesheet" href="/assets/aos/aos.css">
<link rel="stylesheet" href="/assets/glightbox/css/glightbox.min.css">
<link rel="stylesheet" href="/assets/swiper/swiper-bundle.min.css">
<!-- Main CSS File -->
<link rel="stylesheet" href="/assets/css/main.css">
<!-- JITTR CSS File -->
<link rel="stylesheet" href="/assets/css/main2.css">
<link rel="stylesheet" href="/css/flaticon.css">
<!-- Carousel File -->
<link rel="stylesheet" href="/css/carousel.css">
<!-- =======================================================
* Template Name: Bootslander
* Template URL: https://bootstrapmade.com/bootslander-free-bootstrap-landing-page-template/
* Updated: Aug 07 2024 with Bootstrap v5.3.3
* Author: BootstrapMade.com
* License: https://bootstrapmade.com/license/
======================================================== -->
<script src="/js/jquery-3.7.0.min.js"></script>
<script src="/js/jquery-ui.min.js"></script>
<script src="/js/jittr.js"></script>
<style>
.faq code i { font-size: x-large; font-weight: bold; color: red;}
.hero { min-height: 1px; padding: 180px 0 12px 0; }
.tab-pane { padding: 2rem; background-color: #f2f2f2 ;}
.SBimg { border: 1px solid #278714; border-radius: 5%; width: 75% }
</style>
</head>
<body class="index-page">
<header id="header" class="header d-flex align-items-center fixed-top">
<div class="container-fluid container-xl position-relative d-flex align-items-center justify-content-between">
<a href="/" class="logo d-flex align-items-center">
<img src="https://1l2m.sfo3.digitaloceanspaces.com/1l2m_imgs/logoTree0.png" alt="logo"
style="max-height: 150px!important; max-width: 150px!important;"
class="rounded-circle border border-3 border-dark">
<h1 class='sitename'><!-- NOtr -->Just In Time Translations<!-- NOtrEND -->
<img style="width: 5%;" src='https://1l2m.sfo3.digitaloceanspaces.com/flags/EN-CA.30x20.gif'></h1> </a>
<nav id="navmenu" class="navmenu">
<ul>
<li class="dropdown"><a href="#">
<span>Options</span> <i class="bi bi-chevron-down toggle-dropdown"></i></a>
<ul>
<li><a href="index.php">Home</a></li>
<li><a href="pricing.php">Basic Pricing</a></li>
<li><a href="faqs.php">FAQs</a></li>
<li><a href="contact.php">Contact</a></li>
<li><a href="https://onelinetomarket.com">MORE</a></li>
</ul>
</li>
<li><a href="pif.php">
<span style="background-color: #1acc8d; color: black; padding: 5px; border-radius: 25%;">
PIF
</span>
</a>
</li>
<li><a href="ourBO.php">Our BackOffice</a></li>
<li><a href="login.php">Log In</a></li>
</ul>
<i class="mobile-nav-toggle d-xl-none bi bi-list"></i>
</nav>
</div>
</header>
<main class="main">
<!-- Hero Section -->
<section id="hero" class="hero section dark-background">
<img src="https://1l2m.sfo3.digitaloceanspaces.com/1l2m_imgs/hero-bg-2.jpg" alt="" class="hero-bg">
<svg class="hero-waves" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 24 150 28 " preserveAspectRatio="none">
<defs> <path id="wave-path" d="M-160 44c30 0 58-18 88-18s 58 18 88 18 58-18 88-18 58 18 88 18 v44h-352z"></path> </defs>
<g class="wave1"> <use xlink:href="#wave-path" x="50" y="3"></use> </g>
<g class="wave2"> <use xlink:href="#wave-path" x="50" y="0"></use> </g>
<g class="wave3"> <use xlink:href="#wave-path" x="50" y="9"></use> </g>
</svg>
</section>
<!-- /Hero Section -->
<!-- Article Section -->
<section class="article section">
<div class="container section-title" data-aos="fade-up">
<h2>[title]</h2>
</div>
<div class="container" data-aos="fade" data-aos-delay="100">
<div class="row gy-4">
[content]
</div>
</div>
</section>
<!-- /Contact Section -->
</main>
<footer id="footer" class="footer dark-background">
<div class="container footer-top">
<div class="row gy-4">
<div class="col-lg-4 col-md-6 footer-about">
<a href="https://onelinetomarket.com" class="logo d-flex align-items-center">
<span class="sitename"><!-- NOtr -->One Line to Market<!-- NOtrEND --></span>
</a>
<div class="footer-info">
<img src="https://1l2m.sfo3.digitaloceanspaces.com/1l2m_imgs/1logoG-1.gif" style="width: 15%; background-color: white;" class="rounded-circle border border-3 border-dark">
Translate <b>and MARKET</b><br>your WHOLE Website Instantly
</div>
<div class="footer-contact pt-3">
</div>
<div class="social-links d-flex mt-4">
<a href="https://www.facebook.com/JustInTime.Translations"><i class="bi bi-facebook"> </i></a>
</div>
</div>
<div class="col-lg-2 col-md-3 footer-links">
<h4>Useful Links</h4>
<ul>
<li class="dropdown"><a href="#">
<span>Options</span> <i class="bi bi-chevron-down toggle-dropdown"></i></a>
<ul>
<li><a href="index.php">Home</a></li>
<li><a href="pricing.php">Basic Pricing</a></li>
<li><a href="faqs.php">FAQs</a></li>
<li><a href="contact.php">Contact</a></li>
<li><a href="https://onelinetomarket.com">MORE</a></li>
</ul>
</li>
<li><a href="pif.php">
<span style="background-color: #1acc8d; color: black; padding: 5px; border-radius: 25%;">
PIF
</span>
</a>
</li>
<li><a href="ourBO.php">Our BackOffice</a></li>
<li><a href="login.php">Log In</a></li>
</ul>
</div>
<div class="col-lg-2 col-md-3 footer-links">
<h4>Our Policies</h4>
<ul>
<li><a href="/terms.php">Terms of service</a></li>
<li><a href="/privacy.php">Privacy policy</a></li>
<li><a href="/cookies.php">Cookie policy</a></li>
</ul>
<hr>
<ul>
<li><a href="/policies/standards.php">Ethical software development</a></li>
<li><a href="/policies/commercial.php">Commercial Schedule for Public Release</a></li>
<li><a href="/policies/health.php">Health and Safety</a></li>
<li><a href="/policies/skills.php">Skills and Apprenticeships</a></li>
<li><a href="/policies/social.php">Sustainability and Social Value</a></li>
<li><a href="/policies/cyber.php">Data Protection and Cyber Security Policy</a></li>
<li><a href="/policies/financial.php">Financial Assessment</a></li>
<li><a href="/policies/slavery.php">Tackling Modern Slavery in Supply Chains</a></li>
<li><a href="/policies/details.php">Ensuring Ethical Use of Our Software - Detailed Series</a></li>
</ul>
</div>
<div class="col-lg-4 col-md-12 footer-newsletter">
<a href="//promote.trustbyreviews.com/one-line-to-market" target="_blank">
<img src="https://1l2m.sfo3.digitaloceanspaces.com/1l2m_imgs/reviews-tr.png" alt="a-reviews" style="width: 80%">
</a>
</div> </div>
</div>
<div class="footer-copyright">
<div style="float: left; margin-left: 3rem;">
<a href="https://training.kuzik.com/" target="_blank" style="text-decoration: none;">
created by ...
<img class="flg" src="https://1l2m.sfo3.digitaloceanspaces.com/1l2m_imgs/ttt.gif" style="width: 10%">
</a>
<a href="https://www.greatwesthosting.com/" target="_blank">
<img class="flg" src="https://1l2m.sfo3.digitaloceanspaces.com/1l2m_imgs/ross.png" style="width: 10%">
</a>
<img src="https://1l2m.sfo3.digitaloceanspaces.com/1l2m_imgs/uptime.png">
</div>
</div>
<!-- NOtr -->
<div class="container copyright text-center mt-4">
<p>
<span>Website Copyright</span>
<strong class="px-1 sitename">Bootslander</strong>
<span>All Rights Reserved</span>
</p>
<div class="credits">
<!-- All the links in the footer should remain intact. -->
<!-- You can delete the links only if you've purchased the pro version. -->
<!-- Licensing information: https://bootstrapmade.com/license/ -->
Designed by <a href="https://bootstrapmade.com/">BootstrapMade</a>
</div>
</div>
<!-- NOtrEND -->
</footer>
<!-- Scroll Top -->
<a href="#" id="scroll-top" class="scroll-top d-flex align-items-center justify-content-center">
<i class="bi bi-arrow-up-short"> </i>
</a>
<!-- Vendor JS Files -->
<script src="/assets/bootstrap/js/bootstrap.bundle.min.js"></script>
<!--script src="/assets/php-email-form/validate.js"></script-->
<script src="/assets/aos/aos.js"></script>
<script src="/assets/glightbox/js/glightbox.min.js"></script>
<script src="/assets/purecounter/purecounter_vanilla.js"></script>
<script src="/assets/swiper/swiper-bundle.min.js"></script>
<!-- Carousel -->
<script src="/js/jittr_carousel.js"></script>
<!-- Main JS File -->
<script src="/assets/js/main.js"></script>
<script>
$(document).ready(function(){
$('[data-bs-toggle="tooltip"]').tooltip();
});
</script>
<script src='https://dev.api.jit-tr.com/?seo=onelinetomarket.com'></script>
</body>
</html>
+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<title>[title]</title>
</head>
<body>
<h1>[title]</h1>
<p>Description: [description]
[contents]
</body>
</html>