WordPress Hack: Reorder the Admin Menu

For many small business clients pages wind up being the most important WordPress post type. Many of them don’t even want a blog, just a nice looking site where they can update the content periodically, i.e. the contact page, the services page etc.

So for these clients it’s often a little confusing to have “Posts” at the top of the nav menu. Here’s how you would reorder to the nav to put pages on top.

First turn on the custom ordering option:

add_filter('custom_menu_order','__return_true');

Then create a function to filter the menu order array. In the function below we’re using array_splice to cut out the menu starting at position 2 because the “posts” menu item is #3 by default. How did I know that? Just add print_r($menu) and you’ll get a dump of the menu order. After splicing the array, we iterate over the old menu array, the part we extracted ($old), using a foreach loop adding the old menu items back in.

function mc_menu_order($menu) {
// more on array_splice here: https://php.net/manual/en/function.array-splice.php
$old = array_splice($menu,2,count($menu),array('2'=>'edit.php?post_type=page'));
$keys = array_flip($menu);
foreach($old as $item) {
if(!array_key_exists($item,$keys)) {
$menu[] = $item;
}
}
unset($old);
unset($keys);
return $menu;
}

Then just add the api call to insert that function:

add_filter('menu_order','mc_menu_order');

Here it is all together:

//menu reorder
add_filter('custom_menu_order','__return_true');
add_filter('menu_order','mc_menu_order');
function mc_menu_order($menu) {
$old = array_splice($menu,2,count($menu),array('2'=>'edit.php?post_type=page'));
$keys = array_flip($menu);
foreach($old as $item) {
if(!array_key_exists($item,$keys)) {
$menu[] = $item;
}
}
unset($old);
unset($keys);
return $menu;
}

The Simplest WordPress User Access Log Ever

Those of use who develop using pods often find we use it for everything. So here’s a quick tip on using PodsCMS to create a custom user access log.

Step 1: Set up the Pod

I’m assuming you’ve already installed/activate both the PodsCMS and Pods UI plugins. If not, please do so before starting.

Create a new Pod called “logins”.

By default each pod is created with a name and slug field. We’re going to use the name field but you can delete the slug field.

Then you’ll need to create a field for “date”. Of course, Pods stores the date any entry is created in a field called “created” which you can access from within Pods Templates. But it still makes sense to have a date field in the Pod itself, if nothing else for the sake of a clear data model.

So once you have added the date field your Pod will look like this:

Step 2: Add function

Now just add the following code to your functions.php file.

add_action('set_logged_in_cookie','mpv_add_access_log_entry');
function mpv_add_access_log_entry($user) {
$user = explode('|',$user);
$log = new PodAPI(); 
$params = array('datatype'=>'logins');
$params['columns'] = array('name'=>$user[0],'date'=>date('Y-m-d H:i:s'));
$log->save_pod_item(pods_sanitize($params));
}

This function uses the Pod API to insert a row in the logins table. Alternatively you can use the $wpdb class and do something like this:

global $wpdb;
$wpdb->insert($wpdb->prefix.'pod_tbl_logins',array('name'=> $user[0],'date'=> date('Y-m-d H:i:s')));

The only trouble with going this route is that in order to use the pods admin interface to manage the data, you’ll also need to add a row to the wp_pod table. This will change with Pods 2.0 so there’s no need to demonstrate. But I strongly recommend using the PodsAPI class as it will make sure to implement best practices and in 2.0 it will use the $wpdb class anyway.

So that’s it. To create an exportable report of the logins just install the “Exports and Reports” plugin. Or you can use PodsUI to create a custom interface.

Have fun.

WordPress Hack #3

Here’s a function that really should be in WordPress core by now. And maybe it is and I just can’t find it. But to get the source url for a post thumbnail you have to hack. Here it is:

/** 
**
** Parameters: 
** Size (optional): The width/height of the source image. Accepts either a string designating the WordPress image size, ( i.e. "thumbnail", "full","medium") or an array containing a custom size, i.e.  array(250,250) . Defaults to full size
**/
function get_post_thumbnail_url($size = 'full') {
global $post;
$src = wp_get_attachment_image_src( get_post_thumbnail_id($post->ID), $size, false, '' );
echo $src[0];
}

Genesis Framework, Not Too Shabby

So, I’ve posted elsewhere that I’m not a huge fan of theme frameworks. The short version: I’m not sure we need anymore hooks and filters than WordPress Core already provides and my time is better spent learning those hooks than learning some trendy theme hooks that merely obscur or repackage those core WP hooks.

However, then I contradicted myself and went a redesigned my website using the Genesis Framework. So I feel obligated to explain. I chose the Genesis Framework because I like StudioPress. I first used a Brian Gardner theme back in 2008 when it was still “Revolution”. I’ve always found his code clean, efficient and easy to work with. Indeed, I found those traits reflected in Genesis as well.

Moreover, modifying Genesis was (for the most part) much more straight forward than other frameworks like Thesis. For instance, with Genesis you can still use custom template pages without putting all the code into a function. I’m old school so I like that. I also find the core Genesis libraries are intuitively organized so that if you want to know what hooks are involved in a particular piece of the header,  it’s relatively easy to find ‘/lib/structure/header.php’.

So, while in general, I still don’t dig on theme frameworks, Genesis is definitely a good one. Cheers, Brian.

WordPress 3.1: Query Multiple Custom Fields

So I just implemented for the first time the new WordPress ‘meta_query’ structure that was added to WordPress 3.1. I must say, it works swimmingly. Here’s my query:

-> To look up events that start after the current date and then order those events ascending by starting date:

