How could I improve this template system? - php

At the moment, I have a base HTML template file. When ever I want to make a new page, I copy the template and place some require_once statements in between specific tags. I was wondering if there's a better way that would make it unnecessary to copy the template each time. Here's a typical example:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="css/second.css" />
<script language="JavaScript" type="text/javascript"
src="js/validation_functions.js"></script>
<title>Order a Ticket for the ball</title>
</head>
<body>
<div id="banner">St. Tom's Ambulance Ball</div>
<!-- START[container] -->
<!-- "body" -->
<div id="container">
<!-- START[header] -->
<div id="header">
<!-- header -->
<div id="header_text">introduction</div>
<div id="header_cell2">the process</div>
<div id="header_cell3">start</div>
</div>
<!-- END[header -->
<!-- START[content] -->
<!-- "other container" -->
<div id="content">
<!-- START[form] -->
<div id="form">
<?php
require_once(realpath($config["directories"]["views"]."/index.form.view.php"));
?>
</div>
<!-- END[form] -->
<!-- START[data] -->
<!-- "main content" -->
<div id="data">
<?php
require_once(realpath($config["directories"]["views"]."/index.data.view.php"));
?>
</div>
<!-- END[data] -->
<!-- START[side] -->
<div id="side">
<?php
require_once(realpath($config["directories"]["views"]."/index.side.view.php"));
?>
</div>
<!-- END[side] -->
</div>
<!-- END[content] -->
<!-- START[footer] -->
<div id="footer">
<!-- footer -->
<div id="footer_text">
<ul>
<li>home</li>
<li>partners</li>
<li>projects</li>
<li>contact us</li>
</ul>
</div>
<div id="footer_cell2"> </div>
<div id="footer_cell3"> </div>
</div>
<!-- END[footer] -->
</div>
<!-- END[container] -->
</body>
</html>
EDIT: I have taken note of your suggestions to use GET. The new idea is to have each request url formed as index.php?page=page_name. This request would then be dealt with by a main controller which then sets the variables of the template based on the value of $_GET['page']. For this, the template will now be:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="css/second.css" />
<script language="JavaScript" type="text/javascript"
src="js/validation_functions.js"></script>
<title><?php h($title) ?></title>
</head>
<body>
<div id="banner">St. Tom's Ambulance Ball</div>
<!-- START[container] -->
<!-- "body" -->
<div id="container">
<!-- START[header] -->
<div id="header">
<!-- header -->
<div id="header_text"><?php h($header_1) ?></div>
<div id="header_cell2"><?php h($header_2) ?></div>
<div id="header_cell3"><?php h($header_3) ?></div>
</div>
<!-- END[header -->
<!-- START[content] -->
<!-- "other container" -->
<div id="content">
<!-- START[form] -->
<div id="form">
<?php
require_once(realpath($view_1));
?>
</div>
<!-- END[form] -->
<!-- START[data] -->
<!-- "main content" -->
<div id="data">
<?php
require_once(realpath($view_2));
?>
</div>
<!-- END[data] -->
<!-- START[side] -->
<div id="side">
<?php
require_once(realpath($view_3));
?>
</div>
<!-- END[side] -->
</div>
<!-- END[content] -->
<!-- START[footer] -->
<div id="footer">
<!-- footer -->
<div id="footer_text">
<ul>
<li>home</li>
<li>partners</li>
<li>projects</li>
<li>contact us</li>
</ul>
</div>
<div id="footer_cell2"> </div>
<div id="footer_cell3"> </div>
</div>
<!-- END[footer] -->
</div>
<!-- END[container] -->
</body>
</html>
Note: h() is a function that first of all removes all undesired entity tags before echoing a string.
On a related note, at the top of each page I have some controller files which are included with require_once. I was wondering if it would be possible to implement a function that simply includes files based on a specific input string (name of the functionality/page) i.e "index" in this way:
function include_controller($page){
switch($page){
case "index":
require_once(realpath($config["directories"]["controllers"]."/index_.php"));
break;
case "checkout":
require_once(realpath($config["directories"]["controllers"]."/checkout_.php"));
break;
default:
break;
}
}

Instead of hard coding the includes into each file, you could have a controller file in which you pass the page to be displayed through a $_GET variable. The controller then handles the logic and includes the appropriate page or pages. This is the way a lot of MVC frameworks do it.
Edit: To answer your second question, instead of using a switch, you could just check to make sure the file exists. If it does, include that file, otherwise output an error ("Page doesn't exists" or something similar).
function include_controller($page){
if (file_exists($config["directories"]["controllers"]."/$page_.php")) {
// page exists, include it
require_once($config["directories"]["controllers"]."/$page_.php"));
} else {
// page not found
}
}
Obviously you should probably make the function a little more robust and probably limit the files that will be included to a certain directory or something. Also make sure you properly filter the $page variable so users aren't able to access any file.

Keep this one file as your template file. Then for all the functionality in your site always hit this file. Lets sat this file is index.php. So all functionality requests go to index.php. But with different parameters so for functionality A.
index.php?function=a
For functionality b
index.php?function=b
you can add more parameters also.
Now on the basis of a,b and the set of parameters see what files you want to include as require once.

Like the others already said, it would be better to use some kind of MVC framework. Or at least use a template engine (e.g. Smarty). Your example is ok though, for the 90ies :)

