views:

165

answers:

7

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).

+2  A: 

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' );
Peter Bailey
This is how we did it in php as well (back in 03/04), although it seemed pretty kludgey for larger sites.
Jess
+4  A: 

I'm not a php programmer, but I know we can use a framework called Smarty that it works with templates(views), something like asp.net mvc.

look here http://www.smarty.net/

Cleiton
+1 for using a template system. However I would recommend Dwoo over Smarty, Dwoo is a Smarty replacement that is much faster. http://www.dwoo.org/
MitMaro
smarty is a templating system, not a framework
Jacco
I've used Smarty, and it is in fact awesome. Though by itself it is not a solution to my problem.
Steve
PHP is a templating system. Please don't try to make it more than it is...
Tor Valamo
A: 

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.

Anirvan
+1  A: 

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.

PaulBM
+2  A: 

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.

codeincarnate
+1  A: 

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

ajhit406
A: 

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(); ?>
Bryan M.