<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Bootstrap Archives - Michael Soriano</title>
	<atom:link href="https://michaelsoriano.com/tag/bootstrap/feed/" rel="self" type="application/rss+xml" />
	<link>https://michaelsoriano.com/tag/bootstrap/</link>
	<description>I turn code into captivating user experiences for the web</description>
	<lastBuildDate>Fri, 01 Dec 2023 00:56:46 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.4</generator>
	<item>
		<title>How to Build a Company Timeline using Bootstrap and WordPess REST API</title>
		<link>https://michaelsoriano.com/build-company-timeline-bootstrap-wp-rest-api/</link>
					<comments>https://michaelsoriano.com/build-company-timeline-bootstrap-wp-rest-api/#respond</comments>
		
		<dc:creator><![CDATA[Michael Soriano]]></dc:creator>
		<pubDate>Fri, 27 Jul 2018 19:08:32 +0000</pubDate>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<category><![CDATA[REST]]></category>
		<guid isPermaLink="false">http://michaelsoriano.com/?p=6168</guid>

					<description><![CDATA[<p>So our Company wanted to build a Timeline. One that shows our projects throughout the years, decades even. One that is sleek, modern and responsive. We&#8217;re already running WordPress, and have Bootstrap installed. So this shouldn&#8217;t be too bad. It turns out &#8211; it was a pretty fun project to build. Our in house designers [&#8230;]</p>
<p>The post <a href="https://michaelsoriano.com/build-company-timeline-bootstrap-wp-rest-api/">How to Build a Company Timeline using Bootstrap and WordPess REST API</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>So our Company wanted to build a Timeline. One that shows our projects throughout the years, decades even. One that is sleek, modern and responsive. We&#8217;re already running WordPress, and have Bootstrap installed. So this shouldn&#8217;t be too bad. It turns out &#8211; it was a pretty fun project to build.</p>



<p>Our in house designers are responsible for the design of this page. It&#8217;s a little bit of Facebook&#8217;s original timeline layout &#8211; but a lot simpler and minimalist. Here is a preview of how it looks:</p>



<p><img fetchpriority="high" decoding="async" width="875" height="506" class="alignnone size-full wp-image-6685" style="border: 1px solid #ededed;" src="https://michaelsoriano.com/wp-content/uploads/2017/10/timeline.gif" alt=""><br></p>



<p>In a nutshell, this is what we&#8217;re going to accomplish: We&#8217;re going to use custom post types (CPT) for each entry in the Timeline. We&#8217;re grabbing them via JavaScript &#8211; using the WP Rest API as the endpoint. We&#8217;re also using Boostrap&#8217;s grid system &#8211; so our timeline behaves well in mobile.</p>



<p>We are going to build everything as part of the theme. For more advanced users &#8211; you can also build it as a plugin.</p>



<p>Note that you have to be familiar with WordPress, PHP and Front end to follow. There is no download for this &#8211; you simply have to follow along.</p>



<p>Ready to get started? Let&#8217;s begin:</p>



<h3 class="wp-block-heading">The Back-End</h3>



<p>First off, let&#8217;s take care of the data. We need to register the CPT with WordPress and make sure we have the right custom fields. Actually, we only have one custom field necessary &#8211; and that is the year. The year is what the timeline is sorted by (newest to oldest).</p>



<p>Open up <strong>functions.php</strong> in your theme. First let&#8217;s add the CPT initialization.</p>



<pre class="wp-block-code"><code lang="php" class="language-php">function registerTimelineCPT() {
        $labels = array(
            'name' =&gt; __( 'Timeline' ),
            'singular_name' =&gt; __( 'Timeline' ),
            'add_new_item'       =&gt; __( 'Add New Timeline'),
            'new_item'           =&gt; __( 'Timeline'),
            'edit_item'          =&gt; __( 'Edit Timeline'),
            'view_item'          =&gt; __( 'View Timeline'),
            'all_items'          =&gt; __( 'View All'),
        );
        register_post_type( 'timeline',
            array(
                'labels' =&gt; $labels,
                'public' =&gt; true,
                'has_archive' =&gt; false,
                'rewrite' =&gt; false,
                'publicly_queriable' =&gt; true,
                'exclude_from_search' =&gt; true,
                'show_ui' =&gt; true,
                'show_in_nav_menus' =&gt; false,
                'show_in_menu' =&gt; true,
                'show_in_admin_bar' =&gt; false,
                'menu_icon' =&gt; 'dashicons-backup',
                'show_in_rest' =&gt; true,
                'public' =&gt; false, //removes the "permalink"
                'supports' =&gt; array(
                    'title',
                    'excerpt',
                    'thumbnail',
                    'custom-fields'
                )
            )
        );
        //REMOVES COMMENTS
        remove_post_type_support( 'timeline', 'comments' );
}
add_action( 'init', 'registerTimelineCPT' );</code></pre>



<p>Above, we&#8217;re simply creating our CPT called &#8220;Timeline&#8221;. We&#8217;re setting up the labels, what it supports and what it doesn&#8217;t support. Upon logging in you should see a &#8220;<strong>Timeline</strong>&#8221; in your admin area.</p>



<p>Now for the&nbsp; custom fields &#8211; you can easily add this the default way according to <a href="https://codex.wordpress.org/Custom_Fields">WordPress</a>. In my case, I wanted to make it easier for the users to update &#8211; so I&#8217;m using this plugin called &#8220;<a href="https://metabox.io">Meta Box</a>&#8220;. </p>



<p>Our custom field is now easier to set up and become much cleaner to the users.<br>If you have MetaBox installed, adding the field is as simple as below. This goes into your <strong>functions.php</strong>.</p>



<pre class="wp-block-code"><code lang="php" class="language-php">function createMetaBoxes($meta_boxes ){
	$prefix = 'tl_';
	$meta_boxes[] = array(
		'id' =&gt; 'timeline_metabox',
		'title' =&gt; esc_html__( 'Other', $prefix ),
		'post_types' =&gt; array( 'timeline' ),
		'context'    =&gt; 'normal',
		'priority'   =&gt; 'low',
		'autosave'   =&gt; true,
		'fields'     =&gt; array(
			array(
				'name' =&gt; esc_html__( 'Timeline',  $prefix  ),
				'id'   =&gt; 'timeline_year',
				'label_description' =&gt; esc_html__( 'Year', $prefix ),
				'type' =&gt; 'range',
				'min'  =&gt; '1930',
				'max'  =&gt; date("Y"),
				'step' =&gt; 1,
				'std'  =&gt; date("Y"),
			)
		)
	);
	return $meta_boxes;
}
add_filter( 'rwmb_meta_boxes', 'createMetaBoxes' );</code></pre>



<p>Now if you go to the Timeline page, you should see our nice range slider:</p>



<p><img decoding="async" width="545" height="449" class="alignnone size-full wp-image-6705" src="https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-cfield.png" alt="timeline - cpt" srcset="https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-cfield.png 545w, https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-cfield-300x247.png 300w" sizes="(max-width: 545px) 100vw, 545px" /></p>



<p>We&#8217;re also using the following default WordPress fields:</p>



<ul class="wp-block-list">
<li>Title</li>



<li>Excerpt</li>



<li>Featured Image</li>
</ul>



<p>So as you&#8217;re following along, go ahead and add several timelines and make sure these fields are filled out.</p>



<h3 class="wp-block-heading">REST Endpoint</h3>



<p>Before we can call our Timelines through REST, we have to do some setup. Still in <strong>functions.php</strong>, add the code below:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">function restProperties(){
	register_rest_field( 'timeline',
		'timeline_year',
		array(
		   'get_callback' =&gt; 'registerRestCb',
		   'update_callback' =&gt; null,
		   'schema'          =&gt; null,
		)
	 );
	function registerRestCb($object, $field_name, $request){
		return get_post_meta( $object[ 'id' ], $field_name, true );
	}
}
add_action( 'rest_api_init', 'restProperties');</code></pre>



<p>So the above makes the &#8216;timeline&#8217; available as and endpoint in REST. Also, we&#8217;re adding the &#8216;timeline_year&#8217; as a property in the response. To find out more about WP REST API, check their <a href="https://developer.wordpress.org/rest-api/">documentation</a>.</p>



<p>Now, when you hit the endpoint: YOURURL +&#8217;<strong>/wp-json/wp/v2/timeline?_embed&amp;per_page=100</strong>&#8216;, you should now see data as a JSON string. This is enough for us to work with in our Front End. Let&#8217;s go do that now.</p>



<h3 class="wp-block-heading">The Front-End</h3>



<p>Before we continue, I forgot to mention the libraries that we need to work with:</p>



<ul class="wp-block-list">
<li>jQuery</li>



<li>Bootstrap</li>



<li>Handlebars</li>
</ul>



<h4 class="wp-block-heading">Markup</h4>



<p>I&#8217;m going to add the markup first (the handlebar templates), then we&#8217;ll move on to the logic.</p>



<p>This is the <span style="text-decoration: underline;">main template</span>:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;script id="timeline-template" type="text/x-handlebars-template"&gt;
    {{#each this}}
    &lt;div class="decade-wrap" id="decade-{{decade}}"&gt;            
    &lt;h1&gt;{{decade}}s&lt;/h1&gt;
    {{#each @this}}                    
        &lt;div class="col-lg-6 col-md-6 col-sm-6 col-xs-12 timeline-item timeline-index-{{@index}} timeline-{{leftOrRight @index}}"&gt;
            &lt;div class="timeline-year"&gt;{{year}}&lt;/div&gt;
            &lt;div class="timeline-inner-wrap col-lg-8 col-md-8 col-sm-8 col-lg-12 {{pull @index}}"&gt;                
                &lt;div class="timeline-thumbnail" style="background:url('{{img}}') no-repeat #ccc"&gt;                 
                &lt;/div&gt; 
                &lt;div class="timeline-title"&gt;{{title}}&lt;/div&gt;
                &lt;div class="timeline-excerpt"&gt;{{{excerpt}}}&lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
        {{{closeWrap @index}}}
    {{/each}}
    &lt;/div&gt;
    {{/each}}
&lt;/script&gt;</code></pre>



<p>As you can see, we&#8217;re using the Bootstrap col classes to make each item responsive. We&#8217;re also using pull classes &#8211; so the alternate item will be pulled to the left.</p>



<p>The <span style="text-decoration: underline;">decades scroller</span>:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;script id="timeline-decades-template" type="text/x-handlebars-template"&gt; 
{{#each this}}
    &lt;div class="timeline-decades-link-item decade-{{decade}} {{showingOrNot @index}}"&gt;
            &lt;a href="#decade-{{decade}}"&gt;{{decade}}s&lt;/a&gt;
    &lt;/div&gt;
{{/each}}
&lt;/script&gt;</code></pre>



<p>Nothing fancy here, just a list of decades that is clickable.</p>



<p>Lastly, let&#8217;s build the <span style="text-decoration: underline;">wrapper</span>:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;div class="timeline-decade-links-wrapper"&gt;
  &lt;div class="timeline-decade-links"&gt;
       &lt;div class="getting-items"&gt;Getting Items&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div class="timeline-wrapper"&gt;&lt;/div&gt; 
&lt;div class="show-more-wrap"&gt;
   &lt;a href="#"&gt;&lt;img src="showmore.png"&gt;&lt;/a&gt;
&lt;/div&gt;</code></pre>



<p>The above markup simply holds the timelines together. It also has the text &#8220;Getting Items&#8221; &#8211; which acts as our loader &#8211; until our AJAX call completes. Also, we have a &#8220;show more&#8221; button &#8211; so that when clicked &#8211; the rest of the items appear in the bottom.</p>



<p>So the above is our HTML. Now we need JavaScript, which is described below.</p>



<h3 class="wp-block-heading">Getting and Grouping the Items</h3>



<p>This is where we pull the data from our REST endpoint, and pass it on to the handlebars templates that we&#8217;ve created. We also need&nbsp;additional logic &#8211; specifically grouping the decades together to build the scroller.</p>



<p>Let&#8217;s grab our items via .ajax():</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">$(document).ready(function(){
	$.ajax({
		url : '/wp-json/wp/v2/timeline?_embed&amp;per_page=100',
		success : function(data){
                        console.log(JSON.parse(data));
			//TODO :compileTemplates();
			//TODO: bindDecadeScroller();
		},
		error : function(data){
			console.log('Error in fetching timeline...')
		}
	})
});</code></pre>



<p>All things are happening inside the document ready handler. Now if you refresh your browser, you shall see our data in a parsed JSON object.<br><img decoding="async" width="752" height="503" class="alignnone size-full wp-image-6723" src="https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-object.png" alt="timeline object" srcset="https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-object.png 752w, https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-object-300x201.png 300w" sizes="(max-width: 752px) 100vw, 752px" /></p>



<p>Now that we have our objects in place, remove the console.log() line that we have. We have 2 TODOS: functions that we haven&#8217;t built yet, namely&nbsp;<strong>compileTemplates</strong>() and&nbsp;<strong>bindDecadeScroller</strong>(). You can guess what both of them do.</p>



<p>Let&#8217;s add the first function&nbsp;<strong>compileTemplates()</strong>:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function compileTemplates(data){
	var parsed = JSON.parse(data);
	if(parsed.length &gt; 0){
		var obj = buildTimeline(parsed);
		var source  = $("#timeline-template").html();
		var source2 = $("#timeline-decades-template").html();
		var template = Handlebars.compile(source);
		var template2 =  Handlebars.compile(source2);
		$('.timeline-decade-links').html(template2(obj));
		$('.timeline-wrapper').html(template(obj));
	}
}</code></pre>



<p>The above simply compiles the JSON data and hands it over to our templates. This alone should get our views going. But don&#8217;t refresh the browser yet. There are plenty of logic that still needs to happen.</p>



<p>Notice the new function in line 4 called &#8220;<strong>buildTimeline()</strong>&#8220;.&nbsp; On top of that, we have Handlebar helpers that we haven&#8217;t registered &#8211; so the browser will actually throw a fit. This will be covered in the section below &#8220;<strong>View Helpers</strong>&#8220;.</p>



<p>Let&#8217;s build the function called&nbsp;<strong>buildTimeline()</strong>:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function buildTimeline(data){
    function comp(a, b){
        return b - a;
    }
    function compYear(a,b) {
        if (b.year &lt; a.year)
            return -1;
        if (b.year &gt; a.year)
            return 1;
        return 0;
    }
    function grabImg(el){
        var src = '';
        if(el._embedded){
            if(el._embedded['wp:featuredmedia']){
                src = el._embedded['wp:featuredmedia'][0]['source_url'];
            }
        }
        return src;
    }
    $.each(data, function(){
        $(this)[0].timeline_year = parseInt($(this)[0].timeline_year);
    })
    //add decade:
    $.each(data, function(){
        var year = $(this)[0].timeline_year;
        $(this)[0].timeline_year_decade = Math.floor(year / 10) * 10;
    })
    //group decades:
    var decades = [];
    $.each(data, function(){
        decades.push($(this)[0].timeline_year_decade);
    })
    var uniqueDecades = [];
    $.each(decades, function(i, el){
        if($.inArray(el, uniqueDecades) === -1) uniqueDecades.push(el);
    });
    decades = uniqueDecades.sort(comp);
    var clean = Array();
    var final = Array();
    $.each(data, function(i, el){
        var obj = {};
        obj.id = el.id;
        obj.img = grabImg(el);
        obj.title = el.title.rendered;
        obj.excerpt = el.excerpt.rendered;
        obj.year = el.timeline_year;
        obj.year_decade = el.timeline_year_decade;
        clean.push(obj);
    });
    clean = clean.sort(compYear);
    $.each(decades,function(i,el){
        var key = i;
        final[key] = Array();
        $.each(clean,function(x,xel){
            final[key]['decade'] = el;
            if(xel.year_decade == el){
                final[key].push(xel);
            }
        })
    })
    return final;
}</code></pre>



<p>Okay this is the meat of our logic. We&#8217;re trying to grab all of the years in our timelines. And from each of those years, we need to calculate the decade, take out the duplicates and stuff them back to a final array, grouped by decade.</p>



<p>In lines 31-34 is where we calculate the decade, then stuffing it to a new property called &#8220;<strong>timeline_year_decade</strong>&#8220;. Then we&#8217;re doing a couple more loops to remove duplicates, sort and create a clean &#8220;<strong>decades</strong>&#8221; array &#8211; which we need for our final loop in lines 66-75.</p>



<p>Refresh your browser and see what our &#8220;<strong>final</strong>&#8221; array looks like.</p>



<p><img decoding="async" width="780" height="615" class="alignnone size-full wp-image-6729" src="https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-object2.png" alt="timeline - object grouped" srcset="https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-object2.png 780w, https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-object2-300x237.png 300w, https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-object2-768x606.png 768w" sizes="(max-width: 780px) 100vw, 780px" /></p>



<p>Now we our&nbsp;<strong>compileTemplates() </strong>is done, let&#8217;s go and register our <strong>helpers</strong> and do some <strong>CSS</strong>.</p>



<h3 class="wp-block-heading"><strong>View Helpers</strong></h3>



<p>Now we have to do add more scripting to determine additional classes that makes our timeline look the way it does.</p>



<p>In case you haven&#8217;t noticed, our templates are sprinkled with helpers for handlebars. Let&#8217;s register those helpers now.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">Handlebars.registerHelper('leftOrRight', function(index) {
	return index %2 == 0 ? 'left' : 'right';
});
Handlebars.registerHelper('closeWrap', function(index) {
   return (index+1) %2 == 0 ? '&lt;div class="clearfix"&gt;&lt;/div&gt;' : '';
});
Handlebars.registerHelper('pull', function(index) {
   return index %2 == 0 ? '' : 'col-lg-push-4 col-md-push-4 col-sm-push-4';
});
Handlebars.registerHelper('showingOrNot', function(index) {
	if(index == 0){
		return 'showing';
	}
});</code></pre>



<p>The above are view helpers &#8211; that cooperates with the HTML templates that we just built. For instance, the &#8220;leftOrRight&#8221; helper &#8211; determines if a class of &#8220;left&#8221; or &#8220;right&#8221; is to be added. Below are the images for that:</p>



<p>Left Line:</p>



<p><br><img decoding="async" width="142" height="16" class="alignnone size-full wp-image-6713" src="https://michaelsoriano.com/wp-content/uploads/2018/07/left_line.png" alt="left line"><br></p>



<p>Right Line:</p>



<p><br><img decoding="async" width="141" height="16" class="alignnone size-full wp-image-6714" src="https://michaelsoriano.com/wp-content/uploads/2018/07/right_line.png" alt=""><br></p>



<p>Arrow up:<br></p>



<p><img decoding="async" width="12" height="8" class="alignnone size-full wp-image-6730" src="https://michaelsoriano.com/wp-content/uploads/2018/07/arrow-up.png" alt=""><br></p>



<p>Vertical Line:</p>



<p><br><img decoding="async" width="1" height="186" class="alignnone size-full wp-image-6734" src="https://michaelsoriano.com/wp-content/uploads/2018/07/vertical_line.png" alt=""><br></p>



<h3 class="wp-block-heading">The Styles</h3>



<p>Finally, the styles that make our timeline look good. I&#8217;m not going to walk through what each style does. I&#8217;m just going to add this as a reference for you to plugin. You might have a different style depending on your preference.</p>



<pre class="wp-block-code"><code lang="css" class="language-css">.timeline-wrapper {
    position:relative;
    z-index: 99;
}
.decade-wrap {
    overflow:hidden;
    clear:both;
    display:block;
    background:url('vertical_line.png') #fff repeat-y;
    background-position-x: center;
}
.decade-wrap:first-child {
    padding-top: 40px;
}
.decade-wrap:last-child{
    margin-bottom: 75px;
}
.decade-wrap h1 {
    text-align: center;
    background:#fff;
    padding:25px 0 35px;
    font-size:45px;
    color: #0077C8;
}
.timeline-thumbnail {
    background-position-x: center !important;
    background-position-y: center !important;
    background-size: cover !important;
    height:319px;
}
.timeline-item,
.timeline-inner-wrap {
    padding-left:0;
    padding-right:0;
}
.timeline-left {
    background:url('left_line.png') no-repeat right center;
    margin-left: 8px;
}
.timeline-right {
     margin-top: 100px;
    background:url('right_line.png') no-repeat left center;
    margin-left: -15px;
}
.timeline-inner-wrap {
    padding-top: 25px;
}
.timeline-year {
    position: absolute;
    top: 39%;
    font-size:30px;
    font-weight: 500;
    color: #0077C8;
}
.timeline-right .timeline-year {
    padding-left: 35px;
}
.timeline-left .timeline-year {
    right:0;
    padding-right: 34px;
}
.timeline-title {
    font-size: 19px;
    font-weight: 500;
    color: #000;
    padding-top: 15px;
    padding-bottom: 10px;
}
.timeline-decade-links {
    background:#ececec;
    min-height: 60px;
    display: flex;
}
.timeline-decades-link-item {
    width: 100px;
    margin: 0 auto;
    text-align: center;
    font-size: 18px;
    padding-top: 18px;
    height: 60px;
}
.timeline-decades-link-item a:hover,
.timeline-decades-link-item a:focus{
    text-decoration:none;
}
.timeline-decades-link-item.showing {
    background:url('arrow-up.png') transparent no-repeat center bottom;
}
.timeline-decade-links-wrapper {
    overflow: hidden;
}
.timeline-decade-links-wrapper.fixed {
    position: fixed;
    top: 0px;
    z-index: 110;
    left:0;
    width:100%;
}
.admin-bar .timeline-decade-links-wrapper.fixed {
    top:32px;
}
@media(max-width:1199px){
    .timeline-thumbnail {
        height:253px;
    }
    .timeline-item {
        background-position-y: 33%;
    }
    .timeline-year{
        top: 21%;
    }
}
@media(max-width:991px){
    .timeline-thumbnail {
        height:190px;
    }
    .timeline-item {
        background-position-y: 28%;
    }
    .timeline-year{
        top: 18%;
        font-size: 23px;
    }
    .decade-wrap h1 {
        padding: 14px 0 24px;
        font-size: 31px;
    }
}
@media(max-width:768px){
    .timeline-thumbnail {
        height:354px;
        width:410px;
    }
    .decade-wrap {
        background:none;
    }
    .decade-wrap:first-child {
        padding-top:0;
    }
    .decade-wrap h1 {
        padding: 0px 0px 0px 0px;
    }
    .timeline-right {
        margin-top: 0;
    }
    .timeline-item {
        background:#fff;
        margin-left: 0 !important;
        margin-right:0 !important;
    }
    .timeline-year {
        position: relative;
        padding-left: 0 !important;
        padding-right:0 !important;
    }
    .timeline-decade-links {
        display: none;
    }
}
@media(max-width:500px){
    .timeline-thumbnail {
        height:302px;
        width:auto;
    }
}
@media(max-width:375px){
    .timeline-thumbnail {
        height:242px;
    }
}</code></pre>



<p>&nbsp;<br>After our helpers apply the classes, our CSS and images in place &#8211; Bootstrap will take care of the rest. If you refresh, you should see your timeline. Inspect and you see our classes applied.</p>



<p><img decoding="async" width="1006" height="591" class="alignnone size-full wp-image-6718" src="https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-classes.png" alt="timeline classes" srcset="https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-classes.png 1006w, https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-classes-300x176.png 300w, https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-classes-768x451.png 768w" sizes="(max-width: 1006px) 100vw, 1006px" /></p>



<p>Finally, let&#8217;s go ahead and bind that scroller:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">function bindDecadeScroller(){
	 $('.timeline-decades-link-item a').on('click',function(){
		var id = $(this).attr('href');
		var offset = ($(id).offset().top - 150) ;
		$('html, body').stop().animate({
			scrollTop: offset
		}, 1000);
		return false;
	})
}</code></pre>



