Learn

Share Your Knowledge!

This fast-growing section of our site is the new one-stop shop for educational materials for ExpressionEngine with rich and expert content, from both EllisLab and the community. Submit your article, tip, or solution today!

  • Easy Multi-device Local Development with xip.io

    12/30/2016 in: Tips

    You are building a site locally and you’d like to quickly check your work on your iPad, iPhone, another computer, or maybe a client’s laptop. You could pay for a dynamic DNS service, setup a DNS server on your local network, or setup a proxy server perhaps. But there’s an easier way. The key is a “magic domain” service, xip.io, which lets you give meaningful names to your local IP addresses.

    In this example, we will make my local https://awesomesite.dev available to others on my network, including my client’s iOS devices.

    How to do it

    I have my Apache VirtualHost and /etc/hosts file on my iMac configured to use https://awesomesite.dev/ for local development. I’ll add the special xip.io address as a ServerAlias, using the local IP address of my iMac (10.0.1.4):

    ServerName awesomesite.dev
    ServerAlias awesomesite.dev.10.0.1.4.xip.io
    DocumentRoot /Users/derek/Sites/AwesomeSite

    I’m keeping the awesomesite.dev. prefix so I can use this naming system with all my projects and make it clear which VirtualHost I’m accessing. If you’re using MAMP Pro, just go to your Hosts tab and click the + button under the “Aliases” box to add the xip.io address as an alias. Notice that xip.io addresses follow the simple pattern of your domain name, followed by your local IP address, followed by xip.io.

    Now to make sure that links and asset requests go to the right URLs, at the bottom of my config.php file in ExpressionEngine, I add the following:

    if (preg_match('/.*\.xip\.io$/', $_SERVER['HTTP_HOST']))
    {
    	$config['base_url'] = "http://{$_SERVER['HTTP_HOST']}/";
    }

    This block of code tells ExpressionEngine to use the xip.io address as the basis for URLs, but only if the request came from a .xip.io address. The preg_match() conditional validates the HTTP_HOST header for us in this case.

    Use the special {base_url} variable in all of your URL settings which keeps your site ultra-portable. If you do not, then you will need to override site_url, cp_url, theme_folder_url, and upload_preferences for each Upload Destination.

    Never use HTTP_HOST without validating it! It is a request variable, which means it can be faked, and you can’t trust it. If you use it without validation, you run the risk of a cache poisoning attack. That means an attacker could cause all generated links to point to their own servers for people who access your site after they do. If they copy your design, they have an effective phishing attack on your site’s visitors. Always validate the HTTP_HOST header before using it! If you’re using a multi-environment config, make sure yours does this! Exclamation mark!

    Violá

    Make sure to restart your web server after updating your VirtualHost, then anytime you want to pull up your local site on any device on your network, just key the xip.io address into the browser, in my case https://awesomesite.dev.10.0.1.4.xip.io. Then I can work on my iMac and check it instantly on my phone, iPad, or Macbook Air, or let a client spin it up on their device.

    There are many ways to do this; xip.io is just one of the easy and seamless options.

    | Read in 3 minutes
  • Template Routes for Single Entry / Permalink URLs

    12/10/2016 in: Tips, Tutorials, Templating

    Single entry permalink URLs are common on the web. We’re going to apply it to a blog here, as that’s readily understood, but the pattern will work for everything else as well.

    By default ExpressionEngine’s URLs work like this https://example.com/blog/entry/url-title, where “blog” is a template group, and “entry” is a template, which is fine. But nicer would be something like https://example.com/blog/url-title, cause who needs that extra entry segment anyway? You could handle all of this in the blog template group’s index, but that’s inelegant, full of conditionals, hard to read, and hard to maintain.

    Template Routes give us an easy to create and maintain implementation. What you’ll need is the following. A blog template group with the templates index and single-entry.

    Inside of index you’ll put your blog listing, this will cover paginated archives, and categorized listings as well—URLs like https://example.com/blog/P15 and https://example.com/blog/category/cat-url-title.

    Index might look something like this:

    {exp:channel:entries channel='blog' limit='25'}
    	<div class="blog-entry">
    		<h2><a href="{route='blog/single-entry' url_title='template-routes-for-single-entry-permalink-urls'}">{title}</a></h2>
    		<p>{entry_date format='%n/%j/%Y'}</p>
    		{if has_categories}
    			<p><b>in</b>: {categories backspace='2'}<a href="{path='blog'}" title="View more in {category_name}">{category_name}</a>, {/categories}</p>
    		{/if}
    		<p>by: {author}</p>
    	</div>
    
    	{if no_results}
    		{redirect='404'}
    	{/if}
    {/exp:channel:entries}

    See that route= variable above? It’ll come into play in a moment. Next you’ll need a single-entry template that will cover your, well, single entries. And will be reached with URLs like https://example.com/blog/url-title.

    Single Entry will look something like this:

    {exp:channel:entries channel='blog' limit='1' require_entry='yes'}
    	<h1>{title}</h1>
    	<p>{entry_date format='%n/%j/%Y'}</p>
    	{if has_categories}
    		<p><b>in</b>: {categories backspace='2'}<a href="{path='blog'}" title="View more in {category_name}">{category_name}</a>, {/categories}</p>
    	{/if}
    	<p>by: {author}</p>
    
    	{blog_content}
    
    	{if no_results}
    		{redirect='404'}
    	{/if}
    {/exp:channel:entries}

    Now that you have those set up, you need to add your route. Go to Developer > Template Manager > Template Routes and set up a route for the template single-entry Give it a Route of /blog/{url_title:regex[(((?!(P\d+|category\/)).)+?)]} select “no” for “Segments Required?” then save. The regex may look a little complex, so let’s break it down. (((?!(P\d+|category\/)).)+?) uses a negative lookahead assertion, so the route does not match if the second URL segment is either pagination (P\d+) or category/. We want those URL patterns to still use the ExpressionEngine default routing to the blog/index template.

    Now in your templates replace any path variables to your single-entry URLs to use the route= variable in the first code sample. This will make sure that when clicked the visitor is sent to the right place!

    That’s it! Now go forth and clean up your ExpressionEngine URLs today!

    | Read in 3 minutes
  • Image Grid

    12/10/2016 in: Front-end Development, Tips

    Here’s a quick tip for creating a equal sized image grid in HTML and CSS. There are two legit ways to accomplish this pattern, and both ways use the same HTML. I’ve limited the output to eight items for example purposes, but this technique will theoretically work for infinity items.

    <div class="collection">
    	<ul class="img-grid">
    		<li>
    			<figure>
    				<img src="https://expressionengine.com/asset/img/learn/example.png">
    			</figure>
    		</li>
    		<li>
    			<figure>
    				<img src="https://expressionengine.com/asset/img/learn/example.png">
    			</figure>
    		</li>
    		<li>
    			<figure>
    				<img src="https://expressionengine.com/asset/img/learn/example.png">
    			</figure>
    		</li>
    		<li>
    			<figure>
    				<img src="https://expressionengine.com/asset/img/learn/example.png">
    			</figure>
    		</li>
    		<li>
    			<figure>
    				<img src="https://expressionengine.com/asset/img/learn/example.png">
    			</figure>
    		</li>
    		<li>
    			<figure>
    				<img src="https://expressionengine.com/asset/img/learn/example.png">
    			</figure>
    		</li>
    		<li>
    			<figure>
    				<img src="https://expressionengine.com/asset/img/learn/example.png">
    			</figure>
    		</li>
    		<li>
    			<figure>
    				<img src="https://expressionengine.com/asset/img/learn/example.png">
    			</figure>
    		</li>
    	</ul>
    </div>

    I’ve used a div.collection as a wrapper which is unnecessary for this example, but is a good practice. Allowing you to have multiple grids in a single HTML document that can be targeted individually.

    I’m a big proponent of ITCSS, and an object oriented approach to CSS. Here is the object LESS for this grid.

    .img-grid{
    	list-style-type: none;
    	margin: 0;
    
    		li{
    			margin-bottom: 20px;
    		}
    
    		figure{
    			margin: 0;
    
    				img{
    					max-width: 100%;
    				}
    		}
    }
    
    // responsibility
    @media screen and (min-width: 414px){
    	.img-grid{
    		margin: 0 -10px;
    		overflow: hidden;
    
    			li{
    				box-sizing: border-box;
    				float: left;
    				padding: 0 10px;
    				width: 50%;
    			}
    	}
    }
    
    @media screen and (min-width: 750px){
    	.img-grid{
    		li{
    			width: 33.33%;
    		}
    	}
    }
    
    @media screen and (min-width: 1200px){
    	.img-grid{
    		li{
    			width: 25%;
    		}
    	}
    }

    This gives us a single column stack, that expands to two columns, then three and finally four columns at max width. You can adjust the math to work however you like, but I’ve found this to be pretty universally useful, and visually pleasing at all breakpoints.

    You can demo and play with this code here: https://jsfiddle.net/jmathias/6kbjw0ft/

    But this is old school code I hear you cry! Well, sure, I suppose. If you prefer cutting edge you can accomplish the same exact grid with this flex-box code instead.

    .img-grid-flex{
    	display: flex;
    	flex-wrap: wrap;
    	list-style-type: none;
    	margin: 0;
    
    		li{
    			box-sizing: border-box;
    			// grow shrink basis
    			flex: 0 1 100%;
    			// allows incomplete rows to grow as needed.
    			// flex: 1 0 100%;
    			margin-bottom: 20px;
    		}
    
    		figure{
    			margin: 0;
    
    				img{
    					max-width: 100%;
    				}
    		}
    }
    
    // responsibility
    @media screen and (min-width: 414px){
    	.img-grid-flex{
    		margin: 0 -10px;
    
    			li{
    				flex-basis: 50%;
    				padding: 0 10px;
    			}
    	}
    }
    
    @media screen and (min-width: 750px){
    	.img-grid-flex{
    		li{
    			flex-basis: 33.33%;
    		}
    	}
    }
    
    @media screen and (min-width: 1200px){
    	.img-grid-flex{
    		li{
    			flex-basis: 25%;
    		}
    	}
    }

    As you can see the code isn’t much different, just another way to accomplish it. The upside of display: flex is that you don’t need to use floats, or float clearing methods. Additionally, you can have flex box do the math for you and display incomplete rows with larger images. You just need to change flex: 0 1 100%; to flex: 1 0 100%;.

    You can demo and play with this code here: https://jsfiddle.net/jmathias/ox70d053/

    So there you have it. A nice simple Image grid you can use on your ExpressionEngine CMS site today!

    | Read in 3 minutes
  • DRY Pagination

    12/10/2016 in: Tips, Templating

    If you want quick, easy to maintain, and consistent pagination across your site or application, DRY (Don’t Repeat Yourself) is a great way to accomplish this. in ExpressionEngine you can create DRY pagination in a few simple steps.

    First you’ll need a Template Partial. I like to name this par-paginate-links.

    {paginate}
    	{pagination_links page_padding='1'}
    		<div class="pagination">
    			<ul>
    				{first_page}
    					<li class="pg-first"><a href="{pagination_url}"><span>first</span></a></li>
    				{/first_page}
    				{previous_page}
    					<li class="pg-prev"><a href="{pagination_url}"><span>prev</span></a></li>
    				{/previous_page}
    				{page}
    					<li><a href="{pagination_url}"{if current_page} class="act"{/if}>{pagination_page_number}</a></li>
    				{/page}
    				{next_page}
    					<li class="pg-next"><a href="{pagination_url}"><span>next</span></a></li>
    				{/next_page}
    				{last_page}
    					<li class="pg-last"><a href="{pagination_url}"><span>last</span></a></li>
    				{/last_page}
    			</ul>
    		</div>
    	{/pagination_links}
    {/paginate}

    This partial covers paginated links, you can adjust the output to your personal needs, but this is your basic “first, previous, 1, 2, 3, next, last” pattern.

    Now that you have this, all you need to do is call it into the exp:channel:entries tags you want to paginate.

    Something like this,

    {exp:channel:entries channel='blog' limit='10'}
    	HTML Output...
    	{if no_results}
    		{redirect='404'}
    	{/if}
    	{par-paginate-links}
    {/exp:channel:entries}

    And there you have, a clean, fast and simple way to make your websites more maintainable with ExpressionEngine.

    | Read in 2 minutes
  • Responsive Videos

    12/10/2016 in: Front-end Development, Tips

    We all LOVE videos! But they can be a real difficult thing to do responsively. So here is some code to help you make videos responsive in your next ExpressionEngine CMS site.

    The HTML

    <figure class="video">
    	<div class="video-player">
    		<iframe src="//player.vimeo.com/video/39394380?color=f0a400" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
    	</div>
    	<figcaption><a href="http://leihu.com">James Mathias</a> &mdash; Made By Few</figcaption>
    </figure>

    I use a figure, so that I can add a caption, the important part is the div.video-player around the iframe. Here I use a class of .video on the figure as a best practice for potential CSS targeting.

    Speaking of CSS, here is the LESS object.

    .video-player{
    	height: 0;
    	overflow: hidden;
    	padding-bottom: 56.25%; /* 16/9 ratio */
    	padding-top: 30px; /* IE6 workaround */
    	position: relative;
    
    		// set dimensions and position of elements inside .video-player
    		embed, iframe, img, object, video{
    			height: 100%;
    			left: 0;
    			position: absolute;
    			top: 0;
    			width: 100%;
    		}
    }

    That’s all you need. Remember don’t put a width or height attribute on the iframe, the browser will do this math for you!

    You can demo and play with this code here: https://jsfiddle.net/jmathias/g7mwrmxw/

    Now go fill your ExpressionEngine CMS sites with videos, to the brim!

    | Read in 1 minute

ExpressionEngine News

#eecms, #events, #releases