<?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>Edward Stafford&#187; Code Mode</title>
	<atom:link href="http://www.edwardstafford.com/category/technology/code_mode/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.edwardstafford.com</link>
	<description>Technologist, Artist, and Geek</description>
	<lastBuildDate>Wed, 24 Nov 2010 00:37:04 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>WordPress: Use Custom Fields To Add Keyword Metadata to Your Posts</title>
		<link>http://www.edwardstafford.com/2010/02/04/wordpress-use-custom-fields-to-add-keyword-meta-data-to-your-posts/</link>
		<comments>http://www.edwardstafford.com/2010/02/04/wordpress-use-custom-fields-to-add-keyword-meta-data-to-your-posts/#comments</comments>
		<pubDate>Thu, 04 Feb 2010 11:00:10 +0000</pubDate>
		<dc:creator>Ed Stafford</dc:creator>
				<category><![CDATA[Code Mode]]></category>
		<category><![CDATA[blogs]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[How-to]]></category>
		<category><![CDATA[keywords]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[seo]]></category>
		<category><![CDATA[thematic]]></category>
		<category><![CDATA[tips]]></category>
		<category><![CDATA[web development]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.edwardstafford.com/?p=258</guid>
		<description><![CDATA[One of the short-comings with using WordPress is that it does not provide an easy, built-in way to include metadata for your web page descriptions and keywords (and rightfully so). Why Not? The reason is simply that WordPress cannot read your mind. I know it&#8217;s hard to believe when you consider what you can do [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_276" class="wp-caption alignleft" style="width: 262px"><img class="size-medium wp-image-276   " title="Keywords for edwardstafford.com" src="http://www.edwardstafford.com/wp-content/uploads/keywords-black-300x120.png" alt="Keywords at edwardstafford.com" width="252" height="101" /><p class="wp-caption-text">Keywords for edwardstafford.com</p></div>
<p>One of the short-comings with using WordPress is that it does not provide an easy, built-in way to include metadata for your web page descriptions and keywords (and rightfully so). Why Not? The reason is simply that WordPress cannot read your mind. I know it&#8217;s hard to believe when you consider what you can do with wordpress, but it&#8217;s true. The issue with Description and Keyword page metadata is that, to be truely effective, it should be created to  describe the content found on each individual page. It&#8217;s how search engines like google determine how to categorize and index each page. Now, there are some SEO &#8220;experts&#8221; who will argue that this information is not very relevant anymore, and I do agree with that for the most part, but there are still SEO benefits to including this metadata vs. not including it at all.</p>
<p>I&#8217;ve been giving this some thought lately and developed a couple ideas of how to add these features into a wordpress site without too much difficulty. A bulb went off in a moment clarity when I started to think about using the Custom Fields to store page specific metadata. I was even naive enough to think I was on to something new (should have known better) but as I started researching some ideas, I realized there were others already doing similar things. Oh well, a minor detail. I took my own approach to the idea anyway, if for no other reason than a learning exercise. Ultimately, this could be added as a premium feature to any custom theme using a couple hooks and some custom theme options magic.</p>
<p><span id="more-258"></span></p>
<h2>Okay smarty-pants! So how do we include description and keyword metadata?</h2>
<p>The solution isn&#8217;t difficult to implement and can be used to add page specific metadata inside the &lt;head&gt; tag of any wordpress page. In this example, I&#8217;m going to show you a simple solution, but with some creativity and a little thought, you can expand this to provide a more robust solution for your own needs.</p>
<h2>Part I: Defining a Custom &#8220;Keywords&#8221; Field</h2>
<p>Custom Fields are a little used gem found in the Posts and Pages page of the WordPress dashboard / admin back end and available when you add a new post or page, or edit an existing post or page.</p>
<div id="attachment_263" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-263 " title="New Custom Field" src="http://www.edwardstafford.com/wp-content/uploads/custom-fields1-300x152.png" alt="Create a new custom field" width="300" height="152" /><p class="wp-caption-text">Create a new custom field</p></div>
<p>To create a new custom field to use for your page or post keywords, scroll down to the <strong>Custom Fields</strong> section below the main editor and click the &#8220;<strong>Enter new</strong>&#8221; link.</p>
<p>That action will activate the input fields for &#8220;Name&#8221; and &#8220;Value&#8221;.</p>
<p>In the Name field type the name identifier you&#8217;d like to use. This identifier/name will be used to reference the custom field name/value pair later so make it something relevant to avoid confusion. For this example, I am using &#8220;<strong>keywords</strong>&#8220;.</p>
<p>In the Value field, type the string of keywords or phrases that you want to use as the keyword metadata string for the page/post. For this example, I am using <strong>wordpress, seo, metadata, custom fields</strong></p>
<div id="attachment_265" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-265" title="Add New Custom Field Inputs" src="http://www.edwardstafford.com/wp-content/uploads/custom-fields3-300x89.png" alt="" width="300" height="89" /><p class="wp-caption-text">Add New Custom Field Inputs</p></div>
<p>When you&#8217;re done, hit the &#8220;<strong>Add Custom Field</strong>&#8221; button.</p>
<p>If you have already created a <strong>&#8220;keywords&#8221; Custom Field</strong> for a previous page or post, you will have the option of selecting it in future pages and posts from the Name drop down menu.</p>
<div id="attachment_266" class="wp-caption aligncenter" style="width: 310px"><img class="size-medium wp-image-266" title="Custom Fields Menu" src="http://www.edwardstafford.com/wp-content/uploads/custom-fields-menu-300x114.png" alt="Custom Fields Menu" width="300" height="114" /><p class="wp-caption-text">Select from Custom Fields Menu</p></div>
<p>Select the Keywords item from the menu and then add the keywords or phrases for your new page to the Value field. When your done, make sure you hit the &#8220;<strong>Add Custom Field</strong>&#8221; button to confirm it.</p>
<p>That completes Part I. You now have a functional Custom Field assigned to your post/page.</p>
<p>Next up! Adding and understanding the code that generates the keyword metadata tag.</p>
<h2>Part II: The Magic Code.</h2>
<blockquote><p>function set_keywords(){<br />
global $post;<br />
$keywords = get_post_meta($post-&gt;ID, &#8216;keywords&#8217;, true);<br />
$default_keywords = &#8220;Your, selection, of, default, keywords&#8221;;<br />
$metatag= &#8220;&#8221;;</p>
<p>if (empty($keywords)){<br />
$keywords = $default_keywords;<br />
}<br />
if (is_home() || is_front_page()){<br />
$keywords = $default_keywords;<br />
}</p>
<p>$metatag=&#8221;\t&#8221;;<br />
$metatag.= &#8220;&lt;meta name=\&#8221;keywords\&#8221; content=\&#8221;";<br />
$metatag.= $keywords;<br />
$metatag.= &#8220;\&#8221; /&gt;&#8221;;<br />
$metatag.= &#8220;\n\n&#8221;;</p>
<p>echo $metatag;<br />
}<br />
add_action(&#8216;wp_head&#8217;, &#8216;set_keywords&#8217;);</p></blockquote>
<p>Adding this block of code to your Theme&#8217;s <strong>functions.php</strong> file will create and insert page specific Keyword Metadata into inside the &lt;head&gt; tag of your pages and posts assuming you have completed Part I.</p>
<h3>How the code works</h3>
<blockquote><p>function set_keywords(){</p></blockquote>
<p>The first line declares our function and sets the name &#8220;set_keywords&#8221;.</p>
<blockquote><p>global $post;<br />
$keywords = get_post_meta($post-&gt;ID, &#8216;keywords&#8217;, true);<br />
$default_keywords = &#8220;Your, selection, of, default, keywords&#8221;;<br />
$metatag= &#8220;&#8221;;</p></blockquote>
<p>These four lines set up the variables that will be used later in the function.</p>
<p><strong>global $post</strong> allows the function to reference values stored in an array containing post information that was previously set by WordPress outside of the current function.</p>
<p><strong>$keywords = get_post_meta($post-&gt;ID, &#8216;keywords&#8217;, true)</strong> is up next and sets our variable, <strong>$keywords</strong> to a string value equal to the &#8220;<strong>keywords</strong>&#8221; <strong>Custom Variable</strong> if it was set for the current page in Part I by calling the wordpress function <strong>get_post_meta()</strong>.</p>
<p>get_post_meta() is passed three arguments.</p>
<ol>
<li>The post ID (<strong>$post-&gt;ID</strong>)</li>
<li>a Custom Field Name reference (<strong>keywords</strong>)</li>
<li>a boolean value (<strong>true</strong>)</li>
</ol>
<p>These three arguments tell get_post_meta() to grab the &#8220;<strong>keywords</strong>&#8221; Custom Field value for a specific page (<strong>$post_ID</strong> = a reference to the current page) and return a string result (<strong>true</strong>).</p>
<p><strong><span style="color: #999999;">Note</span></strong><span style="color: #999999;">: If the Boolean argument were set to &#8220;false&#8221;, get_post_meta() would return an array object instead of a single string.</span></p>
<p><strong>$default_keywords = &#8220;Your, selection, of, default, keywords&#8221;</strong> sets a set of default keywords to use when the $keywords variable is empty or not set, or when you just want to include a general set of keywords.</p>
<p><strong>$metatag = &#8220;&#8221;</strong> rounds up the variables for the function and is used to build the metadata tag string that will be inserted into the page &lt;head&gt; tag.</p>
<blockquote><p>if (empty($keywords)){<br />
$keywords = $default_keywords;<br />
}</p></blockquote>
<p>The next step in the code is a conditional statement. Here I use the common PHP empty() function passing the <strong>$keywords</strong> variable as an argument to check whether the <strong>$keywords</strong> variable contains a value. If the empty() function returns true it means that <strong>$keywords</strong> does not contain a usable value, or that is has not been set. If this condition is true, it will set the value of $keywords to that of $default_keywords.</p>
<p>If the Keywords Custom Field was set for the current page, then the get_post_meta() function should have set the $keywords variable to a usable value equal to the Keyword Custom Field value. The condition will return false and the variable retains it&#8217;s Custom Field value.</p>
<blockquote><p>if (is_home() || is_front_page()){<br />
$keywords = $default_keywords;<br />
}</p></blockquote>
<p>Next I have another conditional statement that uses WordPress functions  to see if the current page is either the home page &#8211; <strong>is_home()</strong>,  or the &#8220;blog&#8221; page &#8211; <strong>is_front_page()</strong> If the current page matches either of these pages, I want to assign the value of <strong>$default_keywords</strong> to the <strong>$keywords</strong> variable.</p>
<p>The reason I do this is because the content on these pages is more dynamic and has a tendency to change often, effecting keyword relevancy. So I want to provide a generic set of default keywords instead of page content specific keywords.</p>
<p><strong><span style="color: #999999;">Note</span></strong><span style="color: #999999;">: It is possible, using more in-depth techniques not covered here, to also include the Keywords Custom Field for these pages and enable a set of more targeted keywords for them.</span></p>
<blockquote><p>$metatag=&#8221;\t&#8221;;<br />
$metatag.= &#8220;&lt;meta name=\&#8221;keywords\&#8221; content=\&#8221;";<br />
$metatag.= $keywords;<br />
$metatag.= &#8220;\&#8221; /&gt;&#8221;;<br />
$metatag.= &#8220;\n\n&#8221;;</p></blockquote>
<p>These lines are used to build the actual text string creating the metadata tag for our page&#8217;s &lt;head&gt; tag.  for example, if our page contained a keyword Custom Field with a value of  &#8221;keyword1, keyword2, keyword3&#8243;, the output for a blog post or single page would be:</p>
<p><strong>&lt;meta name=&#8221;keywords&#8221; content=&#8221;keyword1, keyword2, keyword3&#8243; /&gt;</strong></p>
<blockquote><p>echo $metatag;<br />
}</p></blockquote>
<p>Wrapping up the function we have <strong>echo $metatag </strong>followed by the closing bracket bringing our function to a close.  <strong>echo $metatag</strong> simply writes the output of the <strong>$metatag</strong> variable to the source of your web page inserting the keyword meta tag in the page&#8217;s &lt;head&gt; tag.</p>
<blockquote><p>add_action(&#8216;wp_head&#8217;, &#8216;set_keywords&#8217;);</p></blockquote>
<p>And finally bringing this code bit to an end is <strong>add_action(&#8216;wp_head&#8217;, &#8216;set_keywords&#8217;)</strong>. The add_action() function is a wordpress function used to hook your custom function to a WordPress action. In this case we are hooking our function <strong>set_keywords</strong> to the wordpress action <strong>wp_head</strong>. This is the piece that actually inserts your meta tag into the page &lt;head&gt; tag.</p>
<p><strong><span style="color: #999999;">Note</span></strong><span style="color: #999999;">: It is up to the individual theme developers to include the wp_head action in their themes, so there is a chance that your theme will not have it. In that case, check the documentation for your theme to see what action hooks are available to you.</span></p>
<p>That pretty much wraps it up!</p>
<div id="_mcePaste"><strong>Umm, Aren&#8217;t you forgetting something?</strong></div>
<p>By now you may be thinking, &#8220;Great, but what about the Description meta tag you mentioned?&#8221;.</p>
<p>You can use this same technique demonstrated here to create unique page descriptions with just a few minor code changes. Just replace keyword references with description references.</p>
<p>Do you have any suggestions to imporve on this? Find it helpful? Have some else to share? Leave a comment!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.edwardstafford.com/2010/02/04/wordpress-use-custom-fields-to-add-keyword-meta-data-to-your-posts/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>YouTube API Hack: Link Your Videos Directly to Your YouTube Channel</title>
		<link>http://www.edwardstafford.com/2009/08/07/youtube-api-hack-link-your-videos-directly-to-your-youtube-channel/</link>
		<comments>http://www.edwardstafford.com/2009/08/07/youtube-api-hack-link-your-videos-directly-to-your-youtube-channel/#comments</comments>
		<pubDate>Fri, 07 Aug 2009 19:09:00 +0000</pubDate>
		<dc:creator>Ed Stafford</dc:creator>
				<category><![CDATA[Code Mode]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[How-to]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[RSS]]></category>
		<category><![CDATA[SimplePie]]></category>
		<category><![CDATA[youtube api]]></category>

		<guid isPermaLink="false">http://www.edwardstafford.com/?p=105</guid>
		<description><![CDATA[Wait! Your a Hacker? First of all, my use of the word &#8220;Hack&#8221; is not the version popularized by the media. It is used here in the context of using a tool (YouTube API) to accomplish a task that was not originally part of the tool&#8217;s design. By using some creative thinking and little trial [...]]]></description>
			<content:encoded><![CDATA[<h2>Wait! Your a Hacker?</h2>
<p><img class="alignleft size-medium wp-image-121" title="Hack It" src="http://www.edwardstafford.com/wp-content/uploads/swissarmy-300x225.jpg" alt="Hack It" width="300" height="225" />First of all, my use of the word &#8220;Hack&#8221; is not the version popularized by the media. It is used here in the context of using a tool (YouTube API) to accomplish a task that was not originally part of the tool&#8217;s design. By using some creative thinking and little trial and error, I was able to accomplish a desired result, and overcome a limitation of the API.</p>
<h2>Ready, Set, GO!!</h2>
<p>While working on a recent project I came across a mildly irritating limitation of the YouTube API. The thing is, I wanted to display a list of recently added YouTube video thumbnails to a web site that link back to the videos in the YouTube users channel.  Easy! right?</p>
<h2>Not So Fast!</h2>
<p>Here&#8217;s the thing. The channel feed returned by the API does include the link back to the YouTube Video, <strong>BUT</strong> it sends the visitor to the usual standard public YouTube page with the video embeded and <strong>NOT </strong>to the Channel of the YouTube member who uploaded it.</p>
<p>For most, this would be fine. But I wanted to be able to preserve a connection and identity between the web site and the YouTube Channel.</p>
<p>Unfortunately, the YouTube API does not provide a direct way to do this [link videos back directly to the YouTube Channel instead of the standard YouTube page]. So what&#8217;s a developer to do? &#8230; Come up with a hack, of course!! (even if is is a small one)..</p>
<h2>First A Note:</h2>
<p>This solution uses the <a title="http://simplepie.org/" href="http://simplepie.org/" target="_blank">Simplepie PHP Code Library</a> to grab the Channel RSS feed</p>
<h2>The Code:</h2>
<blockquote><p>&lt;?php</p>
<p>require_once(&#8216;php/simplepie.inc&#8217;);</p>
<p>$feed = new SimplePie(&#8216;http://gdata.youtube.com/feeds/api/users/[user name]/uploads&#8217;);</p>
<p>$feed-&gt;handle_content_type();</p>
<p>$YT_PlayerPage = &#8220;http://www.youtube.com/user/[user name]#play/uploads/&#8221;;</p>
<p>$YT_VideoNumber = 0;<br />
$ShowMax = 4;</p>
<p>foreach ($feed-&gt;get_items() as $item)<br />
{</p>
<p>if ($enclosure = $item-&gt;get_enclosure())<br />
{</p>
<p>$YT_VidID = substr(strstr($item-&gt;get_permalink(), &#8216;v=&#8217;), 2, 11);</p>
<p>echo &#8216;&lt;a href=&#8221;&#8216; . $YT_PlayerPage . $YT_VideoNumber . &#8220;/&#8221; . $YT_VidID . &#8216;&#8221;title=&#8221;&#8216; . $item-&gt;get_title() . &#8216;&#8221;&gt; &lt;img src=&#8221;&#8216; . $enclosure-&gt;get_thumbnail() . &#8216;&#8221;/&gt;&lt;/a&gt;&#8217;;</p>
<p>}<br />
if($YT_VideoNumber == $ShowMax) break;<br />
$YT_VideoNumber++;<br />
}<br />
?&gt;</p></blockquote>
<h2>Tiptoe Through the Tulips (or walking through the code)</h2>
<p>There you have it. A small block of PHP code and we have the result we&#8217;re looking for. Now let&#8217;s take a look at each line in the code.</p>
<blockquote><p>require_once(&#8216;php/simplepie.inc&#8217;);</p></blockquote>
<p>This line does nothing more than call/include the Simplepie Library. The one thing you may need to change here is the location of the library. I stored it in a directory at the root of my web called &#8220;php&#8221;. So depending where you store your copy of the library, you may need to change this.</p>
<blockquote><p>$feed = new SimplePie(&#8216;http://gdata.youtube.com/feeds/api/users/[user name]/uploads&#8217;);</p></blockquote>
<p>The next line creates a new feed and stores it as $feed. Pretty creative.. huh? Whats happening here is simplepie is grabing the rss feed for the YouTube Channel&#8217;s Uploaded videos.</p>
<p>An important note to make here is that the URI for the RSS passed to SimplePie is not the same as the RSS URI that you would use to subscribe to the channel&#8217;s RSS feed to use with your RSS reader. You will also need to replace [user name] in the URI with the YouTube user name for the channel you want to pull videos from.</p>
<p>The Standard RSS Subscription URI looks like this:<br />
http://gdata.youtube.com/feeds/<span style="text-decoration: underline;"><strong>base</strong></span>/users/[user name]/uploads</p>
<p>While the URI used by the API to grab the RSS looks like this:<br />
http://gdata.youtube.com/feeds/<span style="text-decoration: underline;"><strong>api</strong></span>/users/[user name]/uploads</p>
<p>Notice the difference indicated in bold text (&#8220;base&#8221; vs &#8220;api&#8221;). You will need to be sure you use &#8220;API&#8221; version of the URI. You can get this by copying the public RSS URI and simply changing &#8220;base&#8221; to &#8220;api&#8221;.</p>
<p>At the next line we have:</p>
<blockquote><p>$feed-&gt;handle_content_type();</p></blockquote>
<p>This just makes sure the content is being served out to the browser properly.</p>
<p>The next three lines contain three variables I&#8217;ve added: $<strong>YT_PlayerPage, $YT_VideoNumber</strong> and <strong>$ShowMax</strong></p>
<blockquote><p>$YT_PlayerPage = &#8220;http://www.youtube.com/user/[user name]#play/uploads/&#8221;;</p></blockquote>
<p>This is the first part of the key to getting YouTube links to point directly to the Channel page. This variable holds the base Channel player URI and is used to construct a complete video link. The completed URI link also includes a counter reference and the unique 11 character video ID. To get the URI for the channel player page, visit the YouTube Channel you&#8217;re grabing the video feed from and click on a video link. The complete URI for that video will appear in the browser&#8217;s address bar. Simply copy that URI and eliminate everything following the backslash &#8220;/&#8221; after &#8220;uploads&#8221; (indicated in <strong><span style="color: #ff0000;">red</span></strong>)</p>
<p>http://www.youtube.com/user/[user name]#play/uploads/<span style="color: #ff0000;"><strong>#/xxxxxxxxxxx</strong></span></p>
<blockquote><p>$YT_VideoNumber = 0;</p></blockquote>
<p>The links on the YouTube Channel page contain a counter in the URI and increases by +1 with each link. This is the second part of the key in constructing the direct Channel links. This counter was a portion of the link that was removed in <strong>$YT_PlayerPage</strong>. I&#8217;m not completely clear on what the purpose of the counter is and in my experimenting with this, it did not seem to make a difference what the counter value was as long as the video ID followed it. But since it is the format that is used on YouTube&#8217;s Channel pages, I&#8217;ve figured it would be best to recreate the same thing here. Besides, we are going to use that value later in the code. I&#8217;ve set the initial value of the variable to 0 (zero) because the counter is zero based. (0, 1, 2 &#8230; )</p>
<blockquote><p>$ShowMax = 4;</p></blockquote>
<p>The next line contains the <strong>$ShowMax</strong> variable. This is used to set a limit to the number video links I wanted to display on the page. BUT, there is a trick you need to be aware of here. We are using the <strong>$YT_VideoNumber</strong> to get the counter number for the current video in the Loop (the loop will be described in the next section). But because <strong>$YT_VideoNumber</strong> is zero based, we need to compensate for that in the <strong>$ShowMax</strong> Variable and offset the limit by -1. In other words, to limit the display to 5 items, we need to set <strong>$ShowMax </strong>to 4 because we are including 0 as the first item (0 1 2 3 4) for a total of 5 items. Got it?&#8230; good!</p>
<blockquote><p>foreach ($feed-&gt;get_items() as $item)<br />
{</p></blockquote>
<p>These lines start/open the Loop getting each item in the feed. This is where the code will &#8220;loop&#8221; through each item (video) in the feed and extract the information I wanted for each video.</p>
<blockquote><p>if ($enclosure = $item-&gt;get_enclosure())<br />
{</p></blockquote>
<p>This line sets a conditional variable ($enclosure) to check if the current item in the loop contains enclosure data provided by MRSS (Multimedia RSS) that might be provided with the feed. YouTube feeds do support and provide MRSS enclosure data and we need to be able to pull it from the feed. The get_enclosure() method is part of the SimplePie Library and makes getting access to this data pretty easy.</p>
<blockquote><p>$YT_VidID = substr(strstr($item-&gt;get_permalink(), &#8216;v=&#8217;), 2, 11);</p></blockquote>
<p>This line is the final [and probably most important] part of the key to constructing the Channel video link.  It&#8217;s also the most confusing part at first sight. I mentioned earlier that a video link is provided with the feed that will direct the viewer to a the standard public YouTube page for viewing. This link contains the video ID that we need. The bad news is that the API as far as I could see does not allow a direct or easy way to get the ID for each video [please correct me if I'm wrong here]. The good news is that the ID can be extracted from the link provided with the feed, and that&#8217;s exactly what this line does.</p>
<p>$item-&gt;get_permalink() returns the URI / video  that would direct a visitor to the standard YouTube page. The URI is similar to:<br />
http://www.youtube.com/watch?<span style="color: #ff0000;"><strong>v=xxxxxxxxxxx</strong></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">v=xxxxxxxxxxx of the URI contains the video ID and needs to be extracted.</span><br />
</span></p>
<p><em><strong>substr(strstr($item-&gt;get_permalink(), &#8216;v=&#8217;), 2, 11)</strong> </em>isolates and extracts the video ID and then stores the ID in the <strong>$YT_VidID </strong>variable.</p>
<p><strong>Lets have a closer look.</strong><br />
We need to find the position in the URI string where the video ID starts and then extract it.</p>
<p>The video ID is passed in the URI as in query string paramater &#8220;v&#8221;.  I used the PHP strstr() method to match and find the position of &#8220;v=&#8221;. This will create a new string eliminating everything in front &#8220;v=&#8221; so we are left with &#8220;<span style="color: #ff0000;"><span style="color: #000000;">v=xxxxxxxxxxx&#8221;.</span></span></p>
<p>If you look close, you&#8217;ll notice that <em><strong>strstr($item-&gt;get_permalink(), &#8216;v=&#8217;) </strong></em>and therefore the resulting string, is actually used as the string argument in the substr() method used to isolate the video ID.<em><br />
</em></p>
<p><span style="color: #ff0000;"><span style="color: #000000;"> </span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">The second argument, &#8220;2&#8243; tells the substr method to offset the beginning of the string by two characters. This is to eliminate the &#8220;v&#8221; and &#8220;=&#8221; characters and moves the substring start position to the character after the &#8220;=&#8221; which is the first character of the Video ID. </span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">The third argument, 11, tells the substr method to isolate the next eleven characters from the start position, leaving us with the full video ID &#8220;xxxxxxxxxxx&#8221;.</span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;"> In experimenting and playing with this, I found that all YouTube video IDs are 11 characters long. I limited the substring to 11 instead of allowing it to extend to the end of the URI because, if for some reason additional string data was passed with the URI after the video ID, it would be included as part of  the extracted string and the result would be an invalid ID.</span></span></p>
<p><span style="color: #ff0000;"><span style="color: #000000;">After all that, I had the golden nugget of an isolated video ID which is now stored in the </span></span><strong>$YT_VidID </strong>variable. The hard part is DONE!! (really, it wasn&#8217;t that hard).</p>
<blockquote><p>echo &#8216;&lt;a href=&#8221;&#8216; . $YT_PlayerPage . $YT_VideoNumber . &#8220;/&#8221; . $YT_VidID . &#8216;&#8221;title=&#8221;&#8216; . $item-&gt;get_title() . &#8216;&#8221;&gt; &lt;img src=&#8221;&#8216; . $enclosure-&gt;get_thumbnail() . &#8216;&#8221;/&gt;&lt;/a&gt;&#8217;;</p></blockquote>
<p>The three key pieces needed to construct the direct Channel URIs are now available and the links can be put together. This line, still contained in our loop, constructs the link for each video item in the feed and outputs the HTML markup that will be included in the rendered page. To construct the link, join the three key pieces (the variables) like so:</p>
<p><strong>$YT_PlayerPage . $YT_VideoNumber . &#8220;/&#8221; . $YT_VidID</strong></p>
<p>$YT_PlayerPage = The base URI.<br />
$YT_VideoNumber = The video counter<br />
include a &#8220;/&#8221; character<br />
$YT_VidID = The video ID</p>
<p>The output should look like:<br />
http://www.youtube.com/user/[user name]#play/uploads/<span style="color: #000000;">#/xxxxxxxxxxx</span></p>
<p>Include this string as the value of the href of an HTML &lt;a&gt; tag.<br />
<strong>&#8216;&lt;a href=&#8221;&#8216; . $YT_PlayerPage . $YT_VideoNumber . &#8220;/&#8221; . $YT_VidID . &#8216;</strong><br />
Next add a &#8220;title&#8221; attribute to the &lt;a&gt; tag and set the value to $item-&gt;get_title().<br />
<strong>&#8220;title=&#8221;&#8216; . $item-&gt;get_title() . &#8216;&#8221;&gt;</strong><br />
This will create a hover text that shows the title of the video when the cursor hovers over the link.</p>
<p>Next, include the link content (text or image to act as the visible link). In my sample, I&#8217;ve used a thumbnail of each video.<br />
<strong>&lt;img src=&#8221;&#8216; . $enclosure-&gt;get_thumbnail() . &#8216;&#8221;/&gt;</strong><br />
Note that again I&#8217;m extracting the enclosure data included with MRSS as part of the RSS feed to get the thumbnail image for each video.</p>
<p>Finally add the closing &lt;/a&gt; tag to complete.</p>
<h2>But wait &#8230; There&#8217;s more!!</h2>
<blockquote><p>}</p></blockquote>
<p>The next line is nothing more than a closing bracket that closes and completes the conditional statement that checks for the enclosure data.</p>
<blockquote><p>if($YT_VideoNumber == $ShowMax) break;</p></blockquote>
<p>Remember the <strong>$ShowMax</strong> variable? This is where it comes into play. We are using the $YT_VideoNumber variable that was added to hold the counter for the current video and comparing it to the <strong>$ShowMax</strong> variable used to limit the number of videos the page will display. With each iteration of the loop, the code extracts the information for each video item and increments the counter by +1. The counter actually serves two purposes in the code. First,  to be used in constructing the video URI and second, to control the point at which the loop is to be exited. Why?.. If our video feed has 100 items and we only want to display 5 of them, then it does not make any sense to continue stepping through the loop to read the remaining items. So after we get what we want, we exit the loop to save resources.</p>
<p><strong>What&#8217;s happening here is this:</strong><br />
If the current <strong>$YT_VideoNumber</strong> variable value for the current iteration of the loop matches the value of the <strong>$ShowMax</strong> variable, then &#8220;break&#8221; (exit) out of the loop and we&#8217;re done.</p>
<blockquote><p>$YT_VideoNumber++;</p></blockquote>
<p>BUT, if the values of these variables does not match, then the next line increments the <strong>$YT_VideoNumber</strong> by +1 and continues to the next iteration of the loop.</p>
<blockquote><p>}</p></blockquote>
<p>And Finally, there is the closing bracket of the loop which also brings us to the end of the code block.</p>
<p>So that&#8217;s it. This code will render a set of YouTube video thumbnails in a web page that will link directly back to the video on the YouTube member&#8217;s channel page where ever it is included. But don&#8217;t stop there. Have a look at the other methods available in the YouTube API and SimplePie Library for additional information and data you can extract and use, add your own CSS and markup to the the output to change the layout, appearance, function &#8230; whatever you want.</p>
<p>I hope you found this useful. If you have any thoughts, improvements or comments to share, please post in the comments section here.</p>
<p><strong>And if you do use this in your own projects, I&#8217;d really appreciate a comment in your code, a shoutout or link back to this post. </strong></p>
<p>Happy coding!!!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.edwardstafford.com/2009/08/07/youtube-api-hack-link-your-videos-directly-to-your-youtube-channel/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Another example why Open Source is a good thing! (MySql + SharpDevelop)</title>
		<link>http://www.edwardstafford.com/2007/11/16/another-example-why-open-source-is-a-good-thing-mysql-sharpdevelop/</link>
		<comments>http://www.edwardstafford.com/2007/11/16/another-example-why-open-source-is-a-good-thing-mysql-sharpdevelop/#comments</comments>
		<pubDate>Sat, 17 Nov 2007 03:48:16 +0000</pubDate>
		<dc:creator>Ed Stafford</dc:creator>
				<category><![CDATA[Code Mode]]></category>
		<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.edwardstafford.com/blog/2007/11/16/another-example-why-open-source-is-a-good-thing-mysql-sharpdevelop/</guid>
		<description><![CDATA[I have some new additions and apps that I wanted to integrate into our company web (the company I work for) but this required upgrading from ASP.Net 1.1 to ASP.Net 2.0. Seems simple enough, right? I wish..!! The site uses the MySql .NET Connector (a native ADO connector for .Net) available from MySQL AB. This [...]]]></description>
			<content:encoded><![CDATA[<p>I have some new additions and apps that I wanted to integrate into our company web (the company I work for) but this required upgrading from ASP.Net 1.1 to ASP.Net 2.0. Seems simple enough, right? I wish..!!</p>
<p>The site uses the MySql .NET Connector (a native ADO connector for .Net) available from MySQL AB. This worked flawlessly under the .Net 1.1 framework. I set up the 2.0 framework on our dev server and started testing the site localy to make sure all existing features and functions would still work after the switch. I am happy to announce that everything was working as expected (on the dev server). Now it was time to request the upgrade through the host. After receiving the confirmation that the request was completed, I open a browser and hit the company web. Warning Warning Error Error Error. Oh no!! What happened?</p>
<p>With the release of .NET 2.0, Microsoft included a new security model using a greater level of restriction. The host that is hosting our web makes use of these restriction levels and as it turns out, the .Net connector that we were using violated some .Net security and triggered a Security Exception.</p>
<p><code>Exception Details: System.Security.SecurityException: That assembly does not allow partially trusted callers.</code></p>
<p>I have to give Props to Microsoft for making the problem easy to identify. Looks like all I need to do is allow partially trusted calls from the MySql connector.</p>
<p>Here is where the Beauty of Open Source Software comes in.<br />
<span id="more-20"></span><br />
<a href="http://www.mysql.com/">MySql</a> creates open source database software and tools and freely makes their source code available to anyone who wants it. That means I can take the source, make the changes I need and recompile the binaries again. </p>
<p>But wait! How do I access the source written in C# and recompile the binaries. Don&#8217;t I need something like Visual Studio from Microsoft. Thats like $1,024.99 (quoted from Amazon). </p>
<p>Sure you could drop a grand for VS Pro, or you could download <a href="http://www.icsharpcode.net/OpenSource/SD/">SharpDevelop</a>. <a href="http://www.icsharpcode.net/OpenSource/SD/">SharpDevelop</a> is the IDE equivelant to Visual Studio for C# development -and- did I mention it is FREE!! Yup that&#8217;s right Free Open Source Software (FOSS). I&#8217;ve been using SharpDevelop for a while now, and wouldn&#8217;t think of giving it up.</p>
<p>I fired up SharpDevelop, made the changes to the MySql .Net connector source necessary to allow it to operate within the restricted security settings of the host&#8217;s servers, and recompiled the binaries. As soon as I uploaded my newly compiled MySql Connector to the web server, I opened up my browser of choice and hit the company web site. </p>
<p>SUCCESS!!! All is good in the world again.</p>
<p>So how did using open source provide the advantage here?<br />
1. if the MySql connector were closed, meaning I was not able to alter the code, I would have had to contact the company behind the software and try to get them to work with me towards a solution. The truth is, that is a long process and would probably require that I wait for them to release a new version of their closed proprietary product. With an inoperable web site, that was not an option.</p>
<p>2. Having access to FOSS (Free Open source Software) like SharpDevelop allowed me to do the same thing that other high priced software does, but for a lot less.</p>
<p>In the End, I was able to resolve a high priority issue quickly and at a low cost.</p>
<p>In all fairness, Microsoft does provide a -freely available- (for the beginner) version of Visual Studio IDEs know as Visual Studio Express. However, these are not Open Source and are very limited not only in features, but also in licensing which states what you are allowed to do with the projects you create.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.edwardstafford.com/2007/11/16/another-example-why-open-source-is-a-good-thing-mysql-sharpdevelop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Referencing ASP.NET CheckBox Controls using strings and casting</title>
		<link>http://www.edwardstafford.com/2007/05/22/referencing-aspnet-checkbox-controls-using-strings-and-casting/</link>
		<comments>http://www.edwardstafford.com/2007/05/22/referencing-aspnet-checkbox-controls-using-strings-and-casting/#comments</comments>
		<pubDate>Tue, 22 May 2007 18:05:03 +0000</pubDate>
		<dc:creator>Ed Stafford</dc:creator>
				<category><![CDATA[Code Mode]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.edwardstafford.com/blog/?p=11</guid>
		<description><![CDATA[ASP.NET &#8211; I recently ported one of my older web ASP Application to a web ASP.NET Application which presented a few challenges along the way. One of these challenges was a need to manage a series of 30 check boxes within a form. This part of the application is used to manage user permissions, restricting [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://edwardstafford.com/blog/wp-includes/images/codeModeIcon.png" title="Category: Code Mode" alt="Category: Code Mode" align="left" height="100" width="100" />ASP.NET &#8211; I recently ported one of my older web ASP Application to a web ASP.NET Application which presented a few challenges along the way. One of these challenges was a need to manage a series of 30 check boxes within a form. This part of the application is used to manage user permissions, restricting what areas of the application individual users had access to.</p>
<p>The user permissions are stored in a database as a pipe (&#8220;|&#8221;) delimited string. when the page containing the form loads, the permission string is pulled from the database, and split into an array.</p>
<p>When loading a page, all the checkboxes that indicate a users permission need to be checked.</p>
<p>In good ol&#8217;e fashioned ASP, all the checkboxes in a form would be given the same &#8220;name&#8221; attribute, and a &#8220;value&#8221; attribute containing the permission string. When the page containing the form was loaded, a piece of client-side javascript would run and iterate through all the checkboxes. For each checkbox in the form, the script would then iterate through each permission array item and if the item matched the checkbox value attribute, the checkbox state would be set to &#8220;checked&#8221;.</p>
<p><strong>ASP Form</strong></p>
<pre style="border: 1px solid black; overflow: auto; height: 200px; width: 450px; text-align: left">&lt;form name="permissions" method="post" action="process_page.asp"&gt;
 &lt;table width="461" border="0" cellspacing="0" cellpadding="0"&gt;
 &lt;tr&gt;
  &lt;td&gt;
   &lt;input type="checkbox" name="setPermission" value="user_add"&gt;Add&lt;/ br&gt;
   &lt;input type="checkbox" name="setPermission" value="user_manage" /&gt;Manage&lt;/ br&gt;
   &lt;input type="checkbox" name="setPermission" value="user_delete"&gt;Delete&lt;/ br&gt;
   &lt;input type="checkbox" name="setPermission" value="user_edit"&gt; Edit&lt;/br&gt;
   &lt;input type="checkbox" name="setPermission" value="user_setVisibility" /&gt; set visibility&lt;/br&gt;
  &lt;/td&gt;
  &lt;/tr&gt;
 &lt;/table&gt;
&lt;/form&gt;</pre>
<p>When the ASP page is submitted after altering user permissions (checking or unchecking boxes), server-side code  gets the values of all the checked checkboxes using Request.Form(&#8220;Checkbox_name&#8221;) .value, converts it to a pipe (&#8220;|&#8221;) delimited string, and updates the database with the new delimited string.</p>
<p>When porting this to ASP.NET, we run into a problem when replacing the standard form checkboxes to ASP.NET CheckBox Controls. .Net CheckBox controls cannot have the same &#8220;name&#8221; attribute so we cannot access them as a group like we did in ASP. A workaround for this is to give each CheckBox Control an ID equal to the permission value.</p>
<p><strong>ASP.NET Form</strong></p>
<pre style="border: 1px solid black; overflow: auto; height: 200px; width: 450px; text-align: left">
&lt;form action="" method="post" name="CMSForm" id="CMSForm" runat="server"&gt;
 &lt;table width="100%" border="0" cellspacing="0" cellpadding="0"&gt;
  &lt;tr&gt;
   &lt;td class="p_text1" width="67"&gt;
    &lt;asp:CheckBox ID="user_add" Text="Add" runat="server" cbValue="add_user"/&gt;
    &lt;asp:CheckBox ID="user_manage" Text='View/Manage' runat="server" cbValue="view_user_manager"/&gt;
    &lt;asp:CheckBox ID="user_delete" Text='Delete' runat="server" cbValue="del_user"/&gt;
    &lt;asp:CheckBox ID="user_edit" Text='Edit' runat="server" cbValue="edit_user"/&gt;
    &lt;asp:CheckBox ID="user_setVisibility" Text='Set Visibility' runat="server" cbValue="hide_show_user"/&gt;
   &lt;/td&gt;
  &lt;/tr&gt;
 &lt;/table&gt;
&lt;/form&gt;</pre>
<p><strong>Now for the FUN.NET</strong></p>
<p>Now instead of using a full block of client-side javascript and nested loops as we did in ASP, we can access the ASP.NET CheckBox Controls directly using a few lines of server-side code and Casting.</p>
<p>The key to this is the change from using a &#8220;value&#8221; attribute to contain the permission value to using the Control&#8217;s ID to contain the permission value. Because the permission values are stored and pulled from a database, and split into an array, each array item can also be used to reference the CheckBox Controls directly without having to loop through each control.</p>
<p>To set the checked state of the CheckBox controls, we loop through the permissions array and Cast the string as a CheckBox Control allowing us to access that specific control.</p>
<p>I am using a MySql database here:<br />
First we need to get or data from the database. &#8220;access&#8221; is the DB table column that stores my permission string for each user.</p>
<pre style="border: 1px solid black; overflow: auto; height: 100px; width: 450px; text-align: left">MySqlConnection MyConString = new MySqlConnection(...your datababase connection string here...);
MySqlCommand myCommand = new MySqlCommand("SELECT  access FROM &lt;your dataTable&gt; WHERE emp_ID = &lt;unique ID of user you want to manage&gt; ", MyConString);
MyConString.Open();
MySqlDataReader dr = myCommand.ExecuteReader();</pre>
<p>Next we  get the string value of &#8220;access&#8221; and split it into an array.</p>
<pre style="border: 1px solid black; overflow: auto; height: 175px; width: 450px; text-align: left">try{
 dr.Read();
}
catch(Exception ex){
 however you want ot handle the exception here
}
char[] splitter  = {'|'};
string[] arrPermissions = dr["access"].ToString().Split(splitter);
<strong>
setCheckboxes(arrPermissions);</strong></pre>
<p><strong>setCheckboxes Method</strong> (this is where the magic happens)<br />
This method takes the permissions array as a argument, iterates through the array, casting the string value of each item as a CheckBox, and sets the Checked state of all matching CheckBox Controls.</p>
<pre style="border: 1px solid black; overflow: auto; height: 125px; width: 450px; text-align: left">private void setCheckboxes(string[] arrPermissions)
{
foreach(string strPermission in arrPermissions){
((CheckBox)this.CMSForm.FindControl(strPermission)).Checked = true;
}
}</pre>
<p align="left">The same technique can be applied to other .NET controls as well to change their attributes, styles, or whatever.<br />
I could have just as easily changed the text of the controls using something like: ((CheckBox)this.CMSForm.FindControl(strPermission)).Text= &#8220;I am a CheckBox Control&#8221;;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.edwardstafford.com/2007/05/22/referencing-aspnet-checkbox-controls-using-strings-and-casting/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP &#8211; Break the Web Shackles!</title>
		<link>http://www.edwardstafford.com/2007/05/10/php-its-not-just-for-the-web-anymore/</link>
		<comments>http://www.edwardstafford.com/2007/05/10/php-its-not-just-for-the-web-anymore/#comments</comments>
		<pubDate>Thu, 10 May 2007 16:12:42 +0000</pubDate>
		<dc:creator>Ed Stafford</dc:creator>
				<category><![CDATA[Code Mode]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.edwardstafford.com/blog/?p=10</guid>
		<description><![CDATA[Over the last couple years or so, my development focus has been on the .NET Framework and C# so, I&#8217;m sad to say, it&#8217;s been a while since I&#8217;ve written any &#8220;real&#8221; PHP code. I think the main reason for this is that I have been developing more and more desktop applications and less web [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://edwardstafford.com/blog/wp-includes/images/codeModeIcon.png" title="Code Mode Icon" alt="Code Mode Icon" align="left" height="100" width="100" />Over the last couple years or so, my development focus has been on the .NET Framework and C# so, I&#8217;m sad to say,  it&#8217;s been a while since I&#8217;ve written any &#8220;real&#8221; PHP code.  I think the main reason for this is that I have been developing more and more desktop applications and less web applications. When I was writing web apps, I&#8217;d say my efforts were split pretty much down the middle between PHP and ASP. Then .NET came along with C# and I was hooked. I was able to continue to develop web apps but also transition to desktop development while using the same tools. C# definitely had an advantage here. But alas.. <span id="more-10"></span>I always kept the candle burning for PHP, my old friend, and occasionally checked in on it&#8217;s progress. I was excited about the release of PHP5 and it&#8217;s direction toward a true OO (object orientated) Programing approach. Finally, PHP would include: <span id="intelliTxt"></span></p>
<ul>
<li>&#8220;Real&#8221; Constructors</li>
<li>Added Destructors</li>
<li> Public, protected, and private properties and methods</li>
<li>Data Protection</li>
<li> Abstract classes</li>
<li> Static properties and methods</li>
<li>Exceptions, Custom Exceptions and Exception handling</li>
</ul>
<p>This was a welcome change to PHP in my opinion. It&#8217;s true that with a little bit of work and an occasional hack, you could create classes and &#8220;sudo&#8221; objects in PHP4, BUT no matter how hard you try, it&#8217;s still not OOP. But even with all the improvements, PHP is still primarily used for web development leaving developers with the need to pick up other programing languages if they wish to venture into the desktop development arena. Right?</p>
<p>There is hope! Enter <a href="http://gtk.php.net/" title="PHP-GTK web site">PHP-GTK</a>.  &#8220;What&#8217;s that&#8221; you ask?</p>
<p>Quote: PHP-GTK is an extension for the <acronym title="recursive acronym for PHP: Hypertext Preprocessor">PHP</acronym>      programming language that implements language bindings for      <acronym title="The GIMP Toolkit">GTK+</acronym>. It provides an      object-oriented interface to GTK+ classes and functions and greatly      simplifies writing client-side cross-platform GUI applications.</p>
<p>It is now possible to write functional windowed cross-platform applications for the desktop using PHP and GTK.   &#8230;.<strong>HOORAH!! </strong>Originally released (ver. 0.0.1) in 2001, The project has progressed and come a long way. This is still a work in progress and there is a lot of work to do to make this comparable to other desktop development languages (C#, C++, JAVA etc.) but I am excited by the prospect. This puts PHP on the same playing field as the &#8220;big boys&#8221; and opens a whole new door of opportunities.</p>
<p>Today I finally decided to install the required pieces (GTK, PHP, a couple other packages)  on my windows XP system and threw together a couple very small test apps. So far, so good!</p>
<p>Resources:<br />
<a href="http://www.gnope.org/" target="_blank">http://www.gnope.org/</a><br />
<a href="http://gtk.php.net/" target="_blank"> http://gtk.php.net/</a><br />
<a href="http://www.writingup.com/blog/phpgtk2" target="_blank">http://www.writingup.com/blog/phpgtk2</a><br />
<a href="http://crisscott.com/category/php-gtk/" target="_blank">http://crisscott.com/category/php-gtk/</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.edwardstafford.com/2007/05/10/php-its-not-just-for-the-web-anymore/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Creating Application Shortcuts for Click-Once Applications</title>
		<link>http://www.edwardstafford.com/2007/05/03/no-shortcuts-to-creating-shortcuts/</link>
		<comments>http://www.edwardstafford.com/2007/05/03/no-shortcuts-to-creating-shortcuts/#comments</comments>
		<pubDate>Fri, 04 May 2007 02:57:48 +0000</pubDate>
		<dc:creator>Ed Stafford</dc:creator>
				<category><![CDATA[Code Mode]]></category>
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://www.edwardstafford.com/blog/?p=8</guid>
		<description><![CDATA[While writing my latest C# .NET software application, the need came to be able to allow users to enable and disable an &#8220;auto-start&#8221; feature. Users wanted to control whether the app would start automatically when they start their workstation, or log into their accounts, or whether they had to start it manually. The challenge came [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://edwardstafford.com/blog/wp-includes/images/codeModeIcon.png" title="Category: Code Mode" alt="Category: Code Mode" align="left" height="100" width="100" />While writing my latest C# .NET software application, the need came to be able to allow users to enable and disable an &#8220;auto-start&#8221; feature. Users wanted to control whether the app would start automatically when they start their workstation, or log into their accounts, or whether they had to start it manually. The challenge came out the fact that this was a very small application and was being created using VS C# Express and Click-Once deployment. My options were to either manipulate the registry run keys, or create a method to create/delete an application shortcut in the startup folder. I opted for the shortcut solution figuring it was probably the safest and easiest solution (VS express editions have limited access to registry manipulation, not to mention that any keys created through the use of the application would be orphaned after uninstall).<span id="more-8"></span></p>
<p>The first problem we have with the shortcut solution is that Click-Once deployments do not install (in the traditional sense) on the target system. The applications do not install in the Program Files directory and there is no control over setting or selecting a preferred location to install them. Instead, Click-Once applications are &#8220;installed&#8221; on a per-user basis to the active users profile &gt; [...Documents and Settings\user_account\Local Settings\Apps\...\...] and when deployed in &#8220;off line&#8221; mode, Click_once also adds a sudo shortcut to the Start &gt; All Programs menu. I say &#8220;Sudo&#8221; shortcut because it is not a traditional shortcut (.lnk) file, but instead an application reference file with an extension of .appref-ms</p>
<p>The directories below the &#8220;Apps&#8221; directory containing the executable files are not easily readable and appear to be dynamically generated by the Click-once deployment process [please correct me if I'm wrong]. This makes it impossible to include shortcuts in the project to access the executable without first knowing the absolute path to the executable after installation. If it is possible, I am not aware of how to go about doing it. Normally, I would have control over the installation path and directory structure so that I could include shortcut files with the project and copy/move them to the directories I need (programs folder &#8211; startup folder &#8211; etc) but we don&#8217;t have that ability with click_once deployments.</p>
<p>Another major problem is that the .NET framework does not provide a native class or method for creating shortcuts. Are you kidding me? With everything that the framework includes, I can&#8217;t easily create a (what should be) simple shortcut? PFFT!! Whatever&#8230; Help on the web was scarce and all the suggestions seemed to point to the same reference that showed how to create them using COM add-ins. I don&#8217;t want to go there.</p>
<p>I nearly pulled all my hair out trying to figure out how to overcome these problems and create a shortcut in the startup folder. Then it hit me..wait a minute..the click-once deployment already created an application reference (shortcut) in the All Programs folder. Why can&#8217;t I just use that? I was so caught up in &#8220;how to create the shortcut&#8221; that I almost overlooked the fact that it was already done.</p>
<p><strong>My Solution </strong>(a simplified explaination)<strong>:</strong><br />
This is Tray Icon Application that monitors an XML file and alerts users to updates and changes made to it.</p>
<ol>
<li>Provide a MenuItem in the Tray Icon context menu to enable/disable the &#8220;auto-start&#8221; feature.</li>
<li>Include a method to copy the application reference created in the &#8220;All Programs&#8221; folder to the &#8220;Startup&#8221; folder &#8211; enable auto-start.</li>
<li>Include a method to delete the application reference (copy) from the &#8220;Startup&#8221; folder &#8211; disable auto-start.</li>
<li>Install using click-once deployment.</li>
<li>Test</li>
</ol>
<p><strong><em>How I did it [Code Samples]:</em><br />
</strong><br />
<strong> tsmiAutoStart_CheckChanged method:</strong><br />
This Method is called when the tsmiAutoStart menu item checked state changes</p>
<pre style="border: 1px solid black; overflow: auto; height: 200px; width: 450px">private void tsmiAutoStart_CheckedChanged(object sender, EventArgs e){
 if (tsmiAutoStart.Checked) manage_startupAutoRun("copy");
 else manage_startupAutoRun("delete");
}</pre>
<p><strong>manage_startupAutoRun method:</strong><br />
This method is triggered by the tsmiAutoStart_CheckedChanged method and creates or deletes an application reference shortcut in the users programs &gt; startup menu enables the ability for users to control when/how the application runs (during startup, or manually)</p>
<p>&#8220;Action&#8221; parameter must be a string value of either &#8220;copy&#8221; or &#8220;delete&#8221;</p>
<pre style="border: 1px solid black; overflow: auto; height: 300px; width: 450px">private void manage_startupAutoRun(string action){
 if (string.IsNullOrEmpty(startMenu_FolderName)) startMenu_FolderName = "Publisher Name"; //NOTE: startMenu_FolderName must be set to the value of Project Properties &gt; Publish Tab &gt; Options button &gt; Publisher Name field
  string app_program_file = Environment.GetFolderPath(System.Environment.SpecialFolder.Programs) + "\" + startMenu_FolderName + "\" + Application.ProductName + ".appref-ms";
  bool app_program_file_exists = System.IO.File.Exists(app_program_file);
  string startup_file = Environment.GetFolderPath(System.Environment.SpecialFolder.Startup) + "\" + Application.ProductName + ".appref-ms";
  bool startup_file_exists = File.Exists(startup_file);
  startMenu_FolderName = string.Empty;
  switch (action)
  {
   case "delete":
    //remove application reference shortcut
    if (startup_file_exists) File.Delete(startup_file);
    break;
   case "copy":
    if ((app_program_file_exists) &amp;&amp; (!startup_file_exists)) File.Copy(app_program_file, startup_file);
    //copy application reference shortcut
   break;
   default:
    throw new Exception("An invalid paramater [" + action + "] was passed to the manage_startupAutoRun method: accepts \"copy\" or \"delete\"");
   break;
  }
}</pre>
<p><strong>autostart_enabled method:</strong></p>
<p>Method is called during application load and returns a boolian value (true/false) based on the existance of an application reference shorcut located in the users programs &gt; startup folder.</p>
<p>This method returns a boolean true/false value used to set the checked state of the MenuItem that calls the manage_startupAutoRun method. If the startup folder icon for the app exists, the MenuItem is set to checked and unchecked if it is not. This method is called only once during the application load.</p>
<pre style="border: 1px solid black; overflow: auto; height: 300px; width: 450px">private bool autostart_enabled(){
//check for shortcut in startup folder
//if exists, set "checked" state for menu item
//if not, set "unchecked" state for menu item.
 if (string.IsNullOrEmpty(startMenu_FolderName)) startMenu_FolderName = "Publisher Name"; //NOTE: startMenu_FolderName must be set to the value of Project Properties &gt; Publish Tab &gt; Options button &gt; Publisher Name field
 string app_StartupFolderpath = Environment.GetFolderPath(System.Environment.SpecialFolder.Startup) + "\"  + Application.ProductName + ".appref-ms";
 startMenu_FolderName = string.Empty;
 return File.Exists(app_StartupFolderpath)?  true : false;
}</pre>
<p>In the end, this process allows the user to control an &#8220;auto_start&#8221; feature by using the existing application reference file created in the &#8220;All Programs&#8221; menu and copying it to or deleting it from the Startup Menu programmatically from within the application.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.edwardstafford.com/2007/05/03/no-shortcuts-to-creating-shortcuts/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>

