Beginner's guide to making a template driven PHP site - php

Do you know of any site that can help me start with making template driven sites in PHP?

First off I'll go ahead and start out with Smarty, since I've used it quite a lot. Since this is a community wiki, feel free to plug in examples of your own templating engine should you choose.
Installing Smarty
Templating provides a great way of structuring your HTML and separating out your HTML content from your logic code. It also provides a way to organize individual components of your HTML page, so it's easier to manage, and is more re-usable.
To start, we'll take at showing a simple page with Smarty. First off you need to actually get Smarty. So we'll head down to the Smarty download page. As of this writing, the latest stable version is Smarty 3.0.7, so we'll go ahead and download that. Downloading the .tar.gz file or the .zip file is up to the system you have. For Windows and Mac users (most likely using MAMP or XAMPP), .zip is probably a good choice, though you can always get programs to handle .tar.gz files. Users with Linux or *BSD type systems can grab the .tar.gz version.
Now then, we extract the file and get the following directory layout:
COPYING.lib
demo/
libs/
|__ Smarty.class.php
|__ ... some other files and folders ...
README
SMARTY2_BC_NOTES
Now, Smarty.class.php is the main file we're going to include to use Smarty. It's located in the libs directory. As 'libs' is a pretty generic sounding name, we're going to copy this to our document root folder, and rename it to Smarty. Now our theoretical document root folder is currently empty, so it will end up looking like this:
Smarty/
|__ Smarty.class.php
|__ ... some other files and folders ...
A Simple Template
Now that Smarty is installed, we'll create a very basic template and php script to show how it works. First off, to keep things organized we'll make a templates folder to keep our templates in. Then we'll create a mypage.php file, and a mypage.tpl file in our templates folder:
mypage.php
templates/
|__ mypage.tpl
Smarty/
|__ Smarty.class.php
|__ ... some other files and folders ...
mypage.php
<?php
require_once('Smarty/Smarty.class.php');
$smarty = new Smarty();
$smarty->assign("MYVAR", "Hello World");
$smarty->display("templates/mypage.tpl");
?>
templates/mypage.tpl
<html>
<head>
<title>My Sample Page</title>
</head>
<body>
<h1>{$MYVAR}</h1>
</body>
</html>
Now if we navigate to mypage.php, for example http://localhost:8000/mypage.php, "Hello World" will be displayed in large bold text. So what happend? Let's step through the code:
require_once('Smarty/Smarty.class.php');
Here we include the main Smarty class. We need this for any and all Smarty functionality.
$smarty->assign("MYVAR", "Hello World");
You'll be using this a lot. The assign command takes a value, "Hello World" in this example, and assigns it to a name, "MYVAR". If you look at the template:
<h1>{$MYVAR}</h1>
You'll notice {$MYVAR}. The {}'s indicate to Smarty that it needs to evaluate the expression inside. This could be a command or simply a variable. It could produce output or simply set a variable value. In this case, it simply outputs the value of $MYVAR that we assigned.
$smarty->display("templates/mypage.tpl");
Finally, we tell Smarty to parse the template, then display it as if you had simply echo'ed out HTML in a PHP page. Fancy eh? Now, a lot of people will want to iterate through arrays (ie. a set of db results), so let's take a look at an example of how to achieve that.
Looping Through Arrays
First we'll make adjustments to our code. The new listings are as follows:
mypage.php
<?php
require_once('Smarty/Smarty.class.php');
$myarray = array(
"John",
"Jane",
"Henry",
"Nancy",
"Gorilla"
);
$smarty = new Smarty();
$smarty->assign("MYARRAY", $myarray);
$smarty->display("templates/mypage.tpl");
?>
templates/mypage.tpl
<html>
<head>
<title>My Sample Page</title>
</head>
<body>
<h1>Results</h1>
<ul>
{foreach $MYARRAY as $myvalue}
<li>{$myvalue}</li>
{/foreach}
</ul>
</body>
</html>
If you reload the page, you'll get something like this:
Now, there are only a few changes to note:
$smarty->assign("MYARRAY", $myarray);
Instead of a string value, we assigned a variable which holds an array. This was passed to Smarty which used the data in the {foreach} loop:
<ul>
{foreach $MYARRAY as $myvalue}
<li>{$myvalue}</li>
{/foreach}
</ul>
The foreach in Smarty is much like the foreach of PHP. In this case, Smarty takes the array that was assigned to $MYVALUE and loops through it, setting $myvalue to the result of the current loop value. From there we can use {$myvalue} to refer to each individual item. Now, let's say we want to make this unordered list a widget to reuse in other places. We can do that through using templates themselves as variables.
Template Modularization
HTML can get very long very quickly. Smarty helps manage this by letting you break out parts of the page into individual components. So what we'll do is take our unordered list and put it into a separate page. Our new code will look like this:
mypage.php
<?php
require_once('Smarty/Smarty.class.php');
$myarray = array(
"John",
"Jane",
"Henry",
"Nancy",
"Gorilla"
);
$smarty = new Smarty();
$smarty->assign("MYARRAY", $myarray);
$content = $smarty->fetch("templates/mycontent.tpl");
$smarty->assign("MYCONTENT", $content);
$smarty->display("templates/mypage.tpl");
?>
templates/mypage.tpl
<html>
<head>
<title>My Sample Page</title>
</head>
<body>
<h1>Results</h1>
{$MYCONTENT}
</body>
</html>
mycontent.tpl
<ul>
{foreach $MYARRAY as $myvalue}
<li>{$myvalue}</li>
{/foreach}
</ul>
The result we get is the same, however the backend is now more organized. We can now reuse this mycontent.tpl file in other pages if we want. Common usages of this organization is making header, footer, and other parts of the page individual templates. This lets you narrow down to relevant pieces.
So what happened on the backend? The important command to take note of here is:
$content = $smarty->fetch("templates/mycontent.tpl");
fetch() works like display, except that instead of outputting it right away, it returns the result as a string of the rendered HTML. Note that because $MYARRAY is used in the mycontent.tpl, we have to assign the array right before it, not right before the final display() call. This ordering is important!
Conclusion
This concludes the very basic introduction to Smarty, and using a templating engine to work with managing your content. The Smarty Documentation provides a great resource for seeing all that smarty is capable of. Be sure to look through all the available commands to make sure you're using it efficiently!

