How to include a custom stylesheet on a WordPress options page

(or, “how to put a bunch of error messages in a blog post for effortless traffic”)

Let’s start with what doesn’t work, beginning with including the options page file itself:

If you’re defining a base URL for your includes, for example define('PLUGIN_BASE', plugin_dir_url( __FILE__ ));, you won’t run into any problems enqueuing scripts and stylesheets.
wp_enqueue_style( 'plugin-style', PLUGIN_BASE. 'css/plugin-style.css'); will work fine.
But don’t think about trying to include( PLUGIN_BASE . 'plugin-options.php');, you’ll get a friendly:
Warning: include() [function.include]: URL file-access is disabled in the server configuration
(It seems like include( 'plugin-options.php'); works, but I don’t think it’s the best way to go about it).

If we were suspicious of PLUGIN_BASE before, we’ll quickly progress to dismay and anger once we try to use it in plugin-options.php. A simple call to wp_enqueue_style( 'options-style', PLUGIN_BASE. 'css/options-style.css'); gives us this bizzarre error in the console:

Failed to load resource: the server responded with a status of 404 (Not Found) http://mystagingsite.mysite.com/wp-content/plugins/http://mystagingsite.mysite.com/wp-content/plugins/my-plugin/css/options-style.css?ver=3.4.1

Ok, so maybe the PLUGIN_BASE constant isn’t valid inside of a different class, or something. Let’s forget the definition and just put plugin_dir_url( __FILE__ ) there instead.

Nope.

plugin_dir_path(__FILE__)?
Nope.
dirname(__FILE__)?
Nope.
trailingslashit( dirname( $file ) )?
Nope.
plugin_dir_url( $file )?
Nope.
plugin_basename(__FILE__)?
Nope.
realpath( dirname( __FILE__ ) )?
Nope.
basename(dirname(__FILE__))?
Nope.

What eventually ended up working, though I still couldn’t tell you why, is wp_enqueue_style( 'options-style', plugins_url('/options-style.css', __FILE__) );

So if you got here with any of those errors above, I hope this has helped you out.

Cheat Sheet for the WordPress bundle in TextMate

There wasn’t one of these already, so I made one. Based on the WordPress TextMate Bundle by Shawn Parker & Top Frog Graphics.

GDE Error: Unable to load profile settings

jQuery .fadeIn() opacity bug in Chrome and IE 8

I kept encountering this strange glitch in Chrome when using jQuery’s .fadeIn() effect on a text element. The text would fade in properly, but then flicker to a slightly bolder weight. The text wasn’t bold, so I couldn’t figure out what was going on.

It turns out that in IE 8 (and lower) and in Chrome on some operating systems, the text loses its ClearType while fading, and then has ClearType activated once it’s fully faded in. This causes a distracting jitter. Thankfully there is an easy fix. Add the following to the CSS selector for the text element:

  1. opacity:0.99;
  2. filter:alpha(opacity=99);

This will make the element fade in to only 99%, thus preventing ClearType from engaging, and smoothing out the transition.

Analytics tracking for Lightbox 2 image galleries

I use the Lightbox 2 plugin for the image galleries on this site— it’s a pretty great plugin: loads fast, looks nice, easy to implement… but one gripe I’ve had for a while is the inability to track image views with Google Analytics.

Problem solved…

Open up the file lightbox-resize.js (or lightbox.js if you’re using the non-resizing version), and go down to the showImage: function(), around line 323. You’re going to want to add a line at the end of the function, so it looks like this:

  1.  showImage: function(){
  2.   Element.hide('stimuli_loading');
  3.   new Effect.Appear('stimuli_lightboxImage', { duration: resizeDuration, queue: 'end', afterFinish: function(){ myLightbox.updateDetails(); } });
  4.   this.preloadNeighborImages();
  5.   pageTracker._trackPageview(imageArray[activeImage][0]);
  6.  },

Now, when an image is opened in a lightbox, the image URL will get passed to Google as a pageview. The console output, for those interested, looks like:

To test this, I’m using the Google Analytics Tracking Code Debugger for Chrome.

Events vs. Pageviews

I think the proper way to do this would have been to generate an event, not a pageview… but I’d like to be able to use the click data overlay view within analytics. With the way I have it now, I’ll be able to easily see which images were most clicked within my image galleries.

[highlight]Update: 10/30/10[/highlight]
I didn’t actually confirm that the pageviews were coming through in my Analytics report when I first published this article. A few days later, I noticed that even though the debugger said the beacons were being sent, no data for the image clicks was showing up on my reports. You can see in the screenshot above that my account was being sent as UA-XXXXX-X, not the real account number. It turns out that the Analyticator plugin I’m using for wordpress uses the asynchronous tracking method, not the older synchronous method that I was using in my example above (the above example should still work for the synchronous code).

Then I had a problem with the URLs coming through with the domain name (which is how Lightbox2 refers to them) when Google expects them to only be the path. This was giving me a content item of http://www.brycecorkins.com/http://www.brycecorkins.com/wp-content/uploads/2010/06/DSC_0014.jpg. To fix it, I added a little string modifier to remove the first 27 characters of the string before it’s passed to the tracker. This is very hack-y and not good, I’m hoping someone will give me a better suggestion, but for now, it’s working. The code looks like this:

  1.  showImage: function(){
  2.   Element.hide('stimuli_loading');
  3.   new Effect.Appear('stimuli_lightboxImage', { duration: resizeDuration, queue: 'end', afterFinish: function(){ myLightbox.updateDetails(); } });
  4.   this.preloadNeighborImages();
  5.  
  6.   var urlString = imageArray[activeImage][0].substr(27);
  7.   _gaq.push(['_trackPageview', urlString]);
  8.  },

JQuery Dropdown Message on First Login

I wanted to have a sliding dropdown (Twitter style) displayed to my users after logging into a WordPress site for the first time.

Had to hack this together from a few different sources, so I’m posting the results here in case anyone else is trying to do the same:

Step 1: Display a welcome message to a recently-registered wordpress user (but hide it for older users).

I got most of this info from this post on the WordPress.org support forums, but there was a typo in the code that made it not work.

In your theme’s functions.php

  1. function my_show_extra_profile_fields( $user ) {
  2.  
  3.  global $user_ID;
  4.  if( $user_ID ) {
  5.   $user_info = get_userdata( $user_ID );
  6.   // If user_registered date/time is less than 48hrs from now
  7.   // Message will show for 48hrs after registration
  8.   if ( strtotime( $user_info->user_registered ) > ( time() - 172800 ) )
  9.    echo 'This text only appears to new users';
  10.  }
  11. }

This function inserts the code into the user’s profile page… which is where they’re directed after they log in. I’m using Theme My Login by Jeff Farthing to theme my login and profile pages. The message will display for the first 48 hours after registration, then disappear.

Step 2: Make a nice JQuery slide-in type message box.

  1. <script type="text/javascript">
  2.    $(document).ready(function(){
  3.     $("#notification").slideDown("slow"); //< — this is the animation code
  4.     $("#first_name").addClass("selected");
  5.     $("#last_name").addClass("selected");
  6.    });
  7.    </script>
  8. </script>

This takes any DIV with ID “notification” and slides it down, slowly. The .addClass is specific to my implementation… it highlights the First Name and Last Name fields, to invite the user to fill them out.

Finally, you’ll want to style #notification. Make sure to set its display: property to none

  1. #notification {
  2.  position: absolute;
  3.  top: -20px;
  4.  left: 0px;
  5.  height: 85px;
  6.  width: 100%;
  7.  background: #ffffe0;
  8.  display: none;
  9.  line-height: 10pt;
  10.  font-family: sans-serif;
  11.  padding: 5px 10px;
  12. }

Putting it all together, you have (in my case):

