Create a “load more” widget using PHP, Ajax, and jQuery

Several months ago I created a post that was quite popular: Create a “load more” widget using PHP, Ajax, Mootools, Bootstrap and Mustache.js. Today I decided to port the code from Mootools to jQuery.

Prerequisite

This tutorial requires several prerequisite in order to be completed successfully:

  • The server needs to run PHP5 to be able to use JSON functions.
  • The widget does not need any custom CSS we will only use the famous Bootstrap Framework.
  • We will use the lastest version of jQuery (1.10.1)

For the logic please refer to Create a “load more” widget using PHP, Ajax, Mootools, Bootstrap and Mustache.js, and to see the code refer to the demo

ShprinkOne WordPress theme released

I am pleased to announce the release of my first WordPress Theme: ShprinkOne is a Customizable and Responsive (mobile friendly) theme that can fit any screen (Mobile phone, tablet, laptop, desktop).

Nowadays every Internet company is focusing on mobile, it has been a trend for a long time (“mobile first” was something I heard a lot at eBay) and might continue for a little while. Releasing a theme that would not be mobile friendly was then out of the question.

As an early adopter and big fan of the front-end framework Bootstrap I decided to use its ability to create Responsive markup structure and to provide a set of great UI (Navbar, Buttons etc.), tools (Slideshow, Affix, TypeHead etc.) for this project.

Besides the obvious technical advantages that Bootstrap provides, another aspect made the choice even easier: the Community! You would be amazed by the number of start ups that based their product on Bootstrap! For example some of the ShprinkOne pages were created using jetstrap.com (great mockup tool for Bootstrap) and if you like to often change your theme ShprinkOne allows you to select some of the best Bootstrap themes (from bootswatch.com, divshot.com) that exist directly from the admin page.

For this theme I also wanted to try out Masonry and the Infinite Scroll plugins for jQuery that appeared to be really easy to use. Masonry helps to re-organize the page content and creates a Pinterest like dashboard while Infinite Scroll plugin loads more blog post when you scroll down the page. The WordPress loop page (that is shared by most of the pages: Home, Category, Tag, Author and more..) uses both of them to create a great user experience(No need to switch from page to page, everything is displayed in a single page).

ShprinkOne is Open Source and needs your help to make it even better. If you are interest to help you can fork the project on GitHub.


Screenshots


Features

  • Home page Slideshow
  • Theme customization (Select your style among 10+ free themes)
  • Layout customization (Sidebar-Content, Content-Sidebar or Content)
  • Posts as pins using Masonry
  • Language ready: So far English and French

Get the full list

Twitter Bootstrap: Error compiling mixins.less with lessphp

If you are trying to compile Twitter Boostrap v2.3 CSS using less and lessphp v0.3.8 you have probably faced a “500 Internal Server Error” message.

It is due to a bug on lessphp side. Bootstrap uses less.js and does not support lessphp.

To fix the problem you will need to open mixins.less file and make a change on the following 6 lines.

mixins.less original file

.span@{index} { .span(@index); } // line:578
.offset@{index} { .offset(@index); } // line:584
.span@{index} { .span(@index); } // line:623
.offset@{index} { .offset(@index); } // line:629
.offset@{index}:first-child { .offsetFirstChild(@index); } // line:630
input.span@{index}, textarea.span@{index}, .uneditable-input.span@{index} { .span(@index); } // line:678

mixins.less fixed

(~".span@{index}") { .span(@index); } // line:578
(~".offset@{index}") { .offset(@index); } // line:584
(~".span@{index}") { .span(@index); } // line:623
(~'.offset@{index}') { .offset(@index); } // line:629
(~'.offset@{index}:first-child') { .offsetFirstChild(@index); } // line:630
(~"input.span@{index}, textarea.span@{index}, .uneditable-input.span@{index}") { .span(@index); } // line:678

Sources

Create a “load more” widget using PHP, Ajax, Mootools, Bootstrap and Mustache.js

3 years ago David Walsh created an awesome (his words, but I agree!) NetTuts post called Create a Twitter-Like “Load More” Widget which is still today a reference on learning how to create “load more” widgets.

Today, with the emergence of projects such as Bootstrap (that took the web by a storm) and Mustache.js creating such a widget is getting easier.

Prerequisite

This tutorial requires several prerequisite in order to be completed successfully:

  • The server needs to run PHP5 to be able to use JSON functions.
  • The widget does not need any custom CSS we will only use the famous Bootstrap Framework.
  • We will use the lastest version of Mootools Core (1.4.5) and the Fx.Scroll Class from Mootools More.
  • To finish we will need to use the JavaScript version (Mustache.js) of the great Mustache project.

