Changing the Divi projects custom post type to anything you want

Now fixed for Divi 2.5

Clone this project on GitHub.

I’m currently building a website for a friend of Jane, using the Divi theme from Elegant Themes. The website is for a holiday property letting company. This post explains how I changed the built-in Projects content type to Properties, and how you can change it to anything you want.

The problem

Divi is a great theme to use: it’s very flexible, it’s responsive (so it works equally well on smartphones as well as huge desktop monitors), and it has the easiest, drag-and-drop editor that I’ve ever used for WordPress.

Divi comes with a built in content type called Projects; WordPress calls them ‘custom post types’. I use this content type on my own website to list the various projects that I’ve been involved in over the years.

As you can see from the WordPress admin menu ‘Projects’ appears on the list beneath Posts, Media, Pages, and Comments:

WordPress menu with Divi installed shows Projects
WordPress menu with Divi installed

Divi also ships with a number of attractive ways to display your projects using its Portfolio and Filtered Portfolio modules. You can even display these full-width or as a grid, such as this:

Demo of Divi's Filtered Portfolio module displayed as a grid.
Demo of Divi’s Filtered Portfolio module displayed as a grid.

These are exactly the features that I’d like to use on the property letting website:

  • Keep properties separate from pages and posts, using a custom post type.
  • Display all properties in a grid.
  • Allow users to filter properties based on the categories that are assigned to them.

So, I want all the features of Divi’s built-in Projects custom post type, but I don’t want them to be called Projects. I want them to be called Properties.

Use a child theme

First, I strongly recommend that you use a child theme when customising Divi (or indeed any other WordPress theme). A child theme inherits the functionality and styling of another theme, called the parent theme, and allows you to make local customisations to it which will not be overwritten when the theme updates.

Elegant Themes have a useful walkthrough on how to create a child theme, and why you should be using one.

The WordPress Codex also has useful information about child themes.

How to do it

This very useful post on the Elegant Tweaks blog: “Change Divi Projects URL-permalink” got me started, and about 95% of the way.

I copied the code, added it to the functions.php file in my child theme, and set about editing it.

remove_action / add_action

In a nutshell the code from Elegant Tweaks does two things:

  1. It defines a new function — called child_et_pb_register_posttypes() — that will redefine the characteristics of the Projects content type.
  2. It removes the default Projects custom post type contained in Divi, and replaces it with our one in the child theme.

This last point, I believe, is simply to be tidy: rather than clumsily overwriting the existing ‘project’ custom post type it gracefully removes the old one, and creates a redefined version in its place.

Labels

In that Elegant Themes post the author was only concerned with changing the URL from /projects/ to /photos/. So in his example, the names used in the WordPress admin screens still referred to projects: Edit Project, Add New Project, etc. But I want to change these too.

In the code for a custom post type these are referred to as ‘labels’ and are defined in the $labels array. This is what my code looks like now:

<?php function child_et_pb_register_posttypes() { $labels = array( 'add_new' => __( 'Add New', 'Divi' ),
    'add_new_item' => __( 'Add New Property', 'Divi' ),
    'all_items' => __( 'All Properties', 'Divi' ),
    'edit_item' => __( 'Edit Property', 'Divi' ),
    'menu_name' => __( 'Properties', 'Divi' ),
    'name' => __( 'Properties', 'Divi' ),
    'new_item' => __( 'New Property', 'Divi' ),
    'not_found' => __( 'Nothing found', 'Divi' ),
    'not_found_in_trash' => __( 'Nothing found in Trash', 'Divi' ),
    'parent_item_colon' => '',
    'search_items' => __( 'Search Properties', 'Divi' ),
    'singular_name' => __( 'Property', 'Divi' ),
    'view_item' => __( 'View Property', 'Divi' ),
);

 

As you can see, something I find useful is to list the elements alphabetically. Personally, I find it easier to work this way; your mileage may vary.

Obviously, if you are customising this for your own requirements simply edit this to reflect your needs.

Custom post type options

Next, we define the arguments to be passed to the register_post_type function. These define not only how the custom post type is used but also how it is displayed in the WordPress admin menu: where it sits and what icon it uses.

Slug

The most important option here, for our purpose of customising it, is the 'slug' key. You must set its value (in single quotes) to whatever you need it to be. In my case 'slug' => 'property'. I’ve highlighted this in the snippet below.

Just make sure you don’t set the slug to the same name as an existing page.

Menu icon and position

One useful new addition to the code provided by Elegant Tweaks are the options to set the menu icon and where it sits on the menu.

As these are properties I decided to use the home dashicon.

House icon
dashicons-admin-home

I also decided to move it up a bit, from beneath Comments to immediately below Posts. WordPress uses numbers to specify where custom post types should sit, e.g.

  • 5 — below Posts (this is where I want it to appear)
  • 10 — below Media
  • 15 — below Links
  • 20 — below Pages
  • 25 — below Comments

A full list can be found in the WordPress Codex.

So, here is the code I now have; I’ve highlighed these new menu options plus the ‘slug’ (how it will appear in the URL):

$args = array(
    'can_export' => true,
    'capability_type' => 'post',
    'has_archive' => true,
    'hierarchical' => false,
    'labels' => $labels,
    'menu_icon' => 'dashicons-admin-home',
    'menu_position' => 5,
    'public' => true,
    'publicly_queryable' => true,
    'query_var' => true,
    'show_in_nav_menus' => true,
    'show_ui' => true,
    'rewrite' => apply_filters(
    'et_project_posttype_rewrite_args', array(
    'feeds' => true,
    'slug' => 'property',
    'with_front' => false,
)),
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'comments', 'revisions', 'custom-fields' ),
);

 

Register the post type

The next line now does the grunt work and registers this custom post type with WordPress.

register_post_type( 'project', apply_filters(
    'et_project_posttype_args', $args )
);

This tells WordPress to apply all of these options to the ‘project’ custom post type.

Because we are redefining this existing custom post type (by changing the URL, the menu labels, the menu icon and position) it means that everything else (the default project page layouts and portfolio modules) will work as expected without any further customization.

Categories and tags

The rest of the code I left untouched. This code defines the categories and tags to be used with the projects/properties custom post type.

How it looks now

Adding all the code (see below for the complete script) this is what my WordPress admin menu looks like:

Divi theme now with Properties instead of Projects
Divi theme now with Properties instead of Projects

That’s now working as I expect it. Job done.

Complete code

Here is the full code that I have in my child theme’s functions.php file:

<?php function child_et_pb_register_posttypes() { $labels = array( 'add_new' => __( 'Add New', 'Divi' ),
    'add_new_item' => __( 'Add New Property', 'Divi' ),
    'all_items' => __( 'All Properties', 'Divi' ),
    'edit_item' => __( 'Edit Property', 'Divi' ),
    'menu_name' => __( 'Properties', 'Divi' ),
    'name' => __( 'Properties', 'Divi' ),
    'new_item' => __( 'New Property', 'Divi' ),
    'not_found' => __( 'Nothing found', 'Divi' ),
    'not_found_in_trash' => __( 'Nothing found in Trash', 'Divi' ),
    'parent_item_colon' => '',
    'search_items' => __( 'Search Properties', 'Divi' ),
    'singular_name' => __( 'Property', 'Divi' ),
    'view_item' => __( 'View Property', 'Divi' ),
);

$args = array(
    'can_export' => true,
    'capability_type' => 'post',
    'has_archive' => true,
    'hierarchical' => false,
    'labels' => $labels,
    'menu_icon' => 'dashicons-admin-home',
    'menu_position' => 5,
    'public' => true,
    'publicly_queryable' => true,
    'query_var' => true,
    'show_in_nav_menus' => true,
    'show_ui' => true,
    'rewrite' => apply_filters( 'et_project_posttype_rewrite_args', array(
    'feeds' => true,
    'slug' => 'property',
    'with_front' => false,
)),
'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'comments', 'revisions', 'custom-fields' ),
);

register_post_type( 'project', apply_filters( 'et_project_posttype_args', $args ) );

$labels = array(
    'name' => _x( 'Categories', 'Property category name', 'Divi' ),
    'singular_name' => _x( 'Category', 'Property category singular name', 'Divi' ),
    'search_items' => __( 'Search Categories', 'Divi' ),
    'all_items' => __( 'All Categories', 'Divi' ),
    'parent_item' => __( 'Parent Category', 'Divi' ),
    'parent_item_colon' => __( 'Parent Category:', 'Divi' ),
    'edit_item' => __( 'Edit Category', 'Divi' ),
    'update_item' => __( 'Update Category', 'Divi' ),
    'add_new_item' => __( 'Add New Category', 'Divi' ),
    'new_item_name' => __( 'New Category Name', 'Divi' ),
    'menu_name' => __( 'Categories', 'Divi' ),
);

register_taxonomy( 'project_category', array( 'project' ), array(
    'hierarchical' => true,
    'labels' => $labels,
    'show_ui' => true,
    'show_admin_column' => true,
    'query_var' => true,
) );

$labels = array(
    'name' => _x( 'Tags', 'Property Tag name', 'Divi' ),
    'singular_name' => _x( 'Tag', 'Property tag singular name', 'Divi' ),
    'search_items' => __( 'Search Tags', 'Divi' ),
    'all_items' => __( 'All Tags', 'Divi' ),
    'parent_item' => __( 'Parent Tag', 'Divi' ),
    'parent_item_colon' => __( 'Parent Tag:', 'Divi' ),
    'edit_item' => __( 'Edit Tag', 'Divi' ),
    'update_item' => __( 'Update Tag', 'Divi' ),
    'add_new_item' => __( 'Add New Tag', 'Divi' ),
    'new_item_name' => __( 'New Tag Name', 'Divi' ),
    'menu_name' => __( 'Tags', 'Divi' ),
);

register_taxonomy( 'project_tag', array( 'project' ), array(
    'hierarchical' => false,
    'labels' => $labels,
    'show_ui' => true,
    'show_admin_column' => true,
    'query_var' => true,
) );

$labels = array(
    'name' => _x( 'Layouts', 'Layout type general name', 'Divi' ),
    'singular_name' => _x( 'Layout', 'Layout type singular name', 'Divi' ),
    'add_new' => _x( 'Add New', 'Layout item', 'Divi' ),
    'add_new_item' => __( 'Add New Layout', 'Divi' ),
    'edit_item' => __( 'Edit Layout', 'Divi' ),
    'new_item' => __( 'New Layout', 'Divi' ),
    'all_items' => __( 'All Layouts', 'Divi' ),
    'view_item' => __( 'View Layout', 'Divi' ),
    'search_items' => __( 'Search Layouts', 'Divi' ),
    'not_found' => __( 'Nothing found', 'Divi' ),
    'not_found_in_trash' => __( 'Nothing found in Trash', 'Divi' ),
    'parent_item_colon' => '',
);

$args = array(
    'labels' => $labels,
    'public' => false,
    'can_export' => true,
    'query_var' => false,
    'has_archive' => false,
    'capability_type' => 'post',
    'hierarchical' => false,
    'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'comments', 'revisions', 'custom-fields' ),
);

register_post_type( 'et_pb_layout', apply_filters( 'et_pb_layout_args', $args ) );
}

function remove_et_pb_actions() {
    remove_action( 'init', 'et_pb_register_posttypes', 15 );
}

add_action( 'init', 'remove_et_pb_actions');
add_action( 'init', 'child_et_pb_register_posttypes', 20 );
?>

 

Final thoughts

