In a previous article I made a case for using the Model-View-Controller pattern in your WordPress plugins. If you are reading this article I hope that you are looking at ways to implement MVC in your plugins.

This article looks at implementing MVC using the file_get_contents function. A later article will look at implementing MVC using includes and output buffering.

For these articles I have created three plugins, one which has HTML embedded in the functions, one which uses file_get_contents and one which uses includes. These plugins can be found on the downloads page.

So an example.

Often I see WordPress plugins which have functions with HTML embedded in them like this :-

private function output_post_info( $wp_post ) { ?>; <div id="case-for-mvc-post-data"> <ol> <li>Id = <?php echo $wp_post->ID; ?>;</li> <li>Title = <?php echo $wp_post->post_title; ?></li> <li>Author = <?php echo $wp_post->post_author; ?></li> <li>Date = <?php echo $wp_post->post_date; ?></li> </ol> </div> <a href="<?php echo admin_url().'/plugins.php?page=fofo-the-case-for-mvc'; ?>">Back</a> <?php } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 private function output_post_info ( $wp_post ) { ?> ; < div id = "case-for-mvc-post-data" > < ol > < li > Id = <?php echo $wp_post -> ID ; ?> ; < / li > < li > Title = <?php echo $wp_post -> post_title ; ?> < / li > < li > Author = <?php echo $wp_post -> post_author ; ?> < / li > < li > Date = <?php echo $wp_post -> post_date ; ?> < / li > < / ol > < / div > < a href = " <?php echo admin_url ( ) . '/plugins.php?page=fofo-the-case-for-mvc' ; ?> " > Back < / a > <?php }

For reasons I go into here I do not think this is a good idea.

So we will refactor the above piece of code to use file_get_contents to implement MVC. If you go back 10 years many PHP templating frameworks were built in this way (Smarty for example still does).

The idea is to separate out the pieces of code so that each piece does one thing. From a cognitive point of view this makes each function easier and quicker to understand.

So let’s take the first function.

