Quick Command Line Method to Get Memcached Stats

I had to look for a while to figure this out:

echo stats | nc 127.0.0.1 11211

This assumes the memcached instance is running on a local instance with the standard port. This will output a bunch of statistics about the machine. The one to watch is “evictions,” which represent items getting overwritten before they naturally expired. This would indicate items being cached too long or the server running out of memory.

Is Your Blog Not Receiving Pingbacks? I Fixed Mine.

I recently noticed that my blog was no longer registering pingbacks (the automatic in-comment notification that occurs when somebody else blogs about your post). I like these because they help me understand which of my articles are gaining traction.

My symptoms

  • My other blogs hosted on the same server seem to be pinging fine; however, those have far less posts and plugins
  • I am able to send pingbacks, apparently
  • But ping backs TO my content were dropped (even when I am self-pinging)

The fix

I figured the issue was somehow related to my recent upgrades of WordPress. After scouring the web, I found that the issue was due to a poorly designed timeout setting in WordPress.

  1. Open wp-includes/cron.php in your blog folder
  2. Go to the line that starts with: wp_remote_post( in the spawn_cron function
  3. Change ‘timeout’ => 0.01 to ‘timeout’ => 1 (or any other far more reasonable value)

This will fix blogs that are plagued by this bug.

Q: Hiding JS Files? A: Impossible

In my popular post about hiding your Word Press folder, a reader asked:

Hi Michi, can you help me with this, in the head section i wrote this:

and when we go to the webpage then right click, it will show:

can you teach me or show me how to do that, any help highly appreciated, And im so sorry if my english not good.

This question was complicated enough where I thought a new post might make sense.

For clarification, I believe he is asking if it’s possible to put one thing in the source and another that the browser sees. This is impossible. Anything that the browser can see, the user can see. There is no way to “show” something different in the source of an HTML file versus what the browser sees (except through obfuscation); however, you can forward things along behind the scenes. You want to create an htaccess rule that will redirect your requests.

Let me reiterate that you *cannot* hide the content of the JS file. However, you *can* hide the true folder structure of the web server. If you desire to hide your JS contents, the better solution is a JS minifier.

Alternatively, if your goal is to somehow make it harder for somebody to steal your code and you don’t want ot use a JS minifier, you could write the JavaScript tag dynamically using another piece of JavaScript. However, ultimately, that level of weak obfuscation won’t protect you from anything since Firebug will quickly expose what’s really going on.

I hope that answers your question.

Opacity, Jagged Edges, and Header Tags in IE

screwed up textI discovered a bug in IE today. If:

  1. You have headers (as in <h1>, <h2>, <h3>, etc) and…
  2. That header appears above another transparent area and…
  3. That headers has any transparency effects itself then…
  4. You get jagged edges

This is compounded by the fact that the area I was dealing with was a white box on top of the transparent text, so by all means the area “behind” the headers weren’t transparent. See screen shot to the right.

This is retarded. I have a simple fix for this problem. Simply add this to your CSS code:

  1. /*
  2.  * this is a necessary work around for transparency to work with h tags. 
  3.  */
  4. .container h1, .container h2, .container h3, .container h4, .container h5, .container h6 {
  5.     background-color: white; // or whatever color you are working with
  6. }

Replace “container” with whatever area you need to fix.

This is only a problem in IE; Firefox handles things just fine.

How I Integrated Dugg Mirror When I got Dugg

My regular readers probably didn’t realize, but I was recently on the front page of Digg, Slashdot, and Reddit. Digg and Slashdot are notorious for killing servers that get linked in their stories. If you want to see the stats for the days in question, you should see my post about it. This post is a little geeky, so beware.

Here’s the quick and dirty list for keeping your server up during a Digg Crisis:

  1. Download and enable wp-cache.
  2. Use the .htaccess rule I explain below. It keeps the rest of your site operational and even lets people post comments directly from the mirror!
  3. Turn off miscellaneous plugins. The biggest suspect was my related posts plugin (see below).

CPU Load

When I got on the front page of Reddit, my traffic spiked immediately. My server load went up to about 2.00. A “2.00” is high, but is manageable and won’t cause any real problems. A “1.00” approximately equates to “100% of CPU used.” So you can guess what a “2.00” means. Realizing Digg was coming next, I knew I had to start making preparations, since this graph shows just how much bigger Digg is than Reddit.

I knew my hits would increase 100x, so I had to shut down as much unnecessary stuff as possible. First, I wanted to turn off every plugin I had on Word Press and then activate wp-cache, which would significantly reduces database overhead. Unfortunately, before I was finished configuring the cache settings, I hit the front page of Digg in record time. The server became non-responsive and I couldn’t even hit the “enable” button. My server load sky rocketed past 500.00. At 500, things stop working.

Integrating Dugg Mirror

Dugg Mirror is a service that creates copies of articles that hit the main page of Digg. Their goal is to serve as a backup in case the main source goes down (as it often does). As soon as my server was Dugg, my objective was to forward all traffic to the mirror.

When my server died, I was racing against time to redirect the traffic. Until I redirected the traffic, I couldn’t do anything to mitigate the problem (such as disabling plugins). It took me about five minutes (due to incredible lag) to connect to the server, go to the correct directory, and edit the .htaccess file to add this line at the very top:

RewriteCond %{HTTP_REFERER} (digg.com) [NC]
RewriteRule maybe-google-wanted-to-be-sued-youtube-and-plan-b http://duggmirror.com/tech_news/Why_Google_wanted_YouTube_to_be_Sued/ [R,L,NC]

The first line says, “If this visitor is from digg.com”. The second line (wrapped over two lines) says, “then redirect hits to my google article to the Dugg Mirror.” This redirected everybody who came to my site from Digg that wanted to see my article to the Mirror. Note that the rest of my site worked completely fine, and anybody trying to post a comment directly from the mirror was able to do so.

Upon applying this fix, my server load dropped to 4.00.

To make this work for your dugg articles, use the following:

RewriteCond %{HTTP_REFERER} (digg.com) [NC]
RewriteRule [article URL without beginning/trailing slash or domain] [dugg mirror URL] [R,L,NC]

The Finishing Touches

I made sure my most CPU/MySQL intensive plugins were off when a digg user came (since they were the ones causing problems). I put a snippet of code around my related post plugin that looked like this:

<?php if(FALSE === stristr($_SERVER[‘HTTP_REFERER’], ‘digg.com’)) { 
/* Intensive plugin-code */
} ?>

This snippet basically says, “If this visitor is from Digg, don’t do the burdensome plugins.” The thinking is that if a visitor is coming from Digg, I am likely Dugg, so if I wasn’t lucky enough to see it coming, at least I will mitigate some of the problems.

I also disabled my anti-comment-spam plugins and only kept Akismet running (since I hear Techcrunch uses it). I also initially disabled Spam Karma 2, but I eventually turned back on (I prefer it over Akismet).

As a good example horror story of how a plugin can kill you, I once had the Bad Behavior plugin installed (late 2005). It completely locked up my database when several search bots hit the site because it attempted to log each and everything the bots did. It took me days to figure out my blog was taking down my entire server because of this plugin! (There is a new version out now, but I am too scared to try it now.)

Anyway, my point is for you to be careful with plugins that use the database and only use ones you absolutely need, especially when getting Dugg.

I then finished enabling my blog cache, and my server load fell to 1.00. My server was down for about 5 minutes total. Minutes later, I pointed the traffic back onto my site with Word Press caching enabled and the load sat around 4.00. I won’t know for sure, but I think my server would have survived had I enabled the cache plugin from the beginning (which I tried to do!! 🙁 ).

The next day, I was on Slashdot and my server never went down. This is why I conclude that not enabling the cache plugin had more to do with going down than any other factor.

Non-Word Press Administrators

Note that the web server was fine. MySQL failed. MySQL is much less robust than the web server when it comes to this sort of stuff, and requires significantly more baby-sitting. This is especially true for applications that weren’t designed to scale, such as Word Press. This is why the cache plugin is so powerful.

If you have a web application that is MySQL intensive and NOT Word Press, the steps you need to take to keep your site up are different:

  • Minimize the SQL running on the landing page that is getting Dugg. This may involve turning off things like session logging. For example, I turned off a user tracker that inserted a record into the database every time a visitor came to the site. Disabling this sped things up quite a bit.
  • Create as much static content as possible, at least for the first two hours. After the initial surge, traffic will drop to manageable levels (see hourly graphs near bottom). Your best bet is to “fake” part of your application with static content and a disclaimer to come back later.
  • Increase the memory usage limit for MySQL.
  • Increase the maximum allowed connections to MySQL.
  • Make sure you are using indexes in your queries. The quick and very dirty way of explaining this is if you have a SQL statement “… WHERE blah = ‘some value'”, make sure there is an index on the column blah if that table is more than 500 records and that column has many unique values (i.e., ignore columns like status, gender, or active/inactive). No, that’s not the ideal answer (this is why DBAs make the big bucks), but it’s the quick and dirty explanation why many Word Press plugins tend to contribute to a server dying when getting Dugg. Perhaps I will cover this in more depth another day.

I hope this helps!

Update: Rewrite Rules on Apache 1.3 are Greedy By Default

Well, that was annoying! Some of you may have noticed intermittent outages on my blog while I was trying to fix the URL’s. Scary stuff. Anyway. This post will be gibberish if you don’t understand regular expressions. If you’re one of these people, I suggest you turn back now. 🙂 This is, after all, a technical blog too. 😛

What I discovered was that I was incorrect in my post last night about the catch-all .htaccess entry that would redirect all traffic from michikono.com/blog. Here’s the wrong rewrite rule:

RewriteRule ^/?(.*) http://www.michiknows.com/$1/ [R=301,L]

The goal was to take whatever text came after “michikono.com/blog” (such as the post name), and stick it on the end of “michiknows.com” so that all the old articles translate over without outages. Unfortunately, I noticed a few problems.

The correct code is as follows:

# match just blog
RewriteCond %{REQUEST_URI} blog/?$
RewriteRule . http://www.michiknows.com/ [R,L] 

# match blog posts
RewriteRule (.*) http://www.michiknows.com/$1 [R,L]

Why two regular expressions? Well, I couldn’t use the reluctant modifier (“?”) to make it catch a case when there was no trailing slash. Thus, no matter what I did, it would act as if there no no trailing slash. This broke stuff such as the RSS feed!!

The problem was that Apache 1.3 uses a greedy catch all by default that can not be disabled. In other words, the “*” can’t be set to be non-greedy by adding a “?” behind it. This is possible in virtually all other implementations of regex. The warning flag is that when you put a question mark behind a “+” or “*”, it will give you an error!

So my new solution breaks the problem into two steps.

  1. First, I check specifically for a hard link to the blog home page, which may or may not contain a trailing slash. If so, it will just forward it to this site with a trailing slash.
  2. Then I setup a second catch all rule that just does a straight search and replace. It doesn’t bother with the trailing slash stuff at all since it just snips the entire URL and tags it on.

Why does it seem like the second rule could replace the first? Because the greedy operator acts weird and doesn’t behave as I want. I tried for an hour straight. Believe me. No matter what hack or work around I used, there was always a case that no longer worked (usually the home page bug). And to be honest, regular expressions with Apache are just plain horrible to work with. This solution finally worked, and is what I will settle with (even as I write this post, I tried three other solutions that should work in any other regular expression environment — but failed to generate positive results).

So if you ever decide to move your blog, try the above solutions before giving up.

Who Else Wants to Hide Their WordPress Folder?

Tonight, I solved a very old problem in WordPress security among novice users. I will show you how to hide your WordPress admin directory while still being able to use it! When I say “hide,” I mean you can rename the wp-admin folder to whatever you want!

The Code (for people who don’t want to read)

Copy and paste the following into your .htaccess file (located wherever your WordPress folder is) to “rename” your wp-admin folder! If you are having trouble editing your .htaccess file, you should Google around for that as it’s beyond the scope of this article (or post a question in the comments and maybe another person can help).

  • Change YOURSECRETWORDHERE to something else. It can be any word you want. Just make sure it’s unique and somewhat long. Make it, like, your pets name or something random. Read this post to understand why this matters.
  • Change ADMINFOLDER to the new folder name you want. Letters, numbers, underscores, and dashes only. That ^ in front of it is on purpose. Don’t delete that.

RewriteEngine On
RewriteBase /
##### ABOVE THIS POINT IS ALREADY INSERTED BY WORD PRESS
##### Michi’s code is BELOW #####
RewriteCond %{REQUEST_URI} wp-admin/
RewriteCond %{QUERY_STRING} !YOURSECRETWORDHERE
RewriteRule .*\.php [F,L]
RewriteCond %{QUERY_STRING} !YOURSECRETWORDHERE
RewriteRule ^ADMINFOLDER/(.*) wp-admin/$1?%{QUERY_STRING}&YOURSECRETWORDHERE [L]

##### Michi’s code is ABOVE #####
##### BELOW THIS POINT IS ALREADY INSERTED BY WORD PRESS
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

Note: there are a few drawbacks to this hack. Read the bottom of this post for those.

The Explanation

My adventure started when I read a pretty terrible piece of advice that suggested using the .htaccess file to restrict who sees your admin section by IP. Great, so if I’m at work, I can’t login. So if my IP changes, I can’t login. If I’m at Starbucks, I can’t login. That’s retarded. That’s not a solution!

But it’s on the right track. The .htaccess file can do a lot.

Oh, and if any WordPress developers ever read this, please make the word press admin folder be a variable name you can change! It is retarded that it is a hard coded.

The .htaccess file shines best when it is used for URL rewriting rules. For you non-programmers, the next block explains a little about what I just said. If you don’t care, skip it.

It is good for making URLs access files that don’t necessarily exist on the server exactly as they appear in the URL. For example, Digg.com uses URL rewrites to hide file and variable names. So the URL digg.com/videos certainly does not point to a file or folder actually called “videos”. Rather, it probably turns into something like digg.com/somefilename.ext?type=videos. The point is, you can hide what’s actually happening behind the scenes. I hope you get the idea.

Disabling the wp-admin Folder and Creating a Secret Mirror Folder

There are two steps in blocking access to the wp-admin folder. Disabling it is easy, but making it still functional is the hard part. Additionally, there are CSS files and other dependencies in that folder that must still be used. So after disabling it, a condition must be added that makes it only be disabled when appropriate.

RewriteCond %{REQUEST_URI} wp-admin/
RewriteCond %{QUERY_STRING} !YOURSECRETWORDHERE
RewriteRule .*\.php [F,L]

  1. The first line says “If the word wp-admin is found in the URL…”
  2. The second line says, “And if the query is missing our password…
  3. The third line says “And it’s a PHP file… Deny access.”

We’ll get to that password thing in a minute. At this point, if you visit wp-admin/, it will not work. Half way there!

The next part is the guts of it all. We get to set our very own admin folder! I want to call my admin folder “secret_room”. So here’s how the code would look:

RewriteCond %{QUERY_STRING} !YOURSECRETWORDHERE
RewriteRule ^secret_room/(.*) wp-admin/$1?%{QUERY_STRING}&YOURSECRETWORDHERE [L]

This next block is for you technically oriented people:

The first part basically makes sure the rule doesn’t trigger itself later (recursive condition). This is basically saying “if the URL starts with ‘secret_room,’ then replace that part with wp-admin. Then, add in the query string (things after the question mark). Finally, add in the secret word.”

Now, if I go to the folder secret_room/, it will work just like wp-admin used to!

Don’t use “secret_room.” That’s my example. You use whatever folder name you want. Letters, numbers, underscores, and dashes only.

But we’re not done yet. That secret word thing needs to be customized. Why? Well, try this. Go to your blog’s wp-admin folder, but this time, add on “?YOURSECRETWORDHERE” on the end and it will work too (as in, myblog.com/wp-admin/?YOURSECRETWORDHERE)! Curious why? If you’re a little geeky, read the next block. Otherwise, skip it.

Well, this hack works by changing the URL you type in by adding that “secret word” on the end of it. It only does this when someone visits the “secret_room” folder. But it doesn’t add it on when you just type in the wp-admin/ folder (or any other location). Then, when someone is looking at a wp-admin folder, it looks to see if that secret word is in the URL. If you went to the URL by hand, you likely did not type that word in. But the “secret_room” always makes sure the secret word is attached. This is how it distinguishes between visiting wp-admin directly, and visiting it through the mirror folder. Remember that any re-writing of the URL happens behind the scenes, so your browser won’t show you what’s going on.

Since I just gave this same code to about 10,000 people, it’s in your best interest to change your secret word to be unique to you. Note that nobody will ever see it, including you. You will forget what it is, and realistically, it doesn’t matter what the hell you set it to. As long as it’s not the default one I just gave to you. Ideally, it should be long and something highly unlikely to appear in a URL. Try your name, then maybe add your favorite color. I don’t know. Just do something random. Case matters.

Here is what the final .htaccess, ideally, should look like:

RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} wp-admin/
RewriteCond %{QUERY_STRING} !YOURSECRETWORDHERE
RewriteRule .*\.php [F,L]
RewriteCond %{QUERY_STRING} !YOURSECRETWORDHERE
RewriteRule ^secret_room/(.*) wp-admin/$1?%{QUERY_STRING}&YOURSECRETWORDHERE [L]
# BEGIN WordPress
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