Like many things on my blog I’m primarily putting it here for my own reference, but if you find it useful — or would like to suggest improvements or additional features — please leave a comment below.

Clone this project on GitHub.

Update: Remember to reset your permalinks

Friday 20 March 2015

I meant to say this in the article above. Sometimes WordPress gets a bit muddled when you play around with custom post types.

The way to fix this is to go to Settings > Permalinks > Save Changes.

That’s enough to flush the permalinks and your custom post type should work. I had to do that a couple of times while figuring out how to do this.

Update 2: Plugin discovery

Monday 20 April 2015

A few days ago I discovered this plugin: Divi Page Building for Custom Content Types.

This plugin allows you to use the Divi builder for Posts, or indeed any custom post type.

Update 3: Fix for Divi 2.5

Saturday 26 September 2015

I’ve now (finally) updated the code to make it work fully in Divi 2.5.

In the end it was quite simple: the add_action(...) and remove_action(...) priorities were wrong in my code. These tell WordPress in which order actions should be executed.

In my previous code I was instructing WordPress to unload the default Divi project custom post type before it had even been defined.

The default priority value is 10; I’d set mine to 0 and 1, respectively.

A huge thank you to Craig Campbell for his excellent Chrome Logger extension and ChromePHP class — two tools that greatly helped me work out what was going on.

The stupid EU cookie law

In May 2011 a new law came into effect across the European Union that affects probably around 90% of all websites. The UK government has given UK website owners a year (so, until May 2012) to get up to speed with the legislation and do something about it. The law is to do with how cookies are used.

What is a cookie?

In Web-speak, a cookie is a simple text file that stores information about websites you’ve visited. They can be used for lots of thing, such as for the browser to remember that you are already logged into that website, to store items in a shopping cart on a commerce website, or user preferences on another site.

My main browser (Google Chrome) reports that it has stored 3722 cookies from 1374 web domains.

A cookie for a particular site can only be written to and read by that website. So, Facebook cannot read cookies created by Google websites, and Google websites cannot read cookies created by Facebook.

The worry is, however, that spyware software could potentially access these cookies—they are simple, easily read text files after all—and gain all sorts of information about you, such as browsing habits, personal details, etc. And it seems to be this that the legislation is aiming to address.

The issue

Over the next few months I’m going to have to get my head around this legislation, both for my own websites and for the University of St Andrews website. There has been some interesting and useful discussions about it on various JISC-run inter-university email discussion groups.

My main concern is that this doesn’t ruin the user experience. It’s going to be very, very annoying if you require to give consent to every single website before you can meaningfully use it. My fear is that it’s going to become the Web equivalent of the User Account Control (UAC) nightmare that Windows Vista introduced.

Update

Thursday 5 January

Last night’s post was a bit rushed. I didn’t expand it quite as much as I’d have liked but I was tired and I just wanted to get to bed!

Ironically, I kept waking up during the night thinking about it. At one point Jane was awake so I talked it through with her. She has to put up with that kind of thing from me all the time, poor girl!

Anyway, this morning I got three replies on Twitter:

  1. Surely new cookie guidelines are sensible? Happy to chat about this.
  2. The sad fact is, it puts EU based sites/companies at a disadvantage vs those in the rest of the world.
  3. In intent, sensible. In execution, I’m with @garethjms – stupid. Can only see negatives for UX.

And a couple of comments below (which I’ve only just approved). A nice balance of for and against. I look forward to getting my head around this and posting more about it, here and on my professional blogs.

Blueprint cheat sheet updated for version 1.0.1

20110618-blueprintcheatsheet43

This week I updated my Blueprint CSS framework cheat sheet for Blueprint v.1.0.1 which was released last month.

Changes

I mostly fixed a few typos, and added the new features that the latest version of the framework added: mostly HTML5 input attributes. I made the following changes:

  • NEW—FORMS Added new HTML5 input attributes: email and url.
  • NEW—IE FIXES Added IE8#HACK.
  • FIX—FLOAT CLASSES p .left and p .right was showing the margins only for p .left.
  • FIX—Page 2 was showing a completely different version number from page 1.
  • CHANGE—Updated the list of URLs on page 2, removing one that is now redundant.