And the code:

  1. function my_show_extra_profile_fields( $user ) {
  2.  
  3.  global $user_ID;
  4.  if( $user_ID ) {
  5.   $user_info = get_userdata( $user_ID );
  6.   // If user_registered date/time is less than 48hrs from now
  7.   // Message will show for 48hrs after registration
  8.   if ( strtotime( $user_info->user_registered ) > ( time() - 172800 ) )
  9.    echo '
  10.   <script type="text/javascript">
  11.  
  12.   $(document).ready(function(){
  13.    $("#notification").slideDown("slow"); //< — this is the animation code
  14.    $("#first_name").addClass("selected");
  15.    $("#last_name").addClass("selected");
  16.   });
  17.  
  18.   </script>
  19.   ';
  20.  }
  21.  ?>
  22.  <div id="notification">
  23.   <center><strong>Hey! I see you're new here!</strong> Thanks for registering, and welcome to <strong>evolutionary collective!</strong><br /><br /></center>
  24.  <span style="line-height: 30px;"><img src="/wp-content/themes/twicet/images/edit.png" style="float: left; margin-right: 10px;"/>You might consider filling out <strong style="color: #f79d34">a little more information about yourself</strong> below <br />
  25.  
  26.  <a href="/forum"><img src="/wp-content/themes/twicet/images/forum.png" style="float: left; margin-right: 10px;"/></a>Or, head over to the <a href="/forum">forum</a>, and participate in a discussion!</span>
  27.  
  28. </div>
  29. < ?php
  30.  
  31. }

[highlight]UPDATE:[/highlight]
Also, I thought this would have been pretty obvious, but remember you must include jQuery somewhere in your page, preferably in the header. The easiest way to do this is:

  1. <script src="http://code.jquery.com/jquery-1.4.4.js"></script>

Of course you don't want to include an external file on a live site— but this works for testing purposes.

Conditional Loading Facebook Scripts

I’m working on a client project currently which employs a “Like” button on each of the post pages– but nowhere else on the site. You can see here, Facebook requires 253.2 KB worth of scripts (54% of the entire page!) and adds 2.73 seconds to the page load time (52% of the time).

I’m using the Simple Facebook Connect plugin for the Like button.. so I went into the sfc-base.php file in the plugin’s folder, and tried to find a way to prevent the plugin from loading on non-post pages. After a bit of trial and error, I eventually added a conditional if is_single() to the Facebook script loading function (see line 9 below).

  1. // load the FB script into the head
  2. add_action('wp_enqueue_scripts','sfc_featureloader');
  3. function sfc_featureloader() {
  4.  if (is_single()){
  5.   if ($_SERVER['HTTPS'] == 'on')
  6.    wp_enqueue_script( 'fb-featureloader', 'https://ssl.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php/'.get_locale(), array(), '0.4', false);
  7.   else
  8.    wp_enqueue_script( 'fb-featureloader', 'http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php/'.get_locale(), array(), '0.4', false);
  9.  }
  10. }

Now the Facebook script only loads on individual posts, and the rest of the site is 3 seconds snappier!

WordPress 3.0 Upload Image Fix

After upgrading to WordPress 3.0, I could no longer upload media in the visual editor. Instead of popping up in the lightbox, a whole new page would load, and no images would attach to posts.