Smarty for PHP is an adequate templating system. You can try and use that, plus their documentation to help develop a template driven website.

Depending on your needs you can create your own templateing system with a couple of included files.

Symfony, in addition to being a good framework, offers Twig.

Related

Including PHP file inside smarty template file

I have completely no idea about smarty template system. What I am trying to do is include a php file to get some variable inside a .tpl file (this is a WHMCS template).
I have tried like:
{php} include ('file.php'); {/php} //doesn't work
{include_php file='file.php'} //doesn't work
I have also followed the answer of this question. Still couldn't get it working.
How can I include code.php inside header.tpl of WHMCS? Any help please?
Just for reference: both tpl and php file is in the same directory, if that helps anyway.
It's really not recommended to use php code in Smarty. In fact it's now deprecated and you should avoid such solution as much as possible because it often doesn't have sense.
However if you really want to use PHP in your Smarty files for some reason you need to use SmartyBC (Smarty Backward Compatibility) class instead of Smarty class.
So for example instead of:
require_once(_PS_SMARTY_DIR_.'Smarty.class.php');
$smarty = new Smarty();
you should use:
require_once('SmartyBC.class.php');
$smarty = new SmartyBC();
Then you will be able to use PHP in your Smarty template files
EDIT
If you have just problem with including it's probably your directories problem (however you haven't showed any errors).
I assume you have your files inside your templates directory and you set it properly using:
$smarty->setTemplateDir('templates');
if you simple display index.tpl file in Smarty and you have this PHP file in the same directory (in template directory) you can include it without a path.
However if you include in this index.tpl file another tpl file, when you want to include php file you need to pass the full path to this PHP file, for example:
{include_php 'templates/file.php''}
Your using Smarty the wrong way. The whole point of Smarty is to NOT include any PHP in your presentation bits (views, a.k.a. the good ol' HTML).
So, whatever you're trying to do in that PHP file, just let it do its magic, but send the actual result to Smarty. For example, do you want to show a table of users you get out of a database? Execute the query, fetch the result and pass the results (like an array of results) to smarty like this:
<?php
$smarty = new Smarty();
$users = $db->query('SELECT * FROM users');
// Assign query results to template file.
$smarty->assign('users', $users);
// Compile and display the template.
$smarty->display('header.tpl');
Now, in your smarty template you can access that array like this:
<html>
{foreach from=$users item=user}
Username: {$user->username}<br />
{/foreach}
</html>
I hope you see where I am going. Keep your application logic in the PHP file, and let the template just take care of the looks. Keep the template as dumb as possible!
You get data into Smarty by assigning it. Embedding PHP is not recommended, and deprecated from Smarty 3.
php:
$smarty->assign('foo','bar');
smarty:
{$foo}

replacing file contents in php and saving to a new file

So I would have a template file called template.php and inside, it would have:
<html>
some other content
<?php $name ?>
</html>
Essentially, I want to pull the name from the database and insert it into $name and save that entire page as a new file.
So let say in the database, I had a name called Joe, the new file I create would have the following content inside:
<html>
some other content
Joe
</html>
The only issue I am having is finding the right functions to actually replace the variable from the template file, and being able to save it into a new file.
That's not how templates usually work. You should have a template file, substitute variables for their values, and display it to the user. You can cache these generated templates (the ones that are always the same) but you never make a new template file for each user and save it permanently. That makes managing and updating the application way more difficult than you want.
I recommend using a simple template system like RainTPL. That's what I use for most of my projects... it's very simple to use and provides all the basic functionality you would need.
You can also use just PHP for this... there are a few answers on SO that cover this so I won't get into it.
Using PHP as template engine
Using Template on PHP
Look at the answer I gave to this question a while back. There I explain how "variable parsing" usually works.
When I create a template loader I generally use output buffering with php include. This allows you to run the page as a php file without displaying its content before you are ready. The advantage to "parsing" your php files this way is that you can still run loops and functions.
Here's an example of how to use output buffering with PHP to create what you're wanting.
The Template template.php
<html>
some other content
<?php $name ?>
</html>
Where your database code and stuff is index.php
<?php
$name = 'John Doe';
if( /* some sort of caching system */ ) {
$parsed_template = file_get_contents('parsed_template.html');
}else {
ob_start();
include 'template.php';
$parsed_template = ob_get_clean();
file_put_contents('parsed_template.html', $parsed_template);
}
echo $parsed_template;
?>

How can I use a Smarty template from a Smarty template?

I've run into a funny problem. I need to use Smarty templates within a Smarty template.
Here is why. I use the same templates for various wiki websites, and each website has its own configuration. The configuration contains parts for the main template (such as changed titles and headings, etc).
Here is a simplified example. I've a file topic-list.template.html that's shared across all websites:
<div id="topics">
<h1>{$h1}</h1>
...
</div>
As you can see, this template file contains an <h1> tag that can be customized for each website.
Then for each of the websites I've a configuration file that looks like this (simplified):
$config = [
"h1-titles" => [
"topics" => "Showing Topics in {\$category}"
]
];
As you can see the configuration file contains a Smarty template.
So when I render the topic-list.template.html file, I've to render the $config['h1-titles']['topics'] first through $smarty->fetch("string":$config['h1-titles']['topics']), and then assign it to h1 Smarty variable. My simplified code looks like this:
$h1_tag = $smarty->fetch("string":$config['h1-titles']['topics']);
$smarty->assign('h1', $h1_tag);
$smarty->display('topic-list.template.html');
I wonder if I could somehow insert the $config['h1-titles']['topics'] in the topic-list.template.html file automatically and then it have all rendered in one go?
Please have a look at the docs on String Template Resources. You will immediately notice that your $smarty->fetch('string:…') approach can also be done within a template: {include file="string:…"}
I believe that {eval} tag may help you:
{eval} is used to evaluate a variable as a template. This can be used for things like embedding template tags/variables into variables or tags/variables into config file variables.
http://www.smarty.net/docs/en/language.function.eval.tpl

How is duplicate HTML represented in your codebase, in a non-duplicate way?

Most HTML in a large website is duplicated across pages (the header, footer, navigation menus, etc.). How do you design your code so that all this duplicate HTML is not actually duplicated in your code? For example, if I want to change my navigation links from a <ul> to a <ol>, I'd like to make that change in just one file.
Here's how I've seen one particular codebase handle this problem. The code for every page looks like this:
print_top_html();
/* all the code/HTML for this particular page */
print_bottom_html();
But I feel uncomfortable with this approach (partially because opening tags aren't in the same file as their closing tags).
Is there a better way?
I mostly work with PHP sites, but I'd be interested in hearing solutions for other languages (I'm not sure if this question is language-agnostic).
I'm not a php programmer, but I know we can use a templating system called Smarty that it works with templates(views), something like asp.net mvc does with Razor.
look here http://www.smarty.net/
One solution at least in the case of PHP (and other programming languages) is templates. Instead of having two functions like you have above it would instead be a mix of HTML and PHP like this.
<html>
<head>
<title><?php print $page_title ?></title>
<?php print $styles ?>
<?php print $scripts ?>
</head>
<body>
<div id="nav">
<?php print $nav ?>
</div>
<div id="content">
<?php print $content ?>
</div>
</body>
</html>
Each variable within this template would contain HTML that was produced by another template, HTML produced by a function, or also content from a database. There are a number of PHP template engines which operate in more or less this manner.
You create a template for HTML that you would generally use over and over again. Then to use it would be something like this.
<?php
$vars['nav'] = _generate_nav();
$vars['content'] = "This is the page content."
extract($vars); // Extracts variables from an array, see php.net docs
include 'page_template.php'; // Or whatever you want to name your template
It's a pretty flexible way of doing things and one which a lot of frameworks and content management systems use.
Here's a really, really simplified version of a common method.
layout.php
<html>
<body>
<?php echo $content; ?>
</body>
</html>
Then
whatever_page.php
<?php
$content = "Hello World";
include( 'layout.php' );
Sounds like you need to use include() or require()
<?php
include("header.inc.php");
output html code for page
include("footer.inc.php");
?>
The header and footer files can hold all the common HTML for the site.
You asked for how other languages handle this, and I didn't see anything other than PHP, so I encourage you to check out Rails. Rails convention is elegant, and reflects #codeincarnate 's version in PHP.
In the MVC framework, the current view is rendered inside of a controller-specific layout file that encapsulates the current method's corresponding view. It uses a "yield" method to identify a section where view content should be inserted. A common layout file looks like this:
<html>
<head>
<% #stylesheet and js includes %>
<body>
<div id="header">Header content, menus, etc…</div>
<%= yield %>
<div id="footer">Footer content</div>
</body>
</html>
This enables the application to have a different look and feel or different navigation based on the controller. In practice, I haven't used different layout files for each controller, but instead rely on the default layout, which is named "application".
However, let's say you had a company website, with separate controllers for "information", "blog", and "admin". You could then change the navigation for each in a clean and unobtrusive manner by handling the different layout views in their respective layout files that correspond to their controllers.
You can always set a custom layout in the controller method by stating:
render :layout => 'custom_layout'
There are also great helper methods built into Rails so you don't have to rely on $global variables in PHP to ensure your CSS and Javascript paths are correct depending on your development environment (dev, staging, prod…). The most common are:
#looks in public/stylesheets and assumes it's a css file
stylesheet_link_tag "filename_without_extension"
#looks in public/javascripts and assumes it's a js file
javascript_include_tag "jquery"
Of course, each of these sections could be expounded upon in much greater detail and this is just brushing the surface. Check out the following for more detail:
http://guides.rubyonrails.org/layouts_and_rendering.html
What you suggested works OK. As long as print_top_html and print_bottom_html stay in sync (and you can use automated tests to check this), then you never need to worry about them again, leaving you to focus on the real content of the site -- the stuff in the middle.
Alternatively, you can combine print_top_html and print_bottom_html into a single call, and send it HTML code (or a callback) to place in the middle.
I use the partials system of Zend_View (very similar to Rails). A partial is essentially a small HTML template that has its own variable scope. It can be called from inside views like:
<?php echo $this->partial('my_partial.phtml', array( 'var1' => $myvar ));
The variables that get passed into the construct get bound to local variables inside the partial itself. Very handy for re-use.
You can also render a partial from inside normal code, if you're writing a helper object where you have more complex logic than you'd normally feel comfortable putting in a view.
public function helperFunction()
{
// complex logic here
$html = $this->getView()->partial('my_partial.phtml', array('var1' => $myvar ));
return $html;
}
Then in your view
<?php echo $this->myHelper()->helperFunction(); ?>

Lightweight, PHP based, layout framework...know of any? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a tool, library or favorite off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 9 years ago.
Improve this question
I'm looking for a lightweight, PHP based, layout framework. Like how the Zend Framework, uses layouts, I would like to create a layout template and include only the content for the necessary pages.
<html>
<head>
<title><?= $pageTitle ?></title>
</head>
<body>
<?= $content ?>
</body>
</html>
Anyone know of anything that does this? I would use the Zend Framework, but it's just too much for what I want to achieve.
I vote for PHP. (PHP is a templating engine.)
function template($file, $vars) {
ob_start();
if(count($vars) > 0) { extract($vars); }
include 'views/'.strtolower($file).'.php';
return ob_get_clean();
}
Which, incidentally, lets you do the following.
echo template('layout', array( 'content' => template('page', $myData) ));
Should you even bother using another templating/layout engine at all, when PHP itself can suffice in a mere 6 lines?
Edit:
Perhaps I wasn't clear with how this works.
template() is called with the name of the template (subdirectories for organization work too) with an array object as the second parameter. If the variables given aren't blank, like template('index',null) is, then the array is treated as an associative array: and every key becomes a variable containing the value.
So the logic becomes:
template('my_template', array(
'oranges' => 'apples'
));
And "views/my_template.php" is:
<html>
<head>
<title>Are apples == <?= $oranges ?>?</title>
</head>
<body>
<p style="color: <?= $oranges == 'oranges' ? 'orange" : 'darkgreen' ?>">
Are apples == oranges?
</p>
</body>
</head>
So, every time the variable $oranges is used PHP gets the data that was exported from the array, $vars['oranges'].
So all the output is then taken by ob_get_clean() and returned as a string. To output this string just echo or print, or assign it to an array to be passed as content to the layout. If you understand this, then it is very easy to take what I've written and make a layout out of it, or pages with logic that output JSON even.
I would advise you to experiment with this answer before discarding it. It has a tendency to grow on you.
Edit 2:
As requested I'll show the directory layout that my project would use. Do note that other MVC frameworks use a different structure. But, I like the simplicity of mine.
index.php
application/
framework.php
controllers/
welcome.php
views/
template.php
index.php
For security purposes, I have an .htaccess file that routes every request, except those to js/ or css/, to the index.php script, effectively making my directories hidden. You could even make the CSS via a template if you wished, which I've done, for the use of variables, etc.
So, any call made to template('template', array()) will load the file ./views/template.php automatically. If I included a slash in the name, it becomes part of the path, like so: ./views/posts/view.php.
Edit 3:
thanks for your update. So you must have some code in your index.php file that routes the requested url to the appropriate controller, correct? Could you show some of this? Also, it doesn't look like your views mirror your controller directory. Can you explain a little more how urls map to controllers and/or views? What do you have in framework.php? What does it do? Thanks!
The code I've shown is a tiny excerpt of my private framework for web development. I've talked already about potentially releasing it with a dual-license, or as donation-ware for commercial use, but it's nothing that can't be written by anyone else in a short (15-21 days) time. If you want you can read my source code on GitHub... but just remember that it's still alpha material.
The license is Creative Commons SA.
If you want super-lightweight, you could use an auto-prepend file, mixed with some output buffering to build what you want. For starters, you need to set up your prepend and append files - put the following lines in your .htaccess file (you'll probably want to make the prepend and append files unreadable to visitors, too):
php_value auto_prepend_file prepend.php
php_value auto_append_file append.php
Then in your prepend.php file, you'll want to turn on output buffering:
<?php
ob_start();
In append.php, you'll want to grab the contents of the output buffer, clear the buffer and do any other processing of the content you want (in this example, I set a default page title).
<?php
if (!isset($page_title)) {
$page_title = 'Default Page Title';
}
$content = ob_get_contents();
ob_end_clean();
?>
<html>
<head>
<title><?php echo $page_title; ?></title>
</head>
<body>
<?php echo $content ?>
</body>
</html>
After this, you can write each page normally. Here's an example index.php
<?php
$page_title = "Index Page!";
?>
<h1>This is the <?php echo __FILE__; ?> page</h1>
...and an example other.php that does something halfway interesting:
<?php
$page_title = "Secondary Page!";
?>
<h1>This is the <?php echo __FILE__; ?> page</h1>
<p>enjoy some PHP...</p>
<ol>
<?php for ($i = 1; $i <= 10; $i++) : ?>
<li><?php echo "$i $i $i"; ?></li>
<?php endfor ?>
</ol>
And you're done. You can grow on this a bit, such as initializing DB connection in the prepend, but at some point, you'll probably want to move to a more abstract system that breaks out of a fixed mapping of URLs to paths and files.
I'm actually about to release one at europaphp.org along with examples and a full documentation. It's very similar to the Zend Framework in conventions and coding standards. I'll post something when it is done; probably within the next week.
You can get the code at: [http://code.google.com/p/europa/source/browse/#svn/trunk/Sandbox - Default][1].
That link will bring up the latest svn for the Sandbox which you can just download and start using without any configuration.
Currently, it's faster than most any other PHP framework out there.
[1]: http://code.google.com/p/europa/source/browse/#svn/trunk/Sandbox - Default
BareBones: a one-file, no-configuration, MVC framework for PHP5
FryPHP is about as lightweight as it gets.
Limonade might also be useful... not strictly layout.
I've been using Smarty for ages.
It's mature, actively maintained, and widely supported.
Anyway, you'll find a whole range of template engines here:
http://en.wikipedia.org/wiki/Template_engine_(web)
If you click the languages column, you'll easily see what's available for PHP, and how the engines compare.
Just to throw in another framework: CodeIgniter is IMHO very nice, uses an MVC approach, so you'd output your files as views and says to have a small footprint. It also has a template parser on board.
Cheers,

Categories