Benefits and Drawbacks to Hiding wp-admin

This hack has its drawbacks.

  • The “edit” link on your posts will no longer work. You may want to remove it from your theme.
  • The admin link on your side bar will no longer work. You may want to remove it from your theme.
  • The standard login link will no longer work. Instead, use a bookmark as it will redirect you back to your hidden login page after you finish logging in.

Note that the first two drawbacks can be addressed by editing wp-includes/link-template.php: line 248 and 263. Change “wp-admin” to your new folder name. However, this hack would need to be re-done if you upgrade WordPress. If you make these hacks, it will only be visible to users who have permission to see these links anyway.

There are a few significant upsides:

  • If ever again there is another vulnerability that hits the WordPress wp-admin folder, you are very likely immune.
  • Upgrading WordPress doesn’t un-hide the folder. It will persist through upgrades.

Remember, this hack will not protect you from having an insecure admin password. Although, it could protect you from a hacker since he won’t know where to go after successfully logging in (hah!).

Lastly, be careful when doing this. If you type something wrong, you’ll get server errors (I believe error code 500). Make sure you type it in exactly as you see it in these examples first. Then change one part at a time.

Changing the Admin User

One other point I noticed when tightening up my security was the default admin user name. Now, hah, this is assuming they actually brute force my password and then figure out how to get to the admin folder… good luck.

