<?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>Ardamis &#187; templates</title>
	<atom:link href="http://www.ardamis.com/tag/templates/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ardamis.com</link>
	<description>Ardamis is a blog about web development and technology in general.</description>
	<lastBuildDate>Sat, 04 Feb 2012 15:26:27 +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>A cache-friendly method for reducing WordPress comment spam</title>
		<link>http://www.ardamis.com/2011/08/27/a-cache-proof-method-for-reducing-comment-spam/</link>
		<comments>http://www.ardamis.com/2011/08/27/a-cache-proof-method-for-reducing-comment-spam/#comments</comments>
		<pubDate>Sat, 27 Aug 2011 08:34:53 +0000</pubDate>
		<dc:creator>ardamis</dc:creator>
				<category><![CDATA[Nonsense]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Web Site Dev]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[application]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[comment spam]]></category>
		<category><![CDATA[database]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[spam]]></category>
		<category><![CDATA[templates]]></category>
		<category><![CDATA[themes]]></category>
		<category><![CDATA[web app]]></category>
		<category><![CDATA[xhtml]]></category>

		<guid isPermaLink="false">http://www.ardamis.com/?p=1673</guid>
		<description><![CDATA[A safe-for-cached-pages method of filtering out spam comments by requiring at least some time to have passed between the time the page is loaded and the form is submitted.]]></description>
			<content:encoded><![CDATA[<p>In the endless battle against WordPress comment spam, I&#8217;ve developed and then refined a few different methods for preventing spam from getting to the database to begin with.  My philosophy has always been that a human visitor and a spam bot behave differently (after all, we&#8217;re not dealing with <a href="http://en.wikipedia.org/wiki/Do_Androids_Dream_of_Electric_Sheep%3F#Androids">Nexus-6 model androids</a> here), and an effective spam-prevention method should be able to recognize the differences.  I also have a dislike for CAPTCHA methods that require a human visitor to <em>prove</em>, via an intentionally difficult test, that they aren&#8217;t a bot.  The ideal method, I feel, would be invisible to a human visitor, but still accurately identify comments submitted by bots.</p>
<h2>A history of spam fighting</h2>
<p>The most successful and simple method I found was a server-side system for <a href="http://www.ardamis.com/2007/12/15/using-timestamps-to-reduce-wordpress-comment-spam/">reducing comment spam by using a handshake method involving timestamps</a> on hidden form fields.  The general idea was that a bot would submit a comment more quickly than a human visitor, so if the comment was submitted too soon after the page was loaded, it was rejected.  A human caught in this trap would be able to click the Back button on the browser to resubmit.  This had proven to be very effective on ardamis.com, cutting the number of <a href="http://www.ardamis.com/2010/08/09/reducing-wordpress-spam-comments/">spam comments intercepted by Akismet per day to nearly zero</a>.  For a long time, the only problem was that it required modifying a core WordPress file, <strong>wp-comments-post.php</strong>.  Each time WordPress was updated, the core file was replaced.  If I didn&#8217;t then go back and make my modifications again, <a href="http://www.ardamis.com/2011/01/18/a-chart-illustrating-the-reduction-in-comment-spam-at-ardamis-com/">I would lose the spam protection</a> until I made the changes.  As it became easier to update WordPress (via the admin panel) and I updated it more frequently, editing the core file became more of a nuisance.</p>
<h2>A huge facepalm</h2>
<p>When Google began weighting page load times as part of its ranking algorithm, I implemented the <a href="http://wordpress.org/extend/plugins/wp-super-cache/" title="WP Super Cache">WP Super Cache</a> caching plugin on ardamis.com and configured it to use .htaccess and mod_rewrite to serve cache files.  Page load times certainly decreased, but the amount of spam detected by Akismet increased.  After a while, I realized that this was because the spam bots were submitting comments from static, cached pages, and the timestamps on those pages, which had been generated server-side with PHP, were already minutes old when the page was requested.  The form processing script, which normally rejects comments that are submitted too quickly to be written by a human visitor, happily accepted the timestamps.  Even worse, a second function of my anti-spam method also rejected comments that were submitted 10 minutes or more after the page was loaded.  Of course, most of the visitors were being served cached pages that were already more than 10 minutes old, so even legitimate comments were being rejected.  Using PHP to generate my timestamps obviously was not going to work if I wanted to keep serving cached pages.</p>
<h2>JavaScript to the rescue</h2>
<p>Generating real-time timestamps on cached pages requires JavaScript.  But instead of a reliable server clock setting the timestamp, the time is coming from the visitor&#8217;s system, which can&#8217;t be trusted to be accurate.  Merely changing the comment form to use JavaScript to generate the first timestamp wouldn&#8217;t work, because verifying a timestamp generated on the client-side against one generated with a server-side language would be disastrous.</p>
<p>Replacing the PHP-generated timestamps with JavaScript-generated timestamps would require substantial changes to the system.</p>
<p>Traditional client-side form validation using JavaScript happens when the form is submitted.  If the validation fails, the form is not submitted, and the visitor typically gets an alert with suggestions on how to make the form acceptable.  If the validation passes, the form submission continues without bothering the visitor.  To get our two timestamps, we can generate a first timestamp when the page loads and compare it to a second timestamp generated when the form is submitted.  If the visitor submits the form too quickly, we can display an alert showing the number of seconds remaining until the form can be successfully submitted.  This should hopefully be invisible to most visitors who choose to leave comments, but at the very least, far less irritating than a CAPTCHA system.</p>
<p>It took me two tries to get it right, but I&#8217;m going to discuss the less successful method first to point out its flaws.</p>
<h3>Method One (not good enough)</h3>
<p>Here&#8217;s how the original system flowed.</p>
<ol>
<li>Generate a first JS timestamp when the page is loaded.</li>
<li>Generate a second JS timestamp when the form is submitted.</li>
<li>Before the form is submitted, compare the two, and if enough time has passed, write a pre-determined passcode to a hidden INPUT element, then submit the form.</li>
<li>On the form processing page, use server-side logic to verify that the passcode is present and valid.</li>
</ol>
<p>The problem was that it seemed that certain bots could parse JavaScript enough to drop the pre-determined passcode into the hidden form field before submitting the form, circumventing the timestamps completely and defeating the system.  </p>
<p>It also failed to adhere to one of the basic tenants of form validation &#8211; that the input must be checked on both the client-side and the server-side.</p>
<h3>Method Two (better)</h3>
<p>Rather than having the server-side validation be merely a check to confirm that the passcode is present, method two goes back to comparing the timestamps a second time on the server side. Instead of a single hidden input, we now have two &#8211; one for each timestamp.  This is intended to prevent a bot from figuring out the ultimate validation mechanism by simply parsing the JavaScript.  Finally, the hidden fields are added to the form via jQuery, which makes it easier to implement and may act as another layer of obfuscation. </p>
<ol>
<li>Generate a first JS timestamp when the page is loaded and write it to a hidden form field.</li>
<li>Generate a second JS timestamp when the form is submitted and write it to a hidden form field.</li>
<li>Before the form is submitted, compare the two, and if enough time has passed, submit the form (client-side validation).</li>
<li>On the form processing page, use server-side logic to compare the timestamps a second time (server-side validation).</li>
</ol>
<p>The timestamp handshake works more like it did in the server-side-only method.  We still have to pass something from the comment form to the processing script, but it&#8217;s not too obvious from the HTML what is being done with it.</p>
<h2>The same downside plagues me</h2>
<p>Unfortunately, if we want to have any server-side validation at all, and we do, the core file <strong>wp-comments-post.php</strong> will still have to be modified.  In my experience, the system is not sufficiently effective using just client-side validation.  </p>
<h2>The code</h2>
<p>Two files must be modified to implement the validation.</p>
<p><strong>File 1: The theme&#8217;s comments.php file (older themes) or wp-includes\comment-template.php (newer themes)</strong></p>
<p>Your comment form lives somewhere.  My theme is based on Kubrick, the old default WordPress theme, and my comment form is in my theme folder, in a file named <strong>comments.php</strong>.  If your theme is newer and based on the current default theme, twentyeleven, the form is in <strong>wp-includes\comment-template.php</strong>.  If your theme isn&#8217;t based on either of these, all bets are off.  I know it&#8217;s confusing.  Sorry.</p>
<p>Add the JavaScript that creates and populates the timestamp fields.  Be sure to confirm that your comment form has an ID of <strong>commentform</strong>.  I&#8217;m using jQuery to help fire functions when the page loads.</p>
<pre class="brush: jscript; title: ; notranslate">
&lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
$(document).ready(function(){
	ardGenTS1();
});

function ardGenTS1() {
	// prepare the form
	$('#commentform').append('&lt;input type=&quot;hidden&quot; name=&quot;ardTS1&quot; id=&quot;ardTS1&quot; value=&quot;1&quot; /&gt;');
	$('#commentform').append('&lt;input type=&quot;hidden&quot; name=&quot;ardTS2&quot; id=&quot;ardTS2&quot; value=&quot;1&quot; /&gt;');
	$('#commentform').attr('onsubmit', 'return validate()');
	// set a first timestamp when the page loads
	var ardTS1 = (new Date).getTime();
	document.getElementById(&quot;ardTS1&quot;).value = ardTS1;
}

function validate() {
	// read the first timestamp
	var ardTS1 = document.getElementById(&quot;ardTS1&quot;).value;
//	alert ('ardTS1: ' + ardTS1);
	// generate the second timestamp
	var ardTS2 = (new Date).getTime();
	document.getElementById(&quot;ardTS2&quot;).value = ardTS2;
//	alert ('ardTS2: ' + document.getElementById(&quot;ardTS2&quot;).value);
	// find the difference
	var diff = ardTS2 - ardTS1;
	var elapsed = Math.round(diff / 1000);
	var remaining = 10 - elapsed;
//	alert ('diff: ' + diff + '\n\nelapsed:' + elapsed);
	// check whether enough time has elapsed
	if (diff &gt; 10000) {
		// submit the form
		return true;
	}else{
		// display an alert if the form is submitted within 10 seconds
		alert(&quot;This site is protected by an anti-spam feature that requires 10 seconds to have elapsed between the page load and the form submission.\n\nPlease close this alert window.  The form may be resubmitted successfully in &quot; + remaining + &quot; seconds.&quot;);
		// prevent the form from being submitted
		return false;
	}
}
&lt;/script&gt;
</pre>
<p><strong>File 2: The wp-comments-post.php file</strong></p>
<p>The wp-comments-post.php file lives in the root of WordPress and handles the form processing.  We need to add a few lines that check the contents of our new validation input field.</p>
<p>Somewhere after line 53 or so (where <em>$comment_content</em> is defined), insert the following code.</p>
<pre class="brush: php; title: ; notranslate">
$ardTS1 = ( isset($_POST['ardTS1']) ) ? trim($_POST['ardTS1']) : 1;
$ardTS2 = ( isset($_POST['ardTS2']) ) ? trim($_POST['ardTS2']) : 2;
$ardTS = $ardTS2 - $ardTS1;

if ( $ardTS &lt; 10000 ) {
// If the difference of the timestamps is not more than 10 seconds, exit
    wp_die( __('&lt;strong&gt;ERROR&lt;/strong&gt;:  This site uses JavaScript validation to reduce comment spam.  Either your browser has JavaScript disabled, or the comment was not legitimately submitted.') );
}
</pre>
<p>That&#8217;s it.  Not so bad, right?</p>
<h2>Final thoughts</h2>
<p>One advantage to this method over the old PHP-only method is that even if the core file is replaced and the server-side validation is lost, the client-side validation continues to work, perhaps providing some measure of protection.</p>
<p>The method is safe for use with caching systems that create purely static, HTML pages.  I&#8217;ll follow up later and report on how effective it seems to be at stopping spam comments before they get to Akismet (and into the WordPress database).</p>
<p>Now, for a little extra protection, you can rename the <strong>wp-comments-post.php</strong> file and change the path in the comment form&#8217;s action attribute.  I&#8217;ve <a href="http://www.ardamis.com/2010/08/09/reducing-wordpress-spam-comments/">posted logs</a> showing that some bots just try to post spam directly to the <strong>wp-comments-post.php</strong> file, so renaming that file is an easy way to cut down on spam.  Just remember to come back and delete the <strong>wp-comments-post.php</strong> file each time you update WordPress.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ardamis.com/2011/08/27/a-cache-proof-method-for-reducing-comment-spam/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Programmatically re-enabling Word COM add-ins</title>
		<link>http://www.ardamis.com/2011/05/05/programmatically-re-enabling-word-com-add-ins/</link>
		<comments>http://www.ardamis.com/2011/05/05/programmatically-re-enabling-word-com-add-ins/#comments</comments>
		<pubDate>Thu, 05 May 2011 21:14:09 +0000</pubDate>
		<dc:creator>ardamis</dc:creator>
				<category><![CDATA[Nonsense]]></category>
		<category><![CDATA[application]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Office]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[templates]]></category>

		<guid isPermaLink="false">http://www.ardamis.com/?p=1354</guid>
		<description><![CDATA[A Word macro to re-enable all disabled COM add-ins, then force desired LoadBehaviors on specific add-ins, effectively putting Word back into a certain state.]]></description>
			<content:encoded><![CDATA[<p>Nearly a year ago, I wrote a post on how to <a href="http://www.ardamis.com/2010/06/20/detect-and-fix-word-add-in-problems-with-a-macro-and-batch-file/">detect and fix Word add-in problems with a macro and batch file</a>, in a Windows XP and Office 2007 environment.</p>
<p>This was sufficiently effective, but it was also overly complicated, requiring four separate components:</p>
<ol>
<li>an autoexec Word 2007 macro that runs each time Word is opened</li>
<li>a batch file that runs the registry merge file and writes an entry to a log file</li>
<li>the registry merge file that contains the correct LoadBehavior settings for the add-ins</li>
<li>a text file that acts as a log</li>
</ol>
<p>This month, I decided to rewrite the macro to handle the registry changes and write to the log file.  It was also a good opportunity to dig a bit deeper into VBA, and I also wanted to confirm that it would work in a more modern environment of Windows 7 and Office 2010 (that code is near the bottom of the post). The new system has only two components:</p>
<ol>
<li>an autoexec Word 2007 macro that runs each time Word is opened</li>
<li>a text file that acts as a log</li>
</ol>
<h2>Background</h2>
<p>First, a bit of background.</p>
<p>Many of the problems with Word 2007 are due to Word&#8217;s handling of add-ins. When something unexpected happens in Word, and Word attributes the problem to an add-in, Word will react by flagging it and prompting the user for a decision the next time Word opens. Depending on the severity of the problem and the user&#8217;s response, the add-in can be either &#8216;hard-disabled&#8217; or &#8216;soft-disabled&#8217;.</p>
<p>Microsoft explains the differences between Hard Disabled vs Soft Disabled in a MSDN article at: <a href="http://msdn.microsoft.com/en-us/library/ms268871(VS.80).aspx">http://msdn.microsoft.com/en-us/library/ms268871(VS.80).aspx</a>.</p>
<p>I&#8217;ve explained a bit about the process by which Word disables add-ins at the end of this post, and I&#8217;ve written a shorter post about <a href="http://www.ardamis.com/2010/02/26/fixing-word-2007-add-in-issues/">the basics behind the registry keys responsible for disabling add-ins</a>.</p>
<h2>Handling disabled add-ins programmatically</h2>
<p>A Word macro can access the condition of an add-in via an Application.COMAddIns object, and it can read and write to the registry.  This allows us to tell when an add-in has been disabled and re-enabled it.</p>
<p>My macro has some admittedly hackish parts that need to be cleaned up, there is the matter of unsetting variables to be addressed, and it could certainly be made more elegant, but it works.  Note that a file named <strong>addinslog.txt</strong> must exist in the %TEMP% directory in order for the macro to write the log file.  This is what the Word 2007 macro looks like, using the COM add-in installed with Adobe Acrobat 8 Standard as the required add-in&#8230;</p>
<pre class="brush: plain; title: ; notranslate">
Option Explicit

' Set up a function to search for a key and return true or false
Public Function KeyExists(key)
    Dim objShell
    On Error Resume Next
    Set objShell = CreateObject(&quot;WScript.Shell&quot;)
        objShell.RegRead (key)
    Set objShell = Nothing
    If Err = 0 Then KeyExists = True
End Function

Sub AutoExec()
'
' FixMissingAddins Macro
' Display a message box with any critical but not 'Connected' COM add-ins, then fix them programatically
'
' Oliver Baty
' June, 2010 - April, 2011
'
' Information on the Application.COMAddIns array
' http://msdn.microsoft.com/en-us/library/aa831759(v=office.10).aspx
'
' Running macros automatically
' http://support.microsoft.com/kb/286310
'
' Using Windows Scripting Shell (WshShell) to read from and write to the local registry
' http://technet.microsoft.com/en-us/library/ee156602.aspx

' Declare the WshShell variable (this is used to edit the registry)
    Dim WshShell

' Declare the fso and logFile variables (these are used to write to a txt file)
    Dim fso
    Dim logFile

' Create an instance of the WScript Shell object
    Set WshShell = CreateObject(&quot;WScript.Shell&quot;)

' Declare some other variables
   Dim MyAddin As COMAddIn
   Dim stringOfAddins As String
   Dim listOfDisconnectedAddins As String
   Dim requiredAddIn As Variant
   Dim msg As String

' Notes on deleting registry keys and values in VB
' http://www.vbforums.com/showthread.php?t=425483
' http://www.tek-tips.com/viewthread.cfm?qid=674375
' http://www.robvanderwoude.com/vbstech_registry_wshshell.php

' Create a string containing the names of all 'Connected' COM add-ins named &quot;stringOfAddins&quot;
   For Each MyAddin In Application.COMAddIns
      If MyAddin.Connect = True Then
          stringOfAddins = stringOfAddins &amp; MyAddin.ProgID &amp; &quot; - &quot;
      End If
   Next

' Create an array to hold the names of the critical (required) add-ins named &quot;requiredAddIns&quot;
' Example: change to &quot;Dim requiredAddIns(0 To 4)&quot; if the macro is checking 5 total add-ins)
   Dim requiredAddIns(0 To 0) As String

' Add each required AddIn to the array
   requiredAddIns(0) = &quot;PDFMaker.OfficeAddin&quot;
'   requiredAddIns(1) = &quot;&quot;
'   requiredAddIns(2) = &quot;&quot;
'   requiredAddIns(3) = &quot;&quot;
'   requiredAddIns(4) = &quot;&quot;

' Cycle through the array of required add-ins, and see if they exist in the connected add-ins list
   For Each requiredAddIn In requiredAddIns
      If InStr(stringOfAddins, requiredAddIn) Then
        ' The required add-in is in the string of connected add-ins
         msg = msg
      Else
        ' The required add-in is not in the string of connected add-ins, so add the add-in name to a string named &quot;listOfDisconnectedAddins&quot;
         msg = msg &amp; requiredAddIn &amp; vbCrLf
         listOfDisconnectedAddins = requiredAddIn &amp; &quot; &quot; &amp; listOfDisconnectedAddins
         listOfDisconnectedAddins = Trim(listOfDisconnectedAddins)
      End If
   Next

' If the msg variable is not blank (it contains at least one add-in's name) handle it, otherwise, do nothing
   If msg = &quot;&quot; Then
        ' There are no critical, unconnected add-ins (yay!)
        ' The script can now exit
   Else
        ' There are critical add-ins that are not connected, so handle this
        MsgBox &quot;The following critical Word Add-In(s) are disabled: &quot; &amp; vbCrLf &amp; vbCrLf &amp; msg &amp; vbCrLf &amp; vbCrLf &amp; &quot;To correct this problem, please save any documents you are working on, then close Word and reopen Word.&quot;

            ' I find it extremely hackish to check for each possible key and delete it if found... need to research how to delete the tree
            ' One potential obstacle to this method is that I've seen a DocumentRecovery subkey under Resiliency (only once, while editing this macro), that I haven't researched yet

            ' Note: Since the WSH Shell has no Enumeration functionality, you cannot
            '       use the WSH Shell object to delete an entire &quot;tree&quot; unless you
            '       know the exact name of every subkey.
            '       If you don't, use the WMI StdRegProv instead.
            ' http://www.robvanderwoude.com/vbstech_registry_wshshell.php

            ' More info on WMI StdRegProv at:
            ' http://msdn.microsoft.com/en-us/library/aa393664(v=vs.85).aspx

        ' This is hackish, but it effectively deletes a registry key, if it exists
        If KeyExists(&quot;HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Resiliency\DisabledItems\&quot;) Then
            WshShell.RegDelete &quot;HKCU\Software\Microsoft\Office\12.0\Word\Resiliency\DisabledItems\&quot;
        ElseIf KeyExists(&quot;HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Resiliency\StartupItems\&quot;) Then
            WshShell.RegDelete &quot;HKCU\Software\Microsoft\Office\12.0\Word\Resiliency\StartupItems\&quot;
        ElseIf KeyExists(&quot;HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Resiliency\&quot;) Then
            WshShell.RegDelete &quot;HKCU\Software\Microsoft\Office\12.0\Word\Resiliency\&quot;
        End If

        ' To be completely thorough, we can also set the desired LoadBehavior for certain add-ins
        ' This can be done selectively, and only if the LoadBehavior was incorrect, but the quick and dirty way would be to just force the values

        WshShell.RegWrite &quot;HKLM\SOFTWARE\Microsoft\Office\Word\Addins\PDFMaker.OfficeAddin\LoadBehavior&quot;, 3, &quot;REG_DWORD&quot;

        ' Release the WshShell object
        Set WshShell = Nothing

        ' Declare a few variables for the log file
        Dim user, machine, datetime, output

        Set WshShell = CreateObject(&quot;WScript.Shell&quot;)
        user = WshShell.ExpandEnvironmentStrings(&quot;%USERNAME%&quot;)
        machine = WshShell.ExpandEnvironmentStrings(&quot;%COMPUTERNAME%&quot;)
        temp = WshShell.ExpandEnvironmentStrings(&quot;%TEMP%&quot;)
        ' Convert the slashes in Now to hyphens to prevent a fatal error
        datetime = Replace(Now, &quot;/&quot;, &quot;-&quot;)
        ' Create the string that will be written to the log file
        output = datetime + &quot;, &quot; + user + &quot;, &quot; + machine + &quot;, &quot; + listOfDisconnectedAddins

        ' Write the event to a log file
        logfile = temp + &quot;\addinslog.txt&quot;
        ' http://msdn.microsoft.com/en-us/library/2z9ffy99(v=vs.85).aspx
        ' http://www.devguru.com/technologies/vbscript/quickref/filesystemobject_opentextfile.html
        Set fso = CreateObject(&quot;Scripting.FileSystemObject&quot;)
        Set logFile = fso.OpenTextFile(logfile, 8, True)
        logFile.WriteLine (output)
        logFile.Close
        Set logFile = Nothing
        Set fso = Nothing

        ' Should we clear the variables?

        ' Release the WshShell object
        Set WshShell = Nothing
   End If

   ' Ardamis.com - We're in your macros, fixing your COM add-ins.
End Sub
</pre>
<p>While working on this, I found that there were some gaps in my understanding of the sequence of events that occur when Word 2007 disables a COM add-in.  Please comment if you find that any of this is inaccurate or incomplete.</p>
<h2>What happens when Word launches</h2>
<p>A critical key to the whole business of Word add-ins is HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Resiliency</p>
<p>When Word launches, it looks for data under the Resiliency key and a subkey: HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Resiliency\StartupItems</p>
<p>If the StartupItems subkey contains a REG_BINARY value that corresponds to an add-in, Word throws the familiar warning:</p>
<p><em>Microsoft Office Word</em><br />
<em>Word experienced a serious problem with the ‘[addin name]’ add-in. If you have seen this message multiple times, you should disable this add-in and check to see if an update is available. Do you want to disable this add-in?</em><br />
<em>[Yes] [No]</em></p>
<p>Choosing No at the prompt removes the Resiliency key and allows Word to continue to launch, leaving the LoadBehavior for that add-in unchanged.</p>
<p>Choosing No also writes an Error event to the Application Event Viewer log:</p>
<pre class="brush: plain; title: ; notranslate">
Event Type:	Error
Event Source:	Microsoft Office 12
Event Category:	None
Event ID:	2000
Date:		5/23/2011
Time:		3:15:29 PM
User:		N/A
Computer:	[WORKSTATION_NAME]
Description:
Accepted Safe Mode action : Microsoft Office Word.

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
</pre>
<p>Choosing Yes at the prompt removes the StartupItems subkey and creates a new DisabledItems subkey. This DisabledItems subkey will contain a different REG_BINARY value, the data of which contains information about the disabled add-in.</p>
<p>Choosing Yes also writes an Error event to the Application Event Viewer log:</p>
<pre class="brush: plain; title: ; notranslate">
Event Type:	Error
Event Source:	Microsoft Office 12
Event Category:	None
Event ID:	2001
Date:		5/23/2011
Time:		3:12:36 PM
User:		N/A
Computer:	[WORKSTATION_NAME]
Description:
Rejected Safe Mode action : Microsoft Office Word.

For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
</pre>
<p>At this point, the add-in is &#8216;hard-disabled&#8217;, but not &#8216;soft-disabled&#8217;.</p>
<p>Word then continues to launch, but without loading the add-in.  </p>
<p>To see which add-ins have been hard-disabled, click on the Office Button | Word Options | Add-Ins, and scroll down to &#8220;Disabled Application Add-ins&#8221;.</p>
<p>To see which add-ins have been soft-disabled, click on the Office Button | Word Options | Add-Ins. Select &#8220;COM Add-Ins&#8221; in the Manage menu and click Go.</p>
<p>Word is somewhat tricky in this regard, as the add-in will not have a checkmark, but the LoadBehavior registry value will be unchanged.  At any other time, the presence of a checkmark is an indication of the LoadBehavior, but when an add-in has been hard-disabled, the box will always be unchecked.</p>
<h2>What users can do at this point</h2>
<p>Going through Word Options and enabling the hard-disabled COM add-in will remove the Resiliency key.  This may not make the add-in immediately available in Word, however.</p>
<p>To immediately load the add-in and gain its functionality, you can check the box.  Otherwise, close and reopen Word, which will cause Word to launch with the add-in&#8217;s specified LoadBehavior.</p>
<p>In case you were curious about the keyboard shortcuts used to enable the first disabled add-in in the list of disabled add-ins (maybe you wanted to do something with SendKeys, for example), they are:<br />
<strong>Alt+F, I, A, A, Tab, Tab, Tab, D, Enter, G, Space, Alt+E, C, Alt+F4</strong>.</p>
<p>In summary, deleting the Resiliency key after the &#8220;serious problem&#8221; prompt, then closing and reopening Word, returns Word to a normal operating state.</p>
<p>What I intend to accomplish with the macro is to re-enable the hard-disabled add-in, return any LoadBehavior values back to the desired settings, then prompt the user to save their work and close and reopen Word.</p>
<p>This should return Word to a working state.</p>
<h2>Word 2010 on 64-bit Windows 7</h2>
<p>As a bonus, here&#8217;s the same macro, with some minor adjustments to run in Word 2010 on Windows 7 64-bit, with Adobe Acrobat 9 Pro&#8217;s COM add-in acting as one of the required add-ins.  The OneNote add-in is not enabled in Word by default, and the macro below does not attempt to enable it, but does consider it a required add-in.  This is done to demonstrate the pop-up window.  Note that a file named <strong>addinslog.txt</strong> must exist in the %TEMP% directory in order for the macro to write the log file.</p>
<pre class="brush: plain; title: ; notranslate">
Option Explicit

' Set up a function to search for a key and return true or false
Public Function KeyExists(key)
    Dim objShell
    On Error Resume Next
    Set objShell = CreateObject(&quot;WScript.Shell&quot;)
        objShell.RegRead (key)
    Set objShell = Nothing
    If Err = 0 Then KeyExists = True
End Function

Sub AutoExec()
'
' FixMissingAddins Macro
' Display a message box with any critical but not 'Connected' COM add-ins, then fix them programatically
'
' Oliver Baty
' June, 2010 - April, 2011
'
' Information on the Application.COMAddIns array
' http://msdn.microsoft.com/en-us/library/aa831759(v=office.10).aspx
'
' Running macros automatically
' http://support.microsoft.com/kb/286310
'
' Using Windows Scripting Shell (WshShell) to read from and write to the local registry
' http://technet.microsoft.com/en-us/library/ee156602.aspx

' Declare the WshShell variable (this is used to edit the registry)
    Dim WshShell

' Declare the fso and logFile variables (these are used to write to a txt file)
    Dim fso
    Dim logfile

' Create an instance of the WScript Shell object
    Set WshShell = CreateObject(&quot;WScript.Shell&quot;)

' Declare some other variables
   Dim MyAddin As COMAddIn
   Dim stringOfAddins As String
   Dim listOfDisconnectedAddins As String
   Dim requiredAddIn As Variant
   Dim msg As String

' Notes on deleting registry keys and values in VB
' http://www.vbforums.com/showthread.php?t=425483
' http://www.tek-tips.com/viewthread.cfm?qid=674375
' http://www.robvanderwoude.com/vbstech_registry_wshshell.php

' Create a string containing the names of all 'Connected' COM add-ins named &quot;stringOfAddins&quot;
   For Each MyAddin In Application.COMAddIns
      If MyAddin.Connect = True Then
          stringOfAddins = stringOfAddins &amp; MyAddin.ProgID &amp; &quot; - &quot;
      End If
   Next

' Create an array to hold the names of the critical (required) add-ins named &quot;requiredAddIns&quot;
' Example: change to &quot;Dim requiredAddIns(0 To 4)&quot; if the macro is checking 5 total add-ins)
   Dim requiredAddIns(0 To 1) As String

' Add each required AddIn to the array
   requiredAddIns(0) = &quot;PDFMaker.OfficeAddin&quot;
   requiredAddIns(1) = &quot;OneNote.WordAddinTakeNotesService&quot;
'   requiredAddIns(2) = &quot;&quot;
'   requiredAddIns(3) = &quot;&quot;
'   requiredAddIns(4) = &quot;&quot;

' Cycle through the array of required add-ins, and see if they exist in the connected add-ins list
   For Each requiredAddIn In requiredAddIns
      If InStr(stringOfAddins, requiredAddIn) Then
        ' The required add-in is in the string of connected add-ins
         msg = msg
      Else
        ' The required add-in is not in the string of connected add-ins, so add the add-in name to a string named &quot;listOfDisconnectedAddins&quot;
         msg = msg &amp; requiredAddIn &amp; vbCrLf
         listOfDisconnectedAddins = requiredAddIn &amp; &quot; &quot; &amp; listOfDisconnectedAddins
         listOfDisconnectedAddins = Trim(listOfDisconnectedAddins)
      End If
   Next

' If the msg variable is not blank (it contains at least one add-in's name) handle it, otherwise, do nothing
   If msg = &quot;&quot; Then
        ' There are no critical, unconnected add-ins (yay!)
        ' The script can now exit
   Else
        ' There are critical add-ins that are not connected, so handle this
        MsgBox &quot;The following critical Word Add-In(s) are disabled: &quot; &amp; vbCrLf &amp; vbCrLf &amp; msg &amp; vbCrLf &amp; vbCrLf &amp; &quot;To correct this problem, please save any documents you are working on, then close Word and reopen Word.&quot;

            ' I find it extremely hackish to check for each possible key and delete it if found... need to research how to delete the tree
            ' One potential obstacle to this method is that I've seen a DocumentRecovery subkey under Resiliency (only once, while editing this macro), that I haven't researched yet

            ' Note: Since the WSH Shell has no Enumeration functionality, you cannot
            '       use the WSH Shell object to delete an entire &quot;tree&quot; unless you
            '       know the exact name of every subkey.
            '       If you don't, use the WMI StdRegProv instead.
            ' http://www.robvanderwoude.com/vbstech_registry_wshshell.php

            ' More info on WMI StdRegProv at:
            ' http://msdn.microsoft.com/en-us/library/aa393664(v=vs.85).aspx

        ' This is hackish, but it effectively deletes a registry key, if it exists
        If KeyExists(&quot;HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Word\Resiliency\DisabledItems\&quot;) Then
            WshShell.RegDelete &quot;HKCU\Software\Microsoft\Office\14.0\Word\Resiliency\DisabledItems\&quot;
        ElseIf KeyExists(&quot;HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Word\Resiliency\StartupItems\&quot;) Then
            WshShell.RegDelete &quot;HKCU\Software\Microsoft\Office\14.0\Word\Resiliency\StartupItems\&quot;
        ElseIf KeyExists(&quot;HKEY_CURRENT_USER\Software\Microsoft\Office\14.0\Word\Resiliency\&quot;) Then
            WshShell.RegDelete &quot;HKCU\Software\Microsoft\Office\14.0\Word\Resiliency\&quot;
        End If

        ' To be completely thorough, we can also set the desired LoadBehavior for certain add-ins
        ' This can be done selectively, and only if the LoadBehavior was incorrect, but the quick and dirty way would be to just force the values

        WshShell.RegWrite &quot;HKCU\Software\Microsoft\Office\Word\Addins\PDFMaker.OfficeAddin\LoadBehavior&quot;, 3, &quot;REG_DWORD&quot;

        ' Release the WshShell object
        Set WshShell = Nothing

        ' Declare a few variables for the log file
        Dim user, machine, temp, datetime, output

        Set WshShell = CreateObject(&quot;WScript.Shell&quot;)
        user = WshShell.ExpandEnvironmentStrings(&quot;%USERNAME%&quot;)
        machine = WshShell.ExpandEnvironmentStrings(&quot;%COMPUTERNAME%&quot;)
        temp = WshShell.ExpandEnvironmentStrings(&quot;%TEMP%&quot;)
        ' Convert the slashes in Now to hyphens to prevent a fatal error
        datetime = Replace(Now, &quot;/&quot;, &quot;-&quot;)
        ' Create the string that will be written to the log file
        output = datetime + &quot;, &quot; + user + &quot;, &quot; + machine + &quot;, &quot; + listOfDisconnectedAddins

        ' Write the event to a log file
        logfile = temp + &quot;\addinslog.txt&quot;
        ' http://msdn.microsoft.com/en-us/library/2z9ffy99(v=vs.85).aspx
        ' http://www.devguru.com/technologies/vbscript/quickref/filesystemobject_opentextfile.html
        Set fso = CreateObject(&quot;Scripting.FileSystemObject&quot;)
        Set logfile = fso.OpenTextFile(logfile, 8, True)
        logfile.WriteLine (output)
        logfile.Close
        Set logfile = Nothing
        Set fso = Nothing

        ' Should we clear the variables?

        ' Release the WshShell object
        Set WshShell = Nothing
   End If

   ' Ardamis.com - We're in your macros, fixing your COM add-ins.
End Sub
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.ardamis.com/2011/05/05/programmatically-re-enabling-word-com-add-ins/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Web development tools</title>
		<link>http://www.ardamis.com/2010/08/15/web-development-tools/</link>
		<comments>http://www.ardamis.com/2010/08/15/web-development-tools/#comments</comments>
		<pubDate>Mon, 16 Aug 2010 03:39:17 +0000</pubDate>
		<dc:creator>ardamis</dc:creator>
				<category><![CDATA[Web Site Dev]]></category>
		<category><![CDATA[htaccess]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[script.aculo.us]]></category>
		<category><![CDATA[templates]]></category>
		<category><![CDATA[themes]]></category>
		<category><![CDATA[web app]]></category>
		<category><![CDATA[xhtml]]></category>

		<guid isPermaLink="false">http://www.ardamis.com/?p=842</guid>
		<description><![CDATA[A collection of web development tools for building better sites more easily.]]></description>
			<content:encoded><![CDATA[<p>A collection of web development tools for building better sites more easily.</p>
<h3>Frameworks and scripts</h3>
<p><a href="http://html5boilerplate.com/">HTML5 Boilerplate</a> is the professional badass&#8217;s base HTML/CSS/JS template for a fast, robust and future-proof site.</p>
<p><a href="http://scriptsrc.net/">scriptsrc.net</a> is a collection of script tags of the latest versions of a range of JavaScript libraries.</p>
<p><a href="http://www.modernizr.com/">Modernizr</a> adds classes to the &lt;html&gt; element which allow you to target specific browser functionality in your stylesheet. You don&#8217;t actually need to write any Javascript to use it.</p>
<h3>Images</h3>
<p><a href="http://placehold.it/">placehold.it</a> is a quick and simple image placeholder service.</p>
<h3>Text manipulation</h3>
<p><a href="http://www.textfixer.com/tools/">TextFixer</a> is a collection of online text tools. Remove line breaks from text, alphabetize text, capitalize the first letter of sentences, remove whitespaces, and uppercase text or lowercase text.</p>
<h3>XHTML</h3>
<p><a href="http://willpeavy.com/minifier/">HTML Minifier</a> will minify HTML (or XHTML), and any CSS or JS included in your markup.</p>
<h3>CSS</h3>
<p><a href="http://css3generator.com/">CSS3 Generator</a> is an awesome code generator for CSS3 snippets, and shows the minimum browser versions required to display the effects.</p>
<p><a href="http://procssor.com/">proCSSor</a> is an advanced CSS prettifier with tons of formatting options.</p>
<h3>JavaScript</h3>
<p><a href="http://jsbeautifier.org/">Online javascript beautifier</a> will reformat and reindent bookmarklets, ugly javascript, unpack scripts packed by the popular <a href="http://dean.edwards.name/packer/">Dean Edward&#8217;s packer,</a> as well as deobfuscate scripts processed by javascriptobfuscator.com.  The source code for the latest version is always available on <a href="http://github.com/einars/js-beautify">github</a>, and you can download the beautifier for local use (<a href="http://github.com/einars/js-beautify/zipball/master">zip</a>, <a href="http://github.com/einars/js-beautify/tarball/master">tar.gz</a>) as well.</p>
<h3>Fonts and Typography</h3>
<p>Fontshop.com has written <a href="http://www.fontshop.com/education/">A Field Guide to Typography</a> to get you excited about fonts and typography.</p>
<p><a href="http://www.typetester.org/">Typetester</a> is an online app for comparing different fonts for the screen, you can test up to three fonts at a time and choose the one you like. Its primary role is to make web designer’s life easier.</p>
<p>A quick chart of the <a href="http://www.ampsoft.net/webdesign-l/WindowsMacFonts.html">fonts common to all versions of Windows and the Mac equivalents</a>, or a more extensive <a href="http://media.24ways.org/2007/17/fontmatrix.html">matrix of fonts bundled with Mac and Windows operating systems, Microsoft Office and Adobe Creative Suite</a>.</p>
<p><a href="http://html-ipsum.com/">&lt;html&gt;ipsum</a> has Lorem ipsum already wrapped in HTML tags.  Pre-made paragraphs, lists, etc&#8230;</p>
<p>More resources at: <a href="http://www.smashingmagazine.com/2009/01/27/css-typographic-tools-and-techniques/">50 Useful Design Tools For Beautiful Web Typography</a> and <a href="http://speckyboy.com/2009/01/12/21-typography-and-font-web-apps-you-cant-live-without/">21 Typography and Font Web Apps You Can&#8217;t Live Without</a>.</p>
<h3>Colors</h3>
<p><a href="http://colorschemedesigner.com/">Color Scheme Designer</a>.</p>
<h3>Markup</h3>
<p>Google Webmaster Tools&#8217; <a href="http://www.google.com/webmasters/tools/richsnippets">Rich Snippets Testing Tool</a>.</p>
<p>Use the Rich Snippets Testing Tool to check that Google can correctly parse your structured data markup and display it in search results.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ardamis.com/2010/08/15/web-development-tools/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Detect and fix Word add-in problems with a macro and batch file</title>
		<link>http://www.ardamis.com/2010/06/20/detect-and-fix-word-add-in-problems-with-a-macro-and-batch-file/</link>
		<comments>http://www.ardamis.com/2010/06/20/detect-and-fix-word-add-in-problems-with-a-macro-and-batch-file/#comments</comments>
		<pubDate>Mon, 21 Jun 2010 03:36:37 +0000</pubDate>
		<dc:creator>ardamis</dc:creator>
				<category><![CDATA[Nonsense]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[application]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Office]]></category>
		<category><![CDATA[templates]]></category>
		<category><![CDATA[Windows 7]]></category>

		<guid isPermaLink="false">http://www.ardamis.com/?p=646</guid>
		<description><![CDATA[How to detect when important add-ins are not correctly loaded when Word starts and fix them automatically.]]></description>
			<content:encoded><![CDATA[<div class="notice"><strong>Update 5.5.11:</strong> I&#8217;ve written a better macro that doesn&#8217;t require a separate batch file and registry merge file.  Please check out the new post at:</p>
<p><a style="border-bottom:1px solid #202020;" href="http://www.ardamis.com/2011/05/05/programmatically-re-enabling-word-com-add-ins/">Programmatically re-enabling Word COM add-ins</a></p>
</div>
<p>A few months ago, I wrote a post on <a href="http://www.ardamis.com/2010/02/26/fixing-word-2007-add-in-issues/">fixing Word 2007 add-in issues with a registry merge</a>.  In this post, I&#8217;ll take that idea a little further and explain how to automatically detect and fix add-ins through the use of a macro that runs each time Word is opened and a batch file that runs the registry merge file.  All the end-user needs to do to repair the missing functionality is close and reopen Word.</p>
<p>The idea is that, in a corporate environment, there are certain important add-ins that must be running in order for Word to work normally.  A good example would be an add-in that integrates Word with a document management system.  Should that integration be lost because the add-in failed to load, data may be lost.  Because there is no way to force Word to load certain add-ins, and there is no built-in function in Word for warning users when critically important don&#8217;t load, I decided to come up with a method for alerting the user to the problem and then fixing it with as little inconvenience as possible.</p>
<p>The example code in this post assumes the workstation is running Office 2007 on Windows XP (32-bit).  I would think that the method could be adapted to other environments (Windows 7, Office 2010) without too much trouble.  I&#8217;ve tried to note where differences come up on Windows 7 and 64-bit operating systems.</p>
<p>The process has four components:</p>
<ul>
<li>an autoexec Word 2007 macro that runs each time Word is opened</li>
<li>a batch file that runs the registry merge file and writes an entry to a log file</li>
<li>the registry merge file that contains the correct LoadBehavior settings for the add-ins</li>
<li>a text file that acts as a log</li>
</ul>
<p>The macro can be added to Normal.dotm or saved to a new .dotm file placed in the startup directory.  The .bat batch file, .reg registry file, and .txt log file can be put anywhere, but in this example, they will be saved to a new folder <strong>C:\Word Add-ins fix\</strong>.</p>
<p>In the code examples below, I&#8217;ll be using the <strong>Acrobat PDFMaker Office COM Addin</strong> as the add-in that must always be loaded.  This plugin is installed with Acrobat versions 8.1 and above and adds an Acrobat tab to the ribbon.</p>
<h2>The macro</h2>
<p>The first thing to do is to collect some information on the COM add-ins that are currently installed.  Microsoft Support provides a simple macro for listing all of the COM add-ins at <a href="http://support.microsoft.com/kb/307479">Some COM add-ins are not listed in the COM Add-Ins dialog box in Word</a>.  I recommend using this macro to identify the <strong>ProgID</strong> of your add-ins.  The text to the left of the hyphen is the add-in&#8217;s Description and the text to the right of the hyphen is the ProgID.  </p>
<p>Running the macro from the Microsoft site shows us that the ProgID for the Acrobat PDFMaker Office COM Addin is <strong>PDFMaker.OfficeAddin</strong>.</p>
<p><a href="http://www.ardamis.com/wp-content/uploads/2010/06/Application.COMAddIns-Description-ProgID.png"><img src="http://www.ardamis.com/wp-content/uploads/2010/06/Application.COMAddIns-Description-ProgID.png" alt="" title="Application.COMAddIns-Description-ProgID" width="398" height="154" class="aligncenter size-full wp-image-647" /></a></p>
<p>In Microsoft jargon, an add-in with a LoadBehavior of 3 is &#8216;Connected&#8217;.  The COMAddIn object has a property called Connect that will be True if the add-in is Connected and False if it is not.  The macro first checks the Connect property of each add-in and writes the ProgID of each Connected add-in to a string.  It then checks to see if the string contains a match for each of the required add-ins.  If the required add-in does not exist in the string, the macro will display a message to the user and fire the batch file to reset the LoadBehavior.  It also passes the names of any not connected add-ins to the batch file as a parameter, so that information can be logged.</p>
<p>I found this article from MSDN on the <a href="http://msdn.microsoft.com/en-us/library/aa831759(v=office.10).aspx">COMAddIn object</a> very helpful. </p>
<pre class="brush: plain; title: ; notranslate">
Sub AutoExec()
'
' FindMissingAddins Macro
' Display a message box with any critical but not 'Connected' COM add-ins
'

   Dim msg As String

   Dim MyAddin As COMAddIn
   Dim i As Integer, stringOfAddins As String

   For Each MyAddin In Application.COMAddIns
      If MyAddin.Connect = True Then
          stringOfAddins = stringOfAddins &amp; MyAddin.ProgID &amp; &quot; - &quot;
      End If
   Next

' Update the number of elements in the array
' Example: change to &quot;requiredAddIns(0 To 4)&quot; if you were checking 5 total add-ins)
   Dim requiredAddIns(0 To 0) As String

' Add each required AddIn to the array
   requiredAddIns(0) = &quot;PDFMaker.OfficeAddin&quot;
'   requiredAddIns(1) = &quot;&quot;
'   requiredAddIns(2) = &quot;&quot;
'   requiredAddIns(3) = &quot;&quot;
'   requiredAddIns(4) = &quot;&quot;

   For Each requiredAddIn In requiredAddIns
      If InStr(stringOfAddins, requiredAddIn) Then
         msg = msg
      Else
         msg = msg &amp; requiredAddIn &amp; vbCrLf
         listOfDisconnectedAddins = requiredAddIn &amp; &quot; &quot; &amp; listOfDisconnectedAddins
         listOfDisconnectedAddins = Trim(listOfDisconnectedAddins)
      End If
   Next

   If msg = &quot;&quot; Then
   Else
        MsgBox &quot;The following important add-ins are not running: &quot; &amp; vbCrLf &amp; vbCrLf &amp; msg &amp; vbCrLf &amp; vbCrLf &amp; &quot;Please save your work, then close and reopen Word.&quot;
' Run a batch file that corrects the add-in problems in the registry and pass the list of unconnected add-ins as an argument
        Shell &quot;&quot;&quot;C:\Word Add-ins fix\fixWordAddins.bat&quot;&quot; &quot;&quot;&quot; &amp; listOfDisconnectedAddins &amp; &quot;&quot;&quot;&quot;
   End If

End Sub
</pre>
<p>Edit the macro to fit your environment.  You will need to specify each required add-in&#8217;s ProgID in the <strong>requiredAddIns</strong> array and update the number of add-ins in the array&#8217;s definition.  The macro needs to be named AutoExec in order to run when Word starts.</p>
<p>This is the message that the user will receive if the macro finds that a required add-in is not Connected.</p>
<p><a href="http://www.ardamis.com/wp-content/uploads/2010/06/alert-on-MyAddin.Connect-is-not-True.png"><img src="http://www.ardamis.com/wp-content/uploads/2010/06/alert-on-MyAddin.Connect-is-not-True.png" alt="" title="alert-on-MyAddin.Connect-is-not-True" width="340" height="229" class="aligncenter size-full wp-image-648" /></a></p>
<p>Clicking OK runs the batch file and closes the window.</p>
<h2>The batch file</h2>
<p>The batch file is called by the macro when any of the add-ins are not registered and currently connected.  The batch file references the .reg file that contains the correct LoadBehavior settings and writes an event to the log with information on the username, the machine name, the datetime that the problem was discovered and which add-in(s) were not connected.</p>
<p>Copy the code and save it as <strong>fixWordAddins.bat</strong> to the C:\Word Add-ins fix\ directory or wherever you want.</p>
<pre class="brush: plain; title: ; notranslate">
:: A batch file for running a registry merge to set the LoadBehavior for Word add-ins
::
@echo off

REGEDIT /S &quot;C:\Word Add-ins fix\fixWordAddins.reg&quot;

:: Let's create a little log file and output which user ran the script and at what date and time
:: Set some variables for the date. US format - not localized!
@For /F &quot;tokens=2,3,4 delims=/ &quot; %%A in ('Date /t') do @(
	Set Month=%%A
	Set Day=%%B
	Set Year=%%C
)

:: Set some variables for the time.
@For /F &quot;tokens=1,2,3 delims=/: &quot; %%A in ('Time /t') do @(
	Set Hours=%%A
	Set Minutes=%%B
	Set Meridiem=%%C
)

:: Output to a log file
@echo %username% at %computername% on %Month%/%Day%/%Year% at %Hours%:%Minutes% %Meridiem% (%1) &gt;&gt; &quot;C:\Word Add-ins fix\log.txt&quot;
</pre>
<h2>The registry merge</h2>
<p>Add-ins can be &#8216;hard-disabled&#8217; or &#8216;soft-disabled&#8217; by Word 2007.  Please see my post at  <a href="http://www.ardamis.com/2010/02/26/fixing-word-2007-add-in-issues/">fixing Word 2007 add-in issues with a registry merge</a> for more information about what this means.  The following registry merge will address both issues.</p>
<p>The registry merge will have to be edited for your environment, too.  First, find the LoadBehavior value in the the registry for each of your add-ins in either of two locations:<br />
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\Word\Addins\<br />
HKEY_CURRENT_USER\Software\Microsoft\Office\Word\Addins\</p>
<p>If you don&#8217;t find your add-in in either of those locations, search the registry for the ProgID.</p>
<p>A LoadBehavior of 3 = loaded (this corresponds to a checked box in Word Options/Add-Ins)<br />
A LoadBehavior of 2 = not loaded (this corresponds to an unchecked box in Word Options/Add-Ins)</p>
<p>The only add-ins that you need to worry about here are those that you want to always run (those that normally have a LoadBehavior of 3).  Export those keys and add them to the .reg file.</p>
<p>Copy the code and save it as <strong>fixWordAddins.reg</strong> to the C:\Word Add-ins fix\ directory or wherever you want.  Edit it for the add-ins you wish to load.</p>
<pre class="brush: plain; title: ; notranslate">
Windows Registry Editor Version 5.00

[-HKEY_CURRENT_USER\Software\Microsoft\Office\12.0\Word\Resiliency]

[-HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\12.0\Word\Resiliency]

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\Word\Addins\PDFMaker.OfficeAddin]
&quot;LoadBehavior&quot;=dword:00000003
</pre>
<p>On 64-bit versions of Windows, the add-ins can be found in:<br />
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Office\Word\Addins\</p>
<h2>The log file</h2>
<p>If the log file doesn&#8217;t already exist, the batch file will create it.  Each time the batch file runs, it adds a line to the end of the log file.</p>
<p>An entry will look something like this:</p>
<pre class="brush: plain; title: ; notranslate">
USERNAME at MACHINENAME on 06/17/2010 at 01:02 PM (&quot;PDFMaker.OfficeAddin&quot;)
</pre>
<h2>Caveats</h2>
<p>The macros in a *.dotm can&#8217;t be edited if that template was opened from the startup location.  Open a copy in another location, make your changes and save, and then overwrite the version in the startup location.</p>
<h3>Windows 7</h3>
<p>Note that in Windows 7, the UAC needs your permission to run a .bat file.</p>
<p>The Word startup location in Windows 7 (put any custom *.dotm files here):<br />
\AppData\Roaming\Microsoft\Word\STARTUP</p>
<p>The default location of Normal.dotm in Windows 7:<br />
\AppData\Roaming\Microsoft\Templates</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ardamis.com/2010/06/20/detect-and-fix-word-add-in-problems-with-a-macro-and-batch-file/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My favorite themeforest.net WordPress templates</title>
		<link>http://www.ardamis.com/2010/02/21/my-favorite-themeforest-net-wordpress-templates/</link>
		<comments>http://www.ardamis.com/2010/02/21/my-favorite-themeforest-net-wordpress-templates/#comments</comments>
		<pubDate>Sun, 21 Feb 2010 06:20:56 +0000</pubDate>
		<dc:creator>ardamis</dc:creator>
				<category><![CDATA[Web Site Dev]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[templates]]></category>
		<category><![CDATA[themes]]></category>

		<guid isPermaLink="false">http://www.ardamis.com/?p=483</guid>
		<description><![CDATA[A collection of my favorite themeforest.net WordPress templates, mostly intended for web designers or graphics-related businesses.]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been collecting links to good WordPress templates for a long time.  Because I&#8217;ve been asked a few times recently if I can recommend some templates, I&#8217;m putting them together here.</p>
<h2>Huge, isolated, animated slideshow</h2>
<p>I really like these themes for focusing almost exclusively on one&#8217;s portfolio.  They feature a massive, animated slideshow that keeps the visitor&#8217;s attention on the images.  In some cases, a shadow underneath the slideshow, combined with the animation, creates a 3-D effect to put the portfolio right in the visitor&#8217;s face.</p>
<ul>
<li><a href="http://themeforest.net/item/black-eve-wordpress-version/full_screen_preview/93185">http://themeforest.net/item/black-eve-wordpress-version/full_screen_preview/93185</a></li>
<li><a href="http://themeforest.net/item/novatorix-10-in-1-business-portfolio-and-blog/full_screen_preview/111717">http://themeforest.net/item/novatorix-10-in-1-business-portfolio-and-blog/full_screen_preview/111717</a></li>
<li><a href="http://themeforest.net/item/iportfolio/75877">http://themeforest.net/item/iportfolio/full_screen_preview/75877</a></li>
<li><a href="http://themeforest.net/item/display-3-in-1-business-portfolio-wordpress-/full_screen_preview/74542">http://themeforest.net/item/display-3-in-1-business-portfolio-wordpress-/full_screen_preview/74542</a></li>
<li><a href="http://themeforest.net/item/7-in-1-business-success-wordpress-theme/full_screen_preview/88463">http://themeforest.net/item/7-in-1-business-success-wordpress-theme/full_screen_preview/88463</a></li>
<li><a href="http://themeforest.net/item/flexolio-porfolio-blog-business-cms-wp-theme-/full_screen_preview/81146">http://themeforest.net/item/flexolio-porfolio-blog-business-cms-wp-theme-/full_screen_preview/81146</a></li>
<li><a href="http://themeforest.net/item/discovery-wordpress/full_screen_preview/83792">http://themeforest.net/item/discovery-wordpress/full_screen_preview/83792</a></li>
</ul>
<h2>Confined slideshow</h2>
<p>These themes are a bit more modest than the first collection.  They still accentuate a portfolio of images, but in a less flashy way.  The slideshow exists within a defined banner area, so the look is a little more traditional.  These templates would be a better fit for businesses.</p>
<ul>
<li><a href="http://themeforest.net/item/habitat-blog-and-portfolio-theme/full_screen_preview/125365">http://themeforest.net/item/habitat-blog-and-portfolio-theme/full_screen_preview/125365</a></li>
<li><a href="http://themeforest.net/item/vulcan-minimalist-business-wordpress-theme-4/full_screen_preview/111625">http://themeforest.net/item/vulcan-minimalist-business-wordpress-theme-4/full_screen_preview/111625</a></li>
<li><a href="http://themeforest.net/item/creation-minimalist-business-wordpress-theme/full_screen_preview/113734">http://themeforest.net/item/creation-minimalist-business-wordpress-theme/full_screen_preview/113734</a></li>
<li><a href="http://themeforest.net/item/corporate-business-portfolio-wordpress-theme-/full_screen_preview/81507">http://themeforest.net/item/corporate-business-portfolio-wordpress-theme-/full_screen_preview/81507</a></li>
<li><a href="http://themeforest.net/item/luxury-wordpress-template/full_screen_preview/83220">http://themeforest.net/item/luxury-wordpress-template/full_screen_preview/83220</a></li>
<li><a href="http://themeforest.net/item/tylium-premium-wordpress-theme/full_screen_preview/68229">http://themeforest.net/item/tylium-premium-wordpress-theme/full_screen_preview/68229</a></li>
<li><a href="http://themeforest.net/item/shapeshifter-one-page-infinite-possibilities/full_screen_preview/75759">http://themeforest.net/item/shapeshifter-one-page-infinite-possibilities/full_screen_preview/75759</a></li>
<li><a href="http://themeforest.net/item/delericon-businessportfolio-template-wordpress/full_screen_preview/76635">http://themeforest.net/item/delericon-businessportfolio-template-wordpress/full_screen_preview/76635</a></li>
<li><a href="http://themeforest.net/item/twicet-business-portfolio-wordpress-5-in-1/full_screen_preview/49773">http://themeforest.net/item/twicet-business-portfolio-wordpress-5-in-1/full_screen_preview/49773</a></li>
<li><a href="http://themeforest.net/item/benzo/full_screen_preview/50977">http://themeforest.net/item/benzo/full_screen_preview/50977</a></li>
<li><a href="http://themeforest.net/item/creative-wordpress-theme-9-in-1/full_screen_preview/84549">http://themeforest.net/item/creative-wordpress-theme-9-in-1/full_screen_preview/84549</a></li>
<li><a href="http://themeforest.net/item/levitation-wordpress-business-portfolio-4-in-1/full_screen_preview/60299">http://themeforest.net/item/levitation-wordpress-business-portfolio-4-in-1/full_screen_preview/60299</a></li>
<li><a href="http://themeforest.net/item/mapollo/full_screen_preview/60268">http://themeforest.net/item/mapollo/full_screen_preview/60268</a></li>
<li><a href="http://themeforest.net/item/elite-force-premium-wordpress-theme/full_screen_preview/84456">http://themeforest.net/item/elite-force-premium-wordpress-theme/full_screen_preview/84456</a></li>
</ul>
<h2>Partial-banner image rotation</h2>
<p>These themes use only part of the banner to display a rotating group of images, leaving an area for text next to the images.  This allows a short message or tagline to get equal placement.  These are the most conservative themes.</p>
<ul>
<li><a href="http://themeforest.net/item/designer-portfolio-elegant-template-wordpress/full_screen_preview/96810">http://themeforest.net/item/designer-portfolio-elegant-template-wordpress/full_screen_preview/96810</a></li>
<li><a href="http://themeforest.net/item/bluelight-wordpress-20-portfolio-and-blog/full_screen_preview/40433">http://themeforest.net/item/bluelight-wordpress-20-portfolio-and-blog/full_screen_preview/40433</a></li>
<li><a href="http://themeforest.net/item/quadro-wordpress-version/full_screen_preview/79966">http://themeforest.net/item/quadro-wordpress-version/full_screen_preview/79966</a></li>
<li><a href="http://themeforest.net/item/concept-wordpress-a-premium-wp-theme/full_screen_preview/53845">http://themeforest.net/item/concept-wordpress-a-premium-wp-theme/full_screen_preview/53845</a></li>
<li><a href="http://themeforest.net/item/lightcorners/full_screen_preview/82046">http://themeforest.net/item/lightcorners/full_screen_preview/82046</a></li>
<li><a href="http://themeforest.net/item/concise/full_screen_preview/66396">http://themeforest.net/item/concise/full_screen_preview/66396</a></li>
<li><a href="http://themeforest.net/item/spotlight-portfolio-theme-wordpress-edition/full_screen_preview/80959">http://themeforest.net/item/spotlight-portfolio-theme-wordpress-edition/full_screen_preview/80959</a></li>
<li><a href="http://themeforest.net/item/transformer/82402">http://themeforest.net/item/transformer/82402</a></li>
<li><a href="http://themeforest.net/item/scroller-wordpress-theme/full_screen_preview/83162">http://themeforest.net/item/scroller-wordpress-theme/full_screen_preview/83162</a></li>
<li><a href="http://themeforest.net/item/advantage-wordpress-theme-4-in-1/full_screen_preview/88112">http://themeforest.net/item/advantage-wordpress-theme-4-in-1/full_screen_preview/88112</a></li>
<li><a href="http://themeforest.net/item/durable-5-in-1-business-portfolio-wordpress/full_screen_preview/84440">http://themeforest.net/item/durable-5-in-1-business-portfolio-wordpress/full_screen_preview/84440</a></li>
<li><a href="http://themeforest.net/item/equator-global-community-wordpress-theme/full_screen_preview/65549">http://themeforest.net/item/equator-global-community-wordpress-theme/full_screen_preview/65549</a></li>
<li><a href="http://themeforest.net/item/oxygene-clean-environment/full_screen_preview/62657">http://themeforest.net/item/oxygene-clean-environment/full_screen_preview/62657</a></li>
<li><a href="http://themeforest.net/item/foliothemes-portfolio/full_screen_preview/66448">http://themeforest.net/item/foliothemes-portfolio/full_screen_preview/66448</a></li>
<li><a href="http://themeforest.net/item/eclectic-premium-wordpress-theme/full_screen_preview/63212">http://themeforest.net/item/eclectic-premium-wordpress-theme/full_screen_preview/63212</a></li>
<li><a href="http://themeforest.net/item/bitwork-portfolio-and-business-wordpress-theme/full_screen_preview/87092">http://themeforest.net/item/bitwork-portfolio-and-business-wordpress-theme/full_screen_preview/87092</a></li>
<li><a href="http://themeforest.net/item/business-showcase-corporate-layout-html/full_screen_preview/50191">http://themeforest.net/item/business-showcase-corporate-layout-html/full_screen_preview/50191</a></li>
<li><a href="http://themeforest.net/item/corpomino/full_screen_preview/63883">http://themeforest.net/item/corpomino/full_screen_preview/63883</a></li>
<li><a href="http://themeforest.net/item/photography-and-portfolio-wordpress-theme/full_screen_preview/82048">http://themeforest.net/item/photography-and-portfolio-wordpress-theme/full_screen_preview/82048</a></li>
<li><a href="http://themeforest.net/item/kava-wp-theme-for-cms-business-portfolio-blog/full_screen_preview/82551">http://themeforest.net/item/kava-wp-theme-for-cms-business-portfolio-blog/full_screen_preview/82551</a></li>
</ul>
<h2>Creative themes</h2>
<p>This last group of themes break with the conventions of the above themes and use full-screen-width or otherwise larger-than-normal images that rotate behind the other elements of the site.  Undeniably attention-grabbing, but also slower to load.</p>
<ul>
<li><a href="http://themeforest.net/item/the-architect-wp-edition/full_screen_preview/113414">http://themeforest.net/item/the-architect-wp-edition/full_screen_preview/113414</a></li>
<li><a href="http://themeforest.net/item/photome-photography-and-portfolio-template-wp/full_screen_preview/113474">http://themeforest.net/item/photome-photography-and-portfolio-template-wp/full_screen_preview/113474</a></li>
<li><a href="http://themeforest.net/item/wp-portfolius-v9/full_screen_preview/81863">http://themeforest.net/item/wp-portfolius-v9/full_screen_preview/81863</a></li>
<li><a href="http://themeforest.net/item/photo-graphic-studio-wordpress/full_screen_preview/36070">http://themeforest.net/item/photo-graphic-studio-wordpress/full_screen_preview/36070</a></li>
<li><a href="http://themeforest.net/item/desktop-press-creative-wordpress-theme/full_screen_preview/87968">http://themeforest.net/item/desktop-press-creative-wordpress-theme/full_screen_preview/87968</a></li>
<li><a href="http://themeforest.net/item/luna-premium-wordpress-theme/full_screen_preview/85233">http://themeforest.net/item/luna-premium-wordpress-theme/full_screen_preview/85233</a></li>
</ul>
<h2>Single page</h2>
<p>These are single-page web sites.  These types of pages are great as business cards or resumes, or as place holders while a larger site is developed.</p>
<ul>
<li><a href="http://themeforest.net/item/galeria-single-page-wordpress-portfolio/full_screen_preview/105848">http://themeforest.net/item/galeria-single-page-wordpress-portfolio/full_screen_preview/105848</a></li>
<li><a href="http://themeforest.net/item/path-finder-keyboard-navigation-wordpress-theme/full_screen_preview/109983">http://themeforest.net/item/path-finder-keyboard-navigation-wordpress-theme/full_screen_preview/109983</a></li>
</ul>
<h2>The rest</h2>
<p>I like these, too, but they don&#8217;t fit in any of the above categories.</p>
<ul>
<li><a href="http://standardtheme.com/">http://standardtheme.com/</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.ardamis.com/2010/02/21/my-favorite-themeforest-net-wordpress-templates/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Plogger 3 theme: Broadway</title>
		<link>http://www.ardamis.com/2007/09/10/plogger-3-theme-broadway/</link>
		<comments>http://www.ardamis.com/2007/09/10/plogger-3-theme-broadway/#comments</comments>
		<pubDate>Mon, 10 Sep 2007 05:50:54 +0000</pubDate>
		<dc:creator>ardamis</dc:creator>
				<category><![CDATA[Web Site Dev]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[plogger]]></category>
		<category><![CDATA[templates]]></category>
		<category><![CDATA[themes]]></category>

		<guid isPermaLink="false">http://www.ardamis.com/2007/09/10/plogger-3-theme-broadway/</guid>
		<description><![CDATA[A dark Plogger theme that takes elements from the Yahoo! Broadway page of 2007.]]></description>
			<content:encoded><![CDATA[<p>This is a rough beta of a new, dark, Plogger 3 theme.  It takes elements from the Yahoo! Broadway page of 2007.</p>
<div class="isolate"><a class="hidelink" href="http://www.ardamis.com/images/broadway-ss.jpg"><img style="border: 1px solid #cacaca;" src="http://www.ardamis.com/images/broadway-ss-thumb.jpg" alt="Plogger 3 theme: Broadway screenshot" /></a></div>
<h3>Download the beta version (v0.1 beta)</h3>
<p>Download the beta version of the Plogger 3 Broadway theme here.  I still need to clean up the code and the CSS, and check it more thoroughly in IE6 and some other browsers.</p>
<p class="download"><a href="http://www.ardamis.com/downloads/plogger3-broadway.zip">Download the &#8220;Broadway&#8221; Plogger 3 theme</a></p>
<h3>Updated:  Broadway 2</h3>
<p>I&#8217;ve changed the theme to display the album thumbnails in the same grid format as the picture thumbnails, and also fixed a few other layout bugs.</p>
<p class="download"><a href="http://www.ardamis.com/downloads/broadway2.zip">Download the &#8220;Broadway 2&#8243; Plogger 3 theme</a></p>
<p></p>
<p><strong>Update 12/19/09:</strong> I&#8217;ve updated the theme to be compatible with the recently-released Plogger v.1.0.  If you&#8217;re running an earlier version, I would recommend that you update to the current stable release.</p>
<h3>Want this with Lightbox?</h3>
<p>I&#8217;ve incorporated the Lightbox 2 JavaScript into the Broadway 2 theme.  You can download it at <a href="http://www.ardamis.com/2009/02/24/broadway-2-lightbox-plogger-theme/">Broadway 2 + Lightbox</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ardamis.com/2007/09/10/plogger-3-theme-broadway/feed/</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>Centering the thumbnails in Plogger</title>
		<link>http://www.ardamis.com/2007/08/05/centering-the-thumbnails-in-plogger/</link>
		<comments>http://www.ardamis.com/2007/08/05/centering-the-thumbnails-in-plogger/#comments</comments>
		<pubDate>Sun, 05 Aug 2007 05:00:41 +0000</pubDate>
		<dc:creator>ardamis</dc:creator>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Web Site Dev]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[plogger]]></category>
		<category><![CDATA[templates]]></category>
		<category><![CDATA[themes]]></category>

		<guid isPermaLink="false">http://www.ardamis.com/2007/08/05/centering-the-thumbnails-in-plogger/</guid>
		<description><![CDATA[This post illustrates a method of centering the thumbnails in the album view of the PHP image gallery Plogger. The method automatically adjusts for thumbnails of varying widths and pages containing less than a full row of images. This method is implemented in the Plogger 3 theme: Air, but it should work in any theme [...]]]></description>
			<content:encoded><![CDATA[<p>This post illustrates a method of centering the thumbnails in the album view of the PHP image gallery <a href="http://plogger.org/">Plogger</a>.  The method automatically adjusts for thumbnails of varying widths and pages containing less than a full row of images.</p>
<p>This method is implemented in the <a href="http://www.ardamis.com/2007/07/05/plogger-beta-3-theme-air/">Plogger 3 theme: Air</a>, but it should work in any theme that uses the unordered list derived from the default Plogger theme and that has a fixed and determinable width for the element &#8216;ul.slides&#8217;.</p>
<h2>Overview of the method</h2>
<p>In brief, the template file album.php is edited to add a PHP script that figures out how many thumbnails are in the first row and then adjusts the left margin of each &#8216;li.thumbnail&#8217; in order to keep the same amount of space on either side of each image.  The user is required to manually set 3 variables: <code>$center_thumbs</code>, <code>$total_space</code> and <code>$thumb_padding</code>, and the script does the rest.</p>
<h2>Line-by-line documentation</h2>
<p>Below is all of the relevant code, to be placed into the theme file &#8216;album.php&#8217;.</p>
<pre><code><?php plogger_load_picture();
// Set variables for the thumbnails
$capt = plogger_get_picture_caption();
$date = plogger_get_picture_date();
// Find thumbnail width
$thumb_info = plogger_get_thumbnail_info();
$thumb_width = $thumb_info[0]; // The width of the thumbnail image, in pixels.
$thumb_height = $thumb_info[1];	// The height of the thumbnail image, in pixels.

// Set album page options
$center_thumbs = 'true'; // When the value of "$center_thumbs" is set to 'true', the theme will center the thumbnail images
$total_space = 798; // Set the value of $total_space to equal the width, in pixels, of the interior of 'ul.slides' (i.e. after deducting for any padding)
$thumb_padding = 33; // Set the value of $thumb_padding to equal the sum of all padding and borders on 'ul.slides li.thumbnail', the thumbnail image and the anchor tag (this can be tricky to calculate)

$thumbs_on_page = $GLOBALS["available_pictures"];
$actual_thumb_width = $thumb_width + $thumb_padding;
$max_thumbs_per_row = floor($total_space / $actual_thumb_width);
($thumbs_on_page < $max_thumbs_per_row)? $thumbs_per_row = $thumbs_on_page : $thumbs_per_row = $max_thumbs_per_row ;
$avail_space = $total_space - ($thumbs_per_row * $actual_thumb_width);
$left_margin = floor($avail_space / ($thumbs_per_row + 1));
?>
<li class="thumbnail"<?php if ($center_thumbs == 'true') echo 'style="margin-left: ' . $left_margin . 'px"'; ?>>
</code></pre>
<p>Here&#8217;s how the whole thing works, with each code section followed by a description of what&#8217;s happening:</p>
<pre><code>$center_thumbs = 'true'; // When the value of "$center_thumbs" is set to 'true', the theme will center the thumbnail images
$total_space = 798; // Set the value of $total_space to equal the width, in pixels, of the interior of 'ul.slides' (e.g.: after deducting for any padding)
$thumb_padding = 33; // Set the value of $thumb_padding to equal the sum of all padding and borders on 'ul.slides li.thumbnail', the thumbnail image and the anchor tag (this can be tricky to calculate)
</code></pre>
<p>The centering feature can be toggled on and off by setting <code>$center_thumbs</code> to &#8216;true&#8217; or any other value.  The user will need to specify integer values for <code>$total_space</code> and <code>$thumb_padding</code>, as described in the commented lines.</p>
<pre><code>$thumbs_on_page = $GLOBALS["available_pictures"];</code></pre>
<p>The number of available pictures on the current page is assigned to the <code>$thumbs_on_page</code> variable.</p>
<pre><code>$actual_thumb_width = $thumb_width + $thumb_padding;</code></pre>
<p>The actual width of each &#8216;li.thumbnail&#8217; is calculated and saved as the variable <code>$actual_thumb_width</code>.  The width of the thumbnail image is available to the theme as <code>$thumb_width</code>, but the user must specify a value for <code>$thumb_padding</code>, which is an integer equal to the sum of all of the padding and borders on the thumbnail image, the surrounding anchor tag, and the ul list item &#8216;.thumbnail&#8217;.  This can be rather tricky to calculate, so you may want to increase your figure by a few pixels just to be safe.</p>
<pre><code>$max_thumbs_per_row = floor($total_space / $actual_thumb_width);</code></pre>
<p>The maximum possible number of thumbnails per row is calculated by dividing the useable width of &#8216;ul.slides&#8217; by the actual width of a &#8216;li.thumbnail&#8217;, then rounding down the quotient to the next lowest integer using the PHP function <code>floor()</code>.  For example, if the quotient of <code>$total_space / $actual_thumb_width</code> is 4.9, <code>$max_thumbs_per_row</code> would equal 4, because 5 thumbnails would be wider than the available space.</p>
<pre><code>($thumbs_on_page < $max_thumbs_per_row)? $thumbs_per_row = $thumbs_on_page : $thumbs_per_row = $max_thumbs_per_row ;</code></pre>
<p>The actual number of thumbs in the first row is calculated and assigned to <code>$thumbs_per_row</code> using a ternary operator.  If the number of thumbs on the current page is less than the maximum number possible in a single row, it follows that the row isn't full, and the number of thumbs on the page is assigned to the variable <code>$thumbs_per_row</code>.  However, if the number of thumbs on the page is equal to or greater than the maximum number possible in a single row, it follows that the first row contains the maximum number possible, and so the thumbs will be spaced as though every row is full.  Doing it this way maintains the grid, but if one wanted partially filled rows to be centered according to the number of remaining images, that would be possible.</p>
<pre><code>$avail_space = $total_space - ($thumbs_per_row * $actual_thumb_width);</code></pre>
<p>The amount of white space, <code>$avail_space</code>, is calculated by subtracting from the total usable space the sum of the widths of the thumbs in the first row.</p>
<pre><code>$left_margin = floor($avail_space / ($thumbs_per_row + 1));</code></pre>
<p>Finally, the number of pixels for the left margin of each 'li.thumbnail', <code>$left_margin</code>, is calculated by dividing <code>$avail_space</code> by the sum of 1 plus the number of thumbs in the first row, and then rounding down the quotient to the next lowest integer.  The number of thumbs must be increased by 1 to account for the white space to the right of the last thumbnail.</p>
<p>In practice, the white space to the right of last thumbnail may be a few pixels wider or narrower than the left margins, but this deviation should be limited to within 4 or 5 pixels.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ardamis.com/2007/08/05/centering-the-thumbnails-in-plogger/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Plogger 3 theme: Air</title>
		<link>http://www.ardamis.com/2007/07/05/plogger-beta-3-theme-air/</link>
		<comments>http://www.ardamis.com/2007/07/05/plogger-beta-3-theme-air/#comments</comments>
		<pubDate>Thu, 05 Jul 2007 05:49:52 +0000</pubDate>
		<dc:creator>ardamis</dc:creator>
				<category><![CDATA[Web Site Dev]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[plogger]]></category>
		<category><![CDATA[templates]]></category>
		<category><![CDATA[themes]]></category>
		<category><![CDATA[xhtml]]></category>

		<guid isPermaLink="false">http://www.ardamis.com/2007/07/05/plogger-beta-3-theme-air/</guid>
		<description><![CDATA[Air is a full-featured Plogger 3 stand alone theme that takes visual cues from the Yahoo! TV beta of mid 2007. The theme files validate as XHTML 1.0 Strict (while Plogger itself is either Strict or Transitional, depending on some options). The theme looks nearly identical in Firefox 2.0 and Internet Explorer 7, and uses [...]]]></description>
			<content:encoded><![CDATA[<p>Air is a full-featured Plogger 3 stand alone theme that takes visual cues from the Yahoo! TV beta of mid 2007.  The theme files validate as XHTML 1.0 Strict (while Plogger itself is either Strict or Transitional, depending on some options).  The theme looks nearly identical in Firefox 2.0 and Internet Explorer 7, and uses conditional CSS to be very similar in IE6.  A version of this theme is included in the official <a href="http://www.plogger.org/">Plogger 3</a> build, released on 7/10/07.</p>
<div class="isolate"><a class="hidelink" href="http://www.ardamis.com/images/air-ss.jpg"><img style="border: 1px solid #cacaca;" src="http://www.ardamis.com/images/air-ss-thumb.jpg" alt="Plogger beta 3 theme: Air screenshot" /></a></div>
<p>The fundamental changes are:</p>
<ul>
<li>The theme template files are now primarily HTML with some PHP, rather than being entirely written in PHP.  This will make it easier for people with basic knowledge of HTML to further customize the theme.</li>
<li>The compatibility with Internet Explorer 7 has been greatly improved.  Among other things, a new <a href="http://www.gtalbot.org/BrowserBugsSection/MSIE7Bugs/FloatedClearedBug.html">float and clear bug introduced in IE 7</a> has been avoided.  The theme is inherently much more stable and less prone to breaking in different browsers.</li>
</ul>
<p>Note that this theme is only for use with Plogger 3.  If you&#8217;re using an earlier version, it&#8217;s recommended that you upgrade.</p>
<h3>Download the stable version (v0.1)</h3>
<p>Download the latest stable version of the Plogger 3 Air theme here.  Because I tend to tinker with things, the files here will probably be slightly more up-to-date than those bundled with the full Plogger download.</p>
<p class="download"><a href="http://www.ardamis.com/downloads/plogger3-air.zip">Download the &#8220;Air&#8221; Plogger 3 theme</a></p>
<h3>Download the beta version (v0.2 beta)</h3>
<p>If you don&#8217;t mind the occasional bug or glitch, download the beta version to get a look at some new features.  The album view in v0.2 beta supports centered thumbnails and can be set to display each picture&#8217;s date when no description exists &#8211; take a look at album.php for commented instructions.  I&#8217;ve posted some documentation regarding the method for centering the thumbnails at <a href="http://www.ardamis.com/2007/08/05/centering-the-thumbnails-in-plogger/">Centering the thumbnails in Plogger</a>.  The code should work for any fixed-width theme derived from the default, but the method could be adapted to center many other layouts that use floated list items instead of tables.</p>
<p class="download"><a href="http://www.ardamis.com/downloads/plogger3-air-beta.zip">Download the &#8220;Air&#8221; Plogger 3 theme &#8211; beta</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ardamis.com/2007/07/05/plogger-beta-3-theme-air/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Apricot &#8211; A Minimalist WordPress Theme</title>
		<link>http://www.ardamis.com/2007/06/03/apricot/</link>
		<comments>http://www.ardamis.com/2007/06/03/apricot/#comments</comments>
		<pubDate>Mon, 04 Jun 2007 04:44:28 +0000</pubDate>
		<dc:creator>ardamis</dc:creator>
				<category><![CDATA[Web Site Dev]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[downloads]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[templates]]></category>
		<category><![CDATA[themes]]></category>
		<category><![CDATA[xhtml]]></category>

		<guid isPermaLink="false">http://www.ardamis.com/2007/06/03/apricot/</guid>
		<description><![CDATA[Apricot is a text-centric, minimalist WordPress theme built on a Kubrick foundation.  It does SEO right, straight out of the box.]]></description>
			<content:encoded><![CDATA[<p>Apricot is a text-heavy and graphic-light, widget- and tag-supporting minimalist WordPress theme built on a Kubrick foundation.  Apricot validates as XHTML 1.0 Strict and uses valid CSS.  It natively supports the excellent <a href="http://www.dagondesign.com/articles/other-posts-from-cat-plugin-for-wordpress/">Other Posts From Cat</a> and <a href="http://guff.szub.net/plugins/">the_excerpt Reloaded</a> plugins, should you want to install them.</p>
<p>WordPress version 2.3 introduces native support for &#8216;tags&#8217;, a method of organizing posts according to key words.  Apricot has been updated to use this native tag system.  The tag cloud will appear in the sidebar and the tags for each post appear above the meta data.</p>
<p>I used Apricot on this site for over a year, making little tweaks and adjustments the whole time, so the theme is pretty thoroughly tested in a variety of different browsers and resolutions.  While the markup is derived from the WordPress default theme, Kubrick, I&#8217;ve added a few modifications of my own.  I&#8217;ve listed some of these changes below.</p>
<h3>header.php</h3>
<ul>
<li>Title tag reconfigured to display &#8220;Page Title | Site Name&#8221;</li>
</ul>
<h3>single.php</h3>
<ul>
<li>Post title is now wrapped in H1 tags</li>
<li>Metadata shows when the post was last modified (if ever)</li>
<li><span  style="text-decoration: line-through;">Added links to social bookmarking/blog indexing sites:  Del.icio.us, Digg, Furl, Google Bookmarks, and Technorati</span><br/>I&#8217;ve published a <a href="http://www.ardamis.com/2007/09/02/fixing-warnings-in-the-wordpress-sociable-plugin/">fix for the Sociable plugin</a>, which I&#8217;m now using instead of hard-coded links</li>
<li>If the <a href="http://www.dagondesign.com/articles/other-posts-from-cat-plugin-for-wordpress/">Other Posts From Cat</a> plugin is active, the theme will use it</li>
<li>Comments by the post&#8217;s author can be styled independently</li>
</ul>
<h3>page.php</h3>
<ul>
<li>Displays the page&#8217;s last modified date (instead of date of publication)</li>
</ul>
<h3>index.php</h3>
<ul>
<li>Displays the full text of the latest post and an excerpt from each of the next nine most recent posts</li>
<li>Native support for <a href="http://guff.szub.net/plugins/">the_excerpt Reloaded</a> plugin, if active</li>
</ul>
<h3>sidebar.php</h3>
<ul>
<li>Displays tag cloud, if tags are enabled</li>
</ul>
<h3>search.php</h3>
<ul>
<li>If no results found, displays the site&#8217;s most recent five posts</li>
</ul>
<h3>404.php</h3>
<ul>
<li>Displays the site&#8217;s most recent five posts</li>
</ul>
<h3>footer.php</h3>
<ul>
<li>Archive and index page titles + blog name wrapped in H1 tags</li>
</ul>
<h3>Screen shot</h3>
<p><a class="hidelink" href="http://www.ardamis.com/images/apricot/apricot_full.png" title="Apricot - A WordPress theme by Ardamis.com"><img class="centered" src="http://www.ardamis.com/images/apricot/apricot_500.png" alt="Apricot - A WordPress theme by Ardamis.com" /></a></p>
<h2>Search engine optimization</h2>
<p>Apricot takes care of most of the on-page factors that Google values highly.  It places the post&#8217;s title at the beginning of the title tag and in a H1 tag near the top of the page.  It is free of extraneous markup and the navigation is easily spiderable.  It generates what I think is a pretty logical site structure from the various post and category pages, though I have yet to study the effect of the new tagging system.</p>
<p>I&#8217;ve had a few top-ranked pages with this and other structurally similar layouts.  Your mileage with the search engines may vary, but the layout uses fundamentally sound structural markup, which should give your site a good start.</p>
<h3>Download</h3>
<p>Download the theme from <a href="http://wordpress.org/extend/themes/apricot">http://wordpress.org/extend/themes/apricot</a> or from the link below.</p>
<p class="download"><a href="http://www.ardamis.com/downloads/apricot.zip">Download the Apricot WordPress Theme</a></p>
<h3>What if I want to use an image as a header?</h3>
<p>Lots of people would rather use a graphic as a header, including me, but the WordPress guys insist on each theme uploaded to <a href="http://wordpress.org/extend/themes/">http://wordpress.org/extend/themes/</a> display the blog title and tag line.</p>
<p>If you want to replace the blog title and tag line with an image, download this zip file and follow these instructions (also included in readme.txt).</p>
<p>1. Make a PNG image, name it &#8220;header.png&#8221; and upload it to the /wp-content/themes/apricot/images/ folder.  It should be 800px wide by 130px tall, or less.</p>
<p>2. Replace the original Apricot theme&#8217;s header.php file with the header.php file from this folder.</p>
<p class="download"><a href="http://www.ardamis.com/downloads/apricot-header-with-image.zip">Download the Apricot Image Header</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ardamis.com/2007/06/03/apricot/feed/</wfw:commentRss>
		<slash:comments>56</slash:comments>
		</item>
		<item>
		<title>WordPress comments feed in Google&#8217;s Supplemental Index</title>
		<link>http://www.ardamis.com/2007/01/13/wordpress-comments-feed-in-googles-supplemental-index/</link>
		<comments>http://www.ardamis.com/2007/01/13/wordpress-comments-feed-in-googles-supplemental-index/#comments</comments>
		<pubDate>Sat, 13 Jan 2007 07:58:27 +0000</pubDate>
		<dc:creator>ardamis</dc:creator>
				<category><![CDATA[Google]]></category>
		<category><![CDATA[Web Site Dev]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[blogging]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[templates]]></category>
		<category><![CDATA[themes]]></category>
		<category><![CDATA[troubleshooting]]></category>

		<guid isPermaLink="false">http://www.ardamis.com/2007/01/13/wordpress-comments-feed-in-googles-supplemental-index/</guid>
		<description><![CDATA[I was tired of seeing the majority of my posts&#8217; comments feeds show up in Google&#8217;s Supplemental Index, so I changed all the individual posts&#8217; comments RSS links to rel=&#8221;nofollow&#8221;. This should at least cause Googlebot to stop passing PageRank through those links, but what I really want is for Googlebot to stop spidering the [...]]]></description>
			<content:encoded><![CDATA[<p>I was tired of seeing the majority of my posts&#8217; comments feeds show up in Google&#8217;s Supplemental Index, so I changed all the individual posts&#8217; comments RSS links to rel=&#8221;nofollow&#8221;.  This should at least cause Googlebot to stop passing PageRank through those links, but what I really want is for Googlebot to stop spidering the individual posts&#8217; comment feeds, in hopes that they&#8217;ll eventually be removed from the index. To see only those pages of a site that are in the Supplemental Index, use this neat little search feature: <code>site:DOMAIN.com *** -view</code>.  For example, to see which pages of Ardamis.com are in the SI, I&#8217;d search for: <code>site:ardamis.com *** -view</code>.  This is much easier than the old way of scanning all of the indexed pages and picking them out by hand.</p>
<p>To change all the individual posts&#8217; comments feed links to rel=&#8221;nofollow&#8221;, open &#8216;\wp-includes\feed-functions.php&#8217; and add rel=&#8221;nofollow&#8221; to line 84 (in WordPress version 2.0.6), as so:</p>
<pre class="brush: php; title: ; notranslate">
echo &quot;&lt;a href=\&quot;$url\&quot; rel=\&quot;nofollow\&quot;&gt;$link_text&lt;/a&gt;&quot;;
</pre>
<p>One could use the robots.txt file to disallow Googlebot from all /feed/ directories, but this would also restrict it from the general site&#8217;s feed and the all-inclusive /comments/feed/, and I&#8217;d like the both of these feeds to continue to be spidered. Another, minor consequence of using robots.txt to restrict Googlebot is that Google Sitemaps will warn you of &#8220;URLs restricted by robots.txt&#8221;.</p>
<p>To deny all spiders from any /feed/ directory, add the following to your robots.txt file:</p>
<pre class="brush: plain; title: ; notranslate">
User-agent:*
Disallow: /feed/
</pre>
<p>To deny just Googlebot from any /feed/ directory, use:</p>
<pre class="brush: plain; title: ; notranslate">
User-agent: Googlebot
Disallow: /feed/
</pre>
<p>For whatever reason, the whole-site comments feed at <a href="feed:http://www.ardamis.com/comments/feed/">http://www.ardamis.com/comments/feed/</a> does not appear among my indexed pages, while the nearly empty individual post feeds are indexed.  Also, the general site feed at <a href="http://www.ardamis.com/feed/">http://www.ardamis.com/feed/</a> is in the Supplemental Index.  It&#8217;s a mystery to me why.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ardamis.com/2007/01/13/wordpress-comments-feed-in-googles-supplemental-index/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

