<?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>Keighl</title>
	<atom:link href="http://www.keighl.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.keighl.com</link>
	<description>I provide creative web solutions for all kinds of people.</description>
	<lastBuildDate>Mon, 22 Feb 2010 16:28:41 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Limiting Dates on Two jQuery Datepickers</title>
		<link>http://www.keighl.com/2010/02/limiting-dates-on-two-jquery-datepickers/</link>
		<comments>http://www.keighl.com/2010/02/limiting-dates-on-two-jquery-datepickers/#comments</comments>
		<pubDate>Thu, 04 Feb 2010 04:53:08 +0000</pubDate>
		<dc:creator>Keighl</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[datepicker]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[jquery ui]]></category>
		<category><![CDATA[minDate]]></category>

		<guid isPermaLink="false">http://www.keighl.com/?p=1425</guid>
		<description><![CDATA[Using two jQuery UI Datepickers, how to limit the second calendar so the end cannot come before the beginning. ]]></description>
			<content:encoded><![CDATA[<p>I just ran into a scenario where I had two separate jQuery UI datepickers, and needed to have the first calendar limit the date choices of the second. Essentially a start date and end date. It doesn&#8217;t take a degree in relational physics to know that the end cannot come before the beginning; therefore, anything before the date the user chooses in the first calendar needs to be unavailable in the second calendar. </p>
<pre class="brush: jscript;">
jQuery(document).ready(function($) {

	$('#start').datepicker({
		dateFormat: &quot;@&quot;,
		onSelect: function(dateText, inst) {
			dateText = eval(dateText);
			var min = new Date();
			min.setTime(dateText);
			$('#end').datepicker('option', 'minDate', min);
		}

	});

	$('#end').datepicker({
		dateFormat: &quot;@&quot;,
	});

});
</pre>
<p>It&#8217;s as easy as that. </p>
<p>However, if you&#8217;re localizing this script to the island from <em>Lost</em>, I cannot guarantee that start date will be there in the first place.  </p>
]]></content:encoded>
			<wfw:commentRss>http://www.keighl.com/2010/02/limiting-dates-on-two-jquery-datepickers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Polling WordPress Users on Calendar Functionality</title>
		<link>http://www.keighl.com/2010/01/polling-wordpress-users-on-calendar-functionality/</link>
		<comments>http://www.keighl.com/2010/01/polling-wordpress-users-on-calendar-functionality/#comments</comments>
		<pubDate>Sun, 31 Jan 2010 21:20:54 +0000</pubDate>
		<dc:creator>Keighl</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[calendar]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.keighl.com/?p=1407</guid>
		<description><![CDATA[In preparation for a new calendar plugin, I need to know how people like their calendars. Let me know!]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m in the process of developing a(nother) events calendar plugin for WordPress. I&#8217;m trying to get a feel for the optimal UX; I realize that people like to go about things in various ways on their WordPress installments, and I want this plugin to be a natural fit into the way a blog is normally operated &#8230; not by some grizzly multi-page addition to the interface.</p>
<p>There are a handle-full of questions I&#8217;m dealing with. The most important, is &#8220;how do users prefer to post events?&#8221; There are two general ways I can imagine a plugin going about this one:</p>
<ul>
<li>Create an event from a specific post</li>
<li>Create a discrete event, separate from the posts &#8230; with the option of linking to a post.</li>
</ul>
<p>The database architecture would be very different <code>foreach()</code> of these scenarios. I think that the second would allow for more control over the calendar itself. For instance, if the calendar features events from all over the place (not your blog), the first scenario would require you to make a post for it anyway. With discrete events, you could feature events without an associated post.</p>
<p>However, a very intimate relationship between events and posts is probably what most users would expect from a &#8216;native&#8217; WordPress event function.</p>
<p>Of course, there could be both &#8230; but that would mean, in theory, two separate ways to go about posting events. It could be a few too many avenues for reaching the same goal. Also, that would be a pain for me to document.</p>
<p>If you&#8217;ve got a second, please tell me what you think.</p>
<script type='text/javascript' language='javascript' charset='utf-8' src='http://s3.polldaddy.com/p/2625505.js'></script><noscript> <a href='http://answers.polldaddy.com/poll/2625505/'>View Poll</a></noscript>
<script type='text/javascript' language='javascript' charset='utf-8' src='http://s3.polldaddy.com/p/2625532.js'></script><noscript> <a href='http://answers.polldaddy.com/poll/2625532/'>View Poll</a></noscript>
<script type='text/javascript' language='javascript' charset='utf-8' src='http://s3.polldaddy.com/p/2625535.js'></script><noscript> <a href='http://answers.polldaddy.com/poll/2625535/'>View Poll</a></noscript>
]]></content:encoded>
			<wfw:commentRss>http://www.keighl.com/2010/01/polling-wordpress-users-on-calendar-functionality/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Using Thickbox in WordPress Plugins</title>
		<link>http://www.keighl.com/2010/01/using-thickbox-in-wordpress-plugins/</link>
		<comments>http://www.keighl.com/2010/01/using-thickbox-in-wordpress-plugins/#comments</comments>
		<pubDate>Wed, 27 Jan 2010 18:04:27 +0000</pubDate>
		<dc:creator>Keighl</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[thickbox]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.keighl.com/?p=1374</guid>
		<description><![CDATA[How to use Thickbox in a WordPress plugin; covers loading Thickbox and using jQuery to make it awesome.  ]]></description>
			<content:encoded><![CDATA[<p>I have a few qualms about the reliance on Thickbox in the WordPress admin interface. As a plugin developer, I use the modal-box method frequently; it&#8217;s great for handling all kinds of data asynchronously &#8230; without page refreshes. They keep your file quantities down, and WordPress users are already familiar with how they work.</p>
<p>However, Thickbox is becoming a little antiquated:</p>
<ul>
<li>It&#8217;s no longer maintained (http://jquery.com/demo/thickbox/)</li>
<li>In the WordPress context, it uses annoying $_GET variables to pass data</li>
</ul>
<p>Now that the <a href="http://wordpress.org/development/2010/01/2010-open-source-design/" target="_blank">WordPress interface is being brought towards a more open source model</a>, I hope this is one of things they change. I&#8217;d like to see more integration of the <a href="http://jqueryui.com/demos/dialog/" target="_blank">jQuery UI Dialog widget</a>.</p>
<p>Regardless, Thickbox is how it works now; so here&#8217;s how to use it in a plugin.</p>
<h3>Concept</h3>
<p>The most frequent use (I&#8217;m saying this with no evidence to support my claim) of any modal box in a plugin is to <em>do something</em> without navigating to another page. For instance, you upload an image through a Thickbox; the page stays current, but an image is uploaded asynchronously through the modal-box.</p>
<p>For this example, let&#8217;s imagine that it is necessary for a user to decide something: black or white? We want them to open a box, decide, and close the box all from the plugin&#8217;s interface.</p>
<h3>General Plugin Setup</h3>
<pre class="brush: php;">
&lt;?php
/*
Plugin Name: Black or White?
Plugin URI: http://www.example.com/
Description: You choose.
Version: 0.1
Author: Kyle Truscott
Author URI: http://www.keighl.com
*/

$BlackOrWhite = new BlackOrWhite();

class BlackOrWhite {

	function BlackOrWhite() {
		add_action('admin_menu', array(&amp;$this, 'add_admin'));
		add_action(&quot;admin_print_scripts&quot;, array(&amp;$this, 'js_libs'));
		add_action(&quot;admin_print_styles&quot;, array(&amp;$this, 'style_libs'));
	}

	function add_admin() {
		add_theme_page('BlackOrWhite', 'BlackOrWhite', 'administrator', 'black-or-white', array(&amp;$this, 'admin_view'));
	}

	function js_libs() {
		wp_enqueue_script('jquery');
		wp_enqueue_script('thickbox');
	}

	function style_libs() {
		wp_enqueue_style('thickbox');
	}

	function admin_view() {}

	function choice() {}

}
?&gt;
</pre>
<p>Fairly normal. In order to use Thickbox, you need to queue both the script and style respectively. WordPress has these pre-registered for us, so all we need to do is tell it to load with <code>wp_enqueue_script()</code> and <code>wp_enqueue_style()</code> from the constructor.</p>
<h3>Calling the Thickbox Dialog</h3>
<p>In order to actually have the modal-box pop up, it is necessary to do so through the <code>href</code> parameter of a link. This is where it gets ugly.</p>
<pre class="brush: php;">
function admin_view() {
	?&gt;
	&lt;div class=&quot;wrap&quot;&gt;
		&lt;h2&gt;Black or White?&lt;/h2&gt;
		&lt;p&gt;
			&lt;a class=&quot;thickbox button&quot; href=&quot;&lt;?php echo get_option('siteurl'); ?&gt;/wp-admin/admin-ajax.php?action=choice&amp;width=150&amp;height=100&quot; title=&quot;Choice&quot;&gt;
				Choice
			&lt;/a&gt;
		&lt;/p&gt;
		&lt;p&gt;
			Your choice: &lt;span class=&quot;your-choice&quot;&gt;&lt;/span&gt;
		&lt;/p&gt;
	&lt;/div&gt;
	&lt;?php
}
</pre>
<p>You need to :</p>
<ul>
<li>Declare &#8220;thickbox&#8221; as one of the link&#8217;s classes (&#8220;button&#8221; is nice too)</li>
<li>Direct the link to: <code>&lt;?php echo get_option('siteurl'); ?&gt;/wp-admin/admin-ajax.php?</code></li>
<li>Give it the following $_GET variables
<ul>
<li><strong>action</strong> &#8211; tells WordPress how to handle the AJAX request, or what stuff to load into the Thickbox</li>
<li><strong>width</strong> &#8211; the dialog&#8217;s width in pixels</li>
<li><strong>height</strong> &#8211; the dialog&#8217;s height in pixels</li>
</ul>
</li>
</ul>
<p>The reason for passing the AJAX request through admin-ajax.php is so we can call one of our plugin functions &#8230; the one for the dialog box content. Back in the constructor, simply tell WordPress to which function it should redirect the AJAX request.</p>
<pre class="brush: php;">
function BlackOrWhite() {
 add_action('admin_menu', array(&amp;$this, 'add_admin'));
 add_action(&quot;admin_print_scripts&quot;, array(&amp;$this, 'js_libs'));
 add_action(&quot;admin_print_styles&quot;, array(&amp;$this, 'style_libs'));

 add_action('wp_ajax_choice', array(&amp;$this, 'choice'));
}
</pre>
<p>Now, when the user clicks &#8220;Choose&#8221;, whatever we have stored in choice() will return within the box.</p>
<h3>In the Thickbox</h3>
<p>So far so good, but there is nothing in the modal-box. We need two buttons: <strong>black </strong>and <strong>white</strong>. The dialog box displays whatever is returned from <code>choice()</code>. Therefore, that&#8217;s where the buttons go.</p>
<pre class="brush: php;">
function choice() {
	?&gt;
	&lt;p&gt;
		&lt;a class=&quot;button choice_button&quot; id=&quot;Black&quot;&gt;Black&lt;/a&gt;
		&lt;a class=&quot;button choice_button&quot; id=&quot;White&quot;&gt;White&lt;/a&gt;
	&lt;/p&gt;
	&lt;?php
	exit();
}
</pre>
<p>Don&#8217;t forget to <code>exit()</code> the function, or you&#8217;ll get an annoying 0 in the Thickbox. We don&#8217;t have any <code>href</code> info for these links, because we&#8217;ll be handling their events via jQuery. The goal here is to only have one page, right?</p>
<h3>Some jQuery</h3>
<pre class="brush: php;">
function admin_view() {
	?&gt;

	&lt;script type=&quot;text/javascript&quot;&gt;
		jQuery(document).ready(function($) {
			$('.choice_button').live('click',
				function () {
					var choice = $(this).attr('id');
					tb_remove();
					$('.your-choice').html(choice);
				}
			);
		});
	&lt;/script&gt;

	&lt;!-- The rest of the admin view ... --&gt;

	&lt;?php
}
</pre>
<p>On the click event of either <code>choice_button</code>, we execute a function that returns the user&#8217;s choice to the main interface.  Use the <code>live()</code> method to bind the event, because the buttons were loaded via AJAX.</p>
<p>Removing the Thickbox is much easier than launching it &#8230; simply call the <code>tb_remove()</code> function.</p>
<h3>Conclusion</h3>
<p>All in all, using the Thickbox in WordPress plugins is not that hard, but it could certainly be easier.</p>
<p>Download the full tutorial code here: <a href="http://www.keighl.com/wp-content/uploads/black-or-white.php_1.zip">Black or White?</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.keighl.com/2010/01/using-thickbox-in-wordpress-plugins/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>TinyMCE in WordPress Plugins</title>
		<link>http://www.keighl.com/2010/01/tinymce-in-wordpress-plugins/</link>
		<comments>http://www.keighl.com/2010/01/tinymce-in-wordpress-plugins/#comments</comments>
		<pubDate>Tue, 05 Jan 2010 00:47:33 +0000</pubDate>
		<dc:creator>Keighl</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[tinymce]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wp_enqueue_script]]></category>
		<category><![CDATA[wp_tiny_mce]]></category>

		<guid isPermaLink="false">http://www.keighl.com/?p=1293</guid>
		<description><![CDATA[In order to use TinyMCE from a WordPress plugin, use wp_tiny_mce(), and override the defaults. ]]></description>
			<content:encoded><![CDATA[<p>Unlike some of the other JavaScript assets available to plugin developers through <a href="http://codex.wordpress.org/Function_Reference/wp_enqueue_script"><code>wp_enqueue_script()</code></a>, getting <a href="http://tinymce.moxiecode.com/">TinyMCE</a> to function in your plugin is a little different. You would perhaps expect to use it like this:</p>
<pre class="brush: php; html-script: true;">
&lt;?php
add_action(&quot;admin_print_scripts&quot;, &quot;js_libs&quot;);

function js_libs() {
     wp_enqueue_script('tiny_mce');
}
?&gt;
</pre>
<pre class="brush: jscript; html-script: true;">
&lt;script type=&quot;text/javascript&quot;&gt;

	tinyMCE.init({
		mode : &quot;exact&quot;,
		elements: &quot;a_nice_textarea&quot;,
		theme : &quot;simple&quot;
	});

&lt;/script&gt;
</pre>
<pre class="brush: xml;">
&lt;textarea id=&quot;a_nice_textarea&quot; name=&quot;a_nice_textarea&quot;&gt;&lt;/textarea&gt;
</pre>
<p>However, enqueuing the TinyMCE really won&#8217;t get you any results. You need to use the <code>wp_tiny_mce()</code> function, which is not well documented. Essentially, the function pre-constructs the TinyMCE for you, and you override its default options. The main option to override is <code>editor_selector</code> which points TinyMCE at a specific textarea <code><strong>class</strong></code>.</p>
<pre class="brush: php; html-script: true;">
&lt;?php
wp_tiny_mce( false , // true makes the editor &quot;teeny&quot;
	array(
		&quot;editor_selector&quot; =&gt; &quot;a_nice_textarea&quot;
	)
);
?&gt;

&lt;textarea class=&quot;a_nice_textarea&quot; id=&quot;a_nice_textarea&quot; name=&quot;a_nice_textarea&quot;&gt;&lt;/textarea&gt;
</pre>
<p>You can stick this anywhere you want, and it will work (for the most part). All the available configuration options for TinyMCE can be determined by referencing it within the array. WordPress has a bunch of them determined by default for the post content editor; most of them are fine as is.</p>
<pre class="brush: php;">
// TinyMCE init settings
$initArray = array (
	'mode' =&gt; 'none',
	'onpageload' =&gt; 'switchEditors.edInit',
	'width' =&gt; '100%',
	'theme' =&gt; 'advanced',
	'skin' =&gt; 'wp_theme',
	'theme_advanced_buttons1' =&gt; &quot;$mce_buttons&quot;,
	'theme_advanced_buttons2' =&gt; &quot;$mce_buttons_2&quot;,
	'theme_advanced_buttons3' =&gt; &quot;$mce_buttons_3&quot;,
	'theme_advanced_buttons4' =&gt; &quot;$mce_buttons_4&quot;,
	'language' =&gt; &quot;$mce_locale&quot;,
	'spellchecker_languages' =&gt; &quot;$mce_spellchecker_languages&quot;,
	'theme_advanced_toolbar_location' =&gt; 'top',
	'theme_advanced_toolbar_align' =&gt; 'left',
	'theme_advanced_statusbar_location' =&gt; 'bottom',
	'theme_advanced_resizing' =&gt; true,
	'theme_advanced_resize_horizontal' =&gt; false,
	'dialog_type' =&gt; 'modal',
	'relative_urls' =&gt; false,
	'remove_script_host' =&gt; false,
	'convert_urls' =&gt; false,
	'apply_source_formatting' =&gt; false,
	'remove_linebreaks' =&gt; true,
	'paste_convert_middot_lists' =&gt; true,
	'paste_remove_spans' =&gt; true,
	'paste_remove_styles' =&gt; true,
	'gecko_spellcheck' =&gt; true,
	'entities' =&gt; '38,amp,60,lt,62,gt',
	'accessibility_focus' =&gt; true,
	'tab_focus' =&gt; ':prev,:next',
	'content_css' =&gt; &quot;$mce_css&quot;,
	'save_callback' =&gt; 'switchEditors.saveCallback',
	'wpeditimage_disable_captions' =&gt; $no_captions,
	'plugins' =&gt; &quot;$plugins&quot;
);
</pre>
<p>For a closer look at <code>wp_tiny_mce()</code>, <a href="http://core.trac.wordpress.org/browser/trunk/wp-admin/includes/post.php">check out the source</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keighl.com/2010/01/tinymce-in-wordpress-plugins/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>ExpressionEngine: Filter Access By Member Join Date</title>
		<link>http://www.keighl.com/2009/11/expressionengine-filter-access-by-member-join-date/</link>
		<comments>http://www.keighl.com/2009/11/expressionengine-filter-access-by-member-join-date/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 16:54:46 +0000</pubDate>
		<dc:creator>Keighl</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[expression engine]]></category>
		<category><![CDATA[member join date]]></category>

		<guid isPermaLink="false">http://www.keighl.com/?p=1226</guid>
		<description><![CDATA[Restrict access to data based on a member's join date with ExpressionEngine. Works for all kinds of stuff ... even calendars. ]]></description>
			<content:encoded><![CDATA[<p>Depending on the nature of your content within <a href="http://expressionengine.com/">ExpressionEngine</a>, you may want to discriminate member access to entries based upon when they were registered. For instance, if they pay for the information, you don&#8217;t want them to see backlog entries for free! Unfortunately, EE doesn&#8217;t have an easy global variable for join date; however, a member&#8217;s join date is stored in the database (table <code>exp_members</code>, column <code>join_date</code>), so it is still available for our use. </p>
<p>This process can be done on any template. First, we need to procure the member&#8217;s id number, with which we can filter the database. There is a global variable for this, <code>{member_id}</code>, but it becomes rather unstable when used in conditionals and database queries. I find it easier to simply grab the <code>$SESS</code> data. Make sure the <a href="http://expressionengine.com/docs/templates/php_templates.html">PHP parsing stage is set to <strong>input</strong></a>. </p>
<pre class="brush: php;">
&lt;?php
global $SESS;
$member_id = $SESS-&gt;userdata['member_id'];
?&gt;
</pre>
<p>With this info we can query the database, and use a conditional statement to filter the members&#8217; access. If their join date is after the entry&#8217;s date, we shut them down. </p>
<pre class="brush: php; html-script: true;">
{exp:weblog:entries orderby=&quot;date&quot; sort=&quot;desc&quot; limit=&quot;1&quot;}

	{exp:query sql=&quot;SELECT join_date FROM exp_members WHERE member_id = '&lt;?php echo $member_id; ?&gt;'&quot;}

	    {if {entry_date} &gt; {join_date} }

	        You get what you pay for!

			&lt;!-- EE Entry Data ... --&gt;

	    {if:else}

			Forget about it.  

	    {/if}

	{/exp:query}

{/exp:weblog:entries}
</pre>
<h5>Calendar</h5>
<p>The same principles, as applied above, can be used within an AJAX-ified mini-calendar. <a href="http://www.keighl.com/2009/11/expressionengine-dynamic-calendar-using-jquery/">Check out my post on the matter, because the following code builds upon it</a>.</p>
<p>From within the <code>{if_entries}</code> bit of the calendar tag, you can filter the links by the same method of querying the database with the member&#8217;s id. If their join date is after the entry, they don&#8217;t see a link. </p>
<pre class="brush: php; html-script: true;">
&lt;?php

$weblog =  $_POST['weblog'];

if (isset($_POST['month'])) :
	$month = $_POST['month'];
	$year = $_POST['year'];
else :
	$month = date('m');
	$year = date('Y');
endif;

global $SESS;
$member_id = $SESS-&gt;userdata['member_id'];

?&gt;

{exp:weblog:calendar weblog=&quot;&lt;?php echo $weblog;?&gt;&quot; switch=&quot;calendarToday|calendarCell&quot; month=&quot;&lt;?php echo $month; ?&gt;&quot; year=&quot;&lt;?php echo $year; ?&gt;&quot;}
    &lt;table class=&quot;calendar&quot; border=&quot;0&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;
    	&lt;tr&gt;
	    	&lt;th class=&quot;calendarHeader&quot;&gt;
		    	&lt;a href=&quot;&quot; alt=&quot;{previous_date format=&quot;%m&quot;}&quot; class=&quot;{previous_date format=&quot;%Y&quot;}&quot;&gt;&amp;lt;&lt;/a&gt;
		    &lt;/th&gt;
	    	&lt;th class=&quot;calendarHeader&quot; colspan=&quot;5&quot;&gt;{date format=&quot;%F %Y&quot;}&lt;/th&gt;
		    &lt;th class=&quot;calendarHeader&quot;&gt;
		    	&lt;a href=&quot;&quot; alt=&quot;{next_date format=&quot;%m&quot;}&quot; class=&quot;{next_date format=&quot;%Y&quot;}&quot;&gt;&amp;gt;&lt;/a&gt;
		    &lt;/th&gt;
		    &lt;/tr&gt;
	    &lt;tr&gt;
	    	{calendar_heading}
		    &lt;td class=&quot;calendarDayHeading&quot;&gt;{lang:weekday_abrev}&lt;/td&gt;
		    {/calendar_heading}
	    &lt;/tr&gt;
	    {calendar_rows }
	    	{row_start}&lt;tr&gt;{/row_start}

				{if entries}
				        {entries}

				            {exp:query sql=&quot;SELECT join_date FROM exp_members WHERE member_id = '&lt;?php echo $member_id; ?&gt;' &quot;}
				                {if {entry_date} &gt; {join_date} }
				                    &lt;td class='{switch} calentry' align='center'&gt;
				                        &lt;a href=&quot;{day_path=&lt;?php echo $weblog;?&gt;/index}&quot;&gt;{day_number}&lt;/a&gt;
				                    &lt;/td&gt;
				                {if:else}
				                    &lt;td class='{switch}' align='center'&gt;
				                        {day_number}
				                    &lt;/td&gt;
				                {/if}

				            {/exp:query}

				        {/entries}
				    {/if}

			    {if blank}
					&lt;td class='calendarBlank'&gt;&amp;nbsp;&lt;/td&gt;
				{/if}
		    {row_end}&lt;/tr&gt;{/row_end}
	    {/calendar_rows}
    &lt;/table&gt;
{/exp:weblog:calendar}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.keighl.com/2009/11/expressionengine-filter-access-by-member-join-date/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ExpressionEngine: Dynamic Calendar Using jQuery</title>
		<link>http://www.keighl.com/2009/11/expressionengine-dynamic-calendar-using-jquery/</link>
		<comments>http://www.keighl.com/2009/11/expressionengine-dynamic-calendar-using-jquery/#comments</comments>
		<pubDate>Tue, 24 Nov 2009 15:48:56 +0000</pubDate>
		<dc:creator>Keighl</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[ajax]]></category>
		<category><![CDATA[calendar]]></category>
		<category><![CDATA[expression engine]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://www.keighl.com/?p=1181</guid>
		<description><![CDATA[Create a dynamic calendar using jQuery for Expression Engine with one template and the $.post() method. Let the people scoll!]]></description>
			<content:encoded><![CDATA[<p><a href="http://expressionengine.com/">ExpressionEngine</a> is a great tool for managing any kind of content. A feature users depend on, regardless of whether the application is a simple blog or otherwise, is a mini-calendar. It enables them to quickly shuffle through archives or posts. Thankfully, EE has a nice built in calendar module known as <a href="http://expressionengine.com/docs/modules/weblog/calendar.html"><code>{exp:weblog:calendar}</code></a>. It&#8217;s great at returning one month&#8217;s worth of links, but cycling through to another month (past or previous) takes the user by default to a respective archive page. Now, the user must shift mental gears, and hunt for the info in a new way; ideally, they should be able to cycle through all the months without leaving the calendar or their current page.</p>
<p>With a little help from <a href="http://jquery.com/">jQuery</a> and AJAX, it&#8217;s not a difficult procedure. Essentially, we will create a separate EE template that dynamically generates a calendar, and load it in to another template passing some <code>$_POST</code> variables. When the users clicks &#8220;Next Month,&#8221; the calendar is regenerated without a page refresh.</p>
<h3>Calendar Template</h3>
<p>First, create a new EE template <code>lib/calendar</code>, or whatever you&#8217;d like to call it. Be sure to set the <a href="http://expressionengine.com/docs/templates/php_templates.html">PHP parsing stage to <strong>input</strong></a>. As you can see, the month, year and weblog parameters for the calendar tag are being dynamically accepted from the <code>$_POST</code> array.</p>
<pre class="brush: php; html-script: true;">

&lt;?php
$weblog =  $_POST['weblog'];
if (isset($_POST['month'])) :
	$month = $_POST['month'];
	$year = $_POST['year'];
else :
	$month = date('m');
	$year = date('Y');
endif;
?&gt;

{exp:weblog:calendar weblog=&quot;&lt;?php echo $weblog;?&gt;&quot; switch=&quot;calendarToday|calendarCell&quot; month=&quot;&lt;?php echo $month; ?&gt;&quot; year=&quot;&lt;?php echo $year; ?&gt;&quot;}
    &lt;table class=&quot;calendar&quot; border=&quot;0&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;
    	&lt;tr&gt;
	    	&lt;th class=&quot;calendarHeader&quot;&gt;
		    	&lt;a href=&quot;&quot; alt=&quot;{previous_date format=&quot;%m&quot;}&quot; class=&quot;{previous_date format=&quot;%Y&quot;}&quot;&gt;&amp;lt;&lt;/a&gt;
		    &lt;/th&gt;
	    	&lt;th class=&quot;calendarHeader&quot; colspan=&quot;5&quot;&gt;{date format=&quot;%F %Y&quot;}&lt;/th&gt;
		    &lt;th class=&quot;calendarHeader&quot;&gt;
		    	&lt;a href=&quot;&quot; alt=&quot;{next_date format=&quot;%m&quot;}&quot; class=&quot;{next_date format=&quot;%Y&quot;}&quot;&gt;&amp;gt;&lt;/a&gt;
		    &lt;/th&gt;
		    &lt;/tr&gt;
	    &lt;tr&gt;
	    	{calendar_heading}
		    &lt;td class=&quot;calendarDayHeading&quot;&gt;{lang:weekday_abrev}&lt;/td&gt;
		    {/calendar_heading}
	    &lt;/tr&gt;
	    {calendar_rows }
	    	{row_start}&lt;tr&gt;{/row_start}
		    	{if entries}
			        {entries}
		                &lt;td class='{switch} calentry' align='center'&gt;
		                    &lt;a href=&quot;{day_path=&lt;?php echo $section;?&gt;/index}&quot;&gt;{day_number}&lt;/a&gt;
		                &lt;/td&gt;
			        {/entries}
			    {/if}
			    {if not_entries}
					&lt;td class='{switch}' align='center'&gt;{day_number}&lt;/td&gt;
				{/if}
			    {if blank}
					&lt;td class='calendarBlank'&gt;&amp;nbsp;&lt;/td&gt;
				{/if}
		    {row_end}&lt;/tr&gt;{/row_end}
	    {/calendar_rows}
    &lt;/table&gt;
{/exp:weblog:calendar}
</pre>
<h3>Javascript</h3>
<p>For the user page, where the calendar is to be displayed, first load the jQuery core. Also, create an empty <code>div</code> with an <code>id</code> of &#8220;calendar&#8221; somewhere on the page.</p>
<pre class="brush: xml; light: true;">

&lt;script type=&quot;text/javascript&quot; src=&quot;http://code.jquery.com/jquery-latest.js&quot;&gt;&lt;/script&gt;
</pre>
<p>Create the calendar functions using jQuery&#8217;s <a href="http://docs.jquery.com/Ajax/jQuery.post"><code>$.post</code></a> method to load the calendar. We send it, via post, the data for the specific month/year we&#8217;d like to display. In parallel, jQuery is on the prowl for links embedded in the calendar; clicking on these links trigger the <code>render_calendar()</code> function again, but this time with new month/year data extracted from the prev/next links we set up in <code>lib/calendar</code>. The data is stored as <code>class</code> and <code>alt</code>; you could store them however you want, though.</p>
<pre class="brush: jscript;">
$(document).ready(function(){

	var weblog = &quot;xxxxxx&quot;;
	var month = xx;
	var year = xxxx;

	render_calendar(section,month,year);

	function render_calendar(section,month,year) {
		$.post(
			&quot;{path='lib/calendar'}&quot;,
			{ weblog : weblog, month : month, year : year },
			function(str) {
				$('#calendar').html(str).fadeIn();
			}
		);
	}

	$(&quot;#calendar a&quot;).live(&quot;click&quot;, function(){
		$('#calendar').fadeOut();
		month = $(this).attr('alt');
		year = $(this).attr('class');
		render_calendar(section,month,year);
	});

});
</pre>
<p>And that&#8217;s it!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keighl.com/2009/11/expressionengine-dynamic-calendar-using-jquery/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>jQuery Corner Plugin on Floated Elements</title>
		<link>http://www.keighl.com/2009/10/jquery-corner-plugin-on-floated-elements/</link>
		<comments>http://www.keighl.com/2009/10/jquery-corner-plugin-on-floated-elements/#comments</comments>
		<pubDate>Thu, 22 Oct 2009 14:26:04 +0000</pubDate>
		<dc:creator>Keighl</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[corner plugin]]></category>
		<category><![CDATA[floated elements]]></category>
		<category><![CDATA[ie]]></category>
		<category><![CDATA[ie bugs]]></category>
		<category><![CDATA[jquery]]></category>
		<category><![CDATA[widths]]></category>

		<guid isPermaLink="false">http://www.keighl.com/?p=1131</guid>
		<description><![CDATA[The Corner Plugin for jQuery is a great little tool to take away the pain of rounding corners with CSS. [...]]]></description>
			<content:encoded><![CDATA[<p>The <a href="http://malsup.com/jquery/corner/">Corner Plugin</a> for <a href="http://jquery.com/">jQuery</a> is a great little tool to take away the pain of rounding corners with CSS. I use it most frequently for dynamically rounded navigation tabs, a feature that most clients want. As opposed to aligning background-images in CSS2, or wrestling with border-radius in CSS3, with the Corner Plugin you can just command any page element to round itself automatically.</p>
<p>As with all things, though, the evil IE6 makes you look like a fool when Corner breaks everything on your painstakingly crafted layout. I&#8217;ve deduced that the main bug with IE is that when applied to floated elements without specified widths, IE corners them as if their widths were 100% of the parent container. So, if you have an unordered list of menu items that are floated left of right, it will look horrible. Unfortunately, this scenario is the most common implementation of menu tabs where the widths are entirely unpredictable.</p>
<p>The solution I discovered was apparent only after I diagnosed that undeclared widths were the root problem. With a little more jQuery, there&#8217;s an easy fix.</p>
<pre class="brush: jscript;">
$(document).ready(function(){ 

	jQuery.each($('.nav ul li'), function() {
	    var width = $(this).width();
		$(this).css({ width:width });
	});

	$('.nav ul li').corner(&quot;3px&quot;);

});
</pre>
<p>Assuming that <code>.nav ul li</code> is something like your floated list, before applying the rounded corners assign each matched element a width. This bit uses the <code>each()</code> selector to go over each list item, measure its width, and then apply that width with CSS. Now, IE6 has a specified width for each element, and you can stop pulling out your hair follicles.</p>
<p>And this idea extends to many other IE problems &#8230; if things are ugly, give them explicit widths.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keighl.com/2009/10/jquery-corner-plugin-on-floated-elements/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Recent Comments Without Plugins</title>
		<link>http://www.keighl.com/2009/09/recent-comments-without-plugins/</link>
		<comments>http://www.keighl.com/2009/09/recent-comments-without-plugins/#comments</comments>
		<pubDate>Sun, 27 Sep 2009 17:33:56 +0000</pubDate>
		<dc:creator>Keighl</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[comments]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[recent comments]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.keighl.com/?p=1073</guid>
		<description><![CDATA[Here&#8217;s a very simple PHP script to make WordPress regurgitate some recent comments without installing any plugins &#8230; good for [...]]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a very simple PHP script to make WordPress regurgitate some recent comments without installing any plugins &#8230; good for doing something very specific within a template or a footer. Within the <code>foreach</code> statement, you can print the array items however you want (list, div, br, etc.). The <code><a href="http://codex.wordpress.org/Function_Reference/get_comments">get_comments()</a></code> function has a handful of parameters that can restrict the comments retrieved. As opposed to messing around with the <code>wp_list_comments()</code> to make it display correctly, I prefer to do this. </p>
<p>I&#8217;ve only listed the array items that I think are typically important, but there are a few more available; there&#8217;s a full list of them <a href="http://codex.wordpress.org/Database_Description#Table:_wp_comments">here</a>. </p>
<pre class="brush: php;">
&lt;?php
	$comments = get_comments();

	foreach($comments as $comment) :

		if ($comment-&gt;comment_approved == 1) : 

			echo $comment-&gt;comment_ID;
			echo $comment-&gt;comment_post_ID;
			echo $comment-&gt;comment_author;
			echo $comment-&gt;comment_author_email;
			echo $comment-&gt;comment_author_url;
			echo $comment-&gt;comment_date;
			echo $comment-&gt;comment_content;

		endif;

	endforeach;
?&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.keighl.com/2009/09/recent-comments-without-plugins/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rebranding WordPress</title>
		<link>http://www.keighl.com/2009/09/rebranding-wordpress/</link>
		<comments>http://www.keighl.com/2009/09/rebranding-wordpress/#comments</comments>
		<pubDate>Fri, 11 Sep 2009 17:10:59 +0000</pubDate>
		<dc:creator>Keighl</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[branding]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[logo]]></category>
		<category><![CDATA[rebranding]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.keighl.com/?p=1062</guid>
		<description><![CDATA[More often than not, I&#8217;m doing custom installations of WordPress for clients so they can control their sites without the [...]]]></description>
			<content:encoded><![CDATA[<p>More often than not, I&#8217;m doing custom installations of <a href="http://wordpress.org">WordPress</a> for clients so they can control their sites without the help of a webmaster. One technique I use routinely is &#8216;rebranding&#8217; the WordPress administration area, which basically involves changing the login logo, and the logo in the upper-left corner of the dashboard. Now, this is nice for my clients, but not so nice for WordPress. Leave the other references to WordPress throughout to the administrative area to give them some love for making their product brandable (is that a word?).</p>
<p>There are only a handful of things that need to change in order to brand the administrative backend with a unique logo.They are:</p>
<p><code>/wp-admin/images/logo-login.gif</code><br />
<code>/wp-admin/images/logo-ghost.png</code><br />
<code>/wp-admin/css/login.css</code></p>
<h5>logo-login.gif</h5>
<p>Replace this image with another logo; this asset is the image you see upon logging in to the dashboard. The image is normally 310&#215;70 pixels. If the new logo has the same dimensions, you won&#8217;t need to alter login.css.</p>
<h5>login.css</h5>
<p>Change the attributes of <code>h1 a</a></code> to fit your new logo if it&#8217;s necessary. Most likely, the <code>height</code> and <code>width</code> attributes are good enough, but you might want to add a <code>margin-bottom</code> too. </p>
<pre class="brush: css;">
h1 a {
	background: url(../images/logo-login.gif) no-repeat top center;
	width: 326px;
	height: 67px;
	text-indent: -9999px;
	overflow: hidden;
	padding-bottom: 15px;
	display: block;
}
</pre>
<h5>logo-ghost.png</h5>
<p>Again, replace this one with your new logo. I would recommend leaving this guy at its current dimensions (<code>25x25</code>). If you have trouble with the transparency factor, fill the background with <code>#464646</code>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keighl.com/2009/09/rebranding-wordpress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using Protected Images in ExpressionEngine</title>
		<link>http://www.keighl.com/2009/08/using-protected-images-expression-engine/</link>
		<comments>http://www.keighl.com/2009/08/using-protected-images-expression-engine/#comments</comments>
		<pubDate>Mon, 03 Aug 2009 15:13:36 +0000</pubDate>
		<dc:creator>Keighl</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[.htaccess]]></category>
		<category><![CDATA[expression engine]]></category>
		<category><![CDATA[gd]]></category>
		<category><![CDATA[images]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[security]]></category>

		<guid isPermaLink="false">http://www.keighl.com/?p=953</guid>
		<description><![CDATA[How to display images from within a protected directory, and mask their real path for better security within ExpressionEngine.]]></description>
			<content:encoded><![CDATA[<p>Another <a href="http://expressionengine.com/" target="_blank">ExpressionEngine</a> challenge arose recently involving how to serve up images in a template that are harbored in a directory protected with .htaccess. For this particular client I&#8217;m working with, EE is managing a vast library of images, and only certain members are allowed to see them. The million dollar question was this: How can we deliver images into a members-only template that are .htaccess protected, and at the same time mask the true path of the images? A kind of two tiered security measure.</p>
<p>First of all, we want the images to be rendered on a template that is only visible to members of group-x. This is done easily within EE from the <a href="http://expressionengine.com/docs/cp/templates/template_access.html" target="_blank">Template Access Restriction</a> section of the control panel.</p>
<p>Typically, this would be good enough for protecting sensitive text content, but leaves images still at risk. A real jerk could look at the tag <code>&lt;img src="./images/confidential.png" /&gt;</code> and point all his internet buddies to the path, or take some other stuff he shouldn&#8217;t have his dirty little fingers on. The biggest hole is the simple <code>&lt;img&gt;</code> tag. So, to be safe we can protect the /images/ director with .htaccess &#8230; but now the upstanding citizens of group-x have to authenticate themselves again with credentials outside of EE to view the images. Annoying.</p>
<p>Here&#8217;s what we do. As long you&#8217;ve got an image library on your server (like GD, or ImageMagik), you can hide the real path to the images, and avoid the separate login box. Instead of an absolute or relative path to the image in the <code>src</code> parameter, just send it to a secret script that creates the image.</p>
<pre class="brush: xml; light: true;">&lt;img src=&quot;{path=lib/image}confidential.png/&quot; /&gt;</pre>
<p>This will output something like this when rendered in EE:</p>
<pre class="brush: xml; light: true;">&lt;img src=&quot;http://www.example.com/lib/image/confidential.png/&quot; /&gt;</pre>
<p>What&#8217;s cool in this case is that the image will generated from within this off-site script; the user cannot know the real location of the image. Better yet, because PHP can access protected directories, the user won&#8217;t be prompted to login via .htaccess. And &#8230; (yes there&#8217;s more) if we created the script as its own template in EE, it can be protected just like the main template so only members of group-x will be able to view it. For outsiders, the image will not be generated. It&#8217;s two-tiered protection.</p>
<pre class="brush: php;">
&lt;?php

$image = &quot;{segment_3}&quot;;
$url_path = &quot;{segment_4}&quot;;

switch ($url_path):

	case &quot;image_bin&quot;:
		$path = '../../photos/';
	break;
	case &quot;espionage&quot;:
		$path = '../../state/secrets/';
	break;
	default:
		exit();
endswitch;

if (is_file($path . $image)) {
    $f = $path . $image;
} else {
	exit();
}

header('Content-type: image/png');

$im = @ImageCreateFromJPEG ($f) or // Read JPEG Image
$im = @ImageCreateFromPNG ($f) or // or PNG Image
$im = @ImageCreateFromGIF ($f) or // or GIF Image
$im = false; // If image is not JPEG, PNG, or GIF

if (!$im) {
    readfile ($f);
} else {
    @ImagePNG($im);
}

?&gt;
</pre>
<p>So now, what does this script look like? If you examine the <code>&lt;img&gt;</code> tag above, you&#8217;ll see that the file name (in this case confidential.gif) is actually being sent to the script as a <a href="http://expressionengine.com/docs/templates/globals/url_segments.html" target="_blank">URI Segment Variable</a> &#8230; not as a relative path. The third segment in the URI is the file name. The segments give a lot of extensibility to this process.</p>
<p>For instance, if there were more than one directory that these images are being pulled from, just slap another segment on that represents the path, without giving it away. So, /confidential.png/image_bin/. In this particular case, I went a step further, and assigned a code name for the directory segment, which is then translated privately from within the script in the <code>switch</code>.</p>
<p>The script takes the info from the URI segments, and spits out an image. It&#8217;s that simple.</p>
<p>What&#8217;s beautiful is that, through using this method, you can protect sensitive images through both permitting only certain member groups and hiding the true directories. Oh, and you can still use .htaccess. Now it sounds more like three-tiered security. Sheesh.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keighl.com/2009/08/using-protected-images-expression-engine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Redirecting Members with ExpressionEngine</title>
		<link>http://www.keighl.com/2009/06/redirecting-members-with-expression-engine/</link>
		<comments>http://www.keighl.com/2009/06/redirecting-members-with-expression-engine/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 03:54:31 +0000</pubDate>
		<dc:creator>Keighl</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[expression engine]]></category>
		<category><![CDATA[global variables]]></category>
		<category><![CDATA[login]]></category>
		<category><![CDATA[member groups]]></category>
		<category><![CDATA[redirect]]></category>

		<guid isPermaLink="false">http://www.keighl.com/?p=836</guid>
		<description><![CDATA[A way to redirect member groups to specific templates after they log in with ExpressionEngine. ]]></description>
			<content:encoded><![CDATA[<p>Sometimes simple is better. Actually, simple is almost always better. Especially in web development. This past week, I&#8217;ve been struggling to find a method in <a href="http://expressionengine.com/" target="_blank">ExpressionEngine</a> to redirect member groups to their appropriate templates after logging in.</p>
<p>Here is a little background on what I needed. My client supplies confidential information to subsequent clients. It would be easy to register all their clients as member, and then restrict access to the templates so only members could see them. However, in this case, the company has a handle full of data sets, and its customers subscribe to specific sets; they aren&#8217;t allowed to see the others.</p>
<p>First, it is useful to name associated member groups, weblogs, and templates the same. So if we have four member groups (north, south, east, west), they have each have corresponding weblogs and templates (north, south, east, west). Also, the groups are given access to only their respective templates, which is done through the simple <a href="http://expressionengine.com/docs/cp/templates/template_access.html" target="_blank">Template Access Restriction</a>.</p>
<p>When our members first arrive at the site, they are prompted to login, so we&#8217;ll need a template group specifically for logging them in, <code>{login/index}</code>. This one page will handle everything we need.</p>
<pre class="brush: xml;">
&lt;pre&gt;{exp:member:login_form return=&quot;login/index&quot;}

	&lt;p&gt;&lt;span class=&quot;userpass&quot;&gt;Username&lt;/span&gt;&lt;br/&gt;
	&lt;input type=&quot;text&quot; name=&quot;username&quot;  maxlength=&quot;32&quot; class=&quot;input&quot; /&gt;&lt;/p&gt;

	&lt;p&gt;&lt;span class=&quot;userpass&quot;&gt;Password&lt;/span&gt;&lt;br/&gt;
	&lt;input type=&quot;password&quot; name=&quot;password&quot;  maxlength=&quot;32&quot; class=&quot;input&quot;  /&gt;&lt;/p&gt;

	{if auto_login}
	&lt;p&gt;&lt;input class='checkbox' type='checkbox' name='auto_login' value='1' /&gt; Remember me&lt;/p&gt;
	{/if}

	&lt;p&gt;&lt;input type=&quot;submit&quot; name=&quot;submit&quot; id=&quot;submit&quot; value=&quot;Submit&quot; class=&quot;submit&quot; /&gt;&lt;/p&gt;

	&lt;p&gt;&lt;a href=&quot;{path='member/forgot_password'}&quot;&gt;Forgot your password?&lt;/a&gt;&lt;/p&gt;

{/exp:member:login_form}
</pre>
<p>Notice how the script returns itself to the same template, <code>{login/index}</code>. It doesn&#8217;t really matter where it returns because the bit we are about to add redirects the members after they log in to wherever they need to go &#8230; before the <code>{exp:member:login_form}</code> is queried again. ExpressionEngine gives us a convenient set of global variables that aid our redirections quite nicely. They are <code>{group_id}</code> and <code>{redirect="template/path"}</code>.</p>
<pre class="brush: plain;">
{if logged_in}
	{if group_id == &quot;1&quot;}
    	{redirect='north/index'}
    {if:elseif group_id == &quot;2&quot;}
    	{redirect='south/index'}
    {if:elseif group_id == &quot;3&quot;}
    	{redirect='east/index'}
    {if:elseif group_id == &quot;4&quot;}
    	{redirect='west/index'}
    {if:else}
    	{redirect='login/restricted'}
    {/if}
{/if}
</pre>
<p>The loop determines to which member group the user belongs, and pairs template redirection with that specific <code>{group_id}</code>. Simply identify the id number for each member group (easily found through the CP), and that&#8217;s it! We conclude the <code>{if}</code> loop with an <code>{if:else}</code> statement that takes care of any users who sneak through the log in process.</p>
<p>The <code>{if:else}</code> statement redirects these folks (perhaps they are members, but aren&#8217;t in a member group privy to the information shielded by EE&#8217;s template access) to some other template that tells them, &#8220;you don&#8217;t belong here.&#8221; This is a nice system, because you won&#8217;t need to do any extra coding on the templates the members are redirected towards. EE can handle access to those on its own.</p>
<p>There are limitations, however, to setting up you member redirect in this way. First, it assumes that your member groups are rather static (they are not being created or deleted frequently). If you have a ton of member groups with a ton of corresponding template groups, this would make from a monstrous <code>{if}</code> statement. Another option you have is setting some PHP variables using the EE <code>{group_id}</code> global. To do this you would have to set the PHP parsing to &#8216;output&#8217; on the <code>{login/index}</code> template.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.keighl.com/2009/06/redirecting-members-with-expression-engine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