I noticed that I had an admin user account under the login name “admin”. Well, that’s a no-brainer. I went into the database and ran the following query:

UPDATE wpt_users SET user_login = ‘[my new username]’, user_nicename = ‘[my new username]’ WHERE wpt_users.ID = 1 LIMIT 1;

That solves another part of the problem. Now hackers have to guess not only my password, but also my username.

In Closing…

If you like what you’ve read, I’d appreciate it if you could Digg/Reddit/Stumble this article. 🙂

Michi Knows – Dedicated Blog URL

Update: These re-write rules are wrong. See this post for correct rewrite rules.

My friend gave me a suggestion to make myself a “brand” out of this blog by calling it “Michi Knows”. Apparently, he stumbled into the name while thinking about the URL of my website. Funny story.

Anyway, I liked the name so I bought it. What’s another domain, right? Besides, it was bugging me that my blog had no title and had weird formatting.

Porting Word press over to this domain wasn’t all fun and games. Most importantly, I have tons of incoming links I wasn’t about to 404. My goal was to make sure every single link out there coming to my site would correct redirect. Here’s how I did it.

There is a file called .htaccess that web servers use to setup rules for processing requests. Or in other words, when someone visits a server, that file is checked and any rules listed in it dictate what to do next. My blog was previously located in a folder called blog/. I placed a .htaccess file there and put in the following content:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^/?(.*) http://www.michiknows.com/$1/ [R=301,L]
</IfModule>

