nSurface

Custom login CSS style

The WordPress login screen is pretty bland and sometimes you just want something different. Or maybe you just don’t want to remind your users that you’re using WordPress all the time. Add this to your functions.php file:


/* custom login style */
function custom_login() {
echo '<link rel="stylesheet" type="text/css" href="'.get_bloginfo('template_directory').'/assets/css/custom-login.css" />';
}
add_action('login_head', 'custom_login');

this will add your own stylesheet to the login page. In this case, my stylesheet lives in ‘mytheme/assets/css/custom-login-css’. Then create a CSS file and change it as you see fit. My latest looks like this:


/* Custom Login Styles */

html {background:url(../images/default_large.png)}    /* Page background. Can't use the body tag for this! */
h1 a {    /* Title image (The "WordPress Logo"). Remember to update the height and width your image's dimensions */
background:url(images/default_large.png.none) 0 0 no-repeat;
width:415px;
height:70px;
}

body.login {border-top-color:#dff4fc;}    /* Top bar background color */
.login p#backtoblog a:link, .login p#backtoblog a:visited {color:#17272d;}    /* Link effects in top bar */
.login p#backtoblog a:hover, .login p#backtoblog a:active {color:#17272d;text-decoration:underline;}    /* Rollover link effects in top bar */

form {
 border-radius:0;
 box-shadow:none;
}

div.updated, .login .message, .message{
 background-color:yellow;
 border-radius:0;
}

Redirect to the WordPress homepage after login

Normally after you log into your wordpress site you are directed to the admin dashboard. WordPress assumes that if you log in, that you must want to edit the site somehow. This is probably true in most cases. But in the recent past I’ve been making more and more themes that are private and/or collaborative serving a wide range of people from the computer savvy to near Luddites. Something I heard a lot goes something like: ‘when I log in I get forwarded to some other website and I don’t know how to get back!’. What is this ‘other website’? It turns out it’s the admin dashboard, and it freaks a lot of people out apparently (and can potentially set your computer on fire according to claims). Anyway, there are a lot of reasons you might want to forward your users on to something other than the admin page when they log in, like if you have a private blog and your family has the password to it and they have no reason to see the dashboard (since they don’t even have permissions to create/edit content anyway). Paste this into your functions.php file:


/* login redirect to index page */
function redirect_to_front_page() {
 global $redirect_to;
 if (!isset($_GET['redirect_to'])) {
 $redirect_to = get_option('siteurl');
 }
}
add_action('login_form', 'redirect_to_front_page');

This function will redirect to the home url by default, but with minimal modification you can redirect anywhere you see fit.

Remove that stupid WordPress admin bar

Introduced with WordPress 3.0 (I think?), a little admin bar automatically appears at the top of your wordpress website whenever you’re logged it. While it may be useful for someone, it’s actually pretty annoying and really unsightly in most cases (it can also mess up your site if you have absolute or fixed position items in your theme). There are plugins to remove it, but I prefer to keep everything I can in my functions.php file to increase theme portability and stability. Paste this into your functions file:


//remove admin bar
add_action( 'admin_print_scripts-profile.php', 'hide_admin_bar_prefs' );
function hide_admin_bar_prefs() {
 echo '<style type="text/css">.show-admin-bar { display: none; }</style>';
}
add_filter( 'show_admin_bar', '__return_false' );

forget you ever saw that bar

WordPress Custom Metaboxes

Recently for a theme I was building I found myself in need of some custom metaboxes to be filled with data by the users. The default “custom fields” box can work, but it can also be confusing to people who don’t really know what their doing. It’s also a lot easier to tell someone to “check the “proofread” checkbox” instead of telling them to select  “proofread” item from the “name” column and then type “true” into the corresponding “value” text area. There are a lot of reasons why you might do this, not the least of which is that it makes things cleaner on the back end.

Anyway, I came across a really great, and fairly lightweight function at wefunction.com that makes it really simple to add new metaboxes. It’s really great too because it stores all of the data as a serialized array which can cut down on mysql retrieval costs if you’re needing to pull down a lot of these at once. But, the function he gives doesn’t work if you need a checkbox (which I needed). So I’ve made a simple, but important modification to allow for more flexible input. This is the full code that you would put into your functions.php file:


<?php

$key = "GSD"; //table prefix do not change once set
$meta_boxes = array(
 "callnumber" => array(
 "name" => "callnumber",
 "title" => "Call Number",
 "description" => "enter in the unique library call number for this record",
 "type" => "text"
 ),
 "curated" => array(
 "name" => "curated",
 "title" => "Curated",
 "description" => "Is this post curated?",
 "type" => "checkbox"
 )
);

function create_meta_box() {
 global $key;

 if( function_exists( 'add_meta_box' ) ) {
 add_meta_box( 'new-meta-boxes', ucfirst( $key ) . ' Custom Options', 'display_meta_box', 'post', 'normal', 'high' );
 }
}

function display_meta_box() {
 global $post, $meta_boxes, $key;
?>

 <div>

 <?php
 wp_nonce_field( plugin_basename( __FILE__ ), $key . '_wpnonce', false, true );

 foreach($meta_boxes as $meta_box) {
 $data = get_post_meta($post->ID, $key, true);
 ?>

 <div>
 <label for="<?php echo $meta_box[ 'name' ]; ?>"><?php echo $meta_box[ 'title' ]; ?></label>

 <?php if( $meta_box[ 'type' ]  == "text"): ?>
 <input type="type" name="<?php echo $meta_box[ 'name' ]; ?>" value="<?php echo htmlspecialchars( $data[ $meta_box[ 'name' ] ] ); ?>" />
 <?php elseif($meta_box[ 'type' ]  == "checkbox") : ?>
 <input type="checkbox" name="<?php echo $meta_box[ 'name' ]; ?>" <?php if( $data[ $meta_box[ 'name' ] ] ) echo "checked='checked'"; ?> value="true"/>
 <?php endif; ?>

 <p><?php echo $meta_box[ 'description' ]; ?></p>
 </div>

 <?php } ?>

 </div>
<?php
}

function save_meta_box( $post_id ) {
 global $post, $meta_boxes, $key;

 foreach( $meta_boxes as $meta_box ) {
 $data[ $meta_box[ 'name' ] ] = $_POST[ $meta_box[ 'name' ] ];
 }

 if ( !wp_verify_nonce( $_POST[ $key . '_wpnonce' ], plugin_basename(__FILE__) ) )
 return $post_id;

 if ( !current_user_can( 'edit_post', $post_id ))
 return $post_id;

 update_post_meta( $post_id, $key, $data );
}

add_action( 'admin_menu', 'create_meta_box' );
add_action( 'save_post', 'save_meta_box' );

?>

In most ways it’s identical to the code that I found, but I added a bit of logic to slightly change the html that the script writes for the different input types. I added one element called ‘type’ to the array that you pass into the function :


$meta_boxes = array(
 "callnumber" => array(
 "name" => "callnumber",
 "title" => "Call Number",
 "description" => "enter in the unique library call number for this record",
 "type" => "text"
 ),
 "curated" => array(
 "name" => "curated",
 "title" => "Curated",
 "description" => "Is this post curated?",
 "type" => "checkbox" //this is the addition and should correspond to standard html form language
 )
);

then I added a simple if statement that looks at the value of this ‘type’ value and decides how to print the html and post the data:


<?php if( $meta_box[ 'type' ]  == "text"): ?>
 <input type="type" name="<?php echo $meta_box[ 'name' ]; ?>" value="<?php echo htmlspecialchars( $data[ $meta_box[ 'name' ] ] ); ?>" />
 <?php elseif($meta_box[ 'type' ]  == "checkbox") : ?>
 <input type="checkbox" name="<?php echo $meta_box[ 'name' ]; ?>" <?php if( $data[ $meta_box[ 'name' ] ] ) echo "checked='checked'"; ?> value="true"/>
 <?php endif; ?>

Right now it only recognizes input types of ‘text’ and ‘checkbox’ but following this same logic you could just add other elseif statements and one line of html and make any type of form input work.

It’s a really elegant solution that was already pretty flexible and expandable (it’s not hard to add any number of metaboxes now!), and now it’s just a little bit more versatile.

note: The metadata is stored in a single table entry which makes retrieving a lot of data very simple and fast. However for this same reason, you cannot sort a query from metadata stored with this method. If you need to sort also, take a look at the earlier entry on metaboxes.

Protecting content in custom themes

If you password protect an individual post or page in your wordpress blog, wordpress makes sure that anything returned by the_content() stays hidden from prying eyes. But what if your theme makes use of other functions that might show something else that you want to remain secure (think attachments, metaboxes, etc)? We’ll it’s not in the wordpress conditionals page, but it does exist:

if(!post_password_required()){
//your protected stuff
}

anything inside that if statement should only show up if your user logs into that post.

conditional custom post type template

I’ve always thought I should post some of my WordPress hacks so I can keep them in one place. Maybe they’ll be of use to someone else too.

Anyway, a client of mine wants to be able to post bios of the people associated with the organization. No problem. I define a custom post type “People” that allows the client to add “people” pages with bios, headshots, etc. The problem is that they want three different types of people to show up on different pages. In this case they want a page for team members, one for advisors, and one for sponsors. I could separate post types for each group, but that seems redundant if they’re going to all contain the same types of information anyway. Also, if I need to update the post type then I’d have to make that edit at least three times in three different places. Not good. So instead, I create a custom taxonomy (category) for the “People” named “Relationship” that allows the user to easily assign a person to a group or groups just as they would choose a category.

Now in order to display the people posts I define a page template “People Page.” To make it smart I first want to get the current page’s slug. There are other ways of doing this, but this one is not dependent on the permalink structure.

$post_obj = $wp_query->get_queried_object();
$post_ID = $post_obj->ID;
$post_title = $post_obj->post_title;
$post_slug = $post_obj->post_name

then I call WP_Query and pass $post_slug into the arguments. When working with custom post types and taxonomies, you must remember to change the name of the category and post type in the arguments!

$loop = new WP_Query( array('relationship' => $post_slug, 'orderby' => 'menu_order', 'order' => 'asc', 'post_type' => 'people', 'posts_per_page' => 10 ) );?>

From here you can jump into the loop and do whatever you need your posts to do.

All that’s left was for me to assign the page’s templates to my “People Page Template” and each page is styled the same, using the same post type, but populated by the correct people

One Caveat: The category(taxonomy) slug MUST be identical to the corresponding page slug! If they are different, it will NOT work!

<?php
/*
Template Name: People Page
*/
?>
<!--
look to see what kind of person is being identified by the page slug

!!!THE PAGE SLUG MUST BE IDENTICAL TO THE CATEGORY(RELATIONSHIP) SLUG TO WORK!!!!

Then pass the category slug into the wp_query as a condition

this makes it possible to have as many "people" categories as needed without having to make more identical templates that need to be updated in parallel.
-->

<?php
$post_obj = $wp_query->get_queried_object();
$post_ID = $post_obj->ID;
$post_title = $post_obj->post_title;
$post_slug = $post_obj->post_name;

$loop = new WP_Query( array('relationship' => $post_slug, 'orderby' => 'menu_order', 'order' => 'asc', 'post_type' => 'people', 'posts_per_page' => 10 ) );
?>

<!--enter the loop-->
<?php while ( $loop->have_posts() ) : $loop->the_post(); ?>
<!--perform the same operations for each category-->
<?php endwhile; ?>