$tday = date('Y-m-d H:i:s');
$args = array(
'post_type' => 'events',
'showposts' => 1,
'meta_query'=> array(
array(
'key'=>'simplr_starts',
'value'=> $tday,
'compare' => '>'
)
),
'meta_key'=>'simplr_starts',
'orderby'=>'meta_value',
'order'=>'ASC'
);
$events = new WP_query($args); 
// run the rest of the loop as usual. 

Check out Scribu for more info.

Flutter to Custom Post Types

So I’m working a project right now where I’m converting a WordPress installation from Flutter to the native WordPress custom post type functionality. The reasons for the switch are numerous. For one, it’s always good rule of thumb to use as few plugins as possible. The fewer plugins, the fewer php warning messages, the fewer javascript conflicts, the fewer hooks and filters getting processed on every load, and the fewer hits on the Database server. Secondly, flutter is particularly hard on the database, sometimes adding an extra 5 or more queries for every custom field.

The really great thing about flutter is that it still stores the field values in the  wp_postmeta table which means you don’t have to worry about any real data migration. So you have the luxury of taking it a step at a time.

The first step is to convert those key categories attached to “write panels” into post types. I did this by registering the post type as usual and simply running the following function on the init hook. This function performs a simple DB query to update posts with the specified cat slug into post_types.


function convert_cats_to_types($cat,$type) {
global $wpdb;
$query = $wpdb->prepare("
UPDATE wp_posts SET post_type = '$type' WHERE ID IN
(
SELECT DISTINCT object_id FROM wp_term_relationships rel
INNER JOIN wp_term_taxonomy AS tt ON tt.term_taxonomy_id = rel.term_taxonomy_id AND tt.taxonomy = 'category'
INNER JOIN wp_terms AS t ON t.term_id = tt.term_id AND t.slug = '$cat'
)
");
$results = $wpdb->query($query);
}

There’s no risk of losing data here, we are just changing where the posts in question are show up. The second thing to do is to replace the field-specific metaboxes. We’ll cover that in the next post.

WordPress PodsCMS Widgets

I’m not sure why it took me this long to put this plugin together, but whatever. I’ve been using WordPress PodCMS plugin for a long time now. And quite often I need to add pod stuff to a sidebar. Usually, I’d go find a custom sidebar that I’d made before and adapt it. But then I realized how super easy it would be to have a widget that allows you to select which Pod you want to show and which template you want to show it with !!! so bang!

WordPress PodsCMS Widgets – Version 0.1

Registration Forms: What’s New in 1.5

Last week I released version 1.5 of my Simplr Registration Forms plugin. The new version includes some big fixes and requested features. Particularly, this version now supports WP Multisite and has a few addition profile fields that can be added to the default form. It also includes better security, via WP nonces, and better field validation.

But the most important change is that it includes hooks and filters that allow it to be extended by you, the user.

For instance, let’s add a field to our form that requests the user’s zip code. First, in your functions.php file create a function for displaying the field:

function sample_zip_field($form) {
 $form .=  '<div>';
 $form .=  '<label for="zip">Zip Code:</label>';
 $form .=  '<input type="text" name="zip" value="'.$_POST['zip'] .'"/><br/>';
 $form .=  '</div>';
 return $form;
}

Note that this function receives the parameter $form and then returns $form. Failing to return the form will make the entire registration form disappear. To add this form to the registration use:

add_filter('simplr_add_form_fields', 'sample_zip_field');

But then we also need to make sure this data gets saved when the for gets saved. So you’ll need to create a function for that as well.

function sample_save_meta($user_id) {
if(isset($_POST['zip'])) {
 add_user_meta($user_id, 'user_zip', $_POST['zip']);
 }
return $user_id;
}

Note that in order for this function to work properly it has to receive the $user_id. It is also good practice to return the $user_id at the end of the function, though not necessary.

To make sure your save function is called use the hook:

add_action('simplr_profile_save_meta','sample_save_meta');

With these two “hooks”, you can customize the registration form however you want. You could even set up your field function to only display on certain pages, making it form-specific.

Finally, I’ve also added filters to the labels on the default form fields so you can change them at will. For instance, to change username to “screen name” use the following.

function sample_label_username($label) {
 $label = "Screen name: ";
 return $label;
}
add_filter('simplr_label_username','sample_label_username');

I hope you find the changes useful.

WordPress Real Estate Plugin in the Works

Update: If anyone wants an email when this plugin is ready just leave a comment  here. Or shoot me an email at mike(at)www.mikevanwinkle.com. Or subscribe to my feedburner.

Hmmm. So what they hell have I been doing with my time lately. Not blogging, clearly. Well first there’s the day job, I’m trying to keep it :-). Then I’ve been working on a Real Estate plugin built on the PodsCMS framework. (Which incidentally is about to launch version 1.90) Why a plugin based on a plugin? Well Pods creates the power on the database side to build a better real estate listing system than would be possible using custom fields.

Real Estate listings have LOTS of fields, i.e. List Price, Agent, Square Footage, Neighborhood, etc. Sure you could use WP’s native taxonomies for some of these fields, but there are still going to be a lot of Custom Fields like # of beds, # of baths, etc. And try putting together a standard WP Query to filter for 20 custom fields. Damn. I’m just not that much of a pro I guess.

So the plugin will take the power of the pods framework and package it up in a way that you won’t really have to learn anything about pods in order to use it. I’m also adding some custom functions to create listings, display related listings, etc. Hopefully it will prove a valuable plugin to small to mid-size real estate companies looking to showcase their listings.

Full credit, I started the plugin as part of a freelance project for Big Sea Design. Woot! Woot!