Ignore that weird HTML tag thing. What’s important is the stuff in between.

  1. The first line is telling the server “hey, we’re gonna do some funky stuff with the URL.
  2. The second line tells the server “hey, everything is relative to where we are now” (blog/)
  3. The third line says “change anything you see into http://www.michiknows.com and then put whatever stuff came after “blog/” on the end of the new URL.

Thus, the above code would change:

http://www.michikono.com/blog/some-really-cool-article

Into:

http://www.michiknows.com/some-really-cool-article

Notice the distinction. The (.*) means “anything”, and the $1 refers to the “anything” found in between the parenthesis. The “R” means redirect, the “permanent” is more for stuff like search engines. The L stands for “Last” – as in: “this is the last rule, stop processing more”.

Let me know if anything in my new blog is broken. 🙂

Here’s some things I considered before moving that I hope you all consider if you ever move blogs:

  • Moving means killing any page-rank I may have gained. My blog had a page-rank of 5 in only a few months. I figure I can do it again. 🙂
  • Moving means losing a lot visibility in search results. Now that the content is on an unknown domain, results can omit me a lot. I don’t even know what Technorati is going to do!
  • Any tracking you have of users is destroyed due to the changing of cookie domains. Yep, now everybody is anonymous again.
  • Incoming link tracking in Word Press completely breaks. It currently says “No results found.”

