<?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>WP Theming</title> <atom:link href="http://wptheming.com/feed/" rel="self" type="application/rss+xml" /><link>http://wptheming.com</link> <description>Tutorials, Themes and Plugins</description> <lastBuildDate>Wed, 16 May 2012 15:18:49 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.2</generator> <item><title>Add Infinite Scroll to a WordPress Theme</title><link>http://wptheming.com/2012/03/infinite-scroll-to-wordpress-theme/</link> <comments>http://wptheming.com/2012/03/infinite-scroll-to-wordpress-theme/#comments</comments> <pubDate>Wed, 28 Mar 2012 05:43:01 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[Tutorials]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=2349</guid> <description><![CDATA[Infinite Scroll is a popular way to dynamically load fresh content into a site as a user scrolls down through it. It&#8217;s also quite easy to code into a WordPress theme. Here&#8217;s a quick walkthrough of how to do it: Get the Script Assets Download a copy of &#8220;jquery.infinitescroll.min.js&#8221; from the GitHub repository, and drop [...]]]></description> <content:encoded><![CDATA[<p>Infinite Scroll is a popular way to dynamically load fresh content into a site as a user scrolls down through it.  It&#8217;s also quite easy to code into a WordPress theme.  Here&#8217;s a quick walkthrough of how to do it:<br
/> <span
id="more-2349"></span></p><h3>Get the Script Assets</h3><p>Download a copy of &#8220;<a
href="https://github.com/paulirish/infinite-scroll/blob/master/jquery.infinitescroll.min.js">jquery.infinitescroll.min.js</a>&#8221; from the <a
href="https://github.com/paulirish/infinite-scroll">GitHub repository</a>, and drop it into the &#8220;scripts&#8221; or &#8220;js&#8221; folder of your WordPress theme.</p><p>Pick out the <a
href="http://ajaxload.info/">ajax-loader.gif</a> of your choice, and add it to your theme &#8220;images&#8221; folder.</p><h3>Enqueue the Script</h3><p>You&#8217;ll need to register and enqueue the required script in functions.php:</p><pre class="brush: php; title: ; notranslate">
/**
 * Load javascripts used by the theme
 */
function custom_theme_js(){
	wp_register_script( 'infinite_scroll',  get_template_directory_uri() . '/js/jquery.infinitescroll.min.js', array('jquery'),null,true );
	if( ! is_singular() ) {
		wp_enqueue_script('infinite_scroll');
	}
}
add_action('wp_enqueue_scripts', 'custom_theme_js');
</pre><h3>Init the Script</h3><p>In the code snippet below I list the parameters I used in my theme.  You&#8217;ll likely need to customize these in order to match your theme markup:</p><ul><li>img: The path to the ajax loader image</li><li>nextSelector: Selector for the &#8220;previous posts&#8221; link.</li><li>navSelector:  Containing selector for the previous/next navigation links.</li><li>itemSelector:  Selector for posts.  This might be .hentry, .post, .etc</li><li>contentSelector:  Containing div for your posts.</li></ul><pre class="brush: php; title: ; notranslate">
/**
 * Infinite Scroll
 */
function custom_infinite_scroll_js() {
	if( ! is_singular() ) { ?&gt;
	&lt;script&gt;
	var infinite_scroll = {
		loading: {
			img: &quot;&lt;?php echo get_template_directory_uri(); ?&gt;/images/ajax-loader.gif&quot;,
			msgText: &quot;&lt;?php _e( 'Loading the next set of posts...', 'custom' ); ?&gt;&quot;,
			finishedMsg: &quot;&lt;?php _e( 'All posts loaded.', 'custom' ); ?&gt;&quot;
		},
		&quot;nextSelector&quot;:&quot;#nav-below .nav-previous a&quot;,
		&quot;navSelector&quot;:&quot;#nav-below&quot;,
		&quot;itemSelector&quot;:&quot;article&quot;,
		&quot;contentSelector&quot;:&quot;#content&quot;
	};
	jQuery( infinite_scroll.contentSelector ).infinitescroll( infinite_scroll );
	&lt;/script&gt;
	&lt;?php
	}
}
add_action( 'wp_footer', 'custom_infinite_scroll_js',100 );
</pre><p>Note: Also make sure to update &#8220;custom&#8221; to your own textdomain for translations.</p><h3>Try it out</h3><p>If you load a category or home page the site should now be infinite scrolling.  If not, check the web developer console to see if a script didn&#8217;t load or if there&#8217;s a javascript error.  Also, double check that you&#8217;re selectors listed above are all correct.</p><p>If you scroll to the very end of your site and start to get 404 errors, you may need to add this little patch (which looks liked it&#8217;s already fixed in WordPress 3.4, props @benbalter):</p><pre class="brush: php; title: ; notranslate">
/**
 * If we go beyond the last page and request a page that doesn't exist,
 * force WordPress to return a 404.
 * See http://core.trac.wordpress.org/ticket/15770
 */