Download

You can download it from the usual places including garethjmsaunders.co.uk/blueprint/

It’s released under a Creative Commons Attribution-ShareAlike 2.5 UK license so feel free to use it, adapt it, whatever… The source document (in Microsoft Publisher 2010 format) is available on the site too.

Enjoy!

DigiTech GenEdit 1.6 works in Windows 7 compatibility mode

DigiTech GNX2 GenetX guitar processor
DigiTech GNX2 GenetX guitar processor

I own a DigiTech GNX2 guitar multi-effect processor, or “Guitar WorkStation” as DigiTech called it.  Although it’s a few years old now—I bought it probably around six years ago—it’s still a really nice piece of kit.

One of the things that attracted me to this particular pedal, which I bought to replace a DigiTech RP6 that died on me a few hours before a gig, was that it promised to connect to my PC via MIDI.

Well, I’m delighted to report that the DigiTech GNX2 still connects to my PC running Windows 7 Professional (32-bit).  The trick is to right-click the shortcut icon, select Properties and on the Compatibility tab select “Run this program in compatibility mode for Windows XP (Service Pack 3)“.

As soon as I did that I saw this:

DigiTech GenEdit 1.6a
DigiTech GenEdit 1.6a

In the past I’ve found GenEdit 1.61a really useful as it allows you make adjustments to user presets while sitting at my desk, guitar on my knee, rather than hunched over a floor pedal twiddling the small controls on the “guitar workstation”.

Update

I switched on my DigiTech GNX2 this morning for the first time in a couple of years, to be honest (we’ve had twins, you know!) and … the presets kept randomly ‘flickering’ between one and the next.

So, for example, I’d be on factory preset #1 and while playing the GNX2 would quickly switch to factory preset #2 and then back to #1. Repeat.

My heart sank. I was really looking forward to getting back into playing, until baby #3 arrives and I’ll have to put it on hold for another couple of years.

However, a quick factory reset later and all appears to be well so far.

And what has this to do with GenEdit?  I backed-up all my custom user presets via MIDI in about a minute. Something that would have taken me hours to do with my old DigiTech RP6 as I would have had to manually scroll through each preset and write down all the settings. Genius!

Updating Outlook Appointments gadget for Outlook 2010

Outlook appointments gadget for Windows 7
Outlook appointments gadget for Windows 7

One of my favourite Windows 7 gadgets is the Outlook Appointments gadget. As gadgets go it’s pretty simple: it shows me  upcoming appointments. From Outlook.

But oddly, only when Outlook is open.

Anyhow, when I upgraded Microsoft Office from 2007 to 2010 a couple of weeks ago I discovered that it no longer worked … it just complained that it didn’t have the correct version of Outlook installed.

The hack

But there is a simple hack:

  1. Make sure that you can view hidden and system files (Control Panel > Folder Options > under View tab select “Show hidden files, folders, or drives”).
  2. Close the Outlook upcoming appointments gadget.
  3. In Windows Explorer navigate to C:\Users\YOURNAME\AppData\Local\Microsoft\Windows Sidebar\Gadgets\OutlookAppointmentsGadget.gadget\en-US\js\” where YOURNAME is the name of your user account.
  4. Open the file “outlook.vbs” with Notepad (or other text editor; personally I wouldn’t use WordPad).
  5. On lines 22 and 42 change the two occurrences of the number “12” to “14”.
  6. Save the file.
  7. Open the Outlook  Appointments gadget again.

Outlook Tasks gadget

The same hack also works for the “Outlook Tasks” gadget.

Update

It looks like someone has released pre-hacked versions of Appointments and Tasks called iOutlook which work with Outlook 2010.  The iOutlook Appointments one now offers 3, 5 or 10 appointments.