Anyway, no big deal. I look forward to finally having a blog-only domain. 🙂 Thanks Jackson for the name idea.

RSS Tracker Images

I use Google personalized homepage to track the latest and greatest news. Google recently unveiled a new feature that puts a little plus next to stories. When you click on this plus, the article description slides out underneath.

So I clicked on a feed from CNN and noticed two blank image placeholders appeared and then quickly disappeared. I noticed this was also the case for my Slashdot feeds. So I examined the raw RSS feed on Slashdot, and noticed this:

&lt;img src=”http://rss.slashdot.org/~a/Slashdot/slashdot?i=1sz5lq” border=”0″&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=”http://rss.slashdot.org/~r/Slashdot/slashdot/~4/86854678″/&gt;

In other words, whenever the feed is viewed by a reader that supports HTML (most readers nowadays), a 1×1 pixel image is displayed from the Slashdot server. This allows the server to track where feeds are being viewed from as well as any other information they can scrape such as your IP, the time, if when the feed was pulled, your username (on Slashdot), etc.

This technology is widely used in e-commerce for tracking clicks that lead to sales. While this is an obvious step, I had never really heard about this until now.

One unintended consequence of Google’s reader is that the pixel only fires if I click on the plus image. This means CNN et al. is able to determine if a particular viewer who looks at a description is more likely to come read the full article. It also means the pixel only fires by active user intervention, making the tracking feature largely useless. But then again, if users pinged 25 servers every time they loaded up Google, I think a lot of servers might begin to have problems. 🙂