You can get by with one template if you choose a different way of specifying what page is being requested, such as using a GET variable. You can load the pages in a database and specify each of the included pieces, then have one php 'template engine' that loads the requested page from the database and outputs the template with the right includes.

If your server supports it, you can references to things you want to include on all pages in .htaccess:
php_value auto_prepend_file "header.php"
php_value auto_append_file "footer.php"
(Found this on codingforums.com)

Related

Which is the best way to load header, nav and footer? I used php but I'm not sure

I have got header.html, nav.html and footer.html. I need to load them on a index.php.
is it right? Because this works but I don't know if this is the best way to do.
index.php
<html>
<body>
<header><?php require('../layout/header.html')?></header>
<nav><?php require('../layout/nav.html')?></nav>
<div id="content">Hello World</div>
<footer><?php require('../layout/footer.html')?></footer>
</body>
</html>
header.php
<html>
<body>
<img src="../images/header.png">
</body>
</html>
You cannot have multiple <html> tags in the resulting HTML, i.e., the following code is not valid:
<html>
<html>
<header></header>
</html>
</html>
When you split your HTML into different files in order to reuse code, you have to consider that they will be, probably, injected in a pre-existent HTML code. Therefore, I would suggest the following code:
main.html
<html>
<body>
<!-- Header -->
<?php require('../layout/header.html')?>
<!-- Nav -->
<?php require('../layout/nav.html')?>
<!-- Content -->
<div id="content">Hello World</div>
<!-- Footer -->
<?php require('../layout/footer.html')?>
</body>
</html>
layout/header.html
<header>
<!-- Your header HTML -->
</header>
layout/nav.html
<nav>
<!-- Your Nav HTML -->
</nav>
layout/footer.hml
<footer>
<!-- Your footer HTML -->
</footer>

how to load code using codemirror

I have a PHP file that involved with codemirror which works great, but I want each text area to load the code from other file using PHP like index.php, main.css, main.js, and show preview from all of those files to combines.
My question is that how can write that code inside of each text area to link another page! I have tried to put <?php include('css/main.css'); ?> statement inside of one of text area for css and is not working.
Please see see full codes..
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/codemirror/3.19.0/codemirror.css"> <link rel="stylesheet" href="css/style.css">
<div id="wrap">
<!-- Code Editors --> <section id="code_editors">
<div id="html" class="code_box">
<h3>HTML</h3>
<textarea name="html"></textarea>
</div>
<div id="css" class="code_box">
<h3>CSS</h3>
<textarea name="css"></textarea>
</div>
<div id="js" class="code_box">
<h3>JavaScript</h3>
<textarea name="js"></textarea>
</div>
</section>
<!-- Sandboxing --> <section id="output">
<iframe></iframe> </section> </div>
<script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/3.19.0/codemirror.js"></script>
<!-- For HTML/XML --> <script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/3.19.0/mode/xml/xml.js">/script><script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/3.19.0/mode/htmlmixed/htmlmixed.js"></script>
<!-- For CSS --> <script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/3.16.0/mode/css/css.js"></script>
<!-- For JS --> <script src="//cdnjs.cloudflare.com/ajax/libs/codemirror/3.19.0/mode/javascript/javascript.js"></script> <script src="js/js.js"></script>
Many thanks.
What you are doing is trying to include the css file contents without link tag. Replace <link rel="stylesheet" type="text/css" href="css/main.css"> instead of <?php include('css/main.css'); ?>.