Step 1: PHP/MySQL

The PHP part is more or less what David Walsh created.

Start session

By using session the widget will remember how many posts you loaded during the last visit (in case you open a new page and come back).$_SESSION['posts_start'] is initialised and represent the number of posts already loaded in the page (by default two posts are directly loaded).

/* settings */
session_start();
$number_of_posts = 2; //2 at a time
$_SESSION['posts_start'] = $_SESSION['posts_start'] ? $_SESSION['posts_start'] : $number_of_posts;

Get posts from the Db

The function get_posts has two optional parameters ($start is increased every time you push the “more” button) to get only the posts you wish for.

/* grab stuff */
function get_posts($start = 0, $number_of_posts = 2) {
	/* connect to the db */
	$connection = mysql_connect('localhost','username','password');
	mysql_select_db('db_name',$connection);
	$posts = array();
	/* get the posts */
	$query = "SELECT post_title, post_content, post_name, post_date, ID FROM wp_posts WHERE post_status = 'publish' ORDER BY post_date DESC LIMIT $start,$number_of_posts";
	$result = mysql_query($query);
	while($row = mysql_fetch_assoc($result)) {
		// Remove html tag and truncate the content
		$row['post_content'] = substr(strip_tags($row['post_content']), 0,200) . '...';
		$posts[] = $row;
	}
	/* return the posts in the JSON format */
	return json_encode($posts);
}

Set up the JSON API

The purpose of the following piece of code is to return the desired posts in a JSON format for our widget convenience. If the $_GET['start'] variable is set in the requested URL then we know it has been requested from our widget(via AJAX request). It will then return posts and die.

You could also use the great JSON API plugin

/* loading of stuff */
if(isset($_GET['start'])) {
	/* spit out the posts within the desired range */
	$posts = get_posts($_GET['start'],$_GET['desiredPosts']);
	// decode the result to know the exact length of the result
	// It could be 2, 1 or 0 in this case
	$postsDecoded = json_decode($posts);
	// If the result is not empty we update the session
	if (!empty($postsDecoded))
	{
		/* save the user's "spot", so to speak */
		$_SESSION['posts_start']+= count($postsDecoded);
	}
	echo get_posts($_GET['start'],$_GET['desiredPosts']);
	/* kill the page */
	die();
}

Step 2: HTML (Bootstrap markups)