private function output_posts_html( $posts ) { ?> <div id="case-for-mvc"> <?php $post_count = 0; $hidden_class = ''; $id = 'fofo-first-set'; foreach( $posts as $post ) { ?> <div class="<?php echo $hidden_class; ?>" id="<?php echo $id; ?>"> <div class="fofo-post-box"> <h4><?php echo $post->post_title; ?></h4> <p><?php echo $post->post_exceprt; ?></p> <input type="submit" class="fofo-button" value="Show Post" /> <a href="<?php echo admin_url().'/plugins.php?page=fofo-the-case-for mvc&post_id='.$post->ID; ?>">Show Post Info</a> <div class="fofo-post-detail fofo-hidden"> <?php echo $post->post_content; ?> </div> </div> </div> <?php $post_count++; if( 4 == $post_count ) { $hidden_class = 'fofo-hidden'; $id = 'fofo-second-set'; } ?> <?php } ?> <input type="submit" id="fofo-toggle-show" value="Toggle Shown" /> </div> <?php $this->output_js_file(); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 private function output_posts_html ( $posts ) { ?> < div id = "case-for-mvc" > <?php $post_count = 0 ; $hidden_class = '' ; $id = 'fofo-first-set' ; foreach ( $posts as $post ) { ?> < div class = " <?php echo $hidden_class ; ?> " id = " <?php echo $id ; ?> " > < div class = "fofo-post-box" > < h4 > <?php echo $post -> post_title ; ?> < / h4 > < p > <?php echo $post -> post_exceprt ; ?> < / p > < input type = "submit" class = "fofo-button" value = "Show Post" / > < a href = " <?php echo admin_url ( ) . '/plugins.php?page=fofo-the-case-for mvc&post_id=' . $post -> ID ; ?> " > Show Post Info < / a > < div class = "fofo-post-detail fofo-hidden" > <?php echo $post -> post_content ; ?> < / div > < / div > < / div > <?php $post_count ++ ; if ( 4 == $post_count ) { $hidden_class = 'fofo-hidden' ; $id = 'fofo-second-set' ; } ?> <?php } ?> < input type = "submit" id = "fofo-toggle-show" value = "Toggle Shown" / > < / div > <?php $this -> output_js_file ( ) ; }

So what we now need to do is separate the HTML parts from the PHP parts. We will be reading the HTML in as a string so all PHP must be removed. Any PHP which refers to a variable will need to be replaced with a string which will act as a placeholder.

Any PHP which applies the least bit of logic will also need to come out and be put into the function. In the function we need to load the file with the HTML in it and then use str_replace to replace the placeholders in the HTML with the values in our variables.

What you are aiming for is a file that looks like this :-

<div class="{$hidden_class}" id="{$id}"> <div class="fofo-post-box"> <h4>{$post->post_title}</h4> <p>{$post->post_exceprt}</p> <input type="submit" class="fofo-button" value="Show Post" /> <a href="{$post_info_page}">Show Post Info</a> <div class="fofo-post-detail fofo-hidden"> {$post_content} </div> </div> </div> 1 2 3 4 5 6 7 8 9 10 11 12 13 < div class = "{$hidden_class}" id = "{$id}" > < div class = "fofo-post-box" > < h4 > { $post -> post_title } < / h4 > < p > { $post -> post_exceprt } < / p > < input type = "submit" class = "fofo-button" value = "Show Post" / > < a href = "{$post_info_page}" > Show Post Info < / a > < div class = "fofo-post-detail fofo-hidden" > { $post_content } < / div > < / div > < / div >

and a function that looks like this :-

private function get_posts_html( $posts ) { $template = file_get_contents( dirname(__FILE__).'/display_posts.php' ); $output = '<div id="mvc-with-fgc">'; $post_count = 0; $hidden_class = ''; $id = 'fofo-first-set'; foreach( $posts as $post ) { $output .= $template; $output = str_replace( '{$hidden_class}', $hidden_class, $output ); $output = str_replace( '{$id}', $id, $output ); $output = str_replace( '{$post->post_title}', $post->post_title, $output ); $output = str_replace( '{$post->post_exceprt}', $post->post_excerpt, $output ); $output = str_replace( '{$post_info_page}', admin_url().'/plugins.php?page=fofo-with-fgc&post_id='.$post->ID, $output ); $output = str_replace( '{$post_content}', $post->post_content, $output ); $post_count++; if( 4 == $post_count ) { $hidden_class = 'fofo-hidden'; $id = 'fofo-second-set'; } } $output .= '<input type="submit" id="fofo-toggle-show" value="Toggle Shown" /></div>'; $output .= $this->output_js_file(); return $output; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 private function get_posts_html ( $posts ) { $template = file_get_contents ( dirname ( __FILE__ ) . '/display_posts.php' ) ; $output = '<div id="mvc-with-fgc">' ; $post_count = 0 ; $hidden_class = '' ; $id = 'fofo-first-set' ; foreach ( $posts as $post ) { $output . = $template ; $output = str_replace ( '{$hidden_class}' , $hidden_class , $output ) ; $output = str_replace ( '{$id}' , $id , $output ) ; $output = str_replace ( '{$post->post_title}' , $post -> post_title , $output ) ; $output = str_replace ( '{$post->post_exceprt}' , $post -> post_excerpt , $output ) ; $output = str_replace ( '{$post_info_page}' , admin_url ( ) . '/plugins.php?page=fofo-with-fgc&post_id=' . $post -> ID , $output ) ; $output = str_replace ( '{$post_content}' , $post -> post_content , $output ) ; $post_count ++ ; if ( 4 == $post_count ) { $hidden_class = 'fofo-hidden' ; $id = 'fofo-second-set' ; } } $output . = '<input type="submit" id="fofo-toggle-show" value="Toggle Shown" /></div>' ; $output . = $this -> output_js_file ( ) ; return $output ; }

As you can see we still have a bit of HTML in the function, but it is a lot less than before. In my opinion this makes the function easier to read and therefore maintain than the previous version of the function.

Another strange thing has also happened. Since I am now loading the HTML as a string I can store the output. This means I have more opportunities to use the output in other places. It also means I can carry out all my output in one place if I so desired.

Why is this important?

Well let’s say for, argument’s sake, that I had a post processing step that performed some transformation on the HTML I was using. Before, I would have had to embed this step in the function where the HTML was written. Now I can store each piece of HTML in an array and perform the post processing step in a loop on each array element.

By having the HTML separated in this way I also get greater opportunities to re-use the HTML. Let’s say I have a particular look and feel to all my products. If I show a message to a user in an overlay then I want it to look the same in all my products. Well using this method I can have one HTML template which I can use in all my products.

So it all looks good and the world is now perfect.

But.

There are downsides. It would be nice to use some PHP in the HTML templates. Personally I would rather use the variables themselves rather than having to use a string replace function. Also if you use this method in a WordPress theme and use the Theme Checker it will complain about file_get_contents not being allowed. This is because of the potential security issues using file_get_contents can cause.

In the next article in this series of three I will go into how using includes and output buffering can fix these issues.

The full source for both plugins can be downloaded here

In the meantime have fun coding your WordPress plugins and themes. If you have implemented a templating system or implemented MVC in your own WordPress projects I would love to hear about it so why not leave a comment.