How To Use Custom Post Types To Organize Online Marketing Campaigns


Custom post types add a level of flexibility to WordPress that makes this open-source Web development platform more useful on many levels. Whenever I have been faced with a Web-based task, especially one that involves organizing information, the first thing I do is examine WordPress to determine if it can handle the job. It usually can.

Making Dollars
Image Source1

As an Internet marketer and analyst, I need to be able to organize online marketing campaigns in a way that is trackable in Google Analytics. This is the perfect task for WordPress custom post types.

In this article, we’ll explain how to create a WordPress plugin that enables you to organize Internet marketing campaigns using trackable URLs, shortened versions of those URLs, and trackable QR codes that you can also use for offline marketing activities.

We’ll show you how to create this plugin in a way that maximizes ease of use and functionality. If you have other methods that you have found useful, please share them in the comments. Also, let’s remember that we are standing on the shoulders of WordPress developers who have laid the foundation for easier coding.

Here are the criteria for our custom post type plugin:

  • It must provide a form in which users can specify a landing page to be tracked, the anchor text or content, the term (if this link is a PPC ad), and any additional information about this link.
  • It must provide three custom taxonomy types, so that users can select the URL variables for source, medium and campaign name. This is a taxonomy type because they will be reusable across campaigns and posts.
  • It must be organizable in the admin area and be displayed in the user interface.
  • The output must include a Google Analytics campaign-trackable URL, the information about the URL in human-readable format, a shortened version of the URL using a URL shortener, and a QR code of the shortened URL.

The File Structure

This plugin will use three files. To set up the structure, create a plugin folder named campaign-tracker. Inside the campaign-tracker folder, create the following three PHP files:

  • campaign-tracker.php
  • ga-functions.php
  • campaign-template.php

After you have created the files, we are ready to start adding the code.

The Plugin File