Our widget HTML is fairly simple. It contains a title with a posts counter (#widget .badge),a posts container (#widget .content) and a more button (#widget .more).

<div id="widget">
	<h4 id="widget-title">
		Widget Title <span class="badge badge-info"><?php echo $_SESSION['posts_start'] ?>
		</span>
	</h4>
	<div class="content" style="height: 300px; overflow: auto; margin: 0px;"></div>
	<button class="more btn btn-block">
		More <span class="caret"></span>
	</button>
</div>

Step 3: Mustache template (Bootstrap markups)

The mustache template contains the HTML for posts. The block {{#data}} YOUR HTML {{/data}} is rendered once for each item in the list ({data:[]} see below in the JavaScript part).

The inverted section opens with {{^data}} instead of {{#data}}. The block of an inverted section is rendered only if the value of that section’s tag is null, undefined, false, or an empty list.

For more details please check the Mustache.js documentation.

{{#data}}
<div class="item">
	<img class="thumbnail pull-left" width="50px" height="50px" src="http://placehold.it/50x50" style="margin: 0px 10px 5px 0px;">
	<a href="#">
		<h4 style="margin: 5px 0px;">{{post_title}}</h4>
	</a>
	<p>
		<small>{{post_content}}</small>
	</p>
	<div class="well well-small">
		{{post_date}}
	</div>
</div>
{{/data}}
{{^data}}
	<div class="alert alert-error">No data</div>
{{/data}}

Step 4: Mootools JavaScript

Initialize variables

  • The start variable represent the number of posts already loaded in the page.
  • The initialPosts variable is an array containing posts (either the default number of posts or the last number of posts saved in the session).
  • The desiredPosts variable is here 2 (See the PHP part above).
  • The template variable is either NULL or contains the Mustache template String.
var start = <?php echo $_SESSION['posts_start']; ?>;
var initialPosts = <?php echo get_posts(0,$_SESSION['posts_start']);  ?>;
var desiredPosts = <?php echo $number_of_posts; ?>;
var template = null;

DOM elements

// Widget element
var widget = $('widget'),
// Element to load the posts
content = widget.getElement('.content'),
// the more button
more = widget.getElement('.more'),
// the post counter
counter = widget.getElement('.badge');

Post Handler

The postHandler function purpose is to inject posts into our HTML.

The first execution loads and stores the Mustache template file (via a synchronous Ajax request) then uses the function Mustache.render(template, {'data' : data}) (that returns a HTML String of our posts) to populate the widget HTML.

Next executions (when clicking the “more” button) skip the Ajax request on the template and simply populate the widget HTML.

var postHandler = function(data){
	// Check if the template is already stored
	if (!template){
		// If not we get it
		new Request({
			url: 'load-more.mustache',
			method: 'get',
			async: false,
			onSuccess: function(responseText){
				// the response text is stored as the template
				template = responseText;
			},
			onFailure: function() {
				// insert the failure message
				widget.grab(alerts.templateFailure,'before');
				// get rid of the widget
				widget.dispose();
			}
			// Send the Ajax request
		}).send();
	}
	else{
		// Set the progress bar to 100%
		progressBar.setStyle('width', '100%');
		// Delay the normal more button to come back for a better effect
		more.set.delay(500, more, ['html','More <span class="caret"></span>']);
	}
	// Transform the template (String) into Elements that we can use
	var childrens =  new Element('div', {
		// Mustache requires an object property to reference in order to
		// create loops
		'html' : Mustache.render(template, {'data' : data})
	}).getChildren('*');
	// insert childrens at the end of the content element
	content.adopt(childrens);
	// Scroll to the first element loaded
	scroll.toElement(childrens[0]);
}

Ajax request to get the data

This part of code (I kept only the logic and removed effects) create a Ajax request instance for the more button to use when clicked. We ask the same page to return raw data (JSON) and on success event we either load this data into our template (if responseJSON.length > 0) or remove the more button (no more data to load).

// create the data Ajax request
var request = new Request.JSON({  
	url: 'load-more.php', // ajax script -- same page
	method: 'get',
	// Any calls made to start while the request is running will be ignored.
	link: 'ignore',
	// We do not want IE to cache the result
	noCache: true,
	onSuccess: function(responseJSON) {
		// Check if data is returned
		if (responseJSON.length > 0){
			// Update the total number of items
			start += responseJSON.length;
			// load items on the page
			postHandler(responseJSON);
		}
		else{
			// Remove the more button
			more.dispose.delay(500,more);
		}
	}
});

Add the click event to the “more” button

// add the click event to the more button
more.addEvent('click',function(){  
	// begin the ajax attempt
	request.send({
		data: {  
			'start': start,  
			'desiredPosts': desiredPosts  
		} 
	});  
});

Complete JavaScript

I extensively commented the following code to be as clear as possible. If you are having problems to understand just leave a comment, I will get back to you.

//domready event  
window.addEvent('domready',function() {
	// initialize variables
	var start = <?php echo $_SESSION['posts_start']; ?>;
	var initialPosts = <?php echo get_posts(0,$_SESSION['posts_start']);  ?>;
	var desiredPosts = <?php echo $number_of_posts; ?>;
	// either null or contains the mustache template
	var template = null;
	// Widget element
	var widget = $('widget'),
	// Element to load the posts
	content = widget.getElement('.content'),
	// the more button
	more = widget.getElement('.more'),
	// the post counter
	counter = widget.getElement('.badge');
	// Create alerts elements (Display Success or Failure)
	var alerts = {
			templateFailure : new Element('div',{'class' : 'alert alert-error','html' : 'Could not get the template.'}),
			requestEmpty : new Element('div',{'class' : 'alert alert-info','html' : 'No more data'}),
			requestFailure : new Element('div',{'class' : 'alert alert-error','html' : 'Could not get the data. Try again!'})
	}
	// create the Bootstrap progress bar element
	var progressElement = new Element('div', {
		'class': 'progress',
		'html': "<div class='bar'></div>",
		'styles': {
			'margin-bottom' : 0
		}
	});
	var progressBar = progressElement.getElement('.bar');
	// Create a scroll instance on the widget content
	// This Class is included in Mootools More
	var scroll = new Fx.Scroll(content, {
		duration: 1000,
		wait: false
	});
	// function that handle posts
	var postHandler = function(data){
		// Check if the template is already stored
		if (!template){
			// If not we get it
			new Request({
				url: 'load-more.mustache',
				method: 'get',
				async: false,
				onSuccess: function(responseText){
					// the response text is stored as the template
					template = responseText;
				},
				onFailure: function() {
					// insert the failure message
					widget.grab(alerts.templateFailure,'before');
					// get rid of the widget
					widget.dispose();
				}
				// Send the Ajax request
			}).send();
		}
		else{
			// Set the progress bar to 100%
			progressBar.setStyle('width', '100%');
			// Delay the normal more button to come back for a better effect
			more.set.delay(500, more, ['html','More <span class="caret"></span>']);
		}
		// Transform the template (String) into Elements that we can use
		var childrens =  new Element('div', {
			// Mustache requires an object property to reference in order to
			// create loops
			'html' : Mustache.render(template, {'data' : data})
		}).getChildren('*');
		// insert childrens at the end of the content element
		content.adopt(childrens);
		// Scroll to the first element loaded
		scroll.toElement(childrens[0]);
	}
	// place the initial posts in the page
	postHandler(initialPosts);

	// create the data Ajax request
	var request = new Request.JSON({  
		url: 'load-more.php', // ajax script -- same page
		method: 'get',
		// Any calls made to start while the request is running will be ignored.
		link: 'ignore',
		// We do not want IE to cache the result
		noCache: true,  
		onRequest: function() {
			// Set the progress bar to 0%
			progressBar.setStyle('width', '0%');
			// remove the more button innerHTML and insert the progress bar
			more.empty().grab(progressElement);
		},
		onSuccess: function(responseJSON) {
			// Check if data is returned
			if (responseJSON.length > 0){
				// Update the total number of items
				start += responseJSON.length;
				// Update the counter
				counter.set('html', start);
				// load items on the page
				postHandler(responseJSON);
			}
			else{
				// insert the empty message
				widget.grab(alerts.requestEmpty,'before');
				// Set the progress bar to 100%
				progressBar.setStyle('width', '100%');
				// Remove the more button
				more.dispose.delay(500,more);
				// remove the empty message after 4 seconds
				alerts.requestEmpty.dispose.delay(4000,alerts.requestEmpty);
			}
		},
		onFailure: function() {
			// insert the failure message
			widget.grab(alerts.requestFailure,'before');
			// Set the progress bar to 100%
			progressBar.setStyle('width', '100%');
			// Delay the normal more button to come back for a better effect
			more.set.delay(500, more, ['html','More <span class="caret"></span>']);
		}
	});
	// add the click event to the more button
	more.addEvent('click',function(){  
		// begin the ajax attempt
		request.send({
			data: {  
				'start': start,  
				'desiredPosts': desiredPosts  
			} 
		});  
	});
});

Dependency injection

The Dependency Injection is a complicated term that define a simple idea everybody is using with or without knowing it.

I will try in this post to share the essential and explain it as simple as possible.

What is Dependency Injection (DI)?

A DI is a popular design pattern for large scale Software. The purpose is to simplify the deployment and the Unit tests. However to do so you will need to create a more complex architecture! Before using this design pattern ask yourself if you need it. If your Software can be used on different platforms and configurations you probably need it, if not then it is up to you.

Exemple using PHP

Let’s say your Software is about boats and in order to create a boat Object you need to establish a Database connection.

You naturally create

Class Boat
{
	public function __construct()
	{
		$this->db = new Database('myHost', 'myDb', 'myUser', 'myPassword');
	}
}

As you can see in that example the Boat Class instantiate itself the Database instance with its own parameters. Boats Objects are dependant on the Database Class and its four hard-coded parameters. Without them the database connection is corrupted.

In the future let’s say that you have more Objects that use the same code across your platform. You have Boat, Car, Bus, Plane etc. with the same hard-coded dependency.

If you want to change the Database parameters you will need to go to all your files and change the dependency. This is really bad behaviour when it comes to fair large Software.

Class Boat
{
	public function __construct(String $host, String $db, String $user, String $pass)
	{
		$this->db = new Database($host, $db, $user, $pass);
	}
}

Now we added parameters to the constructor. The same four values are now provided by the piece of code that creates the Boat instance. If you want to change the Database parameters in the future you will not have to change Boat code.

Are we done? Well this is a bit better but our Boat Class is still depending on the Database Class and the four same values.

What happen if in the future you want to use another Database Class? Well once again you will need to change your code…We can do better than that!

Class Boat
{
	public function __construct(Object $db)
	{
		$this->db = $db;
	}
}

In this example our Boat Class is no longer dependent on the Database Class or the four previous values! The piece of code that creates a Boat Class has to inject the Database Object.

Sources