In the Headspace2 plugin… go into /wp-content/plugins/headspace2/js and open the headspace-tags.js file. Around line 67 (function get_tag_element () {) change what’s there to the following:

  1.     function get_tag_element () {
  2.       if ($('#tax-input-post_tag').length == 1)
  3.         return '#tax-input-post_tag';
  4.       else if ($('#tags-input').length == 1)
  5.         return '#tags-input';
  6.       else if ($('#tax-input\\[post_tag\\]').length == 1)
  7.         return '#tax-input\\[post_tag\\]';
  8.     }

Refresh a couple of times, to clear your browser’s cache, and try and attach an image. The usual popup window should now load.

(If you don’t have Headspace2 installed.. maybe it’s some other plugin interfering..?)

Thanks to Aaron Campbell. Found at the Headspace bug tracker.

CSS3

I’ve just implemented a few CSS3 elements for those browsers that support it (and graceful degradation for those that don’t).

Rounded borders, with drop shadows:



Drop shadows on text:



For more information on CSS3 compatibility, and the tutorials that I used, see: The Zen Elements CSS3 Series

Justify Last Line in Paragraph – CSS Hack

The specs for CSS3 include all sorts of great options for justifying text, but those of us with non-CSS3 browsers are left out. One quick hack for justifying the last line in a paragraph is to add a series of underscores (or any other character) to the end of the paragraph block, and color them white.

A regular “text-align: justify;” styled paragraph:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec at dignissim nunc. Duis et magna eu metus faucibus mollis luctus vel nibh. Nulla condimentum est felis. Maecenas laoreet ipsum euismod metus tristique imperdiet. Nunc congue, libero eu scelerisque fringilla, nunc ante lobortis massa, rhoncus feugiat lectus nisi at lectus.

However, if you add to the end of the paragraph:

  1. <font color="#fff">______________________</font>

You get:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec at dignissim nunc. Duis et magna eu metus faucibus mollis luctus vel nibh. Nulla condimentum est felis. Maecenas laoreet ipsum euismod metus tristique imperdiet. Nunc congue, libero eu scelerisque fringilla, nunc ante lobortis massa, rhoncus feugiat lectus nisi at lectus. ______________________

This could be done within a stylesheet, too… I’m just lazy.

Center align a WordPress Image Gallery


I’ve been trying for the last day or so to center align the default WordPress image gallery within a page– without any luck. Finally figured it out this morning, here’s how I did it:

  • Modify include/media.php to remove the gallery styles (this will stop them from overriding our custom style). Around line 738, you’ll see something like:
  1. $output = apply_filters('gallery_style', "
  2. <style type='text/css'>
  3. .gallery {
  4.       margin: auto;
  5. }
  6. .gallery-item {
  7.       float: left;
  8.       margin-top: 10px;
  9.       text-align: center;
  10.       width: {$itemwidth}%;
  11. }
  12. .gallery img {
  13.       border: 2px solid #cfcfcf;
  14. }
  15. .gallery-caption {
  16.       margin-left: 0;
  17. }
  18. </style>
  19. <!– see gallery_shortcode() in wp-includes/media.php –>
  20. <div class='gallery'>");
  • Change this to:
  1. $output = apply_filters('gallery_style', "
  2.       <style type='text/css'>
  3.              #{$selector} img {
  4.                     border: 2px solid #cfcfcf;
  5.              }
  6.              #{$selector} .gallery-caption {
  7.                     margin-left: 0;
  8.              }
  9.       </style>
  10.       <!– see gallery_shortcode() in wp-includes/media.php –>
  11.       <div id='$selector' class='gallery galleryid-{$id}'>");
  • Now in the stylesheet for your theme, add the following:
  1.  
  2. /* MODIFIED CENTER-ALIGNED GALLERY */
  3.  
  4. .gallery {
  5.        clear: both;
  6.        margin-bottom: 10px !important;
  7.        float: right;
  8.        position: relative;
  9.        left: -50%;
  10. }
  11. .gallery br {
  12.        display: none;
  13. }
  14. .gallery-item {
  15.        margin-right: 15px;
  16.        width: auto !important;
  17.        display: inline-block;
  18.        left: 50%;
  19.        margin-top: 10px;
  20.        position: relative;
  21. }
  22. .gallery-icon img {
  23.        height: 75px;
  24.        width: 75px;
  25.        border: solid 1px #ccc !important;
  26.        padding: 5px;
  27.        background: #f4f4f4;
  28. }

The floats and +/-50% adjustments were taken from this guide to centering floated CSS elements. I don’t honestly know how compatible this is, or whether it’s up to standards, but it works for me.