The main plugin file will be campaign-tracker.php. The content of this file will begin the standard way, by providing WordPress with the information that it needs to recognize it is as plugin. We then dive into setting up the CampaignTracker10 class and functions. We will set up our campaign custom post type and register the taxonomies that we will need. We will also initiate our admin interface.

   Plugin Name: Campaign Tracking 1.0
   Plugin URI:
   Description: Google Analytics Campaign Tracking system for WordPress 3.0 and above.
   Author: Joshua Dodson
   Version: 1.0
   Author URI:
   // Include the ga-functions.php helper functions

      class CampaignTracker10 {

         var $meta_fields = array("gaca10-gaurl","gaca10-gaterm","gaca10-gacontent","gaca10-gadescription");

         // This function will create the custom post type. Thanks to Konstantin Kovshenin's example for additional examples of how to construct custom post types (, which inspired much of this.
         function __construct(){
            // Register custom post types
            register_post_type('campaign', array(
            'label' => _x('Campaigns','campaigns label'), // We're labeling the custom posts as Campaigns and also accounting for gettext2 appropriately
            'singular_label' => _x('Campaign','campaign singular label'), // Each post will be called a Campaign
            'public' => true, // These will be public
            'show_ui' => true, // Show the UI in admin panel
            '_builtin' => false, // This is a custom post type, not a built in post type
            '_edit_link' => 'post.php?post=%d',
            'capability_type' => 'post',
            'hierarchical' => false,
            'rewrite' => array("slug" => "campaign"), // This is for the permalinks
            'query_var' => "campaign", // This goes to the WP_Query schema
            'supports' => array('title'/* We only need the default title field, but we could use others such as 'author', 'excerpt', 'editor' ,'custom-fields'*/)

            add_filter("manage_edit-campaign_columns", array(&$this, "edit_columns"));
            add_action("manage_posts_custom_column", array(&$this, "custom_columns"));

            // Register custom taxonomies gasource (for the Campaign Source), gamedium (for the Campaign Medium), and ganame (for Campaign Name)
            // Campaign Source
            register_taxonomy("gasource", array("campaign"), array("hierarchical" => true, "label" => _x( 'Campaign Sources', 'campaign sources taxonomy label' ), "singular_label" => "Campaign Source", "rewrite" => true));
            // Campaign Medium
            register_taxonomy("gamedium", array("campaign"), array("hierarchical" => true, "label" => _x( 'Campaign Mediums', 'campaign mediums taxonomy label' ), "singular_label" => "Campaign Medium", "rewrite" => true));
            // Campaign Name
            register_taxonomy("ganame", array("campaign"), array("hierarchical" => true, "label" => _x( 'Campaign Names', 'campaign names taxonomy label' ), "singular_label" => "Campaign Name", "rewrite" => true));

            add_action("admin_init", array(&$this, "admin_init"));
            add_action("template_redirect", array(&$this, 'template_redirect'));

            add_action("wp_insert_post", array(&$this, "wp_insert_post"), 10, 2);


Let’s give the columns on the admin screen some headings:

function edit_columns($columns)
      $columns = array(
      'cb' => '<input type="checkbox" />',
      'title' => _x('Campaign Title','campaign title label for edit columns'),
      'gaca10_ganame' => _x('Campaign Name','campaign name label for edit columns'),
      'gaca10_gasources' => _x('Campaign Source','campaign source label for edit columns'),
      'gaca10_gasmedium' => _x('Campaign Medium','campaign medium label for edit columns'),
      return $columns;

Let’s specify which columns we would like to show up on the admin screen for this custom post type. We’ll have columns for campaign source, medium and name, in addition to the post’s title.

function custom_columns($column)
      global $post;
      switch ($column)
         // The campaign source
         case "gaca10_gasources":
         $gasources = get_the_terms(0, "gasource");
         if ( $gasources && ! is_wp_error( $gasources ) ) :
         $gasources_html = array();
         foreach ($gasources as $gasource)
         array_push($gasources_html, '<a href="' . get_term_link($gasource->slug, "gasource") . '">' . $gasource->name . '</a>');

         echo implode($gasources_html, ", ");

         // The campaign medium
         case "gaca10_gasmedium":
         $gamediums = get_the_terms(0, "gamedium");
         if ( $gamediums && ! is_wp_error( $gamediums ) ) :
         $gamediums_html = array();
         foreach ($gamediums as $gamedium)
         array_push($gamediums_html, '<a href="' . get_term_link($gamedium->slug, "gamedium") . '">' . $gamedium->name . '</a>');

         echo implode($gamediums_html, ", ");

         // The campaign name
         case "gaca10_ganame":
         $ganames = get_the_terms(0, "ganame");
         if ( $ganames && ! is_wp_error( $ganames ) ) :
         $ganames_html = array();
         foreach ($ganames as $ganame)
         array_push($ganames_html, '<a href="' . get_term_link($ganame->slug, "ganame") . '">' . $ganame->name . '</a>');

         echo implode($ganames_html, ", ");

Once our columns are set up appropriately, we should see the following columns (note that this example is with one campaign already added):

Campaigns in columns3

The next section enables us to specify which template we would like to use to display this custom post type. We will be using the campaign-template.php template:

function template_redirect()
      global $wp;

      // If the post type is set and is campaign…
      if (isset($wp->query_vars["post_type"])) {
         if ($wp->query_vars["post_type"] == "campaign")
            // Then use the campaign-template.php file from this plugin directory
            include WP_PLUGIN_DIR.'/campaign-tracker/campaign-template.php';

If a post is inserted or updated, then loop through the array and update or add the post’s meta data.

function wp_insert_post($post_id, $post = null)
      if ($post->post_type == "campaign")
         foreach ($this->meta_fields as $key)
            $value = $_POST[$key];
            if (empty($value))
               delete_post_meta($post_id, $key);

            if (!is_array($value))
               if (!update_post_meta($post_id, $key, $value))
                  add_post_meta($post_id, $key, $value);
               delete_post_meta($post_id, $key);

               foreach ($value as $entry){
                  add_post_meta($post_id, $key, $entry);

With the following function, we can add custom meta boxes for the admin screen where we edit the campaign:

function admin_init()
      // Add custom meta boxes for the edit campaign screen
      add_meta_box("gaca10-meta", "Campaign Information", array(&$this, "meta_options"), "campaign", "normal", "core");

The following function is for the admin post meta contents. This lets us create the form in which we specify some of the variables for our trackable URL (except for the taxonomies). It also provides a read-only field that shows the shortened URL after the URL variables have been saved.

function meta_options()
      global $post;
      $custom = get_post_custom($post->ID);
         $gaurl = $custom["gaca10-gaurl"][0];
      else{ $gaurl = ''; }
      if($custom["gaca10-gaterm"][0]) {
         $gaterm = $custom["gaca10-gaterm"][0];
      else { $gaterm = ''; }
      if ($custom["gaca10-gacontent"][0]) {
         $gacontent = $custom["gaca10-gacontent"][0];
      else { $gacontent = ''; }
      if ($custom["gaca10-gadescription"][0]) {
         $gadescription = $custom["gaca10-gadescription"][0];
      else { $gadescription = ''; }

      $url = trackable_url();
      if ($custom["campaign_tinyurl"][0]) {
         if($gaurl == '') { $shortenedurl = ''; }
         else{ $shortenedurl = create_tiny_url($url); }

      <label><?php _ex('Website URL:','website url label'); ?></label><input name="gaca10-gaurl" value="<?php echo $gaurl; ?>" /><br />
      <em><?php _ex('(e.g.,','website url example'); ?></em><br /><br />

      <label><?php _ex('Campaign Term:','campaign term label'); ?></label><input name="gaca10-gaterm" value="<?php echo $gaterm; ?>" /><br />
      <em><?php _ex('(identify the paid keywords)','campaign term information'); ?></em><br /><br />
      <label><?php _ex('Campaign Content:','campaign content label'); ?></label><input name="gaca10-gacontent" value="<?php echo $gacontent; ?>" /><br />
      <em><?php _ex('(use to differentiate ads)','campaign content information'); ?></em><br /><br />

      <label><?php _ex('Campaign Description:','campaign description label'); ?></label><input name="gaca10-gadescription" value="<?php echo $gadescription; ?>" /><br />
      <em><?php _ex('(use to remind yourself about this specific link)','campaign description information'); ?></em><br /><br />

      <label><?php _ex('Shortened URL:','shortened URL label'); ?></label><input name="gaca10-gashortened-url" value="<?php echo $shortenedurl; ?>" readonly="readonly" /><br />



Here is how the “Add/Edit Campaign” screen will appear:

Add new post4

If CampaignTracker10 exists, then we initiate the plugin:


      // Initiate the plugin
      add_action("init", "CampaignTracker10Init");

      function CampaignTracker10Init() {
         global $gaca10;
         $gaca10 = new CampaignTracker10();


Combine these functions into the campaign-tracker.php file.

The following taxonomy examples should also be on the “Add/Edit Campaign” screen after everything has been added. Here is the “Campaign Names” taxonomy:

Campaign Names

Here is the “Campaign Mediums” taxonomy:

Campaign Mediums

Here is the “Campaign Sources” taxonomy:

Campaign Sources

Similar to how traditional post categories are set up, you can create new categories or select previous categories.

A note on usage: When you begin to use the system, try to select only one category each from name, source and medium. One category per taxonomy type will prove to be most useful in your actual analysis in Google Analytics. So, as a general rule: one name, one source and one medium per URL.

The Helpful Display Functions

Each of the functions in this section is part of the ga-functions.php file. The functions have been separated from the other functions in order to keep the display functions together.

Our file will begin with the formatted_utm_taxonomy_terms function, which will display a URL-friendly version of the taxonomy terms:

   /* Some Helpful Display Functions */

   function formatted_utm_taxonomy_terms($the_term) {
      global $post;
      $post_terms = get_the_terms( $post->ID, $the_term );
      if ( $post_terms && ! is_wp_error( $post_terms ) ) :
      $encoded_terms = array();
      foreach ($post_terms as $term ) {
         if(!$encoded_terms[] = $term->slug){
            $encoded_terms[] = urlencode($term->name);
      $return_terms = implode('+',$encoded_terms);
      return $return_terms;

The trackable_url function generates the trackable URL from the fields on the admin screen as well as the taxonomies. This appends the appropriate tracking criteria to the URL so that Google Analytics can use the variables and provide information based on these specific variables. To do this, we will use the add_query_arg5 WordPress function.

function trackable_url() {
      global $post;
      $custom = get_post_custom($post->ID);

      // the url
      if ($custom["gaca10-gaurl"][0]) {
         $gaurl = $custom["gaca10-gaurl"][0];
      else { $gaurl = ''; }

      // the term(s)
      if ($gaterm = $custom["gaca10-gaterm"][0]) {
         $gaterm = $custom["gaca10-gaterm"][0];
         $gaterm = urlencode($gaterm);
      else { $gaterm = ''; }

      // the content(s)
      if ($custom["gaca10-gacontent"][0]) {
         $gacontent = $custom["gaca10-gacontent"][0];
         $gacontent = urlencode($gacontent);
      else { $gacontent = ''; }
      $arr_params = array ( 'utm_campaign' => formatted_utm_taxonomy_terms('ganame'), 'utm_source' => formatted_utm_taxonomy_terms('gasource'), 'utm_medium' => formatted_utm_taxonomy_terms('gamedium'), 'utm_term' => $gaterm, 'utm_content' => $gacontent);
      return add_query_arg( $arr_params, $gaurl );


The following functions take the campaign-trackable URL and shortens it with TinyURL6. This method uses wp_remote_get7 to generate the shortened URL. It then saves the shortened URL to the post’s meta data when a post is saved. The trackable_url_tiny function enables us to retrieve the shortened URL in the template.

// Save the shortened trackable URL to the post meta
   function save_shortened_meta($post_ID) {
      $url = trackable_url();
      $shortened_url = create_tiny_url($url);
      update_post_meta($post_ID, "campaign_tinyurl", $shortened_url);
      return $post_ID;
   // Add an action to save it when the post is saved.
   add_action('save_post', 'save_shortened_meta');

   // Retrieve the shortened URL from post meta
   function trackable_url_tiny($url = null, $post_ID) {
      global $post;
      $custom_fields = get_post_custom($post->ID);
      $campaign_tinyurl = $custom_fields['campaign_tinyurl'][0];
      return $campaign_tinyurl;

      return $post_ID;

   // Create shortened trackable URL through the wp_remote_get function
   function create_tiny_url($strURL) {
      $tinyurl = wp_remote_get( ''.$strURL );
      if( is_wp_error( $response ) ) {
         return 'Something went wrong!';
      } else {
         return $tinyurl['body'];


The trackable_url_report function is what provides the human-readable version of the variables. These are broken out by each section. The landing page, campaign name, source, medium, terms and content are all separated and displayed individually if they exist.

function trackable_url_report() {
      global $post;
      $custom = get_post_custom($post->ID);

      // get the url
      if ($custom["gaca10-gaurl"][0]) {
         $gaurl = $custom["gaca10-gaurl"][0];
      else { $gaurl = ''; }
      // get the term(s)
      if ($gaterm = $custom["gaca10-gaterm"][0]) {
         $gaterm = $custom["gaca10-gaterm"][0];
      else { $gaterm = ''; }

      // get the content(s)
      if ($custom["gaca10-gacontent"][0]) {
         $gacontent = $custom["gaca10-gacontent"][0];
      else { $gacontent = ''; }

      // The Landing page
      $url_info ='';
      $url_info.= "<strong>". _x( 'Landing Page:','landing page label') . "</strong> ";
      $url_info.= $gaurl;
      $url_info.= "<br />";

      // The campaign name
      $url_info.= "<strong>". _x( 'Campaign:','campaign label') . "</strong> ";
      $url_info.= formatted_utm_taxonomy_terms('ganame');
      $url_info.= "<br />";

      // The Source
      $url_info.= "<strong>". _x( 'Source:','source label') . "</strong> ";
      $url_info.= formatted_utm_taxonomy_terms('gasource');
      $url_info.= "<br />";

      // The medium
      $url_info.= "<strong>". _x( 'Medium:','medium label') . "</strong> ";
      $url_info.= formatted_utm_taxonomy_terms('gamedium');
      $url_info.= "<br />";

      // The term
      $url_info.= "<strong>". _x( 'Term:','term label') . "</strong> ";
      $url_info.= $gaterm;
      $url_info.= "<br />";

      // The content
      $url_info.= "<strong>". _x( 'Content:','content label') . "</strong> ";
      $url_info.= $gacontent;
      $url_info.= "<br />";

      return $url_info;

The display_description function displays the description of the URL. We’ve broken this part out here in order to keep all of the pieces that are specific to the URL together. This is also the last function in the ga-functions.php file.

function display_description(){
      global $post;
      $custom = get_post_custom($post->ID);
      $description = $custom["gaca10-gadescription"][0];
      return $description;


Combine these functions into the ga-functions.php file, and then we can move onto creating the template file.

The Template File

The final file that we will use to generate the view of the trackable URL is campaign-template.php. You will remember from the campaign-tracker.php file that we have a call in the template_redirect() function to redirect users to this template when viewing the custom post type of campaigns.

For display purposes, we will use the single.php file from the current default WordPress theme, TwentyEleven. You can, of course, use another theme and different styles.

First, we include the ga-functions.php file so that we can use some of our display functions. The campaign template also uses the Google Charts API to generate the QR code8.

The following code will do all of the heavy lifting to display our campaign-trackable URL, the information about the URL, the shortened URL and the QR code. It will also allow us to edit the post if we need to change a variable. Simply drop this code into the loop9.

<h1 class="entry-title"><?php the_title() ?></h1><br />

   echo "<strong>". _x( 'Description:','description label') . "</strong> ";
   echo display_description();
   echo "<br />";
   echo trackable_url_report();
   echo "<br />";
   echo "<strong>". _x('Trackable URL:','trackable URL label') . "</strong> ";
   echo "<a href=".trackable_url()." target='_blank'>".trackable_url()."</a><br />";

   echo "<strong>" . _x('Shortened Trackable URL:','shortened trackable URL label') . "</strong> ";
   echo "<a href=".trackable_url_tiny()." target='_blank'>".trackable_url_tiny()."</a><br />";

   <br />
   <img src=";cht=qr&amp;chl=<?php trackable_url_tiny(); ?>" /><br />
   <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>

When we combine the code, the campaign template will be as follows:

   * The Template for displaying all single posts.
   * @package WordPress
   * @subpackage Twenty_Eleven
   * @since Twenty Eleven 1.0

   // Include the ga-functions.php file so that we can easily display the results

   get_header(); ?>

   <div id="primary">
   <div id="content" role="main">

   <?php while ( have_posts() ) : the_post(); ?>

   <nav id="nav-single">
   <h3 class="assistive-text"><?php _e( 'Post navigation', 'twentyeleven' ); ?></h3>
   <span class="nav-previous"><?php previous_post_link( '%link', __( '<span class="meta-nav">&larr;</span> Previous', 'twentyeleven' ) ); ?></span>
   <span class="nav-next"><?php next_post_link( '%link', __( 'Next <span class="meta-nav">&rarr;</span>', 'twentyeleven' ) ); ?></span>
   </nav><!-- #nav-single -->

   <h1 class="entry-title"><?php the_title() ?></h1><br />

   echo "<strong>". _x( 'Description:','description label') . "</strong> ";
   echo display_description();
   echo "<br />";
   echo trackable_url_report();
   echo "<br />";
   echo "<strong>". _x('Trackable URL:','trackable URL label') . "</strong> ";
   echo "<a href=".trackable_url()." target='_blank'>".trackable_url()."</a><br />";

   echo "<strong>" . _x('Shortened Trackable URL:','shortened trackable URL label') . "</strong> ";
   echo "<a href=".trackable_url_tiny()." target='_blank'>".trackable_url_tiny()."</a><br />";

   <br />
   <img src=";cht=qr&amp;chl=<?php trackable_url_tiny(); ?>" /><br />
   <?php edit_post_link( __( 'Edit', 'twentyeleven' ), '<span class="edit-link">', '</span>' ); ?>

   <?php comments_template( '', true ); ?>

   <?php endwhile; // end of the loop. ?>

   </div><!-- #content -->
   </div><!-- #primary -->

   <?php get_footer(); ?>

When the template is set up and a campaign has been added, then it should display the following page:

Display information10

In Conclusion

By using WordPress custom post types in the method described, it is possible to organize marketing campaigns with the relevant Google Analytics campaign-tracking URL, shortened URL and QR code. This makes organizing marketing campaigns much simpler and more effective.

Custom post types make it very easy to set up a system by which to organize content. And we can get creative in how we use custom post types. They can be very useful when organizing content outside of the normal structure of WordPress and other content management systems (i.e. posts, pages, etc.).

Other possible uses of custom post types include the following:

  • Manage client contacts,
  • Create an employee directory,
  • Keep an inventory of items,
  • Organize other data.


You may be interested in the following resources and articles:



  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17

↑ Back to topShare on Twitter

Joshua Dodson is the Chief Innovation Officer for Converge Consulting, a measurable multi-channel marketing firm for higher education. He focuses on data-driven ways to help clients understand their website users' behavior and improve goal conversion rates. He is a long-time WordPress enthusiast, conference presenter, and innovator.


Note: Our rating-system has caused errors, so it's disabled at the moment. It will be back the moment the problem has been resolved. We're very sorry. Happy Holidays!

  1. 1

    Wow, it seems so interesting. I’m going to read the article right now !
    Thanks !

  2. 3

    Could you post a file download please? Still not clear what code goes in which file.

  3. 6

    If this were Drupal, you could probably get this setup with a module or two and some admin configuration. I don’t get why people say WP is the easy solution, but then you have to do so much petty coding to achieve the simplest things.

    • 7

      Every time somebody dares to mention that another CMS than WordPress can solve the task presented in a Smashing Magazine better, the old and tired Drupal VS WordPress fight rears its ugly head. I frankly think this is misplaced, since WP is clearly a blogging tool, and is far superior in that niche, and similar simple web sites. If you want something more complex, just use Drupal.

      I think The law of the hammer applies here: “If all you have is a hammer, everything looks like a nail”. I doubt that many of the people who will thumb down this comment has ever even tried Drupal, sadly.

      • 8

        My last dance with Drupal was in 2009, and I was amazed at the power of the platform. On the other hand, it took a long, long time to customize the design and find the modules I needed to get the site working the way we wanted it to work.

        WordPress, on the other hand, is pretty much plug-and-play, and customizing themes is relatively simple. Which is why I prefer it for simple websites – even if the client won’t be adding any regular posts.

        I agree 100% that WordPress and Drupal have their respective applications. In the end, though, most web design blogs like Smashing tend to center around WordPress as the one and only CMS, and it certainly seems to be the most popular platform.

        I can appreciate that, since it doesn’t require extensive knowledge of PHP to get WordPress to do what you want it to do, and it’s undoubtedly the least intimidating CMS for entry-level web designers.

        On the other hand, Drupal’s third-party developer community is incredible. I really wish WordPress plugin developers had the same spirit of teamwork that Drupal does. When you search for a module to extend Drupal’s functionality, there might be one or two that fit your needs. But because so many people contribute and refine it, the module you choose is going to be fantastic.

        Unfortunately, WordPress’s plugin repository is more like the wild west. Dozens of plugins for the same feature, each created by one or two developers (or a team of developers looking to turn a profit from their plugin), and each with its own quirks and shortfalls. Sure, there are some diamonds out there, but it takes some digging, experimenting, and most importantly, time.

        I’m still hoping that something will come along and bridge the gap. A CMS that’s as easy to set up as WordPress with a development community that’s as reliable as Drupal’s.

        Maybe someday…

        • 9

          First off, amazing article, terrific. Secondly, regarding the WordPress development community, it may be more profit driven than Drupal, but because it is it has been maturing relentlessly. Any information you had on WP prior to v3 needs to be entirely re-evaluated, it is not the same platform by any means. Many plugins have also reached a mature and stable point in the their development life cycle. You would be hard pressed to find a functionality you could not implement or scale with the current incarnation of WP.

  4. 10

    Nice article.Code is really brilliant.Thanks. .

  5. 11

    Great article but please don’t encourage the use of “var” when declaring class properties. The var keyword is only supported for backwards compatibility reasons, it’s not considered to be the correct way of declaring class properties in php5 and may be discarded in future versions of php.

    One other thing I would like to point out is the improper use of the class constructor in CampaignTracker10. The constructor should be used to define the initial state of the object, nothing more. Having large blocks of code in the constructor is simply bad practice.

    Keep up the good work!

  6. 12

    Hi, The method here is very interesting, but I am a bit unsure what this plugin actually accomplishes. You wrote: “As an Internet marketer and analyst, I need to be able to organize online marketing campaigns in a way that is trackable in Google Analytics. ” Can you elaborate on how this plugin would actually be used?


    • 13

      Yes, I agree, please tell us some real example usage of this plugin.

      Nice tutorial.

    • 14

      What Joshua presents, is essentially a shell or template for any campaign you may be running. If you use multiple landing pages, run specials for a local area or run a club which has four events per week, this will help you get more out of it. I think it’s pretty straightforward as to what it does and what it captures, if it fits within your needs is another question.

      • 15

        Noel, I think it’s not clear to me due to my own ignorance. I don’t understand the underlying concepts–but would like to! What, in this case, does a campaign entail precisely? And what is the template for? The page result above means nothing to me. And the trackable url that it produces also. But I have a hunch it’d be very good for me to understand what this is about. Is there a tutorial somewhere about google analytics and campaigns that would clarify the basic methods here that I am missing?

        • 16

          Hi Ethan,

          Try to google A/B Testing, Landing Pages, online marketing, PPC, Adsense,

          I think you’ll find a lot of interesting for yourself.

    • 18

      Ethan- once again please – what do you know!!!

      you have given a very foolish replying highlighting oyu ignorance of the authors workings.

      In future- work it out for yourself like everybody else.

      If you need any help at all with your website career do not hesitate to email me your questions. I will be happy to help you.

      thanks and regards.

  7. 19

    A ton of our new client requests come along with the baggage of some pre-existing technology. “Make our WordPress site do this”… “make our Concrete5 site do that.” We can either figure out a way to make it work in the pre-existing code base or let the client pay someone else to do it. Of course we know Drupal, or even a simple custom CRUD, is a better solution… but what if it’s not even an option? For that reason, I think this tutorial is completely valid. Thank you.

  8. 20

    Interesting usage of custom post types, the sky really is the limit when it comes to this. WordPress’ flexible nature brings us such a fantastic framework to build upon.

  9. 21

    Very useful post showing custom post types usage. Are you planning to release it as a plugin, it would be very helpful.

  10. 22

    Very interesting. I’ll have to read this in detail a second or third time.

    That said, as someone who is very fond of link tagging (a la the Google Analytics Google URL Builder), I’m not so sure your data structure is optimal. That is, a given shared link actually has many shortened versions. For the most part, the difference is the target platform (e.g. Facebook, Twitter, etc). Typically used for setting the source. But it very well could be another trackable parameter (e.g., day of week of share, time of share, etc.)

    In other words, if a post is a campaign, that campaign can exist across a number of sources, etc. The relationship is one to many, not a flat file. Having to enter each shortening event one by one is quite a bit of overhead. I”ll be the first guy to embrace “No pain. No gain.” but even this is a bit much for my standards.

    Moi? I have two tools:

    1) I developed a WP plugin that will automatically on publish tag, shorten and push out to social media profiles.

    It’s currently in beta. Perhaps I will release it sometime later this year.

    2) For “one off” type shares I use a Google doc spreadsheet. It’s set up so there are defaults, dupe info doesn’t have to be re-entered for each campaign, etc. Mind you, I understand and appreciate that ultimately it should be a database application. I just don’t have that kinda free time.

    Finally, for those who are not familiar with link tagging this might help:

    It’s a five part series so be sure to look for Part 2 as well. I intend on publishing Part 3 later today. In either Part 4 or Part 5 will share the spreadsheet I just mentioned.

    I hope you don’t mind that I shared a couple links. I’m not trying to spam. I’m just letting Smashing-ites know what’s available / possible. Cheers.

  11. 23

    Great Post!!!! Thanks for this magazine.

  12. 24

    I was expecting to read something like this in the graphic: If it isn’t making dollar then it isn’t making cents. ;)

  13. 25

    Hello, thanks for taking the time to build this for us! We appreciate these open efforts to improve our community.

    I have a couple of questions.

    1. I want to build landing pages with a graphical element, such as some text a video and then a call to action, different for each email campaign I create. I have thousands of different subscribers to my email program.

    2. I want to track the success of each campaign, but from the campaign they do to a WordPress Page with those elements (above) on there.

    My Question is if I create a separate page, how do I use this Custom Post Type (CPT) tool you have created to track this?

    1. Do I place the url to the page I have created for each campaign in this tracker?

    The instructions for building this is very clear, however the execution of this (to me) is unclear.

    Any help would be appreciated!

    • 26

      I think there are a lot of missunderstanding around this, otherwise really nice article.

      The code does not implement the actual ‘tracking’ but does generate trackable links. You can use google analytics custom variables or simply save the values to your own database(just like any other GET links). With this type of link structure(&key=value) you can have a single landing page with dynamic ‘appereance’ for each campaign.

      Using a simple example, you already managed to put a lots of shiny badges(custom categories) to your visitors and you also know where they come from(source). Now it`s time to save all of it.

      • 27

        I luckily found this post and I’ve got to say great job.I’m trnyig to extend it out, so that it can be a wordpress plugin, where your blog is the root url shortneing service, forwarding on to the long post names…Any ideas?

  14. 28

    I`ve found two wee errors:

    Double returns here:

    function trackable_url_tiny($url = null, $post_ID) {
    global $post;
    $custom_fields = get_post_custom($post->ID);
    $campaign_tinyurl = $custom_fields[‘campaign_tinyurl’][0];
    return $campaign_tinyurl;

    return $post_ID;

    …and the same functions is being called in the template with no parameters, which might cause faulty links and QR codes.


    The code is kinda messy anyway.

  15. 29

    Would be even better to use WordPress own short URLs (/page=xx) instead of 3rd party like TinyURL?

  16. 30

    thanks bro awesome custom post type.

  17. 31

    Konstantin Kovshenin

    April 26, 2012 9:27 am

    Thanks for the shout! The article you mentioned on my blog is quite old and might be a little bit outdated, but should still work. Cheers!

  18. 32

    Thanks for this tutorial. I have been searching for this. I have seen a lot of tutorials that show the basics of custom post type and some images of what it can do, but I couldn’t find anyone giving all the goods.

    I have a free WordPress coming soon and landing page plugin that only allows the user to create one page. I want to use this technique to create the same kind of plugin, but with unlimited page creation.

↑ Back to top