function custom_paged_404_fix( ) {
	global $wp_query;
	if ( is_404() || !is_paged() || 0 != count( $wp_query-&gt;posts ) )
		return;
	$wp_query-&gt;set_404();
	status_header( 404 );
	nocache_headers();
}
add_action( 'wp', 'custom_paged_404_fix' );
</pre><h3>Possible Issues</h3><p>If you&#8217;re releasing a theme for other people to use, definitely include an option to <strong>turn off</strong> infinite scroll.  It won&#8217;t work for everyone- especially if they have plugins that add social buttons or render additional javascript in the post content.</p><p>I wrote a little more about some of those issues <a
href="http://wptheming.com/2012/03/infinite-scroll-in-wordpress/">in this post</a></p> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2012/03/infinite-scroll-to-wordpress-theme/feed/</wfw:commentRss> <slash:comments>19</slash:comments> </item> <item><title>Infinite Scroll in WordPress</title><link>http://wptheming.com/2012/03/infinite-scroll-in-wordpress/</link> <comments>http://wptheming.com/2012/03/infinite-scroll-in-wordpress/#comments</comments> <pubDate>Tue, 27 Mar 2012 03:02:51 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[Miscellaneous]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=2346</guid> <description><![CDATA[Infinite scroll has become a standard feature in many web applications. Twitter and Facebook are the ones I use every day, but it&#8217;s also in a ton of Tumblr themes and Cargo Collective sites. I feel WordPress themes has been slow to adopt infinite scroll- but after adding it to my site over the weekend [...]]]></description> <content:encoded><![CDATA[<p>Infinite scroll has become a standard feature in many web applications.  Twitter and Facebook are the ones I use every day, but it&#8217;s also in a ton of Tumblr themes and Cargo Collective sites.</p><p>I feel WordPress themes has been slow to adopt infinite scroll- but after adding it to <a
href="http://wptheming.com/">my site</a> over the weekend I understand some of the complications.</p><p><a
href="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2012/03/4998853192_4323105758_z.jpg"><img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2012/03/4998853192_4323105758_z-590x320.jpg" alt="" title="Infinity Pool" width="590" height="320" class="size-large wp-image-2375" /></a></p><p
style="font-size:11px;">(The Infinity Pool comes close, but it&#8217;s not as cool cousin, Infinite Scroll. <a
href="http://www.flickr.com/photos/cawood/4998853192/sizes/z/in/photostream/">CC Image</a>. )</p><p>Unlike Tumblr or Cargo Collective, WordPress (.org) users can use plugins to add all sorts of javascript to posts.  On my site Syntax Highlighting is the main culprit (which I use to display code snippets), but many others have social buttons or lightboxed images.</p><p>When infinite scroll pulls in additional posts via ajax, it doesn&#8217;t load the javascript code from the header or footer of the post that might be needed to display js content (e.g. social buttons, formatted code, etc) properly. That puts theme authors in a bind.  Infinite scroll may be a better end user experience, but it&#8217;s going to lead to more support requests during theme set up.</p><p>However, if you don&#8217;t use much javascript in your post content, or if you display excerpts on your index pages rather than full posts, I&#8217;d suggest trying it out.</p><p><a
href="http://ben.balter.com/">Ben Balter</a> made a fork of the popular Infinite-Scroll plugin which is excellent.  It&#8217;ll <a
href="https://github.com/paulirish/infinite-scroll/pull/141">hopefully get merged</a> into the .org plugin version soon (which I can&#8217;t recommend using in its current state).  If you use <a
href="https://github.com/benbalter/Infinite-Scroll/tree/develop">Ben&#8217;s version</a> of the plugin you should be able to set up infinite scroll for your theme in just a couple minutes.  You can also see it <a
href="http://ben.balter.com/">in action on his site</a>.</p><p>I&#8217;ll also <a
href="http://wptheming.com/2012/03/infinite-scroll-to-wordpress-theme/">posted a tutorial</a> about how to add Infinite Scroll to a theme without a plugin.</p><h3>Useful Links:</h3><ul><li><a
href="http://uxmovement.com/navigation/infinite-scrolling-best-practices/">Infinite Scrolling Best Practices (UX)</a></li><li><a
href="http://www.takadesigns.com/blog/2010/11/29/should-you-use-infinite-scroll-instead-of-pagination-to-load-more-content/">Should You Use Infinite Scroll Instead of Pagination?</a></li><li><a
href="https://github.com/paulirish/infinite-scroll">https://github.com/paulirish/infinite-scroll</a></li></ul> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2012/03/infinite-scroll-in-wordpress/feed/</wfw:commentRss> <slash:comments>2</slash:comments> </item> <item><title>WP Engine Hosting Review</title><link>http://wptheming.com/2012/02/wp-engine-review/</link> <comments>http://wptheming.com/2012/02/wp-engine-review/#comments</comments> <pubDate>Wed, 29 Feb 2012 14:18:31 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[Miscellaneous]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=2302</guid> <description><![CDATA[I've hosted most of my sites with BlueHost for over six years, but I recently migrated this one over to WP Engine.  Mainly I was curious to see what the impact on page speed would be.  As WP Theming has grown in traffic so have the load times– despite good caching, gzipped files, minified scripts and css, and sprited images.]]></description> <content:encoded><![CDATA[<p>I&#8217;ve hosted most of my sites with BlueHost the last six years, but I recently migrated this one over to <a
href="http://wpengine.com/?a_aid=4f6fa618a4f7b">WP Engine</a>.  I was mainly curious to see what the impact on page speed would be.  As <a
href="http://wptheming.com">WP Theming</a> has grown in traffic so have load times– despite good caching, gzipped files, minified scripts and css, and sprited images.</p><h3>Page Speed</h3><p>The home page of the site had a page speed score of 96% before the migration and roughly 81% after.  No theme code changed and the only plugin removal was <a
href="http://wpengine.com/2011/12/no-caching-plugins/">W3 Total Cache</a>.  However, load times improved significantly (as measured by Google):</p><p><img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2012/02/pagespeed.png" alt="This Google Page Speed graph shows that page speeds were 1.47 seconds faster after the migration, which is 25% improvement." width="885" height="391" class="alignnone size-full wp-image-2303" /></p><p>You&#8217;ll notice average page speed is 1.47 seconds <em>faster</em>, which is a significant 25% improvement.  I&#8217;d venture to guess the numbers might be even more impressive for someone who had not already worked to optimize load times.<br
/> <span
id="more-2302"></span></p><h3>Support</h3><p>I&#8217;ve opened about six support tickets since migrating to WP Engine.  All of them got an initial response within 24 hours, and sometimes within minutes.  A few were for items I hope WP Engine automates in the future- such as enabling the CDN and the initial transfer of DNS.  Others were for plugin issues, a broken menu link, and support for the staging environment.  All were resolved fairly quick.</p><p>One major benefit of being with a WordPress dedicated host is that the support team can answer really specific WordPress questions.  I&#8217;ve also met a several of them, and they&#8217;re all super helpful and knowledgeable folks.</p><h3>WP Engine Drawbacks</h3><p>Before you jump ship with your current shared host, there are a couple items to consider.</p><p><b>Cost:</b> WP Engine hosting plans start at $29/mo compared to around $8/mo with a company like <a
href="http://bluehost.com">BlueHost</a> or <a
href="http://hostgator.com">HostGator</a>.  If you have higher traffic levels, you might need the $99/mo plan, compared with around $45/mo for a VPS with a company like <a
href="http://www.inmotionhosting.com/">InMotion</a> and <a
href="http://mediatemple.com/">MediaTemple</a>.</p><p><b>Lots of Sites?</b> If you have a large number of low traffic sites, you&#8217;ll likely want to keep them somewhere that doesn&#8217;t change on a per site basis.  Even though I migrated wptheming.com, I kept my hosting package with BlueHost for other domains- including a multisite install that runs off a subdomain of wptheming.com.</p><p><b>E-mail:</b> WP Engine does not provide email as part of the hosting package, so you&#8217;ll need to use something like <a
href="http://www.google.com/apps/intl/en/business/index.html">Google Apps</a>, which is another couple bucks a month if you don&#8217;t have it already.</p><h3>WP Engine Benefits</h3><p><b>Daily Backups:</b> It&#8217;s amazing how many people don&#8217;t have any backup system for their sites, so it&#8217;s great that WP Engine built this in and made it automatic.  You can and should set up backups on other hosts (of course), but it generally involves a little technical know-how or buying a plugin like <a
href="http://pluginbuddy.com/purchase/backupbuddy/">Backup Buddy</a> or service like <a
href="http://vaultpress.com/">VaultPress</a> (<a
href="#comments">comment</a> if you&#8217;ve found a free and easy way to do it).</p><p><b>Staging Environment:</b> Anyone who develops WordPress sites knows the pain of setting up a staging environment to test new code.  WP Engine has made this fun.  You simply press a button and an exact duplicate of your site is synced to a development environment.</p><p><b>Speed:</b> Site speed can have a huge impact on <a
href="http://blog.kissmetrics.com/loading-time/?wide=1">user experience, pageviews, revenue</a>- so you should be thinking about it.  Google also uses <a
href="http://googlewebmastercentral.blogspot.com/2010/04/using-site-speed-in-web-search-ranking.html">speed as a ranking factor</a> in search results.</p><h3>Verdict</h3><p>If you currently have several sites in the same account, it&#8217;s a lot cheaper to keep those all on a shared host or general VPS.  If one takes off, you can always move it later- like I&#8217;ve done with WP Theming.</p><p>If you run a single install of WordPress with <em>medium to high</em> traffic, WP Engine would probably be a good fit- especially if earn revenue from the site and can afford to pay a bit more for hosting.</p><p>If you run a single install of WordPress with <em>low</em> traffic, WP Engine might still might be a good choice for the convenience of automatic backups, regular security scans, and a knowledgeable support staff.  However, the extra cost won&#8217;t make it worth it for everyone.</p><p>If you have a super high traffic site, you might also want to <a
href="http://www.kalzumeus.com/2012/02/09/why-i-dont-host-my-own-blog-anymore/">read this review</a>.</p><p><b>Disclosure:</b> WP Engine sponsors quite a few WordCamps and WordPress events and they&#8217;ve been offering free hosting to attendees.  My account is one of these complimentary hosting packages.  WP Engine links are affiliate.</p><p><b>Read More</b>: <a
href="http://wpengine.com/?a_aid=4f6fa618a4f7b">WP Engine Website</a></p><h3>Related Reading</h3><ul><li><a
href="http://www.scirra.com/blog/74/making-a-fast-website">Making a Fast Website</a></li><li><a
href="http://www.nytimes.com/2012/03/01/technology/impatient-web-users-flee-slow-loading-sites.html">Impatient Web Users Flee Slow-Loading Sites</a> (NY Times)</li></ul> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2012/02/wp-engine-review/feed/</wfw:commentRss> <slash:comments>12</slash:comments> </item> <item><title>Color Palettes with the Options Framework</title><link>http://wptheming.com/2012/02/color-palettes/</link> <comments>http://wptheming.com/2012/02/color-palettes/#comments</comments> <pubDate>Sun, 12 Feb 2012 19:59:19 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[Tutorials]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=2010</guid> <description><![CDATA[An example of how to extend the Options Framework to enable color palettes to be selected by users.]]></description> <content:encoded><![CDATA[<p>I recently collaborated on a <a
href="http://restaurantengine.com/">project</a> with Brian Casel, another WordPress developer, who wanted options for selecting preset color palettes in the Options Framework.</p><p>The idea is that a user could choose a color palette (light,dark,vibrant) from a select box or image radio button- and all the color pickers would fill with those presets.  The user could then override any of those preset colors if they choose.<br
/> <span
id="more-2010"></span><br
/> <iframe
src="http://www.screenr.com/embed/7sys" width="500" height="305" frameborder="0"></iframe></p><p>View on Screenr: <a
href="http://www.screenr.com/7sys">http://www.screenr.com/7sys</a></p><h3>Load the Javascript</h3><p>In order to have an option like this you actually don&#8217;t have to hack the Options Framework plugin at all, you just need to hook in a little javascript for the options page to use.</p><p>If you want to display the code inline, you can use this hook:</p><pre class="brush: php; title: ; notranslate">
add_action('optionsframework_custom_scripts', 'optionsframework_custom_scripts');
function optionsframework_custom_scripts() { ?&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
jQuery(document).ready(function() {
	// Javascript goes here
});
&lt;/script&gt;
&lt;?php
}
</pre><p>If you have a lot of scripts, it might be better to put them all in a single javascript file and enqueue that:</p><pre class="brush: php; title: ; notranslate">
if ( is_admin() ) {
	// Load additional css and js for image uploads on the Options Framework page
	$of_page= 'appearance_page_options-framework';
	add_action( &quot;admin_print_scripts-$of_page&quot;, 'optionsframework_custom_js', 0 );
}
function optionsframework_custom_js () {
     wp_register_script( 'optionsframework_custom_js', get_bloginfo('template_directory') .'js/optionsframework_custom.js', array( 'jquery') );
     wp_enqueue_script( 'optionsframework_custom_js' );
}
</pre><p>If you are using theme version rather than the plugin version, you can just add the new javascript to options-custom.js.</p><h3>The Options</h3><p>Let&#8217;s keep it simple.  We&#8217;ll create a new option called &#8220;Color Palettes&#8221;, which will be in a drop down select box.  Then we&#8217;ll have two color pickers called &#8220;Primary Color&#8221;, &#8220;Secondary Color&#8221;:</p><pre class="brush: php; title: ; notranslate">
$base_color_scheme_array = array(&quot;dark&quot; =&gt; &quot;Dark&quot;,&quot;light&quot; =&gt; &quot;Light&quot;,&quot;vibrant&quot; =&gt; &quot;Vibrant&quot;);
$options[] = array(
	&quot;name&quot; =&gt; &quot;Design&quot;,
	&quot;type&quot; =&gt; &quot;heading&quot;);
$options[] = array(
	&quot;name&quot; =&gt; &quot;Base Color Scheme&quot;,
	&quot;desc&quot; =&gt; &quot;Choose a base color scheme.&quot;,
	&quot;id&quot; =&gt; &quot;base_color_scheme&quot;,
	&quot;std&quot; =&gt; &quot;fresh&quot;,
	&quot;type&quot; =&gt; &quot;select&quot;,
	&quot;class&quot; =&gt; &quot;mini&quot;, //mini, tiny, small
	&quot;options&quot; =&gt; $base_color_scheme_array);
	$options[] = array( &quot;name&quot; =&gt; &quot;Primary Color&quot;,
	&quot;desc&quot; =&gt; &quot;The primary color for the site.&quot;,
	&quot;id&quot; =&gt; &quot;primary_color&quot;,
	&quot;std&quot; =&gt; &quot;#000000&quot;,
	&quot;type&quot; =&gt; &quot;color&quot; );
$options[] = array(
	&quot;name&quot; =&gt; &quot;Secondary Color&quot;,
	&quot;desc&quot; =&gt; &quot;The secondary color for the site.&quot;,
	&quot;id&quot; =&gt; &quot;secondary_color&quot;,
	&quot;std&quot; =&gt; &quot;#555555&quot;,
	&quot;type&quot; =&gt; &quot;color&quot;);
</pre><h3>Javascript</h3><p>This javascript code will be triggered when someone changes the value of  the select box base_color_scheme.  It will go through and update our two color pickers with the new color.</p><pre class="brush: jscript; title: ; notranslate">
jQuery(document).ready(function($) {
	// Color Scheme Options - These array names should match
	// the values in base_color_scheme of options.php
	// Dark Color Options
	var dark = new Array();
	dark['primary_color']='#e4ff31';
	dark['secondary_color']='#e4ff31';
	// Light Color Options
	var light = new Array();
	light['primary_color']='#6cff00';
	light['secondary_color']='#6cff00';
	// Vibrant Color Options
	var vibrant = new Array();
	vibrant['primary_color']='#065667';
	vibrant['secondary_color']='#065667';
	// When the select box #base_color_scheme changes
	// it checks which value was selected and calls of_update_color
	$('#base_color_scheme').change(function() {
	    colorscheme = $(this).val();
	    if (colorscheme == 'dark') { colorscheme = dark; }
	    if (colorscheme == 'light') { colorscheme = light; }
	    if (colorscheme == 'vibrant') { colorscheme = vibrant; }
	    for (id in colorscheme) {
	        of_update_color(id,colorscheme[id]);
	    }
	});
	// This does the heavy lifting of updating all the colorpickers and text
	function of_update_color(id,hex) {
	    $('#section-' + id + ' .of-color').css({backgroundColor:hex});
	    $('#section-' + id + ' .colorSelector').ColorPickerSetColor(hex);
	    $('#section-' + id + ' .colorSelector').children('div').css('backgroundColor', hex);
	    $('#section-' + id + ' .of-color').val(hex);
	    $('#section-' + id + ' .of-color').animate({backgroundColor:'#ffffff'}, 600);
	}
});
</pre><h3>That&#8217;s It</h3><p>For more information about the Options Framework:</p><ul><li><a
href="http://wptheming.com/options-framework-plugin/">Options Framework Plugin</a></li><li><a
href="http://wptheming.com/options-framework-theme/">Options Framework Theme</a></li></ul><h3> Restaurant Engine</h3><p>If you&#8217;re interested in the work Brian Casel is doing on this, check out <a
href="http://restaurantengine.com/">restaurantengine.com</a>.</p> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2012/02/color-palettes/feed/</wfw:commentRss> <slash:comments>14</slash:comments> </item> <item><title>Options Framework 1.0</title><link>http://wptheming.com/2012/01/options-framework-1-0/</link> <comments>http://wptheming.com/2012/01/options-framework-1-0/#comments</comments> <pubDate>Mon, 16 Jan 2012 03:06:33 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[Plug-ins]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=2216</guid> <description><![CDATA[Version 1.0 of the Options Framework is on its way.  Here's a rundown of the new features.  If you're a developer, please test the beta version before a wider release is done.]]></description> <content:encoded><![CDATA[<p>Although this is the &#8220;milestone&#8221; 1.0 release for the Options Framework there aren&#8217;t any major changes for end users in this version.  It&#8217;s more of a developer release, providing additional filters and hooks.</p><p><img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2012/01/optionsheader.jpg" alt="Options" title="optionsheader" width="590" height="210" class="alignnone size-full wp-image-2227" /><br
/> <small
style="font-size:12px">Image from <a
href="http://www.flickr.com/photos/verbaljam/36824715/">Creative Commons</a></small></p><p>If your theme currently works, it should be fine after this release too.  But I would love for any developers who use it to test it out and make sure.<br
/> <span
id="more-2216"></span><br
/> Below is a little rundown of the new features.  All these updates were instigated via pull requests on GitHub.  The full discussions can be found on <a
href="https://github.com/devinsays/options-framework-plugin/pull/78">Issue #78</a> by <a
href="https://twitter.com/#!/inxilpro">@inxilpro</a>, and <a
href="https://github.com/devinsays/options-framework-plugin/pull/75">Issue #75</a> by <a
href="https://twitter.com/#!/https://twitter.com/#!/mattwiebe">@mattwiebe</a>.  Many thanks to all the contributors and testers.</p><h3>Option ID Not Required</h3><p>In the past theme authors were required to have the &#8220;optionsframework_option_name&#8221; function in their theme to declare the option ID.  In this new version it&#8217;s not required.  If the option ID is not set, it will the simply use theme name with the the &#8220;optionsframework&#8221; as a prefix.</p><p>I&#8217;d recommend leaving it in if it&#8217;s already part of your theme, but on future projects it&#8217;s your choice.</p><h3>Location of Options.php Filterable</h3><p>Not everyone likes to store all their files in the base theme directory.  With this filter you can rename options.php to whatever you like, or move it to whichever directory you like.  Here&#8217;s an example:</p><pre class="brush: php; title: ; notranslate">
add_filter('options_framework_location','options_framework_location_override');
function options_framework_location_override() {
	return array('/extensions/options-renamed.php');
}
</pre><h3>Options Array Filterable</h3><p>The entire options array is also now filterable.  This might be useful if you want to make a minor alteration to the options of a parent theme from a child theme, or if you just want to avoid using optionsframework_options in your theme.</p><p>Here&#8217;s an example that appends an additional option using the filter:</p><pre class="brush: php; title: ; notranslate">
add_filter('of_options', function($options) {
	$options[] = array(
	'name' =&gt; 'New Option Added Via Filter',
	'id' =&gt; 'example_filtered_option',
	'std' =&gt; 'Default',
	'type' =&gt; 'text'
	);
  return $options;
});
</pre><h3>A Fix for User Roles</h3><p>The option panel has always displayed for users who had the edit_theme_options capability, but because of a quirk in the Settings API users actually need the manage_options capability in order to save them.  Now the options should save for anyone with the edit_theme_options capability.</p><h3>Info Option</h3><p>You can now put html into the info option by default- which should make it easier to drop in images or other customizations.</p> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2012/01/options-framework-1-0/feed/</wfw:commentRss> <slash:comments>7</slash:comments> </item> <item><title>Theming the Image Post Format</title><link>http://wptheming.com/2012/01/theming-the-image-post-format/</link> <comments>http://wptheming.com/2012/01/theming-the-image-post-format/#comments</comments> <pubDate>Fri, 13 Jan 2012 22:35:03 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[WordPress Tips]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=2190</guid> <description><![CDATA[Working with post formats in WordPress can be challenging because of the lack of structured data, but jQuery can actually help out quite a bit.]]></description> <content:encoded><![CDATA[<p>Working with post formats in WordPress can be challenging because of the lack of structured data.  For instance, just because a user selects an &#8220;image&#8221; post format, there&#8217;s no guarantee that an image was actually attached to the post.</p><p>Alex King has <a
href="http://alexking.org/blog/2011/10/25/wordpress-post-formats-admin-ui">created a plugin</a> and submitted a couple patches, but until the WordPress UI catches up we as theme developers need to be a little creative.</p><p>In the most recent version of <a
href="http://wordpress.org/extend/themes/portfolio-press">Portfolio Press</a>, I ended up styling the image format to look like this:<br
/> <span
id="more-2190"></span><br
/> <img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2012/01/post-format-590x548.jpg" alt="" title="post-format" width="590" height="548" class="alignnone size-large wp-image-2191" /></p><p>(You can also <a
href="http://themes.wptheming.com/portfolio/blog/">view it</a> on the demo site)</p><h3>Post Format Styling</h3><p>Instead of putting a title above the post like the standard format, I decided to hide it.  In my opinion the focus should be on the image.</p><p>Instead of displaying the the_excerpt like I do for other posts in the archive view, I display the_content so that full images are able to be displayed.</p><p>Then, using jQuery, I built a rollover effect that displays the post title when someone hovers over the image.  If you click on the image, it will take you to the full post.</p><h3>jQuery With Post Formats</h3><p>Using jQuery makes it much easier to work with the post formats because you don&#8217;t need to guess what&#8217;s in the content.  It also fails gracefully if it doesn&#8217;t find the markup it&#8217;s looking for.</p><p>For instance, the rollover effect in Portfolio Press is applied only on the first image detected in the post format- even if the author dropped 12 in there.  If there&#8217;s no image, no additional markup is added.</p><p>The script checks to make sure the image is at least 200px wide.  The rollover title still might not fit in a larger image, but at least it has a chance.</p><p>Authors sometimes link their images to the fullsize version.  However, in the archive view I want the image to only link to the full post.  The script I wrote will unwrap any link around the original image, and replace it with a link to the post in the archive view.  This might not be what some users in intend, but I think the majority will.</p><h3>Enough Talk</h3><p>Here&#8217;s the script I used to create the rollover effect on post format images:</p><pre class="brush: jscript; title: ; notranslate">
    // Image Post Format
    $('#content .format-image').each( function() {
    	var image = $(this).find('img:first');
    	if (image.width() &gt; 200 ) {
	    	var link = $(this).find('.entry-title').children();
	    	var title = link.text();
	    	image.unwrap('a');
	    	image.wrap('&lt;div class=&quot;image-wrap&quot; /&gt;');
	    	image.wrap(link.text(''));
	    	image.parent().append('&lt;h3/&gt;');
	    	$(this).find('h3').text(title).width(image.width() - 20);
    	}
    });
    $('.format-image .image-wrap a').hover( function() {
    	$(this).children('h3').slideDown(100);
    }, function(){
    	$(this).children('h3').slideUp(200);
    });
</pre><h3>View It</h3><p>You can view the <a
href="http://themes.wptheming.com/portfolio/blog/">post formats here</a>.  Portfolio Press 0.9 can be <a
href="https://github.com/devinsays/portfolio-press">downloaded from GitHub</a> (the latest isn&#8217;t in the .org repository yet).</p> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2012/01/theming-the-image-post-format/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Custom Design on WordPress.com</title><link>http://wptheming.com/2012/01/custom-design-on-wordpress-com/</link> <comments>http://wptheming.com/2012/01/custom-design-on-wordpress-com/#comments</comments> <pubDate>Thu, 12 Jan 2012 04:08:28 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[WordPress Tips]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=2154</guid> <description><![CDATA[If you want a highly customized theme for your WordPress site the only option is to self-host, right?  Not so fast...]]></description> <content:encoded><![CDATA[<p>If you want a highly customized theme for your WordPress site the only option is to self-host, right?  Not so fast&#8230;</p><p>I just finished a small project for Bluefin Software <a
href="http://blog.bluefinapps.com/">redeveloping their blog</a>.  They wanted to stay with WordPress.com hosting because of its ability to scale and low maintenance.  And incredibly, by using just the <a
href="http://en.support.wordpress.com/custom-design/">custom design upgrade</a> and widget areas in the <a
href="http://en.blog.wordpress.com/2010/08/09/new-theme-coraline/">Coraline Theme</a>, it was possible to build exactly what their designer had envisioned.<br
/> <span
id="more-2154"></span></p><h3>Bluefin Blog After Custom Design</h3><p><a
href="http://blog.bluefinapps.com/"><img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2012/01/bluefin-590x510.jpg" alt="" title="Bluefin Blog" width="590" height="510" class="size-large wp-image-2157" /></a></p><h3>Bluefin Blog Original</h3><p><img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2012/01/bluefin-original-590x419.jpg" alt="" title="bluefin-original" width="590" height="419" class="size-large wp-image-2161" /></p><h3>Benefits of Using WordPress.com</h3><p>Using WordPress.com has a few benefits:</p><ul><li>It&#8217;s completely free to have a basic blog.  The <a
href="http://en.support.wordpress.com/custom-design/">custom design option</a> is only $30/yr, and <a
href="http://en.support.wordpress.com/domain-mapping/map-existing-domain/">custom domains</a> are only $12.  Together, it&#8217;s still about half as much as using a shared host like HostGator or BlueHost.</li><li>It scales up incredibly well.  WordPress.com serves up <a
href="http://en.wordpress.com/stats/">2.5 billion pageviews a month</a>.  Your site will run fast, content is served off a global CDN, and you never have to worry about upgrading a plugin.</li><li>It handles everything most users need.  Contact forms, polls, stats, twitter widgets, code highlighters, and flickr widgets are all available.</li></ul><h3>Disadvantages of Using WordPress.com</h3><p>If you use WordPress.com you won&#8217;t be able to add any plugins.  You&#8217;re stuck with what they got.  No bbPress or Gravity Forms for you, sorry.</p><p>You can&#8217;t alter the theme markup.  Although it&#8217;s possible to do a lot with CSS, you won&#8217;t be able to do everything- especially in the javascript department.  You&#8217;re also limited to the selection of themes on WordPress.com.</p><h3>Tips for Custom Design on WordPress.com</h3><p>If that doesn&#8217;t deter you, here&#8217;s some tips for working with the custom design option:</p><h4>Pick the Right Theme</h4><p>Before you get heavily involved in the design, try to pick out the theme you want to use and work within it&#8217;s limitations.</p><p>I originally chose <a
href="http://en.blog.wordpress.com/2010/12/10/new-theme-toolbox/">Toolbox</a> to build the site off of since it&#8217;s a blank canvas with good markup, but to make the custom footer work I needed widget areas at the bottom.  That&#8217;s why I switched to <a
href="http://en.blog.wordpress.com/2010/08/09/new-theme-coraline/">Coraline</a>, which has an incredibly flexible layout.</p><h4>Use the Widget Areas</h4><p>Widget areas are the one part (besides the actual post content) where you can control the markup.  Just paste in the HTML you need (no scripts or iframes though).</p><h4>Build the Site Locally</h4><p>I built out the Bluefin design locally using MAMP.  All the free themes on WordPress.com are available on <a
href="http://wordpress.org/extend/themes/">WordPress extend</a> or directly <a
href="https://wpcom-themes.svn.automattic.com/">through SVN</a> from Automattic.</p><h4>Make a Child Theme</h4><p>Once you have the theme you plan to customization, make a child theme, import the WordPress.com content (if you have it), and start styling.  The other advantage of building a child theme is that it will be very easy to switch to self-hosted if you need to in the future.</p><h4>Upload All Your Assets to WordPress.com</h3><p>When you&#8217;re ready to move the design over, simply paste in the contents of your child theme&#8217;s CSS in the custom design editor.  If you&#8217;re using any images, those should be uploaded into your media assets on WordPress.com and replaced in the stylesheet so they can be served from WordPress.com&#8217;s CDN.</p><h3>In Conclusion</h3><p>WordPress.com won&#8217;t be for everyone- but it&#8217;s definitely a great option for some.  It&#8217;s low (or free) price and quality support make it a great option for folks who aren&#8217;t ready to make the plunge on self-hosted, and also for companies and organizations that just need a basic website and fairly unique look.</p><p>Also, as a developer it&#8217;s quite nice.  On a .org site you can do anything with enough time and work, but on .com the scope is inherently limited.  In this case, to 400 lines of CSS.</p> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2012/01/custom-design-on-wordpress-com/feed/</wfw:commentRss> <slash:comments>5</slash:comments> </item> <item><title>Tracking Outbound Links with Google Analytics</title><link>http://wptheming.com/2012/01/tracking-outbound-links-with-google-analytics/</link> <comments>http://wptheming.com/2012/01/tracking-outbound-links-with-google-analytics/#comments</comments> <pubDate>Mon, 09 Jan 2012 17:28:23 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[Miscellaneous]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=2110</guid> <description><![CDATA[I've recently been working on a website that needs to track external link clicks.  This is something that the WordPress.com stats does by default, but not Google Analytics.  If you want to set it up, you'll need to set up a custom tracker event.]]></description> <content:encoded><![CDATA[<p>I&#8217;ve recently been working on a website that needs to track external link clicks in Google Analytics.  This is something that the <a
href="http://wordpress.org/extend/plugins/jetpack/">WordPress.com stats</a> plugin does by default, but not Google.  In order to track external links with Google Analytics, you&#8217;ll need to set up a <a
href="http://code.google.com/apis/analytics/docs/tracking/eventTrackerGuide.html">custom tracker event</a>.<br
/> <span
id="more-2110"></span><br
/> <img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2012/01/events-590x248.gif" alt="" title="events" width="590" height="248" class="alignnone size-large wp-image-2130" /></p><p>The method <a
href="http://support.google.com/googleanalytics/bin/answer.py?hl=en&#038;answer=55527">suggested by Google</a> involves manually applying code to each link.  This is fine if you want to just track a few specific links, but jQuery is more useful if you want to track every external link on the page.</p><h3>Custom Tracking Events</h3><p>The meat of the custom event is this line (which should be fired when an external link is clicked) is:</p><pre class="brush: jscript; gutter: false; title: ; notranslate">
_gat._getTrackerByName()._trackEvent(&quot;Outbound Links&quot;, e.currentTarget.host, url, 0);
</pre><ul><li>&#8220;Outbound Links&#8221; is the category of events to track</li><li>&#8220;e.currentTarget.host&#8221; is the &#8220;action&#8221;, in this case, the domain the user is clicking to.</li><li>&#8220;url&#8221; is the &#8220;label&#8221;, which I use to send the full url of the external link.</li></ul><p>If you&#8217;re unfamiliar with custom events, here&#8217;s the <a
href="http://code.google.com/apis/analytics/docs/tracking/eventTrackerGuide.html">docs page at Google</a>.</p><h3>Code for Detecting and Tracking Outbound Link Clicks</h3><p>This code snippet is highly commented and peppered with console.logs so that you can verify it&#8217;s working correctly and see how it works.  It should only be used in development environments- there&#8217;s a compressed version in the next section for use on live sites.</p><pre class="brush: jscript; title: ; notranslate">
// Outbound Link Tracking with Google Analytics
// Requires jQuery 1.7 or higher (use .live if using a lower version)
// For more info see: http://support.google.com/googleanalytics/bin/answer.py?hl=en&amp;answer=55527
$(&quot;a&quot;).on('click',function(e){
		var url = $(this).attr(&quot;href&quot;);
		// Console logs shows the domain name of the link being clicked and the current window
		console.log('e.currentTarget.host: ' + e.currentTarget.host);
		console.log('window.location.host: ' + window.location.host);
		// If the domains names are different, it assumes it is an external link
		// Be careful with this if you use subdomains
		if (e.currentTarget.host != window.location.host) {
			console.log('external link click');
			// Outbound link!  Fires the Google tracker code.
			_gat._getTrackerByName()._trackEvent(&quot;Outbound Links&quot;, e.currentTarget.host, url, 0);
  		// Checks to see if the ctrl or command key is held down
		// which could indicate the link is being opened in a new tab
		if (e.metaKey || e.ctrlKey) {
			console.log('ctrl or meta key pressed');
			var newtab = true;
		}
		// If it is not a new tab, we need to delay the loading
		// of the new link for a just a second in order to give the
		// Google track event time to fully fire
		if (!newtab) {
			console.log('default prevented');
			e.preventDefault();
                        console.log('loading link after brief timeout');
			//setTimeout('document.location = &quot;' + url + '&quot;', 100);
		}
	}
	else {
		console.log('internal link click');
	}
});
</pre><h3>Compressed Version</h3><p>This is the same code as above, but with comments and console.logs stripped out:</p><pre class="brush: jscript; title: ; notranslate">
// Outbound Link Tracking with Google Analytics
// Requires jQuery 1.7 or higher (use .live if using a lower version)
$(&quot;a&quot;).on('click',function(e){
	var url = $(this).attr(&quot;href&quot;);
	if (e.currentTarget.host != window.location.host) {
		_gat._getTrackerByName('demand')._trackEvent(&quot;Outbound Links&quot;, e.currentTarget.host, url, 0);
		if (e.metaKey || e.ctrlKey) {
		     var newtab = true;
		}
		if (!newtab) {
		     e.preventDefault();
		     setTimeout('document.location = &quot;' + url + '&quot;', 100);
		}
	}
});
</pre><h3>Viewing the Results</h3><p>To see if your custom tracking events are firing correctly, check your Google Analytics dashboard under &#8220;Content > Events > Overview&#8221;.  It may take a couple hours before you start to see the results.  In this screenshot you can clearly see when the tracking began:</p><p><img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2012/01/analytics-events-590x398.gif" alt="" title="analytics-events" width="590" height="398" class="alignnone size-large wp-image-2123" /></p><h3>In WordPress</h3><p>If you are using a plugin for Google Analytics, like <a
href="http://wordpress.org/extend/plugins/google-analyticator/">Google Analyticator</a>, there is a settings fields where you can add javascript to be included with the tracker.  You can also just include it with your other scripts.</p><p>Another option to track links easily in WordPress is to use the stats from <a
href="http://wordpress.org/extend/plugins/jetpack/">Jetpack</a>, which give you outbound click data by default.</p> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2012/01/tracking-outbound-links-with-google-analytics/feed/</wfw:commentRss> <slash:comments>6</slash:comments> </item> <item><title>Using Multiple Google Analytics Trackers</title><link>http://wptheming.com/2011/12/using-multiple-google-analytics-trackers/</link> <comments>http://wptheming.com/2011/12/using-multiple-google-analytics-trackers/#comments</comments> <pubDate>Thu, 29 Dec 2011 23:05:41 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[Miscellaneous]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=2093</guid> <description><![CDATA[Sometimes it's necessary to use multiple Google Analytics trackers on the same site.  If you're doing this, never paste in both of the default tracking scripts that Google provides.]]></description> <content:encoded><![CDATA[<p>Sometimes it&#8217;s necessary to use multiple Google Analytics trackers on the same site.  If you&#8217;re doing this, never paste in both of the default tracking scripts that Google provides.</p><p>Instead, set up the tracking variables and just call the Google script once.  Here&#8217;s what I&#8217;ve used:<br
/> <span
id="more-2093"></span></p><pre class="brush: jscript; title: ; notranslate">
&lt;script&gt;
var _gaq=[
	['_setAccount', 'UA-1111111-1'],['_trackPageview'],['_trackPageLoadTime'],
	['secondTracker._setAccount', 'UA-2222222-1'],['secondTracker._trackPageview'],['secondTracker._trackPageLoadTime']
];
(function(d, t) {
     var g = d.createElement(t),
         s = d.getElementsByTagName(t)[0];
    g.src = '//www.google-analytics.com/ga.js';
    s.parentNode.insertBefore(g, s);
}(document, 'script'));
&lt;/script&gt;
</pre><h3>Notes:</h3><ul><li>This is an optimized version of the GA script from <a
href="http://mathiasbynens.be/notes/async-analytics-snippet">Mathias Bynens</a>.</li><li>You can include more than two.  Just copy the secondTracker code and repeat.</li><li>The &#8220;secondTracker&#8221; label can be changed to anything you like.</li><li>_trackPageLoadTime isn&#8217;t required, but _trackPageview is.</li><li>The code should be placed right before the <a
href="http://code.google.com/apis/analytics/docs/tracking/gaTrackingOverview.html#trackingCodePlacement">close of the body tag</a>.</li></ul> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2011/12/using-multiple-google-analytics-trackers/feed/</wfw:commentRss> <slash:comments>0</slash:comments> </item> <item><title>Ajax Themes</title><link>http://wptheming.com/2011/12/ajax-themes/</link> <comments>http://wptheming.com/2011/12/ajax-themes/#comments</comments> <pubDate>Tue, 20 Dec 2011 00:59:53 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[Tutorials]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=2026</guid> <description><![CDATA[Ajax is a great method for loading new content onto a web page without having to do an entire page refresh.  It's sometimes used in WordPress themes for paging, or comments- but this tutorial explains how to ajaxify larger portions of the site and use HTML5 pushstates.]]></description> <content:encoded><![CDATA[<p>Ajax is a great method for loading new content onto a web page without having to do an entire page refresh.  It&#8217;s sometimes used in WordPress themes <a
href="http://www.problogdesign.com/wordpress/load-next-wordpress-posts-with-ajax/">for paging</a>, loading in full content after <a
href="http://wordpress.org/extend/plugins/ajax-read-more/">an excerpt</a>, or dynamically displaying <a
href="http://wordpress.org/extend/themes/p2">new comments</a> as they are posted.</p><p>Ajax can also be used to load more significant amounts of content, but it gets more complicated.  URLs don&#8217;t update by default, which is important if someone wants to bookmark that particular post or share it.  Browser navigation buttons for &#8220;Back&#8221; and &#8220;Forward&#8221; can also be an issue.</p><p>Thankfully there are HTML5 methods for dealing with browser history and states, and an awesome jquery plugin that provides some fallback for older browsers.  This tutorial will walk you through the code required for a theme that makes extensive use of ajax and also point you to some live demos.<br
/> <span
id="more-2026"></span></p><h3>When to Use Ajax</h3><p><a
href="http://designers.mx"><img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2011/12/designermx-590x302.jpg" alt="" title="designermx" width="590" height="302" class="alignnone size-large wp-image-2047" /></a></p><p>Sites that use ajax well generally have a good reason for it.  One of my favorite ajax sites is <a
href="http://designers.mx/">Designers MX</a>, which hosts music mixes.  By using ajax the site is able to keep the music playing uninterrupted while users navigate through the site.</p><p>When animations could be interrupted by a fresh page load, ajax is also extremely helpful.  I developed a site for <a
href="http://byronreese.com/">Byron Reece</a> that features a large slider at the top for selecting posts.  If the user had to load a new page after clicking on an item on the slider the site interaction would not have worked.</p><p>Sites that have heavy initial page weight but then just need to load in small snippets can benefit enormously from ajax.  An example might be a gallery site that displays a huge amount of thumbnails initially, but then just needs a single request for a larger image when the user selects it.</p><h3>How URL Pushstates Work</h3><p>You&#8217;ll notice on the <a
href="http://byronreese.com/">Byron Reece</a> site that when you click on an a different item in the slider the URL updates even though a fresh page load is not happening.  In modern browsers that support <a
href="https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history">HTML5 push states</a>, this url looks like any other you would normally use on the web.  In legacy browsers, like IE8, it reverts to the hash url structure (#!).</p><p>Most of this URL magic is handled by <a
href="https://github.com/balupton/History.js/">history.js</a>.  All you do is send a title and url for the new browser state when the ajax event happens.</p><h3>A Simple Example</h3><p><a
href="http://themes.wptheming.com/ajax-demo/"><img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2011/12/ajaxdemo-590x295.png" alt="Ajax Demo Theme" title="Ajax Demo Theme" width="590" height="295" class="alignnone size-large wp-image-2049" /></a></p><p>I coded out a much simpler example of an <a
href="http://themes.wptheming.com/ajax-demo/">AJAX driven site using the TwentyEleven theme</a> as a base for an example.  Any links clicked in the top navigation menu will load the new content from that link into the #primary and #secondary divs.</p><p>I wouldn&#8217;t suggest building a site like this, as you don&#8217;t get a whole lot of upside for using ajax here, but it works well for demonstration purposes.</p><h3>Enqueue the Required Javascript</h3><p>For the pushstates to work as I used them, you&#8217;ll need to load <a
href="https://github.com/balupton/History.js/">history.js</a>.  There is a compressed version for use with jquery that can be <a
href="https://github.com/balupton/history.js/blob/master/scripts/bundled/html4+html5/jquery.history.js">downloaded here</a>.  I also load another javascript file that contains the custom code, which I saved in ajax_demo_init.js.</p><pre class="brush: php; title: ; notranslate">
/*
 * Loads the scripts that are required for push_states to work.
 *
 * https://github.com/balupton/History.js
 *
 */
function ajax_demo_init() {
	if ( !is_admin() ) {
		wp_deregister_script('historyjs');
		wp_register_script( 'historyjs', get_bloginfo( 'stylesheet_directory' ) . '/js/jquery.history.js', array( 'jquery' ), '1.7.1' );
		wp_enqueue_script( 'historyjs' );
		wp_register_script( 'ajax_demo_init', get_bloginfo( 'stylesheet_directory' ) . '/js/ajax_demo_init.js', array( 'historyjs' ), false, true );
		wp_enqueue_script( 'ajax_demo_init' );
	}
}
add_action( 'wp_enqueue_scripts','ajax_demo_init' );
</pre><h3>ajax_demo_init</h3><p>This is the custom javascript that enables history.js, tells the site which link targets to load via ajax, and pushes the new browser states.  I&#8217;ll post it as a block here, and then explain in more detail below:</p><pre class="brush: jscript; title: ; notranslate">
jQuery(document).ready(function($) {
	// Establish Variables
	var
		History = window.History, // Note: Using a capital H instead of a lower h
		State = History.getState(),
		$log = $('#log');
	// If the link goes to somewhere else within the same domain, trigger the pushstate
	$('#access a').on('click', function(e) {
		e.preventDefault();
		var path = $(this).attr('href');
		var title = $(this).text();
		History.pushState('ajax',title,path);
	});
	// Bind to state change
	// When the statechange happens, load the appropriate url via ajax
	History.Adapter.bind(window,'statechange',function() { // Note: Using statechange instead of popstate
		load_site_ajax();
	});
	// Load Ajax
	function load_site_ajax() {
		State = History.getState(); // Note: Using History.getState() instead of event.state
		// History.log('statechange:', State.data, State.title, State.url);
		//console.log(event);
		$(&quot;#primary&quot;).prepend('&lt;div id=&quot;ajax-loader&quot;&gt;&lt;h4&gt;Loading...&lt;/h4&gt;&lt;/div&gt;');
		$(&quot;#ajax-loader&quot;).fadeIn();
		$('#site-description').fadeTo(200,0);
		$('#content').fadeTo(200,.3);
		$(&quot;#main&quot;).load(State.url + ' #primary, #secondary', function(data) {
			/* After the content loads you can make additional callbacks*/
			$('#site-description').text('Ajax loaded: ' + State.url);
			$('#site-description').fadeTo(200,1);
			$('#content').fadeTo(200,1);
			// Updates the menu
			var request = $(data);
			$('#access').replaceWith($('#access', request));
		});
	}
});
</pre><h3>Pushing the Title and URL</h3><p>This snippet tells the site which links should be loaded by ajax (&#8216;#access a&#8217;).  To fully ajaxify a site you&#8217;d probably want it to <a
href="http://www.mccran.co.uk/index.cfm/2011/7/27/Simple-JQuery-way-to-detect-links-pointing-to-external-domains">detect external vs internal links</a>, and load all the internal ones with ajax.</p><pre class="brush: jscript; title: ; notranslate">
$('#access a').live('click', function(e) {
	e.preventDefault();
	var path = $(this).attr('href');
	var title = $(this).text();
	History.pushState('ajax',title,path);
});
</pre><p>The path variable is what sets the new url.  The title is what will be at the top of the browser window and show up when bookmarked.</p><p>You might need to be a little careful with the title.  You&#8217;ll notice in my <a
href="http://themes.wptheming.com/ajax-demo">Ajax Demo</a> the full title is there on a fresh page load, but on an ajax load it drops site name from the title.  To get it to match perfectly you&#8217;d have to tweak the title variable slightly.</p><h3>Binding the Listener on Statechange</h3><p>This idea took a little while for me to understand.  When someone clicks on a link that you want to load via ajax, you don&#8217;t actually trigger any of the ajax on that click function.  Instead, you have the click trigger a statechange event and pass it the needed variables for url and title.</p><p>The real work is done in the statechange listener.  Here&#8217;s a real simple example with all the console log events uncommented so you can see what&#8217;s going on:</p><pre class="brush: jscript; title: ; notranslate">
// Bind to state change
// When the statechange happens, load the appropriate url via ajax
History.Adapter.bind(window,'statechange',function() { // Note: Using statechange instead of popstate
     State = History.getState(); // Note: Using History.getState() instead of event.state
     History.log('statechange:', State.data, State.title, State.url);
     console.log(event);
});
</pre><p>(The above doesn&#8217;t actually load content, it just posts to the browser console.)</p><p>In the <a
href="http://themes.wptheming.com/ajax-demo">Ajax Demo</a>, a click on &#8220;Example One&#8221; will display the following in the browser console:</p><pre class="brush: jscript; title: ; notranslate">
statechange: [
Object
, &quot;Example One&quot;, &quot;http://themes.wptheming.com/ajax-demo/example-one/&quot;]
MouseEvent
</pre><p>You can see the event was triggered by a mouseclick, and that &#8220;Example One&#8221; is the new title, &#8220;http://themes.wptheming.com/ajax-demo/example-one&#8221; is the URL that will be loaded.</p><p>Any functions in the statechange listener will also be fired when someone clicks the &#8220;back&#8221; or &#8220;forward&#8221; buttons in their browser.</p><h3>Loading in the New Content via Ajax</h3><p>The final piece is to actually load in the new content using ajax.  If you&#8217;re unfamiliar with how this works, I&#8217;d also read the jQuery documentation the <a
href="http://api.jquery.com/load/">load function</a>.  For the TwentyEleven ajax example, we replace the #primary and #secondary divs with content from the new URL.  This all happens inside the load_site_ajax function:</p><pre class="brush: jscript; title: ; notranslate">
$(&quot;#main&quot;).load(State.url + ' #primary, #secondary', function(data) {
     /* After the content loads you can make additional callbacks*/
});
</pre><p>If you look at the original code, you&#8217;ll also notice that a couple other things I do to let the user know that new content is being loaded.</p><p>As soon as the ajax link is clicked, a loader gif is shown:</p><pre class="brush: jscript; title: ; notranslate">
$(&quot;#primary&quot;).prepend('&lt;div id=&quot;ajax-loader&quot;&gt;&lt;h4&gt;Loading...&lt;/h4&gt;&lt;/div&gt;');
$(&quot;#ajax-loader&quot;).fadeIn();
</pre><p>I also dim the content, so that the user is aware that it will change shortly:</p><pre class="brush: jscript; title: ; notranslate">
$('#content').fadeTo(200,.3);
</pre><p>Once the content has loaded, the ajax loader disappears because the new content doesn&#8217;t have the ajax loader in #primary (remember, it was prepended using javascript).  So, all that&#8217;s left to do is undim the new content:</p><pre class="brush: jscript; title: ; notranslate">
$('#content').fadeTo(200,1);
</pre><p>One final issue I had, is that the menu items weren&#8217;t highlighting correctly because WordPress applies certain classes to them depending on which page it has loaded.  When you load new content into #primary or #secondary and change the URL, the menu will keep the same classes it had on the initial page load.  One way around that is to also reload the menu:</p><pre class="brush: jscript; title: ; notranslate">
// Updates the menu
var request = $(data);
$('#access').replaceWith($('#access', request));
</pre><h3>A Note on Browser Compatibility</h3><p>Benjamin (the creator of history.js) wrote a great post about <a
href="https://github.com/balupton/history.js/wiki/Intelligent-State-Handling">supporting url states in legacy browsers</a>.  By legacy, I really mean Internet Explorer 9 and below (<a
href="http://blogs.msdn.com/b/ie/archive/2011/10/31/html5-history-in-ie10.aspx">IE10 is slated to support it</a>).</p><p>There&#8217;s a couple issues with older browsers, but I think the main one is bookmarking.  If a user visits the home page in IE8, then loads a secondary page via ajax, the URL will look something like this:</p><p><a
href="http://themes.wptheming.com/ajax-demo/#example-one/?&#038;_suid=132434056033304790466820008113">http://themes.wptheming.com/ajax-demo/#example-one/?&#038;_suid=132434056033304790466820008113</a></p><p>However, if you visit that URL directly- it will only load the home page, not the page you thought you bookmarked (http://themes.wptheming.com/ajax-demo/example-one).</p><p>I worked out a method for detecting a hash and loading the correct content after the initial load, but it doesn&#8217;t work in modern browsers- and sort of defeats the point of using ajax since it is now loading the initial page content and then new page content:</p><pre class="brush: jscript; title: ; notranslate">
// For legacy browser support
// Only checks for hashes, so more robust support might be needed if you use anchors
if (window.location.hash) {
	load_site_ajax();
}
</pre><p>I&#8217;m sure someone has worked out a better way to do this!  Please share it in the comments.</p><h3>Additional Thing to Watch Out For</h3><p>If you use social buttons like Google+ or Twitter, don&#8217;t expect them to automatically update with the new URL.  I&#8217;ll write a follow-up post about how to get those working.</p><p>A lot of WordPress themes use body classes for styling.  These won&#8217;t update on an ajax load.</p><h3>Did I Miss Something?</h3><p>If you see anywhere I can improve the code, please share it in the comments- especially about legacy browser support.</p><h3>Download the AJAX Demo Code</h3><p>If you&#8217;d like to get the <a
href="http://themes.wptheming.com/ajax-demo/">Ajax Demo</a> theme code, it&#8217;s available as a $5 dollar download.  The javascript code is the same as posted in this tutorial- just conveniently bundled into a theme version.</p><p><form
id="edd_purchase_2410" class="edd_download_purchase_form" action="" method="POST"><div
class="edd_purchase_submit_wrapper"><span
class="edd_button edd_add_to_cart_wrap edd_gray"><span
class="edd_button_outer"><span
class="edd_button_inner"><input
type="submit" class="edd_button_text edd-submit edd-add-to-cart" name="edd_purchase_download" value="Purchase the Ajax Demo for $5" data-action="edd_add_to_cart" data-download-id="2410"/></span></span></span><a
href="http://wptheming.com/checkout/" class="edd_go_to_checkout edd_button edd_gray" style="display:none;"><span
class="edd_button_outer"><span
class="edd_button_inner"><span
class="edd_button_text"><span>Checkout</span></span></span></span></a><div
class="edd-cart-ajax-alert"><img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/plugins/easy-digital-downloads/includes/images/loading.gif" class="edd-cart-ajax" style="display: none;"/>&nbsp;<span
style="display:none;" class="edd-cart-added-alert">added to your cart</span></div></div><input
type="hidden" name="download_id" value="2410"><input
type="hidden" name="edd_action" value="add_to_cart"></form><br
/> <i>(And thanks for supporting the site!)</i></p> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2011/12/ajax-themes/feed/</wfw:commentRss> <slash:comments>28</slash:comments> </item> <item><title>Event Posts in WordPress</title><link>http://wptheming.com/2011/11/event-posts-in-wordpress/</link> <comments>http://wptheming.com/2011/11/event-posts-in-wordpress/#comments</comments> <pubDate>Mon, 21 Nov 2011 00:18:45 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[Custom Post Types]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=1935</guid> <description><![CDATA[A tutorial explaining how to create an events post type, complete with custom meta boxes and an example query.  There's also an example plugin that can be downloaded from GitHub.]]></description> <content:encoded><![CDATA[<p>WordPress is a constantly maturing platform.  Just over a year ago I wrote a tutorial about creating custom post types for events- but huge improvements around <a
href="http://scribu.net/wordpress/advanced-metadata-queries.html">advanced meta data queries</a> made my previous approach seem hackish.  This post is a much revised update with code examples.<br
/> <span
id="more-1935"></span><br
/> If you need an out-of-the-box solution and aren&#8217;t interested in customizing the code, one of these plugins might be a quicker solution:</p><ul><li><a
href="http://wordpress.org/extend/plugins/the-events-calendar/">The Events Calender</a></li><li><a
href="http://wordpress.org/extend/plugins/calendar-press/">Calendar Press</a></li><li><a
href="http://gigpress.com/">GigPress (For Musicans)</a></li></ul><h3>The Basics</h3><p>Building an events post combines three concepts:</p><ul><li><a
href="http://codex.wordpress.org/Post_Types">Custom Post Types</a></li><li><a
href="http://codex.wordpress.org/Function_Reference/add_meta_box">Custom Metaboxes</a></li><li><a
href="http://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters">Advanced Meta Queries</a></li></ul><h3>Download the Code</h3><p>I built a working plugin with everything I describe here up on <a
href="https://github.com/devinsays/event-posts">GitHub</a>.  You can install the &#8220;Events Posts&#8221; plugin, and move the file &#8220;archive-events.php&#8221; into your theme in order to follow along.</p><p><b><a
href="https://github.com/devinsays/event-posts">Download the Code on GitHub</a></b></p><h3>The Post Type</h3><p>I create a new post type for events.  You could also use a regular post if you don&#8217;t want a separation between your regular posts and event posts, but for the purposes of this tutorial it makes it easier to explain.</p><p>If you&#8217;re not familiar with custom post types, read <a
href="http://justintadlock.com/archives/2010/04/29/custom-post-types-in-wordpress">Justin Tadlock&#8217;s excellent write up</a>.</p><p>Here&#8217;s how you would create a custom post type for events (<a
href="https://github.com/devinsays/event-posts/blob/master/event-posts.php">view on GitHub</a>):</p><pre class="brush: php; title: ; notranslate">
function ep_eventposts() {
	/**
	 * Enable the event custom post type
	 * http://codex.wordpress.org/Function_Reference/register_post_type
	 */
	$labels = array(
		'name' =&gt; __( 'Events', 'eventposttype' ),
		'singular_name' =&gt; __( 'Event', 'eventposttype' ),
		'add_new' =&gt; __( 'Add New Event', 'eventposttype' ),
		'add_new_item' =&gt; __( 'Add New Event', 'eventposttype' ),
		'edit_item' =&gt; __( 'Edit Event', 'eventposttype' ),
		'new_item' =&gt; __( 'Add New Event', 'eventposttype' ),
		'view_item' =&gt; __( 'View Event', 'eventposttype' ),
		'search_items' =&gt; __( 'Search Events', 'eventposttype' ),
		'not_found' =&gt; __( 'No events found', 'eventposttype' ),
		'not_found_in_trash' =&gt; __( 'No events found in trash', 'eventposttype' )
	);
	$args = array(
    	'labels' =&gt; $labels,
    	'public' =&gt; true,
		'supports' =&gt; array( 'title', 'editor', 'thumbnail', 'comments' ),
		'capability_type' =&gt; 'post',
		'rewrite' =&gt; array(&quot;slug&quot; =&gt; &quot;event&quot;), // Permalinks format
		'menu_position' =&gt; 5,
		'menu_icon' =&gt; plugin_dir_url( __FILE__ ) . '/images/calendar-icon.gif',  // Icon Path
		'has_archive' =&gt; true
	);
	register_post_type( 'event', $args );
}
add_action( 'init', 'ep_eventposts' );
</pre><h3>The Metaboxes</h3><p><img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2011/11/event-metaboxes.gif" alt="" title="event-metaboxes" width="309" height="281" class="alignright size-full wp-image-1938" />For the user to be able to select an event start time or event end time, you&#8217;ll need to define a couple meta boxes.  My example puts two metaboxes in the right side of the post, and one for location under the main editor.</p><p>I&#8217;ve written other <a
href="http://wptheming.com/2010/08/custom-metabox-for-post-type/">tutorials about metaboxes</a> if you need a more in-depth overview.</p><p>This is a long code snippet, but the basic idea is that we get the current time and populate the metaboxes of a fresh post with that.  When someone saves a post, it checks that they have permissions to edit, and then overwrites the metabox data if it has changed.</p><pre class="brush: php; title: ; notranslate">
/**
 * Adds event post metaboxes for start time and end time
 * http://codex.wordpress.org/Function_Reference/add_meta_box
 *
 * We want two time event metaboxes, one for the start time and one for the end time.
 * Two avoid repeating code, we'll just pass the $identifier in a callback.
 * If you wanted to add this to regular posts instead, just swap 'event' for 'post' in add_meta_box.
 */
function ep_eventposts_metaboxes() {
	add_meta_box( 'ept_event_date_start', 'Start Date and Time', 'ept_event_date', 'event', 'side', 'default', array( 'id' =&gt; '_start') );
	add_meta_box( 'ept_event_date_end', 'End Date and Time', 'ept_event_date', 'event', 'side', 'default', array('id'=&gt;'_end') );
	add_meta_box( 'ept_event_location', 'Event Location', 'ept_event_location', 'event', 'normal', 'default', array('id'=&gt;'_end') );
}
add_action( 'admin_init', 'ep_eventposts_metaboxes' );
// Metabox HTML
function ept_event_date($post, $args) {
	$metabox_id = $args['args']['id'];
	global $post, $wp_locale;
	// Use nonce for verification
	wp_nonce_field( plugin_basename( __FILE__ ), 'ep_eventposts_nonce' );
	$time_adj = current_time( 'timestamp' );
	$month = get_post_meta( $post-&gt;ID, $metabox_id . '_month', true );
	if ( empty( $month ) ) {
		$month = gmdate( 'm', $time_adj );
	}
	$day = get_post_meta( $post-&gt;ID, $metabox_id . '_day', true );
	if ( empty( $day ) ) {
		$day = gmdate( 'd', $time_adj );
	}
	$year = get_post_meta( $post-&gt;ID, $metabox_id . '_year', true );
	if ( empty( $year ) ) {
		$year = gmdate( 'Y', $time_adj );
	}
	$hour = get_post_meta($post-&gt;ID, $metabox_id . '_hour', true);
    if ( empty($hour) ) {
        $hour = gmdate( 'H', $time_adj );
    }
    $min = get_post_meta($post-&gt;ID, $metabox_id . '_minute', true);
    if ( empty($min) ) {
        $min = '00';
    }
	$month_s = '&lt;select name=&quot;' . $metabox_id . '_month&quot;&gt;';
	for ( $i = 1; $i &lt; 13; $i = $i +1 ) {
		$month_s .= &quot;\t\t\t&quot; . '&lt;option value=&quot;' . zeroise( $i, 2 ) . '&quot;';
		if ( $i == $month )
			$month_s .= ' selected=&quot;selected&quot;';
		$month_s .= '&gt;' . $wp_locale-&gt;get_month_abbrev( $wp_locale-&gt;get_month( $i ) ) . &quot;&lt;/option&gt;\n&quot;;
	}
	$month_s .= '&lt;/select&gt;';
	echo $month_s;
	echo '&lt;input type=&quot;text&quot; name=&quot;' . $metabox_id . '_day&quot; value=&quot;' . $day  . '&quot; size=&quot;2&quot; maxlength=&quot;2&quot; /&gt;';
    echo '&lt;input type=&quot;text&quot; name=&quot;' . $metabox_id . '_year&quot; value=&quot;' . $year . '&quot; size=&quot;4&quot; maxlength=&quot;4&quot; /&gt; @ ';
    echo '&lt;input type=&quot;text&quot; name=&quot;' . $metabox_id . '_hour&quot; value=&quot;' . $hour . '&quot; size=&quot;2&quot; maxlength=&quot;2&quot;/&gt;:';
    echo '&lt;input type=&quot;text&quot; name=&quot;' . $metabox_id . '_minute&quot; value=&quot;' . $min . '&quot; size=&quot;2&quot; maxlength=&quot;2&quot; /&gt;';
}
function ept_event_location() {
	global $post;
	// Use nonce for verification
	wp_nonce_field( plugin_basename( __FILE__ ), 'ep_eventposts_nonce' );
	// The metabox HTML
	$event_location = get_post_meta( $post-&gt;ID, '_event_location', true );
	echo '&lt;label for=&quot;_event_location&quot;&gt;Location:&lt;/label&gt;';
	echo '&lt;input type=&quot;text&quot; name=&quot;_event_location&quot; value=&quot;' . $event_location  . '&quot; /&gt;';
}
// Save the Metabox Data
function ep_eventposts_save_meta( $post_id, $post ) {
	if ( defined( 'DOING_AUTOSAVE' ) &amp;&amp; DOING_AUTOSAVE )
		return;
	if ( !isset( $_POST['ep_eventposts_nonce'] ) )
		return;
	if ( !wp_verify_nonce( $_POST['ep_eventposts_nonce'], plugin_basename( __FILE__ ) ) )
		return;
	// Is the user allowed to edit the post or page?
	if ( !current_user_can( 'edit_post', $post-&gt;ID ) )
		return;
	// OK, we're authenticated: we need to find and save the data
	// We'll put it into an array to make it easier to loop though
	$metabox_ids = array( '_start', '_end' );
	foreach ($metabox_ids as $key ) {
	    $aa = $_POST[$key . '_year'];
		$mm = $_POST[$key . '_month'];
		$jj = $_POST[$key . '_day'];
		$hh = $_POST[$key . '_hour'];
		$mn = $_POST[$key . '_minute'];
		$aa = ($aa &lt;= 0 ) ? date('Y') : $aa;
		$mm = ($mm &lt;= 0 ) ? date('n') : $mm;
		$jj = sprintf('%02d',$jj);
		$jj = ($jj &gt; 31 ) ? 31 : $jj;
		$jj = ($jj &lt;= 0 ) ? date('j') : $jj;
		$hh = sprintf('%02d',$hh);
		$hh = ($hh &gt; 23 ) ? 23 : $hh;
		$mn = sprintf('%02d',$mn);
		$mn = ($mn &gt; 59 ) ? 59 : $mn;
		$events_meta[$key . '_year'] = $aa;
		$events_meta[$key . '_month'] = $mm;
		$events_meta[$key . '_day'] = $jj;
		$events_meta[$key . '_hour'] = $hh;
		$events_meta[$key . '_minute'] = $mn;
	    $events_meta[$key . '_eventtimestamp'] = $aa . $mm . $jj . $hh . $mn;
        }
	// Add values of $events_meta as custom fields
	foreach ( $events_meta as $key =&gt; $value ) { // Cycle through the $events_meta array!
		if ( $post-&gt;post_type == 'revision' ) return; // Don't store custom data twice
		$value = implode( ',', (array)$value ); // If $value is an array, make it a CSV (unlikely)
		if ( get_post_meta( $post-&gt;ID, $key, FALSE ) ) { // If the custom field already has a value
			update_post_meta( $post-&gt;ID, $key, $value );
		} else { // If the custom field doesn't have a value
			add_post_meta( $post-&gt;ID, $key, $value );
		}
		if ( !$value ) delete_post_meta( $post-&gt;ID, $key ); // Delete if blank
	}
}
add_action( 'save_post', 'ep_eventposts_save_meta', 1, 2 );
/**
 * Helpers to display the date on the front end
 */
// Get the Month Abbreviation
function eventposttype_get_the_month_abbr($month) {
    global $wp_locale;
    for ( $i = 1; $i &lt; 13; $i = $i +1 ) {
                if ( $i == $month )
                    $monthabbr = $wp_locale-&gt;get_month_abbrev( $wp_locale-&gt;get_month( $i ) );
                }
    return $monthabbr;
}
// Display the date
function eventposttype_get_the_event_date() {
    global $post;
    $eventdate = '';
    $month = get_post_meta($post-&gt;ID, '_month', true);
    $eventdate = eventposttype_get_the_month_abbr($month);
    $eventdate .= ' ' . get_post_meta($post-&gt;ID, '_day', true) . ',';
    $eventdate .= ' ' . get_post_meta($post-&gt;ID, '_year', true);
    $eventdate .= ' at ' . get_post_meta($post-&gt;ID, '_hour', true);
    $eventdate .= ':' . get_post_meta($post-&gt;ID, '_minute', true);
    echo $eventdate;
}
</pre><h3>Displaying Event Posts on Archive Pages</h3><p>To display event posts on archive pages you should run a pre_get_posts filter (<a
href="http://wptheming.com/2011/11/event-posts-in-wordpress/comment-page-1/#comment-17038">hat tip to Bill Erickson</a>).  This example filter will display the event posts five per page, sorted by their _start_eventtimestamp meta key in ascending order, and only display posts that have a start time that is later than the current time.</p><p>The following code could be placed in functions.php.  For the example plugin, it&#8217;s already in event-posts.php.</p><pre class="brush: php; title: ; notranslate">
/**
 * Customize Event Query using Post Meta
 *
 * @link http://www.billerickson.net/customize-the-wordpress-query/
 * @param object $query data
 *
 */
function ep_event_query( $query ) {
	// http://codex.wordpress.org/Function_Reference/current_time
	$current_time = current_time('mysql');
	list( $today_year, $today_month, $today_day, $hour, $minute, $second ) = split( '([^0-9])', $current_time );
	$current_timestamp = $today_year . $today_month . $today_day . $hour . $minute;
	global $wp_the_query;
	if ( $wp_the_query === $query &amp;&amp; !is_admin() &amp;&amp; is_post_type_archive( 'event' ) ) {
		$meta_query = array(
			array(
				'key' =&gt; '_start_eventtimestamp',
				'value' =&gt; $current_timestamp,
				'compare' =&gt; '&gt;'
			)
		);
		$query-&gt;set( 'meta_query', $meta_query );
		$query-&gt;set( 'orderby', 'meta_value_num' );
		$query-&gt;set( 'meta_key', '_start_eventtimestamp' );
		$query-&gt;set( 'order', 'ASC' );
		$query-&gt;set( 'posts_per_page', '5' );
	}
}
add_action( 'pre_get_posts', 'ep_event_query' );
</pre><h3>Other Queries</h3><p>If you just wanted to display the event posts in the sidebar or on a different template (and not worry about paging), you could do something like this:</p><pre class="brush: php; title: ; notranslate">
 $args = array( 'post_type' =&gt; 'event',
'meta_key' =&gt; '_start_eventtimestamp',
'orderby'=&gt; 'meta_value_num',
'order' =&gt; 'ASC',
'posts_per_page' =&gt; 20,
 );
 $events = new WP_Query( $args );
if ( $events-&gt;have_posts() ) :
	echo '&lt;ul&gt;';
	while ( $events-&gt;have_posts() ) : $events-&gt;the_post();
		echo '&lt;li&gt;&lt;a href=&quot;' . get_permalink() . '&quot;&gt;' . get_the_title() . '&lt;/a&gt;&lt;/li&gt;';
	endwhile;
	echo '&lt;/ul&gt;';
endif;
</pre><h3>Extending</h3><p>This tutorial isn&#8217;t meant to be a full-fledged plugin- just an example to get you started.  Several improvements could be made, such as using a jquery datepicker to select the date (or even just making sure you end time is after your start time and a valid date).  If your primary users are in the United States or other countries on a 12-hour clock, you might want to use an AM/PM selector.</p><p>If you&#8217;re interested in learning more, check out <a
href="http://www.noeltock.com/web-design/wordpress/custom-post-types-events-pt1/">Noel Tock&#8217;s excellent events tutorial</a> which covers some of these examples.</p> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2011/11/event-posts-in-wordpress/feed/</wfw:commentRss> <slash:comments>23</slash:comments> </item> <item><title>Cleaning Up the TimThumb Hack</title><link>http://wptheming.com/2011/08/cleaning-up-the-timthumb-hack/</link> <comments>http://wptheming.com/2011/08/cleaning-up-the-timthumb-hack/#comments</comments> <pubDate>Sat, 27 Aug 2011 22:55:59 +0000</pubDate> <dc:creator>Devin</dc:creator> <category><![CDATA[Tutorials]]></category> <guid
isPermaLink="false">http://wptheming.com/?p=1750</guid> <description><![CDATA[Several of my websites were hacked this last week using the TimThumb exploit.  Here's instructions on how to find the files and replace them- and also the process I used for patching up my sites after the hack.]]></description> <content:encoded><![CDATA[<div
id="attachment_1759" class="wp-caption alignright" style="width: 310px"><img
src="http://wptheming.wpengine.netdna-cdn.com/wp-content/uploads/2011/08/tim-300x176.jpg" alt="" title="tim" width="300" height="176" class="size-medium wp-image-1759" /><p
class="wp-caption-text">Tim Thumb Hacker</p></div><p>Several of my websites were hacked this week using the TimThumb exploit.  The issue has been <a
href="http://markmaunder.com/2011/08/02/technical-details-and-scripts-of-the-wordpress-timthumb-php-hack/">known for a couple weeks</a> now.</p><p>Although I had updated the majority of sites and had notified former clients, I still hadn&#8217;t gotten to some of the smaller sites yet- like my <a
href="http://food.lainehardy.com">girlfriend&#8217;s food blog</a>.</p><p>And word to the wise, your girlfriend&#8217;s food blog should always be top priority.</p><p>Hackers are using a variety of techniques to hijack WordPress sites right now, but this is how I cleaned up the ones on my server.<br
/> <span
id="more-1750"></span></p><h3>Make Backup of Everything</h3><p>Common sense, but worth mentioning again.  You never know when you might accidentally delete a directory you need or wipe part of the database.  Most cPanels wills let you easily export a copy of the database.  And it&#8217;s a lot easier to download a second copy or your files then rebuild them all from scratch.</p><h3>Get Shell Access to Your Host</h3><p>If you only have one site, this may not be necessary.  But I have over twenty WordPress installs running on my server and I wanted to find all the files that were compromised and fix them quickly.  Most hosts offer shell access.  With BlueHost, I just had to go into my control panel and enable it.</p><p>Here&#8217;s BlueHost&#8217;s <a
href="https://my.bluehost.com/cgi/help/180">instructions for setting up shell access</a> and for <a
href="https://my.bluehost.com/cgi/help/301">logging in via shell</a>.</p><h3>Fix TimThumb Vulnerability</h3><p>You can download the latest version of TimThumb with the security fixes here: <a
href="http://timthumb.googlecode.com/svn/trunk/timthumb.php">http://timthumb.googlecode.com/svn/trunk/timthumb.php</a> (Just save the file out).</p><p>Replace any instances of TimThumb.php on your server with the new version.  WooThemes used the name &#8220;thumb.php&#8221; for this file, so you should also look for that.</p><p>If you have shell access you can do a quick search to find all instances of timthumb with:</p><pre>
find *  -iname 'timthumb*' -ls
</pre><p>or</p><pre>
find *  -iname 'thumb.php' -ls (for WooTheme versions)
</pre><p>In many cases I found themes that were not being used and just deleted them directly:</p><pre>
rm -rf path/to/theme
</pre><p>Most theme companies have also already released fixes, so you could also get the latest version directly from them and replace your current theme.</p><h3>Clean Up After the Hack</h3><p>DISCLAIMER: I don&#8217;t consider myself to be a security expert, but these are the steps I took to clean up my site.  If anyone else has additional recommendations, please drop them in the comments or post a link.</p><ol><li>I wiped the entire directory of the hacked site since I didn&#8217;t know which files has been added or compromised.</li><li>I changed my database passwords and uploaded a new clean version of WordPress with a fresh wp-config.php file.</li><p>If you&#8217;re using shell this is very quick (<a
href="http://codex.wordpress.org/Installing_WordPress">http://codex.wordpress.org/Installing_WordPress</a>):<br/></p><pre>
wget http://wordpress.org/latest.tar.gz
tar -xzvf latest.tar.gz
</pre></li><li>I manually checked my backed-up &#8220;wp-content&#8221; to make sure no odd new files had been added.  I specifically checked for files that other folks have reported as being exploited, like:<pre>
/wp-content/uploads/feed-file.php
/wp-content/uploads/feed-files.php
/wp-content/themes/******/cache/.htaccess
</pre><p>The file in my case was:</p><pre>
/wp-content/data.php
</pre><p>There&#8217;s an excellent post that goes into the hacking methods in more detail and suggests other files to check at: <a
href="http://redleg-redleg.blogspot.com/2011/08/malware-hosted-newportalsecom.html">http://redleg-redleg.blogspot.com/2011/08/malware-hosted-newportalsecom.html</a></li><li>I also grepped the backed-up &#8220;wp-content&#8221; directory for any files with base64_decode.  There are legitimate reasons to have base64_decode in a file, but if you don&#8217;t know where the file came from, or what it does, find out.<p>Here&#8217;s how you grep a directory:</p><pre>grep -r base64_decode *</pre><p>If you want to grep your entire server, try</p><pre>grep -r --exclude={wp-app.php,class-simplepie.php,class-IXR.php} base64_decode *</pre></li><li>When I was reasonably confident my backup wp-content directory was clean, I re-uploaded it.</li><li>I reset my <a
href="http://codex.wordpress.org/Hardening_WordPress#File_permissions">file permissions as specified by WordPress</a> in the codex</li><li>I logged back into WordPress and reset the admin passwords.</li><li>I reset my permalinks to be completely sure the htaccess was overwritten.</li></ol><h3>Anything I Missed?</h3><p>If anyone else has other suggestions or recommendations, please post them below.</p><p>And please update <strong>ALL</strong> sites that might have the TimThumb vulnerability.  Your girlfriend will thank you.</p> ]]></content:encoded> <wfw:commentRss>http://wptheming.com/2011/08/cleaning-up-the-timthumb-hack/feed/</wfw:commentRss> <slash:comments>15</slash:comments> </item> </channel> </rss>