Quitting Smarty to do it manually

I am facing the problem that I'm not really sure how to develop without a framework or a template engine. I started coding that way and now I want to go to basics.
I used to work with this MVC schema, using Codeigniter and Smarty as a template engine. What I want to do now is to use raw php without both tools mentioned.
I don't know how to "copy" the concept of Smarty's "block" and "extends".
I used to define a base.tpl file which had html head, only the body tag, and the base css and js files (the ones that are always used in every page of the site), like this: (snippet)
<!DOCTYPE html>
<head>
<meta charset="utf-8" />
<title>Dashboard</title>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport" />
<meta content="" name="description" />
<meta content="" name="author" />
<!-- ================== BEGIN BASE CSS STYLE ================== -->
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
<link href="{site_url()}assets/css/animate.min.css" rel="stylesheet" />
<!-- ================== END BASE CSS STYLE ================== -->
<!-- ================== BEGIN PAGE LEVEL CSS STYLE ================== -->
{block name='custom_css'}{/block}
<!-- ================== END PAGE LEVEL CSS STYLE ================== -->
<!-- ================== BEGIN BASE JS ================== -->
<script src="{site_url()}assets/plugins/pace/pace.min.js"></script>
<!-- ================== END BASE JS ================== -->
</head>
<body>
<div id="page-container" class="fade page-sidebar-fixed page-header-fixed">
<div id="header" class="header navbar navbar-default navbar-fixed-top">
<div class="container-fluid">
{include file='base/header.tpl'}
</div>
</div>
<!-- BEGIN PAGE -->
<div class="page-content">
<!-- BEGIN PAGE CONTAINER-->
<div class="container-fluid">
<!-- BEGIN PAGE HEADER-->
<div class="row-fluid">
<div class="span12">
<!-- BEGIN PAGE TITLE & BREADCRUMB-->
{include file='admin/base/breadcrumb.tpl'}
<!-- END PAGE TITLE & BREADCRUMB-->
</div>
</div>
<!-- END PAGE HEADER-->
{block name='content'}{/block}
</div>
<!-- END PAGE CONTAINER-->
</div>
<!-- END PAGE -->
and then when I need to call this base.tpl I did this:
{extends file='base/base.tpl'}
{block name='custom_css}
<link href="{site_url()}assets/css/pages/blog.css" rel="stylesheet" type="text/css"/>
{/block}
{block name='content'}
<div class="row">
<div class="col-md-3 col-sm-6">
<div class="widget widget-stats bg-green">
<div class="stats-icon stats-icon-lg"><i class="fa fa-globe fa-fw"></i></div>
<div class="stats-title">TODAY'S VISITS</div>
<div class="stats-number">7,842,900</div>
<div class="stats-progress progress">
<div class="progress-bar" style="width: 70.1%;"></div>
</div>
<div class="stats-desc">Better than last week (70.1%)</div>
</div>
</div>
I have been searching but I am affraid I'm missing the right words to search because I am not finding answers.
I would like to be guided please!
Another way could be to do something like this. I feel like this is probably closer to what a template engine ends up with, but with using the {block} syntax instead.
index.php
<?php
$blocks = array();
function add_block($name, $callback){
global $blocks;
ob_start();
$callback();
$output = ob_get_flush();
$blocks[$name] = $output;
}
function get_block($name){
global $blocks;
if(!empty($blocks[$name])){
return $blocks[$name];
}
return '';
}
//stop any errors from being output.
ob_start();
//include the page code
include 'page.php';
$cleanup = ob_end_clean();
//now output the template
include 'template.php';
page.php
<?php
add_block('head', function(){
?><script type="text/javascript">/* Some JS */</script><?php
});
add_block('body', function(){
?><p>Some body text goes here</p><?php
});
template.php
<html>
<head>
<title>Site Title</title>
<?php echo get_block('head'); ?>
</head>
<body>
<?php echo get_block('body'); ?>
</body>
<?php echo get_block('after_body'); ?>
</html>
I'm not sure how smarty does it and have actually never used a templating engine myself. But maybe this could be how it's done.
Say we have:
index.php
page.php
template.php
When we go to index.php it could start and output buffer and include page.php. After the include catch the output buffer and use some regular expressions to match and blocks found within it and put them into variables.
Now do the same for the template.php and find all the blocks in there too and replace the blocks with the blocks found in page.php.
I don't actually think that's how templating engines do it. But that's one possible way.
A very tiny self made, templating engine
based on regex replace using an array hook
to "manually" parse templates
(but i grant you, smarty is more functional)
To any question, feel free to answer me here
The regex match whole file's term like {term-_},
and replace it by a php condition who will be executed on at rendering time.
if a mark" doesn't found in $vars, it will simply replaced by an empty string
Engine
function parse($vars, $tpl)
{
return preg_replace
(
'#\{([a-z0-9\-_]*?)\}#Ssie',
'( ( isset($vars[\'\1\']) )
? $vars[\'\1\']
: \'\'
);',
file_get_contents(TEMPLATE_DIR.$tpl)
);
}
part of index
<html>
<head>...</head>
{body}
</html>
part of body
<body>
<div class='ui'>{username}</div>
</body>
Usage
<?php
// include engine function
define("TEMPLATE_DIR", __DIR__."templates/");
require_once("library/parse.php");
// just init $vars on top of index
$vars = [];
// and access and fill it anywhere
$vars = ["username" => $_SESSION["user"]];
// prepare the body including previous $vars declarations
$vars["body"] = parse($vars, 'body');
echo parse($vars, 'index');
Output
<html>
<head>...</head>
<body>
<div class='ui'>Stack Overflow :)</div>
</body>
</html>
You can improve it by using constant and prevent double wrap marker {{}} or more, or placing debug trace...
Add this to start of engine to prevent templates containing object bracket can be bad interpreted as a templates marker :
$out = file_get_contents(TEMPLATE_DIR.$tpl);
$out = str_replace("{{}}", "{}", $out);
To use constant, you can use perform as like :
$empty = (DEBUG) ? "_EMPTY_" : "";
return preg_replace
(
'#\{([a-z0-9\-_]*?)\}#Ssie',
'( ( isset($vars[\'\1\']) )
? $vars[\'\1\']
: ( defined(\'_\'.strtoupper(\'\1\').\'_\')
? constant(\'_\'.strtoupper(\'\1\').\'_\')
: $empty
)
);',
$out
);
Note:
__DIR__
used in my code is valid for PHP >= 5.3.0 try
but you can use
dirname(__FILE__)
For PHP < 5.3.0 try

HTML Templates -- php?

So, I'm making a site about WWI as a school assignment, and I want this to appear in every document:
<!DOCTYPE html>
<html>
<head>
<title>1914</title>
<script src="modernizr-1.5.js"></script>
<link href="styles.css" type="text/css" rel="stylesheet" />
<meta charset="utf-8" />
</head>
<body>
<div id="container">
<header>
<img src="images/banner.png" alt="World War I" style="border: none"/>
<nav>
<ul>
<li><span>Home</span></li>
<li><span>1914</span></li>
<li><span>1915</span></li>
<li><span>1916</span></li>
<li><span>1917</span></li>
<li><span>1918</span></li>
</ul>
</nav>
</header>
<section>
<article>
<br style="clear: both" />
</article>
<aside>
</aside>
</section>
<footer style="font-weight: bold; letter-spacing: .1em">
Citations •
About
</footer>
</div>
</body>
</html>
I think it's kind of stupid to copy-paste all this into each document, and painstakingly go in and change each page separately if I just want to change one word or tag. Is there a way I can put this in template.htm (or something similar) and have php or javascript code take this and insert everything from the requested file inside of the <article> tag? I don't know a lot of php, so this is probably a piece of cake for you gurus, but I would appreciate the help.
Using php includes:
Save this as top.php
<html>
<head>
<title><?php echo $title; ?></title>
<script src="modernizr-1.5.js"></script>
<link href="styles.css" type="text/css" rel="stylesheet" />
<meta charset="utf-8" />
</head>
<body>
<div id="container">
<header>
<img src="images/banner.png" alt="World War I" style="border: none"/>
<nav>
<ul>
<li><span>Home</span></li>
<li><span>1914</span></li>
<li><span>1915</span></li>
<li><span>1916</span></li>
<li><span>1917</span></li>
<li><span>1918</span></li>
</ul>
</nav>
</header>
<section>
Save this as bottom.php
<aside>
</aside>
</section>
<footer style="font-weight: bold; letter-spacing: .1em">
Citations •
About
</footer>
</div>
</body>
</html>
Then your individual pages would be like this:
<?php $title = '1914'; include("top.php");?>
//This would be where you would make the changes that need to be made on each page.
<article>
<br style="clear: both" />
</article>
<?php include("bottom.php");?>
You could consider one of these popular template engines :
Smarty (becoming outdated)
Latte (used mostly by the Nette community)
Twig (used mostly by the Symfony community)
Mustache (official implementations of this templating engine exist in more than two dozen proramming/scripting languages)
I tend to favor Mustache, mostly because it has an official JS version, an official Ruby version, an official Java version, etc. It allows you to use the same templates frontend and backend, which is very useful for widgets that are first rendered in background and rerendered in foreground at updates.
Put the content in a file abc.php
and then add this to each page you want the desired content in :
<?php
include("abc.php");
?>
So if your code is :
<nav>
<ul>
<li><span>Home</span></li>
<li><span>1914</span></li>
<li><span>1915</span></li>
<li><span>1916</span></li>
<li><span>1917</span></li>
<li><span>1918</span></li>
</ul>
</nav>
</header>
<section>
<article>
<br style="clear: both" />
</article>
<aside>
</aside>
</section>
And you want the part inside <nav> to be repeated in each page, you can put the content between <nav> and </nav> (including the tags) inside abc.php and include abc.php in your file like this :
<?php
include("abc.php");
?>
</header>
<section>
<article>
<br style="clear: both" />
</article>
<aside>
</aside>
</section>
Create the template file as a single file, exactly you have it already, but printing PHP variables in the places where you want content.
eg:
....
<article>
<?php print $mainContent; ?>
</article>
....
Then write a PHP function as follows:
<?php
function insertContentIntoTemplate($mainContent) {
require_once('/path/to/template.php');
}
?>
Now you can load your page content into the template simply by calling the function and passing the content into it for each page.
So, for example, 1914.php could look like this:
<?php
require_once('/path/to/insertFunction.php');
//the text could be loaded from a DB, or from another file, or just as a plain string like this:
$text = "The year was 1914, and the war was just starting.";
insertContentIntoTemplate($text);
?>
Congratulations. You now have a working (albeit very simple) template system. Add more variables / placeholders to your template as required.

Can I reference an external JavaScript file in a PHP file?

I cannot seem to get this to work. I have a small JS file that switches banners depending on the time of day, but it seems that doing an external reference in my PHP file does not work. It works fine in an HTML page.
This is the code in the JavaScript file.
function getStylesheet() {
var currentTime = new Date().getHours();
if (7 <= currentTime && currentTime < 19) {
document.write("<img src='images/banner_day.jpg'>");
} else {
document.write("<img src='images/banner_night.jpg'>");
}
}
getStylesheet();
And here is the reference code I used to call the JavaScript file. Its in a PHP file.
<script src="http://beta.website.com/wp-content/themes/theme/scripts/banner.js"></script>
Everything on the PHP page shows up in the browser, except for the banner that I tried to call with the script.
Here is the entire PHP file code.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<div id="main">
<div class="container">
<div id="header">
<div id="logo">
<img src="http://beta.dfdfdf.com/wp-content/themes/asdafd/images/logo.png" />
</div>
<div id="shadow2"></div>
<div id="shadow1"></div>
<ul id="menu">
<li>df</li>
<li>df</li>
<li>fd df df</li>
<li>The asfdssd asdfds</li>
<li>sf</li>
<li>df</li>
<li>dfd</li>
</ul>
<div id="slogan"><big>"fasfdsads2005."</big></div>
<div id="loginDiv">Login Panel Here</div>
</div>
<div id="banner">
<script src="http://beta.adsfasfasfd.com/wp-content/themes/adfadsf/scripts/banner.js"></script></div>
<div class="sidebar">
Sidebar Content<br />
<br /><br />
blah
blah
blah
</div>
<div class="content">
Main Content
<br />
<br />
<br />
<br />
<br />
<br />
</div>
<div id="footer">
<div class="container">
<div class="footer_column long">
<h3>Cadsfadsfafdfsd.com All Rights Reserved</h3>
<p>dsafasdfdffadffadsdafsdfsadafsdfsadfas</p>
</div>
<div class="footer_column2">
<h3>More Links</h3>
<ul>
<li><a href="http://aadfsdfsdfa.
com">asfsdfa</a></li>
<li><a href="http://ItsNotch.
com">ItsNotch</a></li>
<li><a href="http://adfasfsfaf.
com">adsfasf</a></li>
<li><a href="http://twitter.
com/safs">Twitter</a></li>
<li><a href="https://www.facebook.com/group.php?gid=10215yy20340498">Facebook Fan Page
</a></li>
</ul>
</div>
<div class="footer_column2">
<h3>RSS</h3>
<ul>
<li>RSS Feed</li>
<li>What is RSS?</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Try changing your Javascript to this:
window.onload = function () {
// Uncomment this line to make sure the script is loading/running, then delete it
// alert('Hello, your Javascript is running');
// Declare variables
var currentTime, bannerDiv, newImg;
// Get currentTime
currentTime = new Date().getHours();
// Get 'banner' div
bannerDiv = document.getElementById('banner');
// Get create a new <img>
newImg = document.createElement('img');
// Assign a src="" attribute depending on the time
newImg.src = (currentTime > 7 && currentTime < 19) ? 'images/banner_day.jpg' : 'images/banner_night.jpg';
// add the new image to the document
bannerDiv.appendChild(newImg);
};
And put it in the <head> of the document, so change
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<!-- ....... -->
<div id="banner">
<script src="http://beta.adsfasfasfd.com/wp-content/themes/adfadsf/scripts/banner.js"></script>
</div>
<!-- ....... -->
...to:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript" src="http://beta.adsfasfasfd.com/wp-content/themes/adfadsf/scripts/banner.js"></script>
</head>
<body>
<!-- ....... -->
<div id="banner"></div>
<!-- ....... -->
If it still doesn't work, one of two things is happening:
Your javascript file is not actually at http://beta.adsfasfasfd.com/wp-content/themes/adfadsf/scripts/banner.js so the script cannot be loaded/run. Uncomment the first line to confirm that the script is running.
Your banner images cannot be found at images/banner_night.jpg - make sure your relative paths are correct.
Have you made sure that you've actually got the <script></script> in your head? I certainly can't see it there (unless it is in <?php wp_head();>?).
Having attempted to navigate to http://beta.website.com/wp-content/themes/theme/scripts/banner.js it returns a 404, you'll need to fix this issue first.
Remember that javascript is client side, and all you want to do with php is spit out the tags somewhere for the browser to deal with.
It might be path problem.
What is you images (full) path?
What is you page (full) path?
As it is now it looks for images directory beneath your current page. Is this correct?

Categories