If you didn’t already know of this, I hope this was an interesting read.

IE7: CSS .class#id Is Not The Same as .class #id!

I know that title is horrible, but bear with me. This post is worth reading if you are a novice CSS writer. I hit a CSS bug in IE today that is relatively easy to avoid that involves manipulating an element that has an ID assigned to it by referencing its class.

Some of you may have noticed that I made the site wider by 200 pixels. Well, while doing this, I also decided I would try moving my Adsense banner to the left side on individual blog posts (view an individual post to see this). Here’s what I added in my WordPress code:

<div id=”main” class=”<?php echo (is_single() ? ‘with-ads’ : ‘no-ads’) ?>”>

So basically, when a visitor is viewing a single post, a special class is assigned to the main DIV. So far, simple right? The idea was that on pages without ads, the blog would expand all the way to the left, ensuring no blank gaps in my template (click around to see for yourself). So then I created the following CSS:

.with-ads {
width: 645px;
margin-left: 125px;
}
.no-ads {
width: 765px;
margin-left: 0px;
}

Please note, I don’t claim to be a master-Yoda-CSS-guru and perhaps there’s better ways to do what I did, but also note that my blog integrates with my AJAX code, so I can’t change too many things without breaking other functionality. I used floating columns to do this new formatting (one column on each side of the post), so naturally there are problems when I don’t specify widths. Otherwise, I would just set it to 100%. Anyway, does my CSS work? No:

Yes. Giant gaps of space!

Many of you have encountered this before, I know. But this one is a tricky bastard. Okay, so I thought maybe the default setting for #main was overwriting the width since #main’s non-blog default is to stretch 100% across the screen. Yes, I use the same CSS file for the entire site so that my AJAX functions correctly (try clicking on the icons at the top of the page). So I changed the CSS to:

#main .with-ads {
width: 645px;
margin-left: 125px;
}
#main .no-ads {
width: 765px;
margin-left: 0px;
}

No effect. Damn.

I  banged my head for a long time until I noticed this worked just fine in Opera and Firefox (every good developer tests on at least three browsers! 😉 ). I was scared because this was obviously an IE bug, and I hate doing CSS hacks.

I banged my head for a while until I had the crazy idea of deleting the space between the ID and class. Thus:

#main.with-ads {
width: 645px;
margin-left: 125px;
}
#main.no-ads {
width: 765px;
margin-left: 0px;
}

This worked!

I hit the same bug when trying to make images in my blog have borders except emoticons, which have the CSS class “wp-smiley.” First, the CSS that puts borders:

#rap #main img {
padding: 1px;
border: 1px solid black;
}

Then the CSS for the smiley:

#rap #main img.wp-smiley {
padding: 0px;
border: 1px solid white;
}

Oddly, If I remove that space after “img” or if I take off “#rap #main”, it stops working in all of my browsers. So the first “bug” hit only IE7, but this one hit everything.

Lastly, the whole ID-prefix business seems utterly unnecessary so long as I use a tag ID that is not #main. For example, when I renamed the blog main to use #blog-main, I could correctly modify it with just the class name!

My conclusion is that CSS ID based definitions tends to overwrite class based ones unless that space is omitted. Really, I don’t even know. CSS guru Feed back is appreciated.