<p>This should have a smooth animating effect when you click on the decades on the scroller. Note that our timelines are grouped by decades, encapsulated in a DIV with the ID &#8211; of the decade. So when our scroller is cicked &#8211; it has the ID of the DIV in it&#8217;s href attribute. </p>



<p>So technically, even without our animation &#8211; it will know where to focus naturally.</p>



<p><img decoding="async" width="636" height="673" class="alignnone size-full wp-image-6737" src="https://michaelsoriano.com/wp-content/uploads/2018/07/timeline-responsive.gif" alt="timeline - responsive"></p>



<p>We&#8217;re using .animate() to make that jump smoother. Check jQuery&#8217;s <a href="http://api.jquery.com/animate/">documentation</a> on .animate for more information.</p>



<h3 class="wp-block-heading">Conclusion</h3>



<p>And there you have it. We&#8217;ve just build a pretty cool timeline &#8211; grouped by decades, with a scroller that focuses on the decade when clicked. This is also responsive &#8211; so it looks real good in a mobile device. </p>



<p>Note that this is a pretty basic timeline &#8211; which you can greatly enhance by adding other things. For example, you can add a modal for more details for each of the item. Or even multiple images per item &#8211; one that you can scroll left to right like a slideshow. There are many possibilities.</p>



<p>For the live page, check out the Parsons <a href="https://www.parsons.com/about/timeline/">timeline</a> page.&nbsp;I hope you enjoyed this tutorial. Leave your comments below.</p>
<p>The post <a href="https://michaelsoriano.com/build-company-timeline-bootstrap-wp-rest-api/">How to Build a Company Timeline using Bootstrap and WordPess REST API</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://michaelsoriano.com/build-company-timeline-bootstrap-wp-rest-api/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Building a user registration system – Part 3: The Password Reset Form</title>
		<link>https://michaelsoriano.com/building-a-user-registration-system-part-3-password-reset/</link>
					<comments>https://michaelsoriano.com/building-a-user-registration-system-part-3-password-reset/#comments</comments>
		
		<dc:creator><![CDATA[Michael Soriano]]></dc:creator>
		<pubDate>Sat, 10 Oct 2015 20:27:47 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<category><![CDATA[Codeigniter]]></category>
		<category><![CDATA[MVC]]></category>
		<guid isPermaLink="false">http://michaelsoriano.com/?p=5243</guid>

					<description><![CDATA[<p>So now we&#8217;ve come to the last part of this series. We need a way to let users back in when they forget their passwords. So we&#8217;re going to need a form, a mechanism to notify them with a unique token, as well as another form to actually do the resetting of the password. Plenty [&#8230;]</p>
<p>The post <a href="https://michaelsoriano.com/building-a-user-registration-system-part-3-password-reset/">Building a user registration system – Part 3: The Password Reset Form</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>So now we&#8217;ve come to the last part of this series. We need a way to let users back in when they forget their passwords. So we&#8217;re going to need a form, a mechanism to notify them with a unique token, as well as another form to actually do the resetting of the password. Plenty of going on here, so let&#8217;s start coding.</p>



<p><strong>Update 9/5/2016: </strong> Updated flaw in token creation and token checking for better security. Thanks to <a href="https://michaelsoriano.com/building-a-user-registration-system-part-3-password-reset/#comment-36867">comment by Mohammad</a> and his findings.</p>



<p><strong>Update 7/20/2016: </strong> Added index.php file to the views directory. This is the view that is being used once a successful login is processed.</p>



<p><a href="https://github.com/michaelsoriano/user-registration-codeigniter">View in Github</a></p>



<h3 class="wp-block-heading">The Forgot your Password form</h3>



<p>In our controller &#8220;Main.php&#8221;, let&#8217;s add a new action called &#8220;forgot&#8221;. The code is below and I&#8217;ll explain what is inside:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function forgot()
        {
            $this-&gt;form_validation-&gt;set_rules('email', 'Email', 'required|valid_email');
            if($this-&gt;form_validation-&gt;run() == FALSE) {
                $this-&gt;load-&gt;view('header');
                $this-&gt;load-&gt;view('forgot');
                $this-&gt;load-&gt;view('footer');
            }else{
                $email = $this-&gt;input-&gt;post('email');
                $clean = $this-&gt;security-&gt;xss_clean($email);
                $userInfo = $this-&gt;user_model-&gt;getUserInfoByEmail($clean);
                if(!$userInfo){
                    $this-&gt;session-&gt;set_flashdata('flash_message', 'We cant find your email address');
                    redirect(site_url().'main/login');
                }
                if($userInfo-&gt;status != $this-&gt;status[1]){ //if status is not approved
                    $this-&gt;session-&gt;set_flashdata('flash_message', 'Your account is not in approved status');
                    redirect(site_url().'main/login');
                }
                //build token
                $token = $this-&gt;user_model-&gt;insertToken($userInfo-&gt;id);
                $qstring = $this-&gt;base64url_encode($token);
                $url = site_url() . 'main/reset_password/token/' . $qstring;
                $link = '<a href="' . $url . '">' . $url . '</a>';
                $message = '';
                $message .= '<strong>A password reset has been requested for this email account</strong>
';
                $message .= '<strong>Please click:</strong> ' . $link;
                echo $message; //send this through mail
                exit;
            }
        }
</code></pre>



<p>The action opens up the same way we have with our other forms. We have our validation rules for our &#8220;email&#8221; input field. In our form, all we&#8217;re really asking for our user is to enter their password. So we just need to run a couple of rules against this value: valid email and required. Once our validation passes, we also clean the data with our xss_clean() method which is loaded automatically. </p>



<p>To learn more about the Security Helper click <a href="https://www.codeigniter.com/user_guide/helpers/security_helper.html">here</a>.</p>



<p>Now we check if the email submitted exists in our database through our Model method: getUserInfoByEmail(). So add the code below to our Model (User_Model.php). This method returns the record on success and false on fail.</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function getUserInfoByEmail($email)
    {
        $q = $this-&gt;db-&gt;get_where('users', array('email' =&gt; $email), 1);
        if($this-&gt;db-&gt;affected_rows() &gt; 0){
            $row = $q-&gt;row();
            return $row;
        }else{
            error_log('no user found getUserInfo('.$email.')');
            return false;
        }
    }
</code></pre>



<p>We also need another method that checks grabs the user information. This method called &#8220;getUserInfo()&#8221; simply returns the row and false if none is found:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function getUserInfo($id)
    {
        $q = $this-&gt;db-&gt;get_where('users', array('id' =&gt; $id), 1);
        if($this-&gt;db-&gt;affected_rows() &gt; 0){
            $row = $q-&gt;row();
            return $row;
        }else{
            error_log('no user found getUserInfo('.$id.')');
            return false;
        }
    }
</code></pre>



<p>So back in our &#8220;<em>forgot</em>&#8221; action, we simply set a couple of error messages when we receive a false from our model, or proceed with the token creation &#8220;<em>insertToken</em>()&#8221; on success. Note that we are reusing this method from our previous action when creating a new user.</p>



<p>The code for our view is below. Just some messaging our form and input fields. Notice we&#8217;re using <a href="https://www.codeigniter.com/user_guide/helpers/form_helper.html">CodeIgniter&#8217;s Form class</a>.</p>



<pre class="wp-block-code"><code lang="php" class="language-php">&lt;div class="col-lg-4 col-lg-offset-4">
&lt;h2>Forgot Password&lt;/h2>
&lt;p>Please enter your email address and we'll send you instructions on how to reset your password&lt;br>
&lt;?php 
$fattr = array('class' =--> 'form-signin'); 
echo form_open(site_url().'main/forgot/', $fattr); ?>
&lt;/p>
&lt;div class="form-group">
&lt;?php echo form_input(array(
          'name'=-->'email', 'id'=&amp;gt; 'email', 'placeholder'=&amp;gt;'Email', 'class'=&amp;gt;'form-control', 'value'=&amp;gt; set_value('email'))); ?>
&lt;?php echo form_error('email');?>
&lt;/div>
&lt;p>&lt;?php echo form_submit(array('value'=-->'Submit', 'class'=&amp;gt;'btn btn-lg btn-primary btn-block')); ?>
&lt;?php echo form_close(); ?>&lt;/p>
&lt;/div>

</code></pre>



<p><br>Now go ahead and try out your form. Try an email that doesn&#8217;t exist &#8211; and try one that does. With our unique token code in our action, we continue to construct the link and &#8220;echo&#8221; to the browser. </p>



<p><img decoding="async" width="608" height="365" class="alignnone size-full wp-image-5251" src="https://michaelsoriano.com/wp-content/uploads/2015/10/forgot-password.png" alt="forgot-password" srcset="https://michaelsoriano.com/wp-content/uploads/2015/10/forgot-password.png 608w, https://michaelsoriano.com/wp-content/uploads/2015/10/forgot-password-300x180.png 300w" sizes="(max-width: 608px) 100vw, 608px" /></p>



<p>Remember that this is to be emailed to the user but we are simply echoing it out for demo purposes. The link should look like below:<br><img decoding="async" width="731" height="140" class="alignnone size-full wp-image-7104" src="https://michaelsoriano.com/wp-content/uploads/2015/10/token-1.jpg" alt="" srcset="https://michaelsoriano.com/wp-content/uploads/2015/10/token-1.jpg 731w, https://michaelsoriano.com/wp-content/uploads/2015/10/token-1-300x57.jpg 300w" sizes="(max-width: 731px) 100vw, 731px" /></p>



<h3 class="wp-block-heading">The Reset Password Form</h3>



<p>So now we have a unique link that we&#8217;ve sent to our forgetful user. Once they click on this link &#8211; they better have a page to land on, with a way to reset their password. So let&#8217;s build that now.<br>Let&#8217;s create another action in our controller, name it &#8220;reset_password()&#8221; and add the code below:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function reset_password()
        {
            $token = $this-&gt;base64url_decode($this-&gt;uri-&gt;segment(4));
            $cleanToken = $this-&gt;security-&gt;xss_clean($token);
            $user_info = $this-&gt;user_model-&gt;isTokenValid($cleanToken); //either false or array();
            if(!$user_info){
                $this-&gt;session-&gt;set_flashdata('flash_message', 'Token is invalid or expired');
                redirect(site_url().'main/login');
            }
            $data = array(
                'firstName'=&gt; $user_info-&gt;first_name,
                'email'=&gt;$user_info-&gt;email,
                'token'=&gt;base64_encode($token)
            );
            $this-&gt;form_validation-&gt;set_rules('password', 'Password', 'required|min_length[5]');
            $this-&gt;form_validation-&gt;set_rules('passconf', 'Password Confirmation', 'required|matches[password]');
            if ($this-&gt;form_validation-&gt;run() == FALSE) {
                $this-&gt;load-&gt;view('header');
                $this-&gt;load-&gt;view('reset_password', $data);
                $this-&gt;load-&gt;view('footer');
            }else{
                $this-&gt;load-&gt;library('password');
                $post = $this-&gt;input-&gt;post(NULL, TRUE);
                $cleanPost = $this-&gt;security-&gt;xss_clean($post);
                $hashed = $this-&gt;password-&gt;create_hash($cleanPost['password']);
                $cleanPost['password'] = $hashed;
                $cleanPost['user_id'] = $user_info-&gt;id;
                unset($cleanPost['passconf']);
                if(!$this-&gt;user_model-&gt;updatePassword($cleanPost)){
                    $this-&gt;session-&gt;set_flashdata('flash_message', 'There was a problem updating your password');
                }else{
                    $this-&gt;session-&gt;set_flashdata('flash_message', 'Your password has been updated. You may now login');
                }
                redirect(site_url().'main/login');
            }
        }
</code></pre>



<p>So our users will land in our page called &#8220;reset_password&#8221;, with a token in the url. First we need to process that and determine if its a good token. This is accomplished by our model&#8217;s isTokenValid() method. This method is the same method we had in our &#8220;complete&#8221; action when we are registering a new user &#8211; so this is nothing new. </p>



<p>And if you remember, this method returns user information on success &#8211; so we go on with our setup for the form. We pass this information using $data array straight to our view, reset_password.php:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">&lt;div class="col-lg-4 col-lg-offset-4">
&lt;h2>Reset your password&lt;/h2>
&lt;h5>Hello &lt;?php echo $firstName; ?>, Please enter your password 2x below to reset&lt;/h5>
&lt;p>&lt;?php
    $fattr = array('class' =--> 'form-signin'); echo form_open(site_url().'main/reset_password/token/'.$token, $fattr); ?>&lt;/p>
&lt;div class="form-group">
&lt;?php echo form_password(array('name'=-->'password', 'id'=&amp;gt; 'password', 'placeholder'=&amp;gt;'Password', 'class'=&amp;gt;'form-control', 'value' =&amp;gt; set_value('password'))); ?&amp;gt; &lt;?php echo form_error('password') ?>&lt;/div>
&lt;div class="form-group">
&lt;?php echo form_password(array('name'=-->'passconf', 'id'=&amp;gt; 'passconf', 'placeholder'=&amp;gt;'Confirm Password', 'class'=&amp;gt;'form-control', 'value'=&amp;gt; set_value('passconf'))); ?> &lt;?php echo form_error('passconf') ?>&lt;/div>
&lt;p>&lt;?php echo form_hidden('user_id', $user_id);?>
&lt;?php echo form_submit(array('value'=-->'Reset Password', 'class'=&amp;gt;'btn btn-lg btn-primary btn-block')); ?>
&lt;?php echo form_close(); ?>&lt;/p>
&lt;/div></code></pre>



<p>Clicking the link with the token will run our view. And if you did it correctly, it should render like below:</p>



<p><br><img decoding="async" width="606" height="412" class="alignnone size-full wp-image-5255" src="https://michaelsoriano.com/wp-content/uploads/2015/10/reset-password.png" alt="reset-password" srcset="https://michaelsoriano.com/wp-content/uploads/2015/10/reset-password.png 606w, https://michaelsoriano.com/wp-content/uploads/2015/10/reset-password-300x204.png 300w" sizes="(max-width: 606px) 100vw, 606px" /></p>



<p>Finally, we do some validation and sanitation on the passwords entered. Once passed, we continue to encrypt our user&#8217;s password through the create_hash() method. Remember this method is from our <a href="https://defuse.ca/php-pbkdf2.htm">Password class</a> that we&#8217;ve also used when creating new users. Then we update the user&#8217;s password on success.</p>



<h3 class="wp-block-heading">Conclusion</h3>



<p>So there you have our basic user registration system, explained in detail. Remember that this is mainly to get a grasp on what goes on behind the scenes of such a system as well as learning the ropes of <a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC</a>. It is also important to know that this is not production code. There are plenty of improvements to be made. But this should be enough to get you started.</p>
<p>The post <a href="https://michaelsoriano.com/building-a-user-registration-system-part-3-password-reset/">Building a user registration system – Part 3: The Password Reset Form</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://michaelsoriano.com/building-a-user-registration-system-part-3-password-reset/feed/</wfw:commentRss>
			<slash:comments>46</slash:comments>
		
		
			</item>
		<item>
		<title>Building a user registration system – Part 2: The Set Password and Login Forms</title>
		<link>https://michaelsoriano.com/building-a-user-registration-system-part-2-login-form/</link>
					<comments>https://michaelsoriano.com/building-a-user-registration-system-part-2-login-form/#comments</comments>
		
		<dc:creator><![CDATA[Michael Soriano]]></dc:creator>
		<pubDate>Thu, 10 Sep 2015 10:01:52 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<category><![CDATA[Codeigniter]]></category>
		<category><![CDATA[MVC]]></category>
		<guid isPermaLink="false">http://michaelsoriano.com/?p=5108</guid>

					<description><![CDATA[<p>So let&#8217;s continue with our registration system. We left off at the point where we have the registration page setup. So let&#8217;s try it out and fill in some information. Add your name and an email address. The fields should have validation, so you should see an error if you missed a field, or the [&#8230;]</p>
<p>The post <a href="https://michaelsoriano.com/building-a-user-registration-system-part-2-login-form/">Building a user registration system – Part 2: The Set Password and Login Forms</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>So let&#8217;s continue with our registration system. We left off at the point where we have the registration page setup. So let&#8217;s try it out and fill in some information. Add your name and an email address. The fields should have validation, so you should see an error if you missed a field, or the email is invalid. We also check if the email is duplicate &#8211; so you should see an error for that as well.</p>



<p><strong>Update 9/5/2016: </strong> Updated flaw in token creation and token checking for better security. Thanks to <a href="https://michaelsoriano.com/building-a-user-registration-system-part-3-password-reset/#comment-36867">comment by Mohammad</a> and his findings.</p>



<p><strong>Update 7/20/2016: </strong> Added index.php file to the views directory. This is the view that is being used once a successful login is processed.</p>



<p><a href="https://github.com/michaelsoriano/user-registration-codeigniter">View in GitHub</a><br></p>



<p><img decoding="async" width="600" height="368" class="alignnone size-full wp-image-5109" src="https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-0.jpg" alt="user-reg-0" srcset="https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-0.jpg 600w, https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-0-300x184.jpg 300w" sizes="(max-width: 600px) 100vw, 600px" /></p>



<p>Once you fill out the fields, check your database for the new entries. The user table should look like below:</p>



<p><img decoding="async" width="600" height="154" class="alignnone size-full wp-image-5113" src="https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-1a.jpg" alt="user-reg-1a" srcset="https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-1a.jpg 600w, https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-1a-300x77.jpg 300w" sizes="(max-width: 600px) 100vw, 600px" /></p>



<p>Note that we have the status set to &#8220;pending&#8221; as well as the role set to &#8220;subscriber&#8221;. We also have the password blank at the moment. Open the &#8220;tokens&#8221; table and you should see a new entry as well:</p>



<p><br><img decoding="async" width="600" height="154" class="alignnone size-full wp-image-5111" src="https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-2.jpg" alt="user-reg-2" srcset="https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-2.jpg 600w, https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-2-300x77.jpg 300w" sizes="(max-width: 600px) 100vw, 600px" /><br></p>



<p>Notice our user ids match in both tables. You should also be seeing our message in the browser &#8211; which is the message we will be sending through email to our user:<br></p>



<p><img decoding="async" width="600" height="154" class="alignnone size-full wp-image-5115" src="https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-3.jpg" alt="user-reg-3" srcset="https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-3.jpg 600w, https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-3-300x77.jpg 300w" sizes="(max-width: 600px) 100vw, 600px" /><br>Now we&#8217;re ready to code the 2nd part of the registration process.</p>



<h3 class="wp-block-heading">The &#8220;Complete&#8221; your registration page</h3>



<p>So our user gets an email to complete the registration. This email has a link with a &#8220;token&#8221; that ties the user id and the time created. So the code below is for our &#8220;complete&#8221; action. imply add to our Main controller:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function complete()
        {
            $token = base64_decode($this-&gt;uri-&gt;segment(4));
            $cleanToken = $this-&gt;security-&gt;xss_clean($token);
            $user_info = $this-&gt;user_model-&gt;isTokenValid($cleanToken); //either false or array();
            if(!$user_info){
                $this-&gt;session-&gt;set_flashdata('flash_message', 'Token is invalid or expired');
                redirect(site_url().'main/login');
            }
            $data = array(
                'firstName'=&gt; $user_info-&gt;first_name,
                'email'=&gt;$user_info-&gt;email,
                'user_id'=&gt;$user_info-&gt;id,
                'token'=&gt;$this-&gt;base64url_encode($token)
            );
            $this-&gt;form_validation-&gt;set_rules('password', 'Password', 'required|min_length[5]');
            $this-&gt;form_validation-&gt;set_rules('passconf', 'Password Confirmation', 'required|matches[password]');
            if ($this-&gt;form_validation-&gt;run() == FALSE) {
                $this-&gt;load-&gt;view('header');
                $this-&gt;load-&gt;view('complete', $data);
                $this-&gt;load-&gt;view('footer');
            }else{
                $this-&gt;load-&gt;library('password');
                $post = $this-&gt;input-&gt;post(NULL, TRUE);
                $cleanPost = $this-&gt;security-&gt;xss_clean($post);
                $hashed = $this-&gt;password-&gt;create_hash($cleanPost['password']);
                $cleanPost['password'] = $hashed;
                unset($cleanPost['passconf']);
                $userInfo = $this-&gt;user_model-&gt;updateUserInfo($cleanPost);
                if(!$userInfo){
                    $this-&gt;session-&gt;set_flashdata('flash_message', 'There was a problem updating your record');
                    redirect(site_url().'main/login');
                }
                unset($userInfo-&gt;password);
                foreach($userInfo as $key=&gt;$val){
                    $this-&gt;session-&gt;set_userdata($key, $val);
                }
                redirect(site_url().'main/');
            }
        }
</code></pre>



<p>First order of business is to validate the token. We grab it from the url with CI&#8217;s <a href="http://www.codeigniter.com/user_guide/general/urls.html">uri helper</a>: &#8220;segment(4)&#8221;. The code below &#8220;isTokenValid()&#8221; resides in our model, which checks the validity of the token and returns the user information on success and false on no. </p>



<p>Note that I&#8217;m only using a weak time check &#8211; which compares to strings to be equal. You should implement your own mechanism which does a dateDiff or something like that.</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function isTokenValid($token)
    {
       $tkn = substr($token,0,30);
       $uid = substr($token,30);
        $q = $this-&gt;db-&gt;get_where('tokens', array(
            'tokens.token' =&gt; $tkn,
            'tokens.user_id' =&gt; $uid), 1);
        if($this-&gt;db-&gt;affected_rows() &gt; 0){
            $row = $q-&gt;row();
            $created = $row-&gt;created;
            $createdTS = strtotime($created);
            $today = date('Y-m-d');
            $todayTS = strtotime($today);
            if($createdTS != $todayTS){
                return false;
            }
            $user_info = $this-&gt;getUserInfo($row-&gt;user_id);
            return $user_info;
        }else{
            return false;
        }
    }
</code></pre>



<p>Going back to our action, we simply create the &#8220;$data&#8221; array which we&#8217;ll need in our form. We&#8217;re also loading a &#8220;<a href="https://defuse.ca/php-pbkdf2.htm">Password</a>&#8221; class &#8211; which does the heavy lifting for our passwords. The class creates a dynamic salt appended to the password. The default hash is &#8220;sha256&#8221; and is fully configurable.<br></p>



<p>So token is good, validation passes &#8211; we then move on to updating our user information: &#8220;updateUserInfo()&#8221;. This goes in our model:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function updateUserInfo($post)
    {
        $data = array(
               'password' =&gt; $post['password'],
               'last_login' =&gt; date('Y-m-d h:i:s A'),
               'status' =&gt; $this-&gt;status[1]
            );
        $this-&gt;db-&gt;where('id', $post['user_id']);
        $this-&gt;db-&gt;update('users', $data);
        $success = $this-&gt;db-&gt;affected_rows();
        if(!$success){
            error_log('Unable to updateUserInfo('.$post['user_id'].')');
            return false;
        }
        $user_info = $this-&gt;getUserInfo($post['user_id']);
        return $user_info;
    }
</code></pre>



<p>The above simply updates our table with the new password, login time and the status to &#8220;active&#8221;. We have enough to complete our registration process.</p>



<p>Our view called &#8220;complete&#8221; will contain our HTML:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">&lt;div class="col-lg-4 col-lg-offset-4">
&lt;h2>Almost There!&lt;/h2>
&lt;h5>Hello &lt;?php echo $firstName; ?>. Your username is &lt;?php echo $email;?>&lt;/h5>
&lt;small>Please enter a password to begin using the site.&lt;/small> &lt;?php 
    $fattr = array('class' =&amp;gt; 'form-signin');
    echo form_open(site_url().'main/complete/token/'.$token, $fattr); ?>
&lt;div class="form-group">&amp;nbsp;&lt;/div>
&lt;div class="form-group">&amp;nbsp;&lt;/div>
&lt;?php echo form_submit(array('value'=&amp;gt;'Complete', 'class'=&amp;gt;'btn btn-lg btn-primary btn-block')); ?> 
&lt;?php echo form_close(); ?>&lt;/div></code></pre>



<p>Note that I&#8217;m using <a href="http://getbootstrap.com/">Bootstrap</a>, so our form automatically looks nice. I&#8217;m also using CI&#8217;s <a href="http://www.codeigniter.com/user_guide/helpers/form_helper.html">form helper</a> which makes our form building faster</p>



<p>Our form should look like below:</p>



<p><img decoding="async" width="600" height="366" class="alignnone size-full wp-image-5118" src="https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-4.jpg" alt="user-reg-4" srcset="https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-4.jpg 600w, https://michaelsoriano.com/wp-content/uploads/2015/09/user-reg-4-300x183.jpg 300w" sizes="(max-width: 600px) 100vw, 600px" /></p>



<p>On success you will notice that we set the session with the user data that we&#8217;ve fetched from the back end &#8220;<a href="http://www.codeigniter.com/user_guide/libraries/sessions.html?highlight=set_userdata#CI_Session::set_userdata">set_userdata()</a>&#8220;. We&#8217;re also redirecting them to the homepage of our site. On failure, we user CI&#8217;s &#8220;<a href="http://www.codeigniter.com/user_guide/libraries/sessions.html">set_flashdata()</a>&#8221; to set an error message temporarily in session, and displaying it above our form.</p>



<h3 class="wp-block-heading">The Login Form</h3>



<p>With what we&#8217;ve done above &#8211; it&#8217;s now possible to create a login form. See, we&#8217;re using an encryption technology that only our application can process. So it is important that we create our registration system first, before we can create a login form. </p>



<p>This way &#8211; we can test it properly.</p>



<p>The code below is our controller logic for our login form:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function login()
        {
            $this-&gt;form_validation-&gt;set_rules('email', 'Email', 'required|valid_email');
            $this-&gt;form_validation-&gt;set_rules('password', 'Password', 'required');
            if($this-&gt;form_validation-&gt;run() == FALSE) {
                $this-&gt;load-&gt;view('header');
                $this-&gt;load-&gt;view('login');
                $this-&gt;load-&gt;view('footer');
            }else{
                $post = $this-&gt;input-&gt;post();
                $clean = $this-&gt;security-&gt;xss_clean($post);
                $userInfo = $this-&gt;user_model-&gt;checkLogin($clean);
                if(!$userInfo){
                    $this-&gt;session-&gt;set_flashdata('flash_message', 'The login was unsucessful');
                    redirect(site_url().'main/login');
                }
                foreach($userInfo as $key=&gt;$val){
                    $this-&gt;session-&gt;set_userdata($key, $val);
                }
                redirect(site_url().'main/');
            }
        }
</code></pre>



<p>Nothing new in the code above. Again, we&#8217;re setting validation rules for our 2 fields. We grab the post array and clean it via <a href="http://www.codeigniter.com/user_guide/helpers/security_helper.html">xss_clean()</a>. Then we get to our model which has the checkLogin() method below:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function checkLogin($post)
    {
        $this-&gt;load-&gt;library('password');
        $this-&gt;db-&gt;select('*');
        $this-&gt;db-&gt;where('email', $post['email']);
        $query = $this-&gt;db-&gt;get('users');
        $userInfo = $query-&gt;row();
        if(!$this-&gt;password-&gt;validate_password($post['password'], $userInfo-&gt;password)){
            error_log('Unsuccessful login attempt('.$post['email'].')');
            return false;
        }
        $this-&gt;updateLoginTime($userInfo-&gt;id);
        unset($userInfo-&gt;password);
        return $userInfo;
    }
    public function updateLoginTime($id)
    {
        $this-&gt;db-&gt;where('id', $id);
        $this-&gt;db-&gt;update('users', array('last_login' =&gt; date('Y-m-d h:i:s A')));
        return;
    }
</code></pre>



<p>The above selects all columns where the user id and password match. Note that we&#8217;re using the validate_password() method from our Password class. We then update the login time and return the user information back to our controller.</p>



<p>Our login form view contains the code below:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">&lt;div class="col-lg-4 col-lg-offset-4">
&lt;h2>Please login&lt;/h2>
&lt;?php $fattr = array('class' =&amp;gt; 'form-signin');
         echo form_open(site_url().'main/login/', $fattr); ?>
&lt;div class="form-group">&amp;nbsp;&lt;/div>
&lt;div class="form-group">&amp;nbsp;&lt;/div>
&lt;?php echo form_submit(array('value'=&amp;gt;'Let me in!', 'class'=&amp;gt;'btn btn-lg btn-primary btn-block')); ?>
&lt;?php echo form_close(); ?>
&lt;p>Don't have an account? Click to &lt;a href="&lt;?php echo site_url();?>main/register">Register&lt;/a>&lt;/p>
&lt;p>Click &lt;a href="&lt;?php echo site_url();?>main/forgot">here&lt;/a> if you forgot your password.&lt;/p>
&lt;/div></code></pre>



<p>Again, using CI&#8217;s form helper along with Bootstrap classes to make our form nice. We also have a link back to the &#8220;<a href="https://michaelsoriano.com/building-a-user-registration-system-using-the-codeigniter-framework-part-1/">Register</a>&#8221; page, which we covered in the first part of this tutorial. Finally, we have another link to the &#8220;Forgot&#8221; password link &#8211; which I&#8217;ll cover in Part 3.</p>



<p>Stay tuned.</p>
<p>The post <a href="https://michaelsoriano.com/building-a-user-registration-system-part-2-login-form/">Building a user registration system – Part 2: The Set Password and Login Forms</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://michaelsoriano.com/building-a-user-registration-system-part-2-login-form/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Building a user registration system &#8211; Part 1: The New User Form</title>
		<link>https://michaelsoriano.com/building-a-user-registration-system-part-1-new-user-form/</link>
					<comments>https://michaelsoriano.com/building-a-user-registration-system-part-1-new-user-form/#comments</comments>
		
		<dc:creator><![CDATA[Michael Soriano]]></dc:creator>
		<pubDate>Fri, 21 Aug 2015 04:31:40 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<category><![CDATA[Codeigniter]]></category>
		<category><![CDATA[MVC]]></category>
		<guid isPermaLink="false">http://michaelsoriano.com/?p=5091</guid>

					<description><![CDATA[<p>Almost every website will have some form of public and restricted area. WordPress for instance, has the admin side where you can create posts, manage plugins, install themes etc. For this tutorial, we are going to create a similar mechanism. One that will restrict users from accessing sections of the site. We will create a [&#8230;]</p>
<p>The post <a href="https://michaelsoriano.com/building-a-user-registration-system-part-1-new-user-form/">Building a user registration system &#8211; Part 1: The New User Form</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Almost every website will have some form of public and restricted area. WordPress for instance, has the admin side where you can create posts, manage plugins, install themes etc. For this tutorial, we are going to create a similar mechanism. </p>



<p>One that will restrict users from accessing sections of the site. We will create a system that will allow them to create their own account, reset their password and even update their profile.</p>



<p><strong>Update 8/13/2018:&nbsp;</strong>Added the entire CI application in the repo, allowing faster setup and debug. CI version is 3.0.2 The setup steps below might not be necessary for usage.</p>



<p><strong>Update 9/5/2016: </strong> Updated flaw in token creation and token checking for better security. Thanks to <a href="https://michaelsoriano.com/building-a-user-registration-system-part-3-password-reset/#comment-36867">comment by Mohammad</a> and his findings.</p>



<p><strong>Update 7/20/2016: </strong> Added index.php file to the views directory. This is the view that is being used once a successful login is processed.</p>



<p><a href="https://github.com/michaelsoriano/user-registration-codeigniter">View in Github</a></p>



<p><img decoding="async" width="659" height="400" class="alignnone size-full wp-image-5974" src="https://michaelsoriano.com/wp-content/uploads/2015/08/user-reg.gif" alt="user-reg"><br></p>



<p>I&#8217;m going to assume that you are familiar with CodeIgniter, or other MVC frameworks. You don&#8217;t have to be an expert &#8211; just know enough that you will be able to follow along without me having to explain too much. We are also going to utilize Bootstrap &#8211; so our pages will look nice. Finally, the focus of this tutorial is learning how the process works. We&#8217;re not really here to look at design patterns, performance or database design.</p>



<p>So ready to get started? Roll up your sleeves and let&#8217;s start writing.</p>



<h3 class="wp-block-heading">Get things setup</h3>



<p>So obviously we&#8217;re going to need to store data &#8211; so we need a database. We will need a table that will house our users. Below is the SQL code to get you up and running. I&#8217;m calling the database &#8220;user-registration&#8221; &#8211; which is a stupid name actually. Name yours anything you want.</p>



<pre class="wp-block-code"><code lang="sql" class="language-sql">CREATE DATABASE IF NOT EXISTS `user-registration` DEFAULT CHARACTER SET latin1 COLLATE latin1_swedish_ci;
USE `user-registration`;

CREATE TABLE IF NOT EXISTS `ci_sessions` (
  `id` varchar(40) NOT NULL,
  `ip_address` varchar(45) NOT NULL,
  `timestamp` int(10) unsigned NOT NULL DEFAULT '0',
  `data` blob NOT NULL,
  PRIMARY KEY (`id`),
  KEY `ci_sessions_timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `tokens` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `token` varchar(255) NOT NULL,
  `user_id` int(10) NOT NULL,
  `created` date NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=26 ;

CREATE TABLE IF NOT EXISTS `users` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `email` varchar(100) NOT NULL,
  `first_name` varchar(100) NOT NULL,
  `last_name` varchar(100) NOT NULL,
  `role` varchar(10) NOT NULL,
  `password` text NOT NULL,
  `last_login` varchar(100) NOT NULL,
  `status` varchar(100) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=42 ;
</code></pre>



<p>We&#8217;re going to use <a href="https://github.com/bcit-ci/CodeIgniter/archive/3.0.2.zip">CodeIgniter 3.0.2</a>. Download and install in your web server.<br>In config &gt; config.php add the two lines below. I&#8217;ll explain these later.</p>



<pre class="wp-block-code"><code lang="php" class="language-php">$config['roles'] = array('subscriber', 'admin');
$config['status'] = array('pending', 'approved');</code></pre>



<p>Open database.php, and add your database credentials. It would be something like:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">$db['default'] = array(
	'dsn'	=&gt; '',
	'hostname' =&gt; 'localhost',
	'username' =&gt; 'root',
	'password' =&gt; '',
	'database' =&gt; 'user-registration',
	... //additional stuff here...
);</code></pre>



<p>Create a new controller named Main.php and a model, name it User_model.php. In the next sections, we will tie these things together.</p>



<p>But first let&#8217;s look at the workflow of our system:<br><img decoding="async" width="383" height="500" class="alignnone size-full wp-image-5099" src="https://michaelsoriano.com/wp-content/uploads/2015/08/process-user-reg.jpg" alt="process-user-reg" srcset="https://michaelsoriano.com/wp-content/uploads/2015/08/process-user-reg.jpg 383w, https://michaelsoriano.com/wp-content/uploads/2015/08/process-user-reg-230x300.jpg 230w" sizes="(max-width: 383px) 100vw, 383px" /><br></p>



<p>So our first step is the registration form. Users fill out this form which will only consist of their name and email. This will write a record to our database &#8211; but the account will only be in &#8220;pending&#8221; status. This will also trigger an email containing a token (which expires in a day), when clicked &#8211; will allow the user to finish the registration process. This form will have a password and password confirmation. This will update the record &#8211; and make the account &#8220;active&#8221;.</p>



<p>We will automatically login the user, but now that they have an account &#8211; they can actually utilize the login and reset password form.</p>



<p>It also makes sense for us to build the pages in this exact order. So we got: 1) register 2) complete 3) login 4) forgot password.</p>



<p>So inside our routes.php, add the default controller to ours:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">$route['default_controller'] = 'main';</code></pre>



<p>Also, let&#8217;s setup our autoload.php:</p>



<pre class="wp-block-code"><code lang="JavaScript" class="language-JavaScript">$autoload['helper'] = array('url');
$autoload['libraries'] = array('session');</code></pre>



<p>Now we can move forward.</p>



<h3 class="wp-block-heading">The Registration</h3>



<p>So the very first thing we need is the HTML that contains our form. Let&#8217;s create a new file called &#8220;register.php&#8221; and put it in our &#8220;views&#8221; folder. Add the code below:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">&lt;div class="col-lg-4 col-lg-offset-4">
    &lt;h2>Hello There&lt;/h2>
    &lt;h5>Please enter the required information below.&lt;/h5>
&lt;?php
    $fattr = array('class' => 'form-signin');
    echo form_open('/main/register', $fattr); ?>
    &lt;div class="form-group">
      &lt;?php echo form_input(array('name'=>'firstname', 'id'=> 'firstname', 'placeholder'=>'First Name', 'class'=>'form-control', 'value' => set_value('firstname'))); ?>
      &lt;?php echo form_error('firstname');?>
    &lt;/div>
    &lt;div class="form-group">
      &lt;?php echo form_input(array('name'=>'lastname', 'id'=> 'lastname', 'placeholder'=>'Last Name', 'class'=>'form-control', 'value'=> set_value('lastname'))); ?>
      &lt;?php echo form_error('lastname');?>
    &lt;/div>
    &lt;div class="form-group">
      &lt;?php echo form_input(array('name'=>'email', 'id'=> 'email', 'placeholder'=>'Email', 'class'=>'form-control', 'value'=> set_value('email'))); ?>
      &lt;?php echo form_error('email');?>
    &lt;/div>
    &lt;?php echo form_submit(array('value'=>'Sign up', 'class'=>'btn btn-lg btn-primary btn-block')); ?>
    &lt;?php echo form_close(); ?>
&lt;/div></code></pre>



<p>Note that I&#8217;m not going to go through what goes in our header and footer template because it&#8217;s irrelevant to this tutorial. Just know that it&#8217;s basic HTML, along with a link to Bootstrap CSS. Our markup above is a mix of PHP and HTML. This is using CodeIgniter&#8217;s Form Class &#8211; which makes it real easy to do validation and data filter and sanitation.</p>



<p>So in our Main controller, let&#8217;s add a constructor and include the necessary components for our class. We&#8217;ll also set up our status and roles arrays inside this constructor:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">class Main extends CI_Controller {
        public $status;
        public $roles;
        function __construct(){
            parent::__construct();
            $this->load->model('User_model', 'user_model', TRUE);
            $this->load->library('form_validation');
            $this->form_validation->set_error_delimiters('&lt;div class="error">', '&lt;/div>');
            $this->status = $this->config->item('status');
            $this->roles = $this->config->item('roles');</code></pre>



<p>So we&#8217;re loading our model &#8220;User_model&#8221; by default, the &#8220;form_validation&#8221; library and setting some HTML for our form errors. You&#8217;ll also notice the 2 properties (status and roles) &#8211; which grabs it from &#8220;$this->config&#8221;. Remember in our config file &#8211; we created 2 arrays? We&#8217;re simply outputting it here for easy access.</p>



<p>Now I know you&#8217;re saying this is better if these entries was in their own table in the database. Again, this is not a tutorial on database design. We&#8217;re simply doing it this way because it is not our focus. Let&#8217;s continue with our &#8220;register&#8221; method:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function register()
        {
            $this->form_validation->set_rules('firstname', 'First Name', 'required');
            $this->form_validation->set_rules('lastname', 'Last Name', 'required');
            $this->form_validation->set_rules('email', 'Email', 'required|valid_email');
            if ($this->form_validation->run() == FALSE) {
                $this->load->view('header');
                $this->load->view('register');
                $this->load->view('footer');
            }else{
                if($this->user_model->isDuplicate($this->input->post('email'))){
                    $this->session->set_flashdata('flash_message', 'User email already exists');
                    redirect(site_url().'main/login');
                }else{
                    $clean = $this->security->xss_clean($this->input->post(NULL, TRUE));
                    $id = $this->user_model->insertUser($clean);
                    $token = $this->user_model->insertToken($id);
                    $qstring = $this->base64url_encode($token);
                    $url = site_url() . 'main/complete/token/' . $qstring;
                    $link = '' . $url . '';
                    $message = '';
                    $message .= 'You have signed up with our website
';
                    $message .= 'Please click: ' . $link;
                    echo $message; //send this in email
                    exit;
                };
            }
        }</code></pre>



<p>Alright, plenty of going on up there. So the validation rules are setup initially. Our form contains 3 fields: Last name, First name and email. They&#8217;re all required fields, plus the email address must be in valid format.</p>



<p>You will notice in the block where our form is validated, we&#8217;re checking &#8220;isDuplicate()&#8221; from our model: $this->user_model. This is so that we won&#8217;t have duplicate records of the same email. Remember, we are using their email address as their username. </p>



<p>So if it&#8217;s a duplicate &#8211; we simply use CodeIgniter&#8217;s set_flashdata() and redirect them to the login page (which is not built yet).</p>



<p>If the email address is good, we continue by cleaning up the $_POST array. Notice that we have 2 methods right after the cleaning: insertUser() and insertToken(). So we write the record to our database, then we create a new token (let&#8217;s quickly run this SQL so we have this token table).</p>



<pre class="wp-block-code"><code lang="sql" class="language-sql">CREATE TABLE IF NOT EXISTS `tokens` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `token` varchar(255) NOT NULL,
  `user_id` int(10) NOT NULL,
  `created` date NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=26 ;</code></pre>



<p>Another thing, you will also see that we&#8217;re using a local method called &#8220;<a href="http://php.net/manual/en/function.base64-encode.php#103849">base64url_encode()</a>&#8221; &#8211; which is a way of outputting base64 code &#8211; that is in a web safe format. So in our controller, you can add these two methods in the bottom. Think of them as local &#8220;helper&#8221; methods.</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function base64url_encode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
public function base64url_decode($data) {
    return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}</code></pre>



<p>I am not putting them in a the &#8220;helpers&#8221; for CI &#8211; because these methods are only to be used in controllers &#8211; since they are &#8220;URL&#8221; related. And as you can see, we only have one controller. But as your application grows, and you have many controllers, it&#8217;s best to move this into a real CI Helper.<br>Finally, we create our final URL, to our &#8220;complete&#8221; action and echo it out.&nbsp;<strong>In production, this will be done through an email, in HTML format.</strong></p>



<h3 class="wp-block-heading"><strong>Some Back-end Stuff</strong></h3>



<p>Our model &#8220;User_model&#8221; is empty. Let&#8217;s go ahead and fill it up. We need 3 methods for our register to work remember? It&#8217;s 1) isDuplicate(), 2) insertUser() and insertToken(). First let&#8217;s create a constructor with our roles and status arrays:</p>



<pre class="wp-block-code"><code lang="php" class="language-php">public function insertUser($d)
    {
            $string = array(
                'first_name'=>$d['firstname'],
                'last_name'=>$d['lastname'],
                'email'=>$d['email'],
                'role'=>$this->roles[0],
                'status'=>$this->status[0]
            );
            $q = $this->db->insert_string('users',$string);
            $this->db->query($q);
            return $this->db->insert_id();
    }
    public function isDuplicate($email)
    {
        $this->db->get_where('users', array('email' => $email), 1);
        return $this->db->affected_rows() > 0 ? TRUE : FALSE;
    }
    public function insertToken($user_id)
    {
        $token = substr(sha1(rand()), 0, 30);
        $date = date('Y-m-d');
        $string = array(
                'token'=> $token,
                'user_id'=>$user_id,
                'created'=>$date
            );
        $query = $this->db->insert_string('tokens',$string);
        $this->db->query($query);
        return $token . $user_id;
    }</code></pre>



<p>So judging from the method names &#8211; they&#8217;re pretty self explanatory correct? Also, if you&#8217;ve worked with CodeIgniter before, you&#8217;ll notice the syntax of interacting with the database. It used to be called &#8220;active record&#8221;, which is now the <a href="http://www.codeigniter.com/user_guide/database/query_builder.html">Query Builder</a> class. Makes it real easy for non DBA&#8217;s like me to write queries.</p>



<p>The three methods all return either an array or a string on success, and &#8220;false&#8221; on failure. The return values are handled accordingly in our controller methods discussed previously. Pay token is simply a random number that we create and insert into the database. This token has an accompanying user id and a time stamp in the same row. This makes it possible for us to fetch the user, and find if it&#8217;s a valid request, in the appropriate time frame.</p>



<p>Let&#8217;s break it here for now. We have plenty more to come in the next part(s).</p>
<p>The post <a href="https://michaelsoriano.com/building-a-user-registration-system-part-1-new-user-form/">Building a user registration system &#8211; Part 1: The New User Form</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://michaelsoriano.com/building-a-user-registration-system-part-1-new-user-form/feed/</wfw:commentRss>
			<slash:comments>54</slash:comments>
		
		
			</item>
		<item>
		<title>How to make a SharePoint List work with Bootstrap &#8211; using SPServices and jQuery</title>
		<link>https://michaelsoriano.com/sharepoint-bootstrap-using-spservices-and-jquery/</link>
					<comments>https://michaelsoriano.com/sharepoint-bootstrap-using-spservices-and-jquery/#comments</comments>
		
		<dc:creator><![CDATA[Michael Soriano]]></dc:creator>
		<pubDate>Fri, 17 Jul 2015 16:23:46 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[SharePoint]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[SOAP]]></category>
		<category><![CDATA[SPServices]]></category>
		<guid isPermaLink="false">http://fearlessflyer.com/?p=4446</guid>

					<description><![CDATA[<p>For those of you who have worked with SharePoint in the past, particularly with lists, CEWPs (Content Editor Web Part) and front end code, then you probably know that these lists do not work well in mobile. The markup is just too messy &#8211; invalid tags, divs inside spans, inline Javascripts, inline styles and even [&#8230;]</p>
<p>The post <a href="https://michaelsoriano.com/sharepoint-bootstrap-using-spservices-and-jquery/">How to make a SharePoint List work with Bootstrap &#8211; using SPServices and jQuery</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>For those of you who have worked with SharePoint in the past, particularly with lists, CEWPs (<a href="https://support.office.com/en-ca/article/Content-Editor-Web-Part-c1350ff6-934c-4c2e-8e53-1ec3b548a0dc">Content Editor Web Part</a>) and front end code, then you probably know that these lists do not work well in mobile. The markup is just too messy &#8211; invalid tags, divs inside spans, inline Javascripts, inline styles and even tables! So it&#8217;s no surprise that making SharePoint work with Bootstrap is not an easy task.</p>
<h5>Note that this plugin will require the following files:</h5>
<ul>
<li>jquery.min.js</li>
<li>jquery.SPServices-2014.02.min.js</li>
<li>bootstrap.min.css</li>
</ul>
<p>In this post, I will show you how to use a Javascript plugin that I&#8217;ve written to basically recreate the markup of these SP lists so it works with Bootstrap / Mobile. It also has extra functionality like paging, filters, expand/collapse and other options. By the time we&#8217;re done, your list will look real good in desktop, tablet and mobile view:<br />
<a href="https://github.com/michaelsoriano/sp-bootstrap-list-viewer">View in Github</a></p>
<h3>How to use the Plugin:</h3>
<p>Note that I&#8217;ve only tested this with SharePoint 2013. You may need administrator rights to your website, as well as you should know how to work with custom lists and document libraries and such.<br />
After you have downloaded the files, open the &#8220;sp-bootstrap-list-viewer.html&#8221; in you text editor. This is where you will add the plugin information.<br />
You have to change the CHANGE-TO-YOUR-PATH in the JavaScript and CSS inclusion &#8211; to your downloaded path.<br />
Then, you add 2 things: the list name, the &#8220;Answer&#8221; column. The rest of the options are optional such as the &#8220;filterBy&#8221; and &#8220;rowLimit&#8221;. The table below will show you want the rest of the options do.<br />
<img decoding="async" class="alignnone size-full" src="https://michaelsoriano.com/wp-content/uploads/2015/07/sp-list3.jpg" alt="sp-list1" width="412" height="358" /><br />
Once you have edited the html file, upload it to a location in your SharePoint site, typically a document library. You will need to copy the location of the file.<br />
<img decoding="async" class="alignnone size-full" src="https://michaelsoriano.com/wp-content/uploads/2015/07/sp-list2.jpg" alt="sp-list1" width="412" height="358" /><br />
Let&#8217;s go ahead and add a CEWP into your SharePoint page. in the &#8220;Content Link&#8221; input, add the location of the html file you&#8217;ve just uploaded.<br />
<img decoding="async" class="alignnone size-full" src="https://michaelsoriano.com/wp-content/uploads/2015/07/sp-list1.jpg" alt="sp-list1" width="412" height="358" /><br />
Click &#8220;OK&#8221; and if everything is configured correctly, you should see the plugin do its thing:<br />
<img decoding="async" class="alignnone size-full wp-image-4447 noborder" src="https://michaelsoriano.com/wp-content/uploads/2015/07/sp-bootstrap-list-viewer.gif" alt="sp-bootstrap-list-viewer" width="787" height="520" /><br />
The table below contains the options for the plugin and an explanation of what they&#8217;re for:</p>
<table class="table table-bordered">
<thead>
<tr>
<th>Option name</th>
<th>Default Value</th>
<th>Required?</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">instance</th>
<td>Random Value</td>
<td>Yes</td>
<td>Used as the &#8220;Id&#8221; of your plugin</td>
</tr>
<tr>
<th scope="row">listName</th>
<td>none</td>
<td>Yes</td>
<td>Name of the SP list</td>
</tr>
<tr>
<th scope="row">question</th>
<td>Title</td>
<td>Yes</td>
<td>Title of the row</td>
</tr>
<tr>
<th scope="row">answer</th>
<td>none</td>
<td>Yes</td>
<td>Body of the row</td>
</tr>
<tr>
<th scope="row">filterBy</th>
<td>none</td>
<td>No</td>
<td>Category column to filter rows</td>
</tr>
<tr>
<th scope="row">rowLimit</th>
<td>5</td>
<td>No</td>
<td>Number of rows to show</td>
</tr>
</tbody>
</table>
<p>One thing to remember. If you plan to use the plugin multiple times in a page, you need to change the &#8220;instance&#8221; value to a random number prefixed with alphanumeric characters. You also need to make this the &#8220;Object&#8221; name of your html (where it says var <strong>spBL233565656</strong> = new spBootstrapList &#8230;). This will make the instances of your plugin unique in every page and will not clash with each other.</p>
<h3>Under the hood:</h3>
<p>For those of you who want to know more about how the plugin works, I will show you some of it&#8217;s main functionality. Note that this was originally built for a FAQ list for SharePoint, hence the FAQ names such as &#8220;Question&#8221; and &#8220;Answer&#8221;. Though the plugin will work with any kind of SP list.</p>
<h6>Requirements</h6>
<p>We will need some help with Mark Anderson&#8217;s <a href="https://github.com/sympmarc/SPServices">SPServices</a> &#8211; a jQuery plugin that basically does the web service calls for us. This allows us to work with the lists&#8217; data and convert it to our desired markup. Of course we will need <a href="http://getbootstrap.com/">Bootstrap </a>&#8211; which will take care of the responsive and overall styles, as well as <a href="https://jquery.com/">jQuery</a> for DOM manipulation.<br />
Notice the required scripts and styles. You can link to them externally or download them to a document library in SharePoint. Our constructor spBootstrapList() calls our Javascript class, passing along our required arguments. Again, the variable name &#8220;spBL233565656&#8221; and the value for &#8220;instance&#8221; has to be identical. This is for using it multiple of these in a single page.<br />
So going into the Javascript plugin: <strong>sp-bootstrap-list-viewer.js</strong>, you will see that on first load there&#8217;s a public method that gets called to set things up &#8220;init()&#8221;. This makes the initial call to the plugin &#8220;SPServices&#8221;. As I&#8217;ve mentioned, the plugin does the AJAX call to the SharePoint web service. It uses SOAP as its protocol so the request / response will be in XML format. Our init() method also checks for valid fields:</p>
<pre class="">var init = function(){
var ajax = methods.callSPServices(_settings.rowLimit, true);
$(ajax.responseXML).SPFilterNode("z:row").each(function(e) {
    var errors = Array();
    if(typeof $(this).attr('ows_' + _settings.question) == 'undefined'){
        errors.push("Invalid field name for Question: " + _settings.question);
    }
    if(typeof $(this).attr('ows_' + _settings.answer) == 'undefined'){
        errors.push("Invalid field name for Answer: " + _settings.answer);
    }
    if(_settings.filterBy !== '') {
        if(typeof $(this).attr('ows_' + _settings.filterBy) == 'undefined'){
            errors.push("Invalid field name for FilterBy: " + _settings.filterBy);
        }
    }
    _errors = errors;
    methods.parseResponse($(this));
});
</pre>
<p>Then we parse our response and we fill our internal object &#8220;_faqs&#8221;: Notice the SharePoint internal list names that start with &#8220;ows_&#8221; &#8211; these are how it comes out of the <a href="https://developers.google.com/doubleclick-publishers/docs/soap_xml">SOAP response</a>. We parse it to our own object with more meaningful keys and it&#8217;s values:</p>
<pre>parseResponse : function(resp){
    var record = {};
    record.question = resp.attr('ows_' + _settings.question);
    record.answer = resp.attr('ows_' + _settings.answer);
    record.created = resp.attr('ows_' + 'Created');
    if(_settings.filterBy !== ''){
        record.filterBy = resp.attr('ows_' + _settings.filterBy);
    }
    _faqs.push(record);
},
</pre>
<p>By the way, in order for us to make public methods from within our plugin is that we assign it to the &#8220;this&#8221; keyword. This way it becomes accessible from the outside. Here is an example of all the public methods of our plugin:</p>
<pre>this.paginate = paginate;
this.filter = filter;
this.showHideFilters = showHideFilters;
this.clearFilter = clearFilter;
this.showHideAnswer = showHideAnswer;
</pre>
<p>Continuing with our process, note that we need the &#8220;_faq&#8221; array to be filled for our next method to fire. This method is called <strong>methods.buildFaqs()</strong>, So we built another object called &#8220;methods&#8221; and inside this is a series of functions. This will be our &#8220;internal&#8221; methods.<br />
If you look at the buildFaqs() method, the code looks like below:</p>
<pre class="">buildFaqs : function(){
  var output = '';
  for(var i=0; i&lt;_faqs.length; i++){
    var hr = (i != (_faqs.length-1)) ? '</pre>
<p><em>[code above has been truncated &#8211; due to syntax highlighting error]</em><br />
So you see, we have our SharePoint list data in our array, and we build the HTML from it.</p>
<h6>Pagination</h6>
<p>Our pagination logic is quite interesting. We use the Bootstrap pagination HTML, and for each page, we need to do a <a href="http://www.w3schools.com/ajax/">AJAX</a> call in order to get the next page ID. This is how SharePoint determines where to offset the record when a query is made by using &#8220;<a href="https://social.msdn.microsoft.com/Forums/en-US/02663336-3185-498a-904f-86845106b624/getlistitems-with-jquery-using-listitemcollectionpositionnext-as-a-query-option?forum=sharepointdevelopmentprevious">ListItemCollectionPositionNext</a>&#8221; as a parameter.</p>
<pre>var buildPagination = function(){
  if(_errors.length &gt; 0) {
      $('#'+ _settings.instance+' .spBLPagerContainer').html('');
      console.log('Exiting buildPagination()');
      return false;
  }
  methods.getTotal(); //inside here we build filters
  if(parseInt(_totalRecords) &gt; parseInt(_settings.rowLimit)) { //yes paginate
      var pages = Math.ceil(_totalRecords / _settings.rowLimit);
      var positions = Array('');
      for (var i=0; i &lt; (pages - 1); i++) { //builds the values required 'ListItemCollectionPositionNext'
          var pos = '';
          if(i == 0){ //skips first to not pass pos
              positions.push(methods.getNextPos(pos));
          }else{
              var offset = i;
              positions.push(methods.getNextPos(positions[offset]));
          }
      }
  // console.log(positions);
  methods.buildPagination(positions);
  }else{ // no need to paginate
      $('#'+ _settings.instance+' .spBLPagerContainer').html('');
  }
}
</pre>
<p>We then proceed to build the actual markup with our internal method: methods.buildPagination():</p>
<pre class="">buildPagination : function(items){
  if(_firstLoad == false){
      $('#'+ _settings.instance+' .spBLPagerContainer').html(pager);
  }
  _positions = items;
  var pager = '</pre>
<p>&nbsp;<br />
<em>[code above has been truncated &#8211; due to syntax highlighting error]</em><br />
Each button has an inline &#8220;onclick&#8221; that calls our public &#8220;paginate()&#8221; method. Each of them also has the attribute &#8220;data-position&#8221; which holds the offset &#8220;ID&#8221; that we talked about:</p>
<pre>var paginate = function(clicked){
  if($(clicked).parents('li').hasClass('active') || $(clicked).parents('li').hasClass('disabled')){
      return false;
  }
  $('#'+ _settings.instance+' .pagination li').removeClass('active');
  var pos = $(clicked).attr('data-position') != '' ? $(clicked).attr('data-position') : '';
  if($(clicked).hasClass('NextButton')){
      $('#'+ _settings.instance+' a[data-position="'+pos+'"]').not('.NextButton').parents('li').addClass('active');
  }else if($(clicked).hasClass('PrevBtn')){
      $('#'+ _settings.instance+' a[data-position="'+pos+'"]').not('.PrevBtn').parents('li').addClass('active');
  }else{
      $(clicked).parents('li').addClass('active');
  }
  methods.updateNextPrevBtns(pos);
  methods.clearFaqs();
  var options = {
      CAMLViewFields: methods.fieldsToRead(true),
      CAMLQuery: methods.query(),
      CAMLRowLimit : _settings.rowLimit,
      CAMLQueryOptions: ""
  }
  var ajax = $().SPServices(methods.mergeSPCommon(options));
  $(ajax.responseXML).SPFilterNode("z:row").each(function(e) {
      methods.parseResponse($(this));
  });
  methods.buildFaqs();
}
</pre>
<p>You noticed too from the code above that we use SPServices on each click. That&#8217;s because we are only grabbing a predefined set of records &#8211; which is the limit that we pass into our plugin.</p>
<h6>Filters</h6>
<p>So the plugin supports filtering. This means that you can choose a field from your list and make that a &#8220;filter&#8221; column.<br />
First, assuming you&#8217;ve selected a valid field, we have to build it. Take a look at the code below:</p>
<pre>getFilterByValues : function(resp){
  var filterList = Array();
  var filterListUnique = Array();
  $(resp.responseXML).SPFilterNode("z:row").each(function(e) {
      var filterValue = $(this).attr('ows_' + _settings.filterBy);
          if(typeof filterValue !== 'undefined'){ //only add to array if theres a value
              filterList.push(filterValue);
          }
  });
  $.each(filterList,function(i,el){ //get rid of duplicates
      if($.inArray(el, filterListUnique) === -1){
          filterListUnique.push(el);
      }
  });
  _filterByListUnique = filterListUnique;
  _filterByList = filterList;
}
</pre>
<p>The above simply grabs the data. And since there are duplicate entries &#8211; we will have to make them unique and fill up our &#8220;_filterByListUnique&#8221; array. This is next:</p>
<pre class="">buildFilters : function(){
  var count = 0;
  var out = '';
  out +=</pre>
<p><em>[code above has been truncated &#8211; due to syntax highlighting error]</em><br />
The above builds out the checkboxes we need for our filtering capabilities. Now when each item is clicked, it triggers our filter() method:</p>
<pre>var filter = function(clicked){
  _firstLoad = false;
  _filterByValues = [];
  $('#'+ _settings.instance+'-filtersArray :checkbox:checked').each(function(e){
      _filterByValues.push($(this).val());
  })
  methods.filter();
}
</pre>
<p>Which actually calls our internal methods.filter() method:</p>
<pre>filter : function(){
  $('#'+ _settings.instance+'-filtersArray input').attr('disabled', 'disabled');
  $('#'+ _settings.instance+' .clearFilter').attr('disabled', 'disabled');
  methods.clearFaqs();
  var ajax = methods.callSPServices(_settings.rowLimit, true);
  $(ajax.responseXML).SPFilterNode("z:row").each(function(e) {
      methods.parseResponse($(this));
  });
  setTimeout(function(){
      methods.buildFaqs();
      buildPagination();
      $('#'+ _settings.instance+'-filtersArray input').removeAttr('disabled');
      $('#'+ _settings.instance+' .clearFilter').removeAttr('disabled');
  },10);
  if(_filterByValues.length &gt; 0){
      $('#'+ _settings.instance + ' .clearFilter').show();
  }else{
      $('#'+ _settings.instance + ' .clearFilter').hide();
  }
}
</pre>
<p>A lot going on here. You see that we make a new AJAX call through SPServices, passing our filter value. We parse the response, rebuild our items through &#8220;methods.buildFaqs()&#8221; and rebuild our pagination through buildPagination().<br />
There&#8217;s much more logic in the plugin such as the creating the <a href="https://msdn.microsoft.com/en-us/library/dd588092%28v=office.11%29.aspx">CAML</a> queries &#8211; but I decided not to go through them. If you&#8217;re well versed with .NET and SharePoint &#8211; you will be able to decipher these easy.</p>
<h3>Console Debugging</h3>
<p>Once you have the code in place &#8211; save and refresh your page. If by any reason some of the options are passed incorrectly, error handling is added and will be displayed in the HTML. You also need to turn on the console for more messages of what&#8217;s going on. I&#8217;ve added a couple of helpers that will get you information about your list such as getAllColumns(). This will display all of the fields that belong to the list you&#8217;re working with. Simply use the instance name + getAllColumns().</p>
<h3>Conclusion</h3>
<p>As you can see, we can make SharePoint internal lists work responsively. We may have to redo the markup entirely &#8211; but there are web services in place to grab the data. Thanks to open source code such as SPServices, jQuery and Bootstrap &#8211; our task becomes somewhat easier.<br />
Feel free to comment below.</p>
<p>The post <a href="https://michaelsoriano.com/sharepoint-bootstrap-using-spservices-and-jquery/">How to make a SharePoint List work with Bootstrap &#8211; using SPServices and jQuery</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://michaelsoriano.com/sharepoint-bootstrap-using-spservices-and-jquery/feed/</wfw:commentRss>
			<slash:comments>56</slash:comments>
		
		
			</item>
		<item>
		<title>Let&#8217;s Add Next and Previous Buttons to our Bootstrap Photo Gallery</title>
		<link>https://michaelsoriano.com/next-and-previous-buttons-bootstrap-photo-gallery/</link>
					<comments>https://michaelsoriano.com/next-and-previous-buttons-bootstrap-photo-gallery/#comments</comments>
		
		<dc:creator><![CDATA[Michael Soriano]]></dc:creator>
		<pubDate>Thu, 02 Jan 2014 07:07:55 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<category><![CDATA[jQuery]]></category>
		<guid isPermaLink="false">http://fearlessflyer.com/?p=3875</guid>

					<description><![CDATA[<p>Update 11/14/2015: This has been converted into a jQuery plugin so the code below may be different from the demo files. For more information on how to use the plugin, read the first section in the previous tutorial. In our previous tutorial, we learned how to create a photo gallery with Bootstrap. Our gallery looks [&#8230;]</p>
<p>The post <a href="https://michaelsoriano.com/next-and-previous-buttons-bootstrap-photo-gallery/">Let&#8217;s Add Next and Previous Buttons to our Bootstrap Photo Gallery</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><strong>Update 11/14/2015:</strong> This has been converted into a jQuery plugin so the code below may be different from the demo files. For more information on how to use the plugin, read the first section in the <a href="https://michaelsoriano.com/create-a-responsive-photo-gallery-with-bootstrap-framework/">previous</a> tutorial.</p>
<hr />
<p>In our previous <a title="Create a Responsive Photo Gallery with Bootstrap Framework" href="https://michaelsoriano.com/create-a-responsive-photo-gallery-with-bootstrap-framework/">tutorial</a>, we learned how to create a photo gallery with <a href="http://getbootstrap.com/">Bootstrap</a>. Our gallery looks nice and pretty, regardless of screen size. When an image is clicked, a modal box appears with a larger version of the image. If you haven&#8217;t done so, you might want to &#8220;<a title="Exploring the Bootstrap 3.0 Grid System" href="https://michaelsoriano.com/exploring-the-bootstrap-3-0-grid-system/">Explore Bootstrap&#8217;s Grid System</a>&#8221; first before getting your hands dirty.<br />
<a class="viewdemo" href="https://rawgit.com/michaelsoriano/bootstrap-photo-gallery/master/demo.html" rel="nofollow">View Demo</a><br />
<a class="" href="https://github.com/michaelsoriano/bootstrap-photo-gallery" target="_blank" rel="noopener">View in Github</a><br />
Now we&#8217;re going to add some control buttons right below the large image, so you can navigate through the gallery right in the modal window. Take a look at what we&#8217;re building in the image below.<br />
<a href="https://rawgit.com/michaelsoriano/bootstrap-photo-gallery/master/demo.html"><img decoding="async" class="alignnone size-full wp-image-3876" src="https://michaelsoriano.com/wp-content/uploads/2014/01/bootstrap-gallery-1.gif" alt="bootstrap-gallery-1" width="610" height="357" /></a><br />
I know that there are plenty of plugins that do this sort of thing. But I like doing things from scratch just to learn how things work. Ready to get started &#8211; let&#8217;s begin.</p>
<h3>Add HTML inside the &#8220;Click&#8221; Event</h3>
<p>We&#8217;re going to have to add our markup via Javascript. This is because the contents of our modal box doesn&#8217;t really exist yet when the page loads. In our last tutorial, we&#8217;re already have a click event where we&#8217;re building our large image. We simply need to append to this code. See below (in between where it says &#8220;Start of new code&#8221; and &#8220;End of new code&#8221;).</p>
<pre>
$('li img').on('click',function(){
  var src = $(this).attr('src');
  var img = '<img decoding="async" src="' + src + '" class="img-responsive"/>';
  //Start of new code
  var index = $(this).parent('li').index();
  var html = '';
  html += img;
  html += '<div style="height:25px;clear:both;display:block;">';
  html += '<a class="controls next" href="'+ (index+2) + '">next &raquo;</a>';
  html += '<a class="controls previous" href="' + (index) + '">&laquo; prev</a>';
  html += '</div>';
  //End of new code
  $('#myModal').modal();
  $('#myModal').on('shown.bs.modal', function(){
      $('#myModal .modal-body').html(html);
  })
  $('#myModal').on('hidden.bs.modal', function(){
      $('#myModal .modal-body').html('');
  });
 });
</pre>
<p><strong><u>Explanation:</u></strong> &#8211; this click event is inside the small image that was clicked. We just need to know which index it is from the list of images we have. We can achieve this by using jQuery&#8217;s <strong>.index()</strong> method. So we wrote:</p>
<pre>
var index = $(this).parent('li').index();
</pre>
<p>Meaning, we want the image that was clicked, traversing to it&#8217;s parent (list item) and grabbing it&#8217;s index. Then assigning it to a variable &#8220;index&#8221;. Note that our index is array based &#8211; so the first element is a zero.<br />
Next, we create the actual markup that we&#8217;re adding right in the modal box. You see we start with our image, then our div containing our next and previous links. You see how we consume the variable &#8220;index&#8221; that we created previously:</p>
<pre>
html += '<a class="controls next" href="'+ (index+2) + '">next &raquo;</a>';
html += '<a class="controls previous" href="' + (index) + '">&laquo; prev</a>';
</pre>
<p>Notice that our &#8220;Next&#8221; button has a &#8220;+2&#8221; for it&#8217;s &#8220;href&#8221; attribute. That&#8217;s because we want a number that is ahead of the current image that is showing, plus another because we started with zero &#8211; remember? Try out the new code by clicking on an image. As soon as our modal window pops up, you see our new previous and next buttons in place. But don&#8217;t click them yet &#8211; we haven&#8217;t written that part. <img decoding="async" class="alignnone size-full wp-image-3877" src="https://michaelsoriano.com/wp-content/uploads/2014/01/bootstrap-gallery-2.png" alt="bootstrap-gallery-2" width="593" height="389" /></p>
<h3>Create the logic when the buttons are clicked</h3>
<p>Now let&#8217;s take care of what happens when our buttons are clicked. Let&#8217;s think about what we need to achieve for a minute. First, we need to change the image &#8220;src&#8221; attribute of our large image to the next (or previous) image in the list. We already have our index so that shouldn&#8217;t be too hard. We also need to increment (or decrement) our index each time we click. Oh, we also have to hide the next button &#8211; once we get to the last image. The same behavior needs to happen to the previous button when we hit the first image. Add the code below right outside our document ready handler:</p>
<pre>
 $(document).on('click', 'a.controls', function(){
   //this is where we add our logic
   return false;
});
</pre>
<p>This just sets up our click handler for both previous and next buttons. Note that we have &#8220;.control&#8221; as a class to both links &#8211; so we only have to code once. Notice that we&#8217;re also binding the click event of our link to a parent element (in this case the document). This <a href="http://stackoverflow.com/questions/8614981/jquery-event-handler-on-not-working">binding technique</a> is used because our link is not present yet even when document is ready (reason why we wrote it outside of the .ready()).<br />
<strong><u>Replace the current image</u></strong><br />
Now let&#8217;s add this code inside our click handler:</p>
<pre>
var index = $(this).attr('href');
var src = $('ul.row li:nth-child('+ index +') img').attr('src');
$('.modal-body img').attr('src', src);
</pre>
<p><strong><u>Explanation:</u></strong> &#8211; first, we set up a variable called &#8220;index&#8221; (not the same as the index that we created previously as this is local to the anonymous function it&#8217;s in). This variable contains the number that is in the &#8220;href&#8221; of the link clicked. Variable &#8220;src&#8221; goes back to our un-ordered list, grabs the &#8220;nth-child&#8221; with the index as the number, grabs the image inside it and takes the &#8220;src&#8221; attribute.<br />
Finally, it assigns the &#8220;src&#8221; value and replaces the current image with it. <strong><u>Increment or Decrement the Link Counters</u></strong> At the same time, whenever our links are clicked, we&#8217;d want to change it&#8217;s &#8220;href&#8221; value. Add the code below:</p>
<pre>
var newPrevIndex = parseInt(index) - 1;
var newNextIndex = parseInt(newPrevIndex) + 2;
if($(this).hasClass('previous')){
    $(this).attr('href', newPrevIndex);
    $('a.next').attr('href', newNextIndex);
}else{
    $(this).attr('href', newNextIndex);
    $('a.previous').attr('href', newPrevIndex);
}
</pre>
<p><strong><u>Explanation:</u></strong> &#8211; Again, we create 2 new variables: &#8220;newPrevIndex&#8221; &#8211; which as a less than one value of the current index, and &#8220;newNextIndex&#8221; which has plus two. We then create an &#8220;if else&#8221; block. We check if the link clicked by checking it&#8217;s class, then we change both buttons &#8220;href&#8221; attributes accordingly.<br />
<strong><u>Hide links when last or first image is reached</u></strong><br />
Now we need to hide the &#8220;next&#8221; link when we reach the last image in the list and hide the &#8220;previous&#8221; when the first image is reached. We also need to re-show them when we go the opposite direction. Add the code below:</p>
<pre>
var total = $('ul.row li').length + 1;
//hide next button
if(total === newNextIndex){
    $('a.next').hide();
}else{
    $('a.next').show()
}
//hide previous button
if(newPrevIndex === 0){
    $('a.previous').hide();
}else{
    $('a.previous').show()
}
</pre>
<p><strong><u>Explanation:</u></strong> &#8211; this part is pretty simple. It simply takes the total number of list items in our gallery (var total), and makes that the basis of our comparisons. You will see the first &#8220;if&#8221; block checking if the total is the same as the new index. If it is, simply hide the &#8220;next&#8221; button, if not &#8211; show the link again. The next &#8220;if&#8221; block checks if our previous index is &#8220;0&#8221; (which is our first item), then hides and shows our &#8220;previous&#8221; link.<br />
<strong><u>What about if the last item IS clicked?</u></strong> Okay, the above code handles when the links are clicked &#8211; but what if the last OR the first item is clicked so the modal window has the first or last item. This will still have BOTH buttons in view right? In this case, we simply need to &#8220;trigger&#8221; the same click handler we just wrote above. We do this by adding the code below &#8211; right when we create the html in our modal window:</p>
<pre>
$('#myModal').on('shown.bs.modal', function(){
    $('#myModal .modal-body').html(html);
    //this will hide or show the right links:
    $('a.controls').trigger('click');
})
</pre>
<h3>Some CSS</h3>
<p>Finally, adding some styles to our links so it looks better. Note that I didn&#8217;t really spend a lot of time styling the links because this is pretty much open to your liking. Instead, I just wrote a couple of lines to make the links presentable:</p>
<pre>
.controls{
    width:50px;
    display:block;
    font-size:11px;
    padding-top:8px;
    font-weight:bold;
}
.next {
    float:right;
    text-align:right;
}
</pre>
<h3>Conclusion</h3>
<p>So now let&#8217;s see what we have: 1) a fully responsive photo gallery (Bootstrap powered), 2) a modal pop up when a thumbnail is clicked and 3) control buttons that navigate through the images once clicked. And we wrote all of this without a plugin! How cool is that! If you haven&#8217;t seen the demo, feel free to check it out <a href="https://rawgit.com/michaelsoriano/bootstrap-photo-gallery/master/demo.html" rel="nofollow">here</a>.</p>
<p>The post <a href="https://michaelsoriano.com/next-and-previous-buttons-bootstrap-photo-gallery/">Let&#8217;s Add Next and Previous Buttons to our Bootstrap Photo Gallery</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://michaelsoriano.com/next-and-previous-buttons-bootstrap-photo-gallery/feed/</wfw:commentRss>
			<slash:comments>66</slash:comments>
		
		
			</item>
		<item>
		<title>Create a Responsive Photo Gallery with this plugin and the Bootstrap Framework</title>
		<link>https://michaelsoriano.com/create-a-responsive-photo-gallery-with-bootstrap-framework/</link>
					<comments>https://michaelsoriano.com/create-a-responsive-photo-gallery-with-bootstrap-framework/#comments</comments>
		
		<dc:creator><![CDATA[Michael Soriano]]></dc:creator>
		<pubDate>Tue, 19 Nov 2013 04:45:05 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<category><![CDATA[grid]]></category>
		<guid isPermaLink="false">http://fearlessflyer.com/?p=3789</guid>

					<description><![CDATA[<p>This is the original page for bootstrap-photo-gallery plugin. It started out as a tutorial, then I converted it into a plugin. The README in Github is now the official documentation for the plugin &#8211; with a more detailed change log as well as instructions on how to use + options. This page is now simply [&#8230;]</p>
<p>The post <a href="https://michaelsoriano.com/create-a-responsive-photo-gallery-with-bootstrap-framework/">Create a Responsive Photo Gallery with this plugin and the Bootstrap Framework</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>This is the original page for <strong>bootstrap-photo-gallery</strong> plugin. It started out as a tutorial, then I converted it into a plugin. The README in Github is now the official documentation for the plugin &#8211; with a more detailed change log as well as instructions on how to use + options.</p>



<p>This page is now simply an archive of the original tutorial. Note that I&#8217;ve been having issues with my syntax highlighter (<em>for the code in tutorial</em>) &#8211; so the code in the steps may not show in its entirety.</p>



<p><a class="viewdemo" href="http://demo.michaelsoriano.com/bootstrap-gallery/master/demo.html" rel="nofollow">View Demo</a><br><a class="" href="https://github.com/michaelsoriano/bootstrap-photo-gallery" target="_blank" rel="noopener">View in Github</a></p>



<p><img decoding="async" width="920" height="669" class="alignnone size-full wp-image-6417" src="https://michaelsoriano.com/wp-content/uploads/2018/01/bs-gallery.gif" alt="bootstrap photo gallery"><br></p>



<p><strong>Update 1/7/2018: </strong> The plugin now uses Bootstrap 4 &#8211; which is entirely different from the previous version.<br><strong>Update 6/24/2016: </strong> Several enhancements have been made to the plugin. See the following list for the most recent changes:</p>



<p>1) The Modal box that opens is always going to be the large modal. Images will scale up to 100% to fill the entire modal box. You still have the option of having a small thumbnail and linking to a different image for the large size &#8211; mainly for performance purposes.</p>



<p>2) A new plugin option called &#8220;fullHeight&#8221; that allows you to have different heights in the thumbnails inside the grid. Most people want to see uniform heights, so I default this value to &#8220;true&#8221;. If you want to see dynamic heights, simply set this to &#8220;false&#8221;. Note that this doesn&#8217;t affect the modal images.</p>



<p>3) I&#8217;ve separated the styles into it&#8217;s own stylesheet. You now have to include this stylesheet in your document, or you can simply copy the contents into your own stylesheet. I tried making everything inline so you only have to include the JS file, but it&#8217;s been growing and having an external CSS is the only way to manage.</p>



<p>4) Added glyphicons for the &#8220;Next&#8221; and &#8220;Previous&#8221; links in the modal. This just looks better.</p>



<p><img decoding="async" width="750" height="466" class="alignnone size-full wp-image-5884" src="https://michaelsoriano.com/wp-content/uploads/2013/11/new-bsp-features.jpg" alt="" srcset="https://michaelsoriano.com/wp-content/uploads/2013/11/new-bsp-features.jpg 750w, https://michaelsoriano.com/wp-content/uploads/2013/11/new-bsp-features-300x186.jpg 300w" sizes="(max-width: 750px) 100vw, 750px" /></p>



<p>5) Images are required to have an alt tag, so I&#8217;m outputting the value of this into the modal as the title.</p>



<p>6) You can have additional text underneath the grid thumbnails by having a &#8220;p&#8221; tag with a class of &#8220;text&#8221;. I grab this value and put it in the modal as well.</p>



<p><strong>Update 12/13/2015: </strong> I&#8217;ve updated the plugin to support linking to a different image when shown in the modal box. Continue reading below for instructions.</p>



<p><strong>Update 11/14/2015: </strong>This code for this tutorial have been converted into a jQuery plugin. This means that it&#8217;s now easier to create a responsive photo gallery. The original tutorial is still available below (where is says &#8220;Original Tutorial&#8221;). Note that you don&#8217;t need to follow it if you&#8217;re using the plugin. But it&#8217;s good to know the inner workings of Bootstrap regardless.</p>



<h3 class="wp-block-heading">How to use the Plugin:</h3>



<p>Download the files from <a href="https://github.com/michaelsoriano/bootstrap-photo-gallery">Github</a>. Note that you will need to have jQuery and Bootstrap (CSS and JS) in your pages for the plugin to work effectively. It has been tested it with jQuery 1.10.2 and Bootstrap 3.3.5. Then add the plugin file (<strong>jquery.bsPhotoGallery.js</strong>) right below jQuery.</p>



<p>Please see README in Github for more details.</p>



<p>Then it&#8217;s time to initialize our plugin and pass in the options.</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">$(document).ready(function(){
  $('ul.first').bsPhotoGallery({
    "classes" : "col-lg-2 col-md-4 col-sm-3 col-xs-4 col-xxs-12",
    "hasModal" : true
  });
});</code></pre>



<p>Explanation: We are wrapping the code in a document.ready function so jQuery is available throughout. The selector $(ul.first) is the markup for our images, and .bsPhotoGallery is our plugin.</p>



<p>We need to pass in our Bootstrap classes into the &#8220;classes&#8221; argument so it&#8217;s important to know how the <a href="https://michaelsoriano.com/exploring-the-bootstrap-3-0-grid-system/">Bootstrap Grid system</a> works. And if you want to have a &#8220;modal box&#8221; appear with your image when clicked, you simply add the &#8220;<strong>hasModal</strong>&#8221; : true agrument.</p>



<h3 class="wp-block-heading">Benefits of using this Plugin</h3>



<p>By using this plugin, you don&#8217;t need to manually add the Bootstrap classes to each of the list item that you create. This just gets added dynamically as soon as the plugin kicks in. It also adds the Bootstrap helpers for clearing different heights of images OR if you have some kind of caption underneath (like the <a href="http://demo.michaelsoriano.com/bootstrap-gallery/master/demo.html">demo</a>)</p>



<p>Moreover, the plugin has the &#8220;modal&#8221; functionality which requires some Javascript to write anyway. So we might as well bundle them all up to one complete plugin.</p>



<h3 class="wp-block-heading">Linking to a different image in the Modal</h3>



<p>In a some cases you want to show an entirely different image when the modal box is shown. Simply add an extra attribute to the image called &#8220;<strong>data-bsp-large-src</strong>&#8220;, and the value being the path to the image desired.</p>



<p><strong>Below is the old tutorial</strong> &#8211; if you choose to follow it instead to using the plugin.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h3 class="wp-block-heading">The Original Tutorial Starts Here:</h3>



<p><strong>Remember:</strong> You don&#8217;t have to follow these steps if you&#8217;ve gone through the steps above in using the plugin. But if you want to build your own, then the tutorial below is good.</p>



<p>So you&#8217;ve been tasked with creating a photo gallery for you website. One that looks good on a desktop, a phone &#8211; even a tablet. One that has a grid of thumbnails, plus a modal functionality when the thumbnails are clicked.</p>



<p>This is part one of two series. Part two is where we add &#8220;previous&#8221; and &#8220;next&#8221; links to our modal box, click <a title="Let’s Add Next and Previous Buttons to our Bootstrap Photo Gallery" href="https://michaelsoriano.com/next-and-previous-buttons-bootstrap-photo-gallery/">here</a> to view it.</p>



<p>Well you&#8217;re in luck. Not only that we&#8217;ll show you how to code it &#8211; but we&#8217;ll show you using the most advanced front end framework yet! It&#8217;s called Bootstrap. For those of you living under a rock and have never heard of it &#8211; here&#8217;s a <a href="http://getbootstrap.com/">good start</a>.</p>



<p>Before we begin, make sure you read our <a href="https://michaelsoriano.com/exploring-the-bootstrap-3-0-grid-system/">in-depth look of Bootstrap&#8217;s grid system</a>. This will make you familiar of the classes we need to make the gallery. Also, if you haven&#8217;t seen the demo, below is a preview of what we&#8217;re building. See how the grid responds when we shrink the page?</p>



<p>So ready to start? Let&#8217;s code:</p>



<h3 class="wp-block-heading">Create the Markup</h3>



<p>Assuming that you&#8217;ve downloaded and linked to Bootstrap&#8217;s files, let&#8217;s create our .container div, along with an un-ordered list. Each list item will contain your images.</p>



<p>Save it and we should have something like below:</p>



<p><img decoding="async" width="650" height="628" class="alignnone noborder size-full wp-image-3791" src="https://michaelsoriano.com/wp-content/uploads/2013/11/tut1.jpg" alt="tut1"><br>Nothing magical here, just an un-ordered list of images with no styles. Now let&#8217;s apply the Bootstrap classes. First, add a &#8220;row&#8221; to the ul tag. Second, add classes &#8220;col-lg-2&#8221;, &#8220;col-md-2&#8221;, &#8220;col-sm-3&#8221; and &#8220;col-xs-4&#8221; to each list item.</p>



<p>Save and view it in the browser:</p>



<p><img decoding="async" width="650" height="310" class="alignnone size-full wp-image-3792" src="https://michaelsoriano.com/wp-content/uploads/2013/11/tut2.jpg" alt="tut2"></p>



<p>Believe it or not, we&#8217;re halfway done. Didn&#8217;t we say Bootstrap makes front end development faster? Try re-sizing your browser, and see how the thumbnails and the grid behave.</p>



<p><img decoding="async" width="630" height="350" class="alignnone size-full wp-image-3793" src="https://michaelsoriano.com/wp-content/uploads/2013/11/resp-photo-gallery2.gif" alt="resp-photo-gallery2"><br></p>



<pre class="wp-block-code"><code lang="css" class="language-css">ul {
  padding:0 0 0 0;
  margin:0 0 0 0;
}
ul li {
  list-style:none;
  margin-bottom:25px;
}
ul li img {
  cursor: pointer;
}</code></pre>



<p>Add a few CSS styles just to get rid of the list styles and unnecessary padding and margins.</p>



<h3 class="wp-block-heading">Different Heights for the Images</h3>



<p>In cases where you need to show images with different orientations, additional text or simply just different sizes. The grid naturally breaks with this pattern. To resolve this, basically you need to add an element that will clear the items. Bootstrap has a class for this called &#8220;clearfix&#8221;.</p>



<p>The element needs to be added where you want them to clear. For example, if you&#8217;re using &#8220;col-lg-2&#8221; (which means 6 columns), right after the 6th image, you add the element. </p>



<p>In addition, you have to add helper classes to only make them appear at certain viewports, such as &#8220;visible-lg-block&#8221;. So the element will have classes like below:</p>



<p><strong>&#8220;clearfix visible-lg-block&#8221;</strong><br></p>



<p>So if you look closely at our markup, there are list items that are inserted just for this purpose:</p>



<p><br><img decoding="async" width="650" height="349" class="alignnone size-full wp-image-5302" src="https://michaelsoriano.com/wp-content/uploads/2013/11/variable-height.jpg" alt="variable-height" srcset="https://michaelsoriano.com/wp-content/uploads/2013/11/variable-height.jpg 650w, https://michaelsoriano.com/wp-content/uploads/2013/11/variable-height-300x161.jpg 300w" sizes="(max-width: 650px) 100vw, 650px" /></p>



<p>This should solve the variable height issues with the grid. Now we&#8217;re ready to move on to the next part.</p>



<h3 class="wp-block-heading">Create the Light Box (Modal)</h3>



<p>So we want the large version of the image be shown in a lightbox as soon as we click on the thumbnail. Bootstrap&#8217;s got a pre-built Javascript Modal that makes this easy as well. Add the following to your markup:</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">&lt;div id="myModal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
&lt;div class="modal-dialog">&lt;!-- /.modal-content -->&lt;/div>
&lt;p>&lt;!-- /.modal-dialog -->&lt;/p>
&lt;/div></code></pre>



<p><br>The above code is what makes up the modal pop up box. Now let&#8217;s add some Javascript to make our images happen. Make sure you&#8217;ve linked to the Bootstrap.js file, as well as the jQuery library.</p>



<p>Then add a new set of script tags, plus the code below:</p>



<pre class="wp-block-code"><code lang="javascript" class="language-javascript">$(document).ready(function(){
   $('li img').on('click',function(){
        var src = $(this).attr('src');
        var img = '';
        $('#myModal').modal();
        $('#myModal').on('shown.bs.modal', function(){
            $('#myModal .modal-body').html(img);
        });
        $('#myModal').on('hidden.bs.modal', function(){
            $('#myModal .modal-body').html('');
        });
   });
})</code></pre>



<p>The above code simply calls the .modal() function as soon as we click a thumbnail. The contents of the modal box is grabbed from the 2 variables we created (src, img) which is the image tag and original src of the image clicked.</p>



<p>Now test your code by clicking on an image. To close the modal, click anywhere outside the popup.</p>



<p><img decoding="async" width="630" height="350" class="alignnone size-full wp-image-3794" src="https://michaelsoriano.com/wp-content/uploads/2013/11/resp-photo-gallery3.gif" alt="resp-photo-gallery3"><br>And guess what? I believe that&#8217;s it! It would be good to have a previous and next button on the large image so we can cycle through the images. Maybe even add a &#8220;swipe&#8221; functionality as well. </p>



<p>Let&#8217;s tackle that in <a title="Let’s Add Next and Previous Buttons to our Bootstrap Photo Gallery" href="https://michaelsoriano.com/next-and-previous-buttons-bootstrap-photo-gallery/">part two</a> of this session so stay tuned.</p>



<h3 class="wp-block-heading">Conclusion</h3>



<p>As you can see, we didn&#8217;t do much code at all to create our responsive photo gallery. Imagine all the steps we have to take if it weren&#8217;t for our amazing Bootstrap framework. Think of all the manual calculations, measurements, css code etc. Thank you Bootstrap!</p>



<p>Let us know what you think in the comments below. We will have a download for this project when we finish <a title="Let’s Add Next and Previous Buttons to our Bootstrap Photo Gallery" href="https://michaelsoriano.com/next-and-previous-buttons-bootstrap-photo-gallery/">part 2</a> of the series.</p>
<p>The post <a href="https://michaelsoriano.com/create-a-responsive-photo-gallery-with-bootstrap-framework/">Create a Responsive Photo Gallery with this plugin and the Bootstrap Framework</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://michaelsoriano.com/create-a-responsive-photo-gallery-with-bootstrap-framework/feed/</wfw:commentRss>
			<slash:comments>124</slash:comments>
		
		
			</item>
		<item>
		<title>Exploring the Bootstrap 3.0 Grid System</title>
		<link>https://michaelsoriano.com/exploring-the-bootstrap-3-0-grid-system/</link>
					<comments>https://michaelsoriano.com/exploring-the-bootstrap-3-0-grid-system/#comments</comments>
		
		<dc:creator><![CDATA[Michael Soriano]]></dc:creator>
		<pubDate>Thu, 14 Nov 2013 03:57:06 +0000</pubDate>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<category><![CDATA[frameworks]]></category>
		<category><![CDATA[grid]]></category>
		<category><![CDATA[Responsive Design]]></category>
		<guid isPermaLink="false">http://fearlessflyer.com/?p=3767</guid>

					<description><![CDATA[<p>Understanding what this framework can do for your next responsive site The idea of a grid system has been around since the 960.gs framework days. Web designers from all over the world began realizing the importance of pixel perfect alignment, gutter spacing and the rule of thirds. Gone are the days of grid-less web pages. [&#8230;]</p>
<p>The post <a href="https://michaelsoriano.com/exploring-the-bootstrap-3-0-grid-system/">Exploring the Bootstrap 3.0 Grid System</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Understanding what this framework can do for your next responsive site<br />
The idea of a grid system has been around since the <a href="http://960.gs/">960.gs</a> framework days. Web designers from all over the world began realizing the importance of pixel perfect alignment, gutter spacing and the rule of thirds. Gone are the days of grid-less web pages. And yes, things were great. Up until recently. <strong>Responsive web design</strong> was born.<br />
<img decoding="async" src="https://michaelsoriano.com/wp-content/uploads/2013/11/bstrap.jpg" alt="bstrap" width="600" height="392" class="alignnone size-full wp-image-3768" /><br />
The problem was 960.gs, along with older frameworks had static page widths. Since we are now designing for multiple screen sizes, web frameworks had to adapt quickly.<br />
Enter Zurb <a href="http://foundation.zurb.com/">Foundation</a>. The first responsive framework that had web designers pee in their pants. Big sites such as <a href="http://www.esquire.co.uk/">Esquire UK</a>, <a href="http://upmagazine-tap.com/">Up Magazine</a> and <a href="http://thenextweb.com/">The Next Web</a> redesigned and we kept resizing our browsers in awe. We were simply amazed on how elements of the pages shifted gracefully. Horizontal scrollbars were a thing of the past and modern web design became &#8211; well, more modern.<br />
Now we have the latest and the greatest Bootstrap 3. Despite their awesome <a href="http://getbootstrap.com/css/">documentation</a>, my focus is to elaborate on just the heart of the framework &#8211; the grid system.<br />
Let&#8217;s dive in and see what Bootstrap&#8217;s grid system is all about.</p>
<h3>The Basic .col-xx-xx Classes</h3>
<p>Bootstraps column classes are what makes up the individual columns of the grid. It&#8217;s main purpose is to align your components into &#8211; you guessed it, columns. They&#8217;re designed to have 3 sections:<br />
<img decoding="async" src="https://michaelsoriano.com/wp-content/uploads/2013/11/col-classes.jpg" alt="col-classes" width="557" height="223" class="noborder alignnone size-full wp-image-3769" /><br />
The prefix part &#8220;col&#8221; &#8211; just organizes all the col classes together, sort of like a namespace. And if you&#8217;ve worked with other frameworks in the past, the 3rd section &#8220;12&#8221; just tells us to occupy 12 columns out of the maximum 12. Pretty basic right?<br />
But what about the 2nd part? In our example, it&#8217;s the &#8220;lg&#8221;. This tells the browser to primarily use this for large screens only (default is 1170 pixels and above). Meaning, since we can use multiple classes on any element, <strong>we can <u>now</u> design for multiple sizes of the screen</strong>. Pretty powerful eh?<br />
<strong><u>So how does it do that?</u></strong><br />
So if you investigate the css, and look for that particular class (.col-lg-12), you will see that it&#8217;s enclosed in a media query:</p>
<pre>
@media (min-width: 1200px) {
.col-lg-12 {
    width: 100%;
  }
}
</pre>
<p>As a matter of fact, ALL of the &#8220;lg&#8221; classes are inside this media query. So the rule only applies to a specific screen resolution. The rest of the sizes (md for 970px, sm for 768px and xs for less than 768px) contains the rules for its respective classes. Pretty forward thinking right?<br />
<strong><u>Show me an example of its usefulness:</u></strong><br />
A common scenario is a two-column layout, with content on the left and sidebar on the right. With just a single class applied to both areas: red div has a class of <strong>col-lg-9</strong> and green div has <strong>col-lg-3</strong>.<br />
But most of the time &#8211; your sidebar&#8217;s content is not ready for a full page width in medium and small view ports. So you wish the sidebar doesn&#8217;t snap to the bottom right away right?<br />
<img decoding="async" src="https://michaelsoriano.com/wp-content/uploads/2013/11/example1.gif" alt="example1" width="650" height="384" class="alignnone size-full wp-image-3770" /><br />
<strong>The solution:</strong> apply multiple .col classes into the same divs (one for each of the view port sizes). Take a look at the next example &#8211; where we apply a different column number ONLY on the extra small (<strong>.col-xs-12</strong>).<br />
<img decoding="async" src="https://michaelsoriano.com/wp-content/uploads/2013/11/example2.gif" alt="example2" width="650" height="384" class="alignnone size-full wp-image-3771" /><br />
You see how the divs retained their 2 column layout all the way until the extra small view port is reached. Only then, did our sidebar snap to the bottom at full width. So you see how <strong>useful</strong> this is yet?</p>
<h3>Classes &#8220;row&#8221; and &#8220;container&#8221;</h3>
<p>Let&#8217;s jump out of the columns and look at the classes that wrap them. We have two important classes that do just that.<br />
<strong><u>.row</u></strong><br />
Just as the word describes &#8211; a row is something that is on one horizontal layer. Similar to a &#8220;record&#8221; in a database, or a &#8220;row&#8221; in a table. In Bootstrap, if you want elements to be in one horizontal layer &#8211; use a class <strong>.row</strong>.<br />
<img decoding="async" src="https://michaelsoriano.com/wp-content/uploads/2013/11/example3.gif" alt="example3" width="650" height="384" class="alignnone size-full wp-image-3772" /><br />
The dark grey divs both have a class &#8220;.row&#8221;. A <strong>row</strong> basically acts as a traditional div tag, but instead can be applied as a class. I&#8217;ve used class .row on a header or footer tag &#8211; and it works really well.<br />
<strong><u>.container</u></strong><br />
Ideally, you add your HTML elements that need to be grouped together inside a class .container. The &#8220;max-width&#8221; properties for each break point (the media queries) are defined in this class. It is a very important class. One that is required to make things work the way they do.<br />
According to Bootstrap&#8217;s docs, containers are:</p>
<blockquote><p>
Easily center a page&#8217;s contents by wrapping its contents in a .container. Containers set max-width at various media query breakpoints to match our grid system.
</p></blockquote>
<p>Containers also follow the default padding rule of 15 pixels on each side. So the contents are automatically flushed together with just the right amount of gutter space all the time.</p>
<h3>How does Nesting work?</h3>
<p>Nesting means adding more .col classes inside of existing .col classes. Most of the time, you would need to add a .row class first &#8211; before nesting your .col divs inside in order to see desired results.<br />
<strong>So when do you need to nest?</strong><br />
All the time! If you inspect most HTML documents &#8211; it&#8217;s already a series of nested DOM elements so nesting your .col classes is already expected behavior. Although in Bootstrap, nesting will save you a lot of work calculating and deciding how wide a column has to be.<br />
<img decoding="async" src="https://michaelsoriano.com/wp-content/uploads/2013/11/example4.gif" alt="example4" width="650" height="384" class="alignnone size-full wp-image-3773" /><br />
See both green divs have that have .col-lg-6 classes? These are nested inside the red div (the parent div).  Also, notice that a nested .col-lg-6 class takes up 50% of the parent div&#8217;s width. In other words, all you really need to remember is the 12 grid rule &#8211; no matter how deep the nesting goes.<br />
Note that I also applied the multiple classes technique (discussed above) to the child classes shown in the screenshot above. This is so that when resized, both div&#8217;s retain it&#8217;s 6 column width &#8211; until the last view port kicks in.</p>
<h3>Pushing, Pulling and Offsetting</h3>
<p>For even deeper customization of the grid elements, Bootstrap allows you to shift the columns around. Push and pull classes allow you to move the column # times to the left (also know as pull), or # times to the right (push).<br />
<img decoding="async" src="https://michaelsoriano.com/wp-content/uploads/2013/11/ordering.jpg" alt="ordering" width="475" height="228" class="noborder alignnone size-full wp-image-3775" /><br />
So consider the markup below. Even though the green div is written right above the red div, the push and pull classes allows us to order them as if they were otherwise.</p>
<pre>
<div class="col-md-4 col-md-push-4"><p>green pushed 4</p></div>
<div class="col-md-4 col-md-pull-4"><p>red pulled 4</p></div>
</pre>
<p>The code above makes it so the divs appear in the browser in a different order.<br />
<img decoding="async" src="https://michaelsoriano.com/wp-content/uploads/2013/11/push-pull.png" alt="push-pull" width="600" height="226" class="alignnone size-full wp-image-3776" /><br />
<strong><u>What makes it work?</u></strong><br />
If you inspect the push and pull classes, it utilizes the right and left property respectively &#8211; in percents. Since everything in Bootstrap is positioned relatively, using left and right will automatically just work.</p>
<pre>
@media (min-width: 992px)
   .col-md-pull-4 {
      right: 33.33333333333333%;
   }
   .col-md-push-4 {
      left: 33.33333333333333%;
   }
}
</pre>
<p><strong><u>Offsets</u></strong><br />
Offsetting classes is similar to push and pull classes &#8211; except for the &#8220;offset&#8221; keyword in the class name. Also similar to push and pull, the number in the class tells the browser how many columns to offset the element.<br />
<img decoding="async" src="https://michaelsoriano.com/wp-content/uploads/2013/11/offsetting.jpg" alt="offsetting" width="525" height="235" class="alignnone noborder size-full wp-image-3774" /><br />
The difference with offsetting is that it uses the margin left property. So if your element is right next to another element &#8211; it will simply push itself against it by the designated percentage. See the code below for a <strong>.col-md-offset-4</strong> class:</p>
<pre>
@media (min-width: 992px)
 .col-md-offset-4 {
    margin-left: 33.33333333333333%;
 }
</pre>
<p>You see how this can be useful? You can simply apply this class to whichever you want to offset and still retain the responsive margins effectively. Pretty good right?</p>
<h3>Visibility Classes</h3>
<p>Although this has nothing to do with the grid, I thought it is worth a mention. We&#8217;ve all worked with a system that has a default class for a &#8220;display:none&#8221;. Well not only does Bootstrap have this (it&#8217;s called .hidden), but they&#8217;ve taken it an extra step. I like to call them the &#8220;visibility&#8221; classes.<br />
These classes do just that &#8211; controls the visibility of elements &#8211; across multiple views. Now, when designing your web site, you just now have to pick which elements to show, hide in large, medium and small views &#8211; then simply apply the visibility classes. The table below (taken from Bootstrap&#8217;s website) explains what the classes do in specific view ports.</p>
<style>
.is-visible {
color: #468847;
background-color: #dff0d8 !important;
}
</style>
<table class="table table-bordered table-striped responsive-utilities" style="margin-top:35px; margin-bottom:45px;">
<thead>
<tr>
<th></th>
<th>
              Extra small devices<br />
              <small>Phones (&lt;768px)</small>
            </th>
<th>
              Small devices<br />
              <small>Tablets (≥768px)</small>
            </th>
<th class="hidden-xs">
              Medium devices<br />
              <small>Desktops (≥992px)</small>
            </th>
<th class="hidden-xs">
              Large devices<br />
              <small>Desktops (≥1200px)</small>
            </th>
</tr>
</thead>
<tbody>
<tr>
<th><code>.visible-xs</code></th>
<td class="is-visible">Visible</td>
<td class="is-hidden">Hidden</td>
<td class="is-hidden hidden-xs">Hidden</td>
<td class="is-hidden hidden-xs">Hidden</td>
</tr>
<tr>
<th><code>.visible-sm</code></th>
<td class="is-hidden">Hidden</td>
<td class="is-visible">Visible</td>
<td class="is-hidden hidden-xs">Hidden</td>
<td class="is-hidden hidden-xs">Hidden</td>
</tr>
<tr>
<th><code>.visible-md</code></th>
<td class="is-hidden">Hidden</td>
<td class="is-hidden">Hidden</td>
<td class="is-visible hidden-xs">Visible</td>
<td class="is-hidden hidden-xs">Hidden</td>
</tr>
<tr>
<th><code>.visible-lg</code></th>
<td class="is-hidden">Hidden</td>
<td class="is-hidden">Hidden</td>
<td class="is-hidden hidden-xs">Hidden</td>
<td class="is-visible hidden-xs">Visible</td>
</tr>
</tbody>
<tbody>
<tr>
<th><code>.hidden-xs</code></th>
<td class="is-hidden">Hidden</td>
<td class="is-visible">Visible</td>
<td class="is-visible hidden-xs">Visible</td>
<td class="is-visible hidden-xs">Visible</td>
</tr>
<tr>
<th><code>.hidden-sm</code></th>
<td class="is-visible">Visible</td>
<td class="is-hidden">Hidden</td>
<td class="is-visible hidden-xs">Visible</td>
<td class="is-visible hidden-xs">Visible</td>
</tr>
<tr>
<th><code>.hidden-md</code></th>
<td class="is-visible">Visible</td>
<td class="is-visible">Visible</td>
<td class="is-hidden hidden-xs">Hidden</td>
<td class="is-visible hidden-xs">Visible</td>
</tr>
<tr>
<th><code>.hidden-lg</code></th>
<td class="is-visible">Visible</td>
<td class="is-visible">Visible</td>
<td class="is-visible hidden-xs">Visible</td>
<td class="is-hidden hidden-xs">Hidden</td>
</tr>
</tbody>
</table>
<h3>Conclusion</h3>
<p>I believe we&#8217;ve looked at the core classes that will get you up and running with Bootstrap&#8217;s grid system. This alone, if used properly &#8211; will save you countless hours of development time. Don&#8217;t forget to read up on the rest of Bootstrap&#8217;s many features such as the built-in components, Javascript plugins and of course, the rest of the styles. Good luck and have fun coding!<br />
Last of all, I would like to keep this an open discussion. If there&#8217;s anything that you would like to add, please leave a comment. I will be more than happy to answer questions or append to the article.</p>
<p>The post <a href="https://michaelsoriano.com/exploring-the-bootstrap-3-0-grid-system/">Exploring the Bootstrap 3.0 Grid System</a> appeared first on <a href="https://michaelsoriano.com">Michael Soriano</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://michaelsoriano.com/exploring-the-bootstrap-3-0-grid-system/feed/</wfw:commentRss>
			<slash:comments>21</slash:comments>
		
		
			</item>
	</channel>
</rss>
