Merry Christmas from WebDevStudios!
Change WordPress permalinks on pages to have a .html extension
We are working on a new website built with WordPress MU, BuddyPress and bbPress and our client requested that all of the pages and posts of each MU site have a .html extension. Ok, so posts are easy just head to your “Permalink Settings” page, click the “Custom Structure” radio button and add something like “/%postname%.html”. Pretty simple huh?
So what about pages? I found a great plugin called .html on Pages which will add a .html extension to all of your pages. This plugin will also automatically remove the .html extension from any pages that are nested as a parent page. Soooo: yourwebsite.com/mypage.html will turn into yourwebsite.com/mypage/mysubpage.html.
We ran into a problem, well not so much a problem because the plugin does what it is supposed to do, but we want to not add .html to the end of the blog page. We want /blog.html to be just /blog so we had to make a few modifications to the plugin. If you are comfortable with php the mod is small and here it is:
Add the following code where ever you want inside of the plugin. This code filters any instance of /blog.html and returns /blog.
function blog_permalinks_page_link($permalink, $page) {
$pos = strpos($permalink, “/blog.html”);
if ($pos !== false) {
$permalink = str_replace(“/blog.html”,”/blog”,$permalink);
}
return $permalink;
}
add_filter( ‘page_link’, ‘blog_permalinks_page_link’, 10, 2 );
Next you will need to alter the html_page_permalink() function and add the following code to the top of it:
$string=$_SERVER['REQUEST_URI'];
$pos = strpos($string, “/blog.html”);
if ($pos !== false) {
switch_to_blog(1);//We are using WPMU if you are not you won’t need this line.
wp_redirect( get_option(‘home’).str_replace(“/blog.html”,”/blog”,$string), 301 );
exit();
}else{
$pos = strpos($string, “/blog”);
if ($pos !== false) {
$_SERVER['REQUEST_URI'] =str_replace(“/blog”,”/blog.html”,$string);
global $wp;
$wp->parse_request();
}
}
The above code makes the redirect of any hits on /blog.html to /blog (which shouldn’t happen because of the link filter) and hard-codes the request-URL so WordPress thinks it’s pulling from the page /blog.html when it’s now on /blog. That’s it, pretty simple… If you are not good with php you can download the modified plugin here: http://webdevstudios.com/downloads/html-on-pages.zip
I’m sure this plugin could easily be modified to work with other extentions like .htm or .php, which could cut down on the amount of 301 redirects you would have to make when migrating to WordPress which by the way everybody running a blog or basic CMS should be doing!
SQL: Script to attach and detach Databases for mass moves
I dont know about most of you, but this is something that I have had to do on multiple occasions, moving databases to a new SAN/drive/etc. And the environments that I normally have to support have WAY too many databases to sit and detach, move, then reattach by hand. A lot of scripts out there arent very intuitive, and some other blogs I have read can be rather misleading.
The following scripts were originally borrowed from somewhere out there, over the rainbow, and tweak to meet the requirements that make my life easier. Unlike most scripts you will find, this one actually pulls out the filenames from the system database to help with locating, moving, and reattaching. (This is sort of important since a lot of applications create thier own databases, and being that there are do many, I would have to sit and document everything). Obviously, from this script, I only want databases that are on the M: drive, so the script will only pull out those values. Change that to whatever you want it to be. @DBPath and @LogPath are the new locations where I will be moving the files to.
--Declare variables
DECLARE @DBPath varchar(400)
DECLARE @LogPath varchar(400)
SET @DBPath = 'H:SQLDATA'
SET @LogPath = 'I:SQLLOGS'
use [master]
--You can copy and past these results into a new query window for the re-attach script
Select 'EXEC sp_attach_db @dbname='''+ [name] + ''',',
'@filename1=''' + @DBPath + REVERSE(SUBSTRING(REVERSE(filename), 0, CHARINDEX('', REVERSE(filename), 1))) + ''',', +
'@filename2='''+ @LogPath + [name] +'_Log.ldf''' from sysdatabases
where dbid > 4 AND filename LIKE 'M:%'
Now this is only the step for creating the scripts to re-attach the databases. The following is the detach script.--Code to generate detach script
Select 'EXEC sp_detach_db ''' + [name] + '''' from sysdatabases where dbid > 4 AND filename LIKE 'M:%'
I hope this helps someone out, it has sure saved my butt some work a few times.
MOSS: Enable versioning from C#
Add a web reference to the Lists.asmx web service. Call it whatever you want, I used “PDLists”. The following code will access a document library or list, and enable versioning. Simple, but effective.
I use this code in a command line application, saves a lot of time from not logging into a site, finding the list or library, opening settings, opening versioning properties, and then enabling.
public static void EnableVersioning(string URL, string ListName)
{
PDLists.Lists EnableVersions = new PDLists.Lists();
EnableVersions.Credentials = CredentialCache.DefaultCredentials;
EnableVersions.Url = URL + “lists.asmx”;
XmlNode _response = null;
XmlNode ndList = EnableVersions.GetList(ListName);
XmlNode ndVersion = ndList.Attributes["Version"];
XmlDocument xmlDoc = new System.Xml.XmlDocument();
XmlNode ndProperties = xmlDoc.CreateNode(XmlNodeType.Element, “List”, “”);
XmlAttribute ndVersionAttrib = (XmlAttribute)xmlDoc.CreateNode(XmlNodeType.Attribute, “EnableVersioning”, “”);
ndVersionAttrib.Value = “TRUE”;
ndProperties.Attributes.Append(ndVersionAttrib);
XmlDocument doc = new System.Xml.XmlDocument();
XmlElement batchElement = doc.CreateElement(“Batch”);
XmlNode newItemhome = EnableVersions.GetListCollection();
try
{
_response = EnableVersions.UpdateList(ndList.Attributes["ID"].Value, ndProperties, null, null, null, ndVersion.Value);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + “\n ” + ex.StackTrace);
}
Console.WriteLine(“[versioning enabled]“);
}
MOSS: Excessive Sync errors on Sharepoint 2007 Front End Web Server
In several MOSS deployments with multiple front ends, I have noticed many sync issues in the event logs.
A runtime exception was detected. Details follow.
Message: Cannot insert duplicate key row in object 'dbo.UserMemberships' with unique index 'CX_UserMemberships_RecordId_MemberGroupId_SID'.
The statement has been terminated.
Techinal Details:
System.Data.SqlClient.SqlException: Cannot insert duplicate key row in object 'dbo.UserMemberships' with unique index 'CX_UserMemberships_RecordId_MemberGroupId_SID'.
The statement has been terminated.
at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
at Microsoft.Office.Server.Data.SqlSession.ExecuteNonQuery(SqlCommand command)
at Microsoft.Office.Server.UserProfiles.WSSSynchSqlSession.SynchExecuteNonQuery(SqlCommand cmd, Boolean throwOnFail)
at Microsoft.Office.Server.UserProfiles.WSSSynchSqlSession.SynchExecuteNonQuery(SqlCommand cmd)
at Microsoft.Office.Server.UserProfiles.SiteSynchronizer.WriteChangeLogConsumed()
at Microsoft.Office.Server.UserProfiles.SiteSynchronizer.Synch()
at Microsoft.Office.Server.Diagnostics.FirstChanceHandler.ExceptionFilter(Boolean fRethrowException, TryBlock tryBlock, FilterBlock filter, CatchBlock catchBlock, FinallyBlock finallyBlock)
stsadm -o sync -listolddatabases 0
You can then use this information to query SQL and see which databases are having issues. OR, you can use this VBS script to get the information:
Set Args = WScript.Arguments
Connstr = "Driver={SQL Server};Server=SQL2005;Database=Config_DB"
Set Connect = CreateObject("ADODB.Connection")
Connect.Open Connstr
strInput = Args.Item(0)
Set DB = Connect.Execute("SELECT Id, ClassId, Name, Status, Version, Properties FROM Objects WHERE (Id = '" & strInput & "')")
Do Until DB.Eof
WScript.Echo Db("Id")
WScript.Echo Db("ClassId")
WScript.Echo Db("Name")
WScript.Echo Db("Status")
WScript.Echo Db("Version")
'WScript.Echo Db("Properties")
DB.MoveNext
Loop
stsadm -o sync -deleteolddatabases 0
stsadm -o preparetomove -contentdb -contentdb : -site
stsadm -o deletecontentdb -url -databaseserver -databasename
To reattach:stsadm -o addcontentdb -url
I hope that saves someone else some time.
OCS: Microsoft Communicator Mobile
MOSS: Shared Service Provider Search Service Error
I fixed the problem by assigning an indexer to the SSP. Not exactly sure how it happened that the indexer was never assigned, but here are the steps:
1. Open Central Administration
2. Go to the Application tab
3. Select “Create or Manage this farm’s shared services”
4. Use drop-down list for the SSP, select Edit Properties
5. Assign an indexer server
MOSS: Installing Adobe PDF Ifilter 6.0 on MOSS 2007 (Now With WSS Support)
Here are the instructions for installing the PDF IFilter 6.0 on a SharePoint 2007 server to allow PDF files to be indexed (full text) by the Search and for the icon to be shown next to PDF documents.
- Download Adobe PDF IFilter 6.0 from Adobe.
- Stop the IIS Admin service: Start -> Run -> services.msc -> IIS Admin Service -> Stop
- Run the Adobe PDF IFilter 6.0 Setup program to install the filter on the server.
- Copy the ICPDF.GIF file to “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\Template\Images”
- Edit the file C:\Program Files\Common Files\Microsoft Shared\Web server extensions\60\Template\Xml\DOCICON.XML
- Add an entry for the .pdf extension.
<Mapping Key=”pdf” Value=”icpdf.gif”/>
- Add an entry for the .pdf extension.
- Perform an iisreset or recycle the SharePoint Application Pools
- Add the .pdf file type to the index list:
- Go to Central Administration, then to the Shared Services Administration Web of the current SSP, go to Search Settings and next to File Type
- Add a new file type pdf
- Perform a Full Update on the Search content indexes
Note: The ICPDF.GIF file is included in the file.
WordPress Security
The most important part of any website is your website security. Imagine losing all of your content, including posts, media, and comments. Even worse imagine spam links hiding in your content. Keeping your website safe from hacker bots should be a top priority for anyone running their own website.
Last week I gave a WordPress Security presentation at the NYC WordPress Meetup. We covered some very important security topics, including my list of top WordPress security tips. One of my tips was to stay current on your WordPress version.
Many out of date WordPress installations were hacked by an internet worm a few weeks ago. This hack affected any WordPress websites running versions prior to 2.8.3. The latest version of WordPress is 2.8.4 so basically any site older than two versions was vulnerable to the security exploit.
WebDevStudios offers WordPress Support Packages to keep you safe from such an attack. All current support package clients were safe from the attack and had no reason to worry. This is the peace of mind every website owner should have. Why worry about security? Let WebDevStudios do it for you!
Be sure to check out my WordPress Security presentation for essential tips below:
Announcing WPClassroom.com: Online WordPress Training
We are excited to announce the launch of our latest project: WPClassroom.com!
WPClassroom.com features online training classes for WordPress. Easily learn how to manage and maintain a WordPress powered website using the most powerful online training software powered by Cisco WebEx. Learn from a live instructor who will show examples, demos, use-case scenarios, and tips and tricks for managing WordPress.
Our first class, WordPress for Beginners, is scheduled for Wednesday, September 9th from 6pm-9pm EDT. Each class holds a max of 25 students so there is no overcrowding to worry about. WordPress for Beginners will feature a 2 hour training class on WordPress, followed by a 1 hour Q&A session. That’s a total of 3 hours of WordPress training!
We will begin to offer more advanced classes on plugin and theme development at a later date. We are looking forward to sharing our knowledge and experiences with anyone looking to gain a better understanding of how WordPress works!



