I made a poster for my favorite WordPress meetup.
Blog
-
When renaming your WP admin user, don’t neglect your comments
A few months ago, popular people in the WordPress community (including Matt) made a push to stop using the user name “admin.” A considerably-sized brute force attack targeted this user name specifically since so many users never change or create an administrator with another name.
I followed the wisdom of the crowd and this post I found that walks you through the process of creating a new user and deleting “admin” while moving all the posts in the process. It wasn’t until a few weeks later when I noticed a problem.
I like to use themes that highlight my comments. This allows users to quickly find my updates about plugins and answers to questions that have been asked in a sea of one hundred comments. Well, all the comments I wrote while my user ID was 1 and my user name was admin were no longer highlighted.
There is a user_id column in the wp_comments table that is not changed when you delete a user and move their posts to a new owner. You need to run a MySQL query like this to implement the fix:
UPDATE wp_comments SET user_id = 11132 WHERE user_id = 1Before executing a query like this on a WP database, the new administrator’s user ID needs to be identified so you can change
11132, which is one of my user IDs. If you do not know how to find a user ID, search this page for “user id.” -
Clobber spam users WordPress plugin
I’ve built another plugin for WordPress websites with open registration. This plugin makes it easy to prevent spam accounts from publishing posts.

A screen shot of the dashboard this plugin creates Frequently asked questions
- What does this thing do?
- This plugin adds an item to the Users menu of your administration dashboard. Click the “Clobber Spam” link and you will see a page that puts the most recently created user names next to the email address and the title of the most recently created post by that user. You can check a box next to the users that have submitted spam and click a button to delete all their posts and prevent them from logging in again.
- Why not just delete the users?
- Because the software these spammers use will try to submit more than one post for each account, sometimes days later. If you delete the user, the same user name can be recreated. We can prevent the account from being used by changing the password and email address. The spam software is forced to create a new account to continue bothering us. Also, I already use a really good plugin to delete old and unused user accounts. It is called Inactive User Deleter by shra and I regularly use it to delete users with no posts and no comments that are at least 6 months old.
- Can this process of deleting spam post submissions be automated?
- I would love to build the “akismet for posts” because I could make a lot of money selling it. I have been using Ban Hammer and Stop Spammer Registrations and I still decided to build this plugin to handle about 50 posts a week that these plugins are failing to prevent.
- Can you add feature X?
- Send me your idea, and we can have a conversation.
I have been running a WordPress website with open author registration for a few years, and the majority of the plugins I have written have been focused on making the management of that sort of site easier. Here is a list of the unreleased plugins I am using that I have created:
- Count comment author URL as link: Include the comment author URL in the max links allowed for comment moderation
- Disable comment author homepage links: Removes home page links from comment author user names
- Hold posts with links: Set post status to pending when a new post is published containing any hyperlinks
- Show pending posts count: Show the number of pending posts in the admin dashboard menu just like comments
A list of the plugins I have published is always available on WordPress.org. I also use a version of WP Status Notifier that I have modified to include a post excerpt and a hyperlink that starts the user deletion process.
With this plugin, Clobber spam users, I am going to stop deleting spam user accounts immediately and simply prevent their use for a number of months instead. I have given some thought to making the registration process more cumbersome for everyone, but I don’t want to sacrifice the user experience of real humans to fight the bots.
Here is a download link: clobber-spam-users.zip @ WordPress.org
-
Detecting mixed case strings in ASP Classic
I needed to detect a mixed case string in classic ASP. I define a mixed case string as containing both upper and lower case characters, like AuxagGsrLpa. I could not find a free function on the web to make this decision, so I wrote one.
<% Function isMixedCase( str ) 'detects mixed case strings using the english alphabet 'ignores spaces and other non-alphabetic characters str = trim( str ) isMixed = false lastCase = "" for i=1 to len( str ) currentChar = mid( str, i, 1 ) if asc( currentChar ) >= 65 and asc( currentChar ) <= 90 then if lastCase <> "" and lastCase <> "upper" then isMixed = true exit for else lastCase = "upper" end if else if asc( currentChar ) >= 97 and asc( currentChar ) <= 122 then 'lower if lastCase <> "" and lastCase <> "lower" then isMixed = true exit for else lastCase = "lower" end if else lastCase = "" end if end if next if isMixed then isMixedCase = true else isMixedCase = false end if End Function %>
Here are a few test strings to demonstrate the functionality:
<% response.write "Hello " & isMixedCase( "Hello " ) & " <br>" response.write "hello! " & isMixedCase( "hello!" ) & " <br>" response.write "HELLO " & isMixedCase( "HELLO " ) & " <br>" response.write "hello there " & isMixedCase( "hello there" ) & " <br>" response.write "hellothere " & isMixedCase( "hellothere" ) & " <br>" response.write "hellotherE " & isMixedCase( "hellotherE" ) & " <br>" %>Here is the resulting HTML output of the tests:
Hello True
hello! False
HELLO False
hello there False
hellothere False
hellotherE True -
Matching MD5 hashes in ASP.NET and ASP Classic
The goal of this page is to put two MD5 code samples on the same web page, one for ASP classic and one for ASP.NET. String formatting (like ASCII vs UTF-8) can trip up coding these two routines. These two code samples will produce the same MD5 hash output.
Classic ASP/VBScript MD5
The ASP code is simple once you have a copy of md5.asp from http://frez.co.uk. The only file in the ZIP that you need is md5.asp.
<!--#include file="md5.asp"-->
<% response.write md5("[email protected]") %>
ASP.NET MD5
The keys to getting the .net output to match are
encoding.asciiandtoString("x2").<%@ Import Namespace="System.Security.Cryptography" %> <script language="VB" runat="server"> Public Sub Page_Load( sender As Object, e As EventArgs ) Dim strPlainText as String = "[email protected]" dim md5Hasher as MD5 = MD5.create( ) dim result as byte( ) = md5Hasher.computeHash( encoding.ascii.getBytes( strPlainText)) for each singleByte as byte in result response.write ( singleByte.ToString("x2") ) next End Sub </script>
-
aspSmartUpload.dll usage
aspSmartUpload.dll Q&A
- Frequently asked questions
- IIS7 installation and configuration
- Registry key and properties
- Troubleshooting errors
- Downloads and official documentation
- What is aspSmartUpload.dll?
- A 32-bit library to facilitate file uploads via ASP Classic and IIS.
- Will aspSmartUpload.dll work on Windows Server 2008 64 bit with IIS7?
- Yes.
- Install at
C:\Windows\SysWOW64\ - Register the DLL via command prompt:
regsvr32 C:\Windows\SysWOW64\aspSmartUpload.dll - Enable 32-bit applications on the website’s application pool
- Mind the Maximum Requesting Entity Body Limit property, a member of the Limits Properties under the ASP icon of the website profile in IIS7. The maximum file size is limited by the request object to the number of bytes set there. You may log 500 errors with a description of,
ASP 0104 : 80004005 Operation not Allowed, Request objectif the file sent with the request is bigger than the set limit. - Another Limit Property controls the amount of time the server allows ASP requests to complete. The Script Time-out property defaults to one minute thirty seconds.
- Can this DLL upload files to another Server 2008 in the same domain?
- Yes. Change the user account that handles Anonymous Access in the Authentication section of IIS7 to Application Pool User. Use a UNC path in your call to
mySmartUpload.Save. - ASP 0104 : 80004005 Operation not Allowed, Request object
- Configuration prevents file size. Adjust the IIS7 Limit Properties.
- error: -2146778286 Server.CreateObject Failed, 800ac352 Server object
- True story: one day I could not escape these errors until I rebooted the Windows machine. Restarting the IIS service may also work (
iisreset /NOFORCEat a command prompt). - error: -2147024882 Server.CreateObject Failed, 8007000e Server object
- Make sure the DLL is registered and in the proper location.
- Unable to save file (Error 1120)
- This could be permissions on the folder for the Internet Guest Account. However, I had to reboot the server containing the upload script to stop this error. My setup is the script runs on one server and the files are saved on another. I believe the server where the files were saved was not found during boot up (because it was also rebooting) and so the save directory was unavailable.
- Where is the registry key?
HKEY_LOCAL_MACHINE\SOFTWARE\Advantys\aspSmartUploadKey properties:
- TotalMaxFileSize
- MaxFileSize
- AllowedFilesList
- DeniedFilesList
- DenyPhysicalPath
How to modify these properties in code:
dim mySmartUpload set mySmartUpload = Server.CreateObject("aspSmartUpload.SmartUpload") mySmartUpload.TotalMaxFileSize = 8388608 mySmartUpload.MaxFileSize = 2097152 mySmartUpload.AllowedFilesList = "jpg,jpeg,png" mySmartUpload.DeniedFilesList = "bat,exe,com,asp" mySmartUpload.DenyPhysicalPath = FalseRead more details about these properties here.
IIS7 Installation and configuration
IIS7 considerations:
Errors
If you do not have the ability to IIS reset or reboot the server that holds this DLL, your life may be miserable. I have been using this DLL for years, and sometimes the only way to prevent aspSmartUpload.dll from erroring is to restart the machine.
Downloads & documentation
These files were distributed more then 10 years ago by Advantys, the makers of the DLL.
-
How to: add images to reddit sidebar
Here is one quick and dirty way to add an image to the sidebar of a subreddit. You must be a moderator of a subreddit in order to edit its stylesheet.
- Upload the image
- Add this CSS to the stylesheet:
/* add image to the bottom of the sidebar */
.side .usertext-body{ padding-bottom: 400px; background: url(%%image_name%%) no-repeat; background-position: bottom center; } - Replace
%%image_name%%with the name of your uploaded image - Change
padding-bottom: 400px;to a value in pixels that is at least the height of your image
Similarly, here is a CSS code that will add an image to the top of the reddit sidebar:
/* add image to the top of the sidebar */
.side { padding-top: 400px; background: url(%%image_name%%) no-repeat center; }
This adds a background image to the sidebar and positions it at the bottom. The padding creates enough blank space to make the image visible.
This won’t work if you already have a background image on the the sidebar as part of other visual changes on the subreddit.
-
gif2frames.exe: Extract frames from an animated GIF
I built a Windows 32 bit command line executable, gif2frames.exe. (Go to download)
This tool will take an animated GIF image file and save a separate static image for each frame in PNG, BMP or JPG format.
The reason GIFs are useful is because the files can be optimized to reduce the size on disk. If a frame is visible for 1 or 10 seconds, a single copy of the frame may be stored inside the image file and a frame delay can help the player coordinate the animation.
For this reason, when you say “extract frames from a gif file” you could mean two things; each unique frame could be extracted just once, or each frame could be extracted for each unit of time it is visible. If you want the latter, you must then decide on a rate of frames per second.
Also interesting: the timing is funny business. Minimum frame rates (per second) can be determined by the software displaying the GIF file (more info at the bottom of this page). This makes the number of frames in a film strip style export of frames hard to calculate. I workaround this problem by finding the frame with the shortest display time and divide all the other times by this number. This means animations where all frames are shown for three seconds will only produce one image for each frame. If this is not what you are looking for, try ImageMagick (convert.exe).
Usage
Here are a few cmd.exe examples showing basic calls.
Animated GIF to PNG images
C:\>gif2frames.exe at.gifAnimated GIF to BMP images
gif2frames at.gif -bmpAnimated GIF to JPG images
gif2frames at.gif -jpgOnly unique frames
gif2frames at.gif -png -uniqueDownloads
-
Top users WordPress plugin
I wrote a new plugin to list the contributors to a WordPress website. The comment and post counts are added together, and the top X users are listed in a simple table alongside the counts.
Download top-users-by-comment-plus-post-count.zip.
Installation instructions
- Upload the `top-users-by-comment-plus-post-count` folder to the `/wp-content/plugins/` directory
- Activate the plugin through the ‘Plugins’ menu in WordPress
- Place this or a similar function call in your theme: <?php top_users_by_comment_plus_post_count( 10 ); ?>
CSS sample
This is the CSS I am using to style the output.
#top-users-by-comment-plus-post-count td.tu-author{ padding-right: 8px; } #top-users-by-comment-plus-post-count td.tu-count{ text-align: right; }Sample output
I added tab and line break characters for readability.
<table id="top-users-by-comment-plus-post-count"> <tr><td class="tu-author">DisgustedInDenver</td><td class="tu-count">297</td></tr> <tr><td class="tu-author">Corey</td><td class="tu-count">109</td></tr> <tr><td class="tu-author">G11</td><td class="tu-count">60</td></tr> <tr><td class="tu-author">jmbecker13</td><td class="tu-count">10</td></tr> <tr><td class="tu-author">trustmedotcom</td><td class="tu-count">9</td></tr> <tr><td class="tu-author">ulfwolf</td><td class="tu-count">8</td></tr> <tr><td class="tu-author">noscamsforme</td><td class="tu-count">8</td></tr> <tr><td class="tu-author">who8dapple</td><td class="tu-count">7</td></tr> <tr><td class="tu-author">cindmo</td><td class="tu-count">7</td></tr> <tr><td class="tu-author">nytemare4u</td><td class="tu-count">7</td></tr> </table> -
Disable comment author links in WordPress
I just wrote a new plugin to disable commenter names from linking to the website URLs they may provide when commenting.
Some themes allow commenters to provide a home page URL along with their comment. The comment author’s name then becomes a link to that website wherever it appears on your site. This plugin removes those links.
Download disable-comment-author-links.zip
Installation instructions
- Upload the `disable-comment-author-links` folder to the `/wp-content/plugins/` directory
- Activate the plugin through the ‘Plugins’ menu in WordPress
-
Add content to the bottom of every WordPress post
Bottom of every post is a WordPress plugin I wrote in July of 2011. This plugin is a simple filter that adds some content to the bottom of each post. I thought for sure a plugin like this would already exist, and I was surprised to find a few very complex solutions with way more features than necessary.
This plugin has no other features and adds no administration options pages in your admin dashboard (because you can edit the settings via the Plugin editor). The message that is appended to each post is saved in a text file in the plugin directory. I chose a file on disk instead of a WordPress database option because I dislike plugin options pages for simple plugins.
This plugin will never be updated, and that is a good thing. It is very simple and designed for you to make edits to suit your needs. An update would erase your customizations, so there will never be a new version.
- How can I edit the message?
- To edit the message that will be added to the bottom or footer of your posts, Go to Plugins > Editor and choose “Bottom of every post” with the top right selector. The plugin’s files will be loaded on the right. Choose the file `bottom_of_every_post.txt` and edit at will.
- How can I remove the message from my home page posts?
- You’ll have to edit the plugin. Find this line:
if( !is_page( ) && file_exists( $fileName )){…and change that code to one of these lines depending on your configuration:
Blog post home page
if( !is_page( ) && !is_home( ) && file_exists( $fileName )){Static front page
if( !is_page( ) && !is_front_page( ) && file_exists( $fileName )){ - How can I not show the message on a certain category?
-
First, be sure whether you need a category exclusion or a custom post type exclusion. For categories, add a call to
has_category:Exclude a category
if( !is_page( ) && !has_category('portfolio') && file_exists( $fileName )){Exclude a custom post type
if( !is_page( ) && 'portfolio' != get_post_type() && file_exists( $fileName )){
Download bottom-of-every-post.zip
Installation instructions
- Modify `bottom-of-every-post.txt` to contain the content you would like at the bottom of every post
- Upload the `bottom-of-every-post` folder to the `/wp-content/plugins/` directory
- Activate the plugin through the ‘Plugins’ menu in WordPress
I am also going to use this code to teach a few people how to create their own WP plugins. Here is the full source code of my new plugin:
<?php /* Plugin Name: Bottom of every post Plugin URI: https://coreysalzano.com/wordpress/bottom-of-every-post/ Description: Add some content to the bottom of each post. Version: 1.0 Author: Corey Salzano Author URI: http://profiles.wordpress.org/users/salzano/ License: GPL2 */ /* avoid a name collision, make sure this function is not already defined */ if( !function_exists("bottom_of_every_post")){ function bottom_of_every_post($content){ /* there is a text file in the same directory as this script */ $fileName = dirname(__FILE__) ."/bottom_of_every_post.txt"; /* we want to change `the_content` of posts, not pages and the text file must exist for this to work */ if( !is_page( ) && file_exists( $fileName )){ /* open the text file and read its contents */ $theFile = fopen( $fileName, "r"); $msg = fread( $theFile, filesize( $fileName )); fclose( $theFile ); /* append the text file contents to the end of `the_content` */ return $content . stripslashes( $msg ); } else{ /* if `the_content` belongs to a page or our file is missing the result of this filter is no change to `the_content` */ return $content; } } /* add our filter function to the hook */ add_filter('the_content', 'bottom_of_every_post'); } ?> -
“Time ago” formatting in ASP classic
Today, I needed to convert a time stamp like “1/25/2011 10:42:11 AM” to a readable sentence format like “2 months and 6 hours ago.” Here’s the code I came up with:
function timeAgo( byval time ) sentence = "" hits = 0 piecesAgo = array( 0, 0, 0, 0, 0, 0 ) piecesTotals = array( 0, 12, 30, 24, 60, 60 ) labels = array( "year", "month", "day", "hour", "minute", "second" ) dateAddSymbols = array( "yyyy", "m", "d", "h", "n", "s" ) for p=0 to uBound( piecesAgo ) piecesAgo( p ) = 0 + datediff( dateAddSymbols( p ), time, now( )) if piecesAgo( p ) <> 0 then time = dateAdd( dateAddSymbols( p ), piecesAgo( p ), time ) end if next 'remove negative values for p=uBound( piecesAgo ) to 0 step -1 if piecesAgo( p ) < 0 and p > 0 then piecesAgo( p ) = piecesAgo( p ) + piecesTotals( p ) piecesAgo( p-1 ) = piecesAgo( p-1 ) - 1 end if next for p=0 to uBound( piecesAgo ) if piecesAgo( p ) <> 0 then if len( sentence ) > 0 then sentence = sentence & " and " end if sentence = sentence & piecesAgo( p ) & " " & labels( p ) if piecesAgo( p ) > 1 then sentence = sentence & "s" end if hits = hits + 1 if hits >= 2 then exit for end if end if next set piecesAgo = nothing set piecesTotals = nothing set labels = nothing set dateAddSymbols = nothing timeAgo = sentence & " ago" end function
