Convert error_reporting value constants into human-readable form:

I wanted to work out which errors were being logged given the error_reporting value from a php.ini file, so I spent 10 minutes writing this: (code below)

Error reporting value: Human readable format:

and here’s the code:

jQuery(document).ready(function($){
    function convert_error_constant_to_human_readable( value ) {
       var errors = {
        1: 'E_ERROR',
        2: 'E_WARNING',
        4: 'E_PARSE',
        8: 'E_NOTICE',
        16: 'E_CORE_ERROR',
        32: 'E_CORE_WARNING',
        64: 'E_COMPILE_ERROR',
        128: 'E_COMPILE_WARNING',
        256: 'E_USER_ERROR',
        512: 'E_USER_WARNING',
        1024: 'E_USER_NOTICE',      
        2048: 'E_STRICT',
        4096: 'E_RECOVERABLE_ERROR',
       }
       var human_readable_errors = [];
       for (var error in errors) {
         if (errors.hasOwnProperty(error)) {
           if ( value >= error && (value - error) % ( 2 * error) == 0 ) {
               var value = value - error;
               human_readable_errors.push( errors[error] );
           }
         }
       }
       return human_readable_errors;
    }
    $('#convert-to-human-readable').on( 'click', function(){
        var value = $('#error-reporting').val();
        var human_readable = convert_error_constant_to_human_readable( value );
        $('#human-readable').val( human_readable.join("\n") );
    });
});

Front End Event Submissions

I’ve just announced another extension for Event Organiser: Event Organiser Frontend Submissions (or FES for short).

This plug-in allows you to create forms which allow users to submit their own events, which are then published (subsequent to admin moderation – if desired). It makes accepting user-contributed events much easier.

At the time of writing this plug-in is still in beta – but this is where you can help. I simply need people to use the plug-in, and report back with any issues they encounter. As a thank you, you’ll receive a free license key for when the plug-in goes on sale. This will entitle you to upgrades and support for an entire year.

Event Organiser FES is now available for purchase.

For more details, screenshots and to sign-up as a beta-tester, please see this page: http://wp-event-organiser.com/blog/announcements/front-end-event-submissions/

Get post content by ID

This post was originally published in November 2012, but was (accidentally) discarded during a migration. I used the wayback machine to retrieve the content and re-post it again.

As you may know the WordPress functions the_content() and get_the_content(), unlike their get_the_title() counterpart, cannot be used outside the loop. Naively ‘in the loop’ means just making sure the $post variable is global and points to the desired post.

So when someone asked why their code wasn’t working when they had used get_the_title() without passing it a post ID or declaring $post as global, the answer was simple.

What they said next threw me.

I find it extremely strange that the_content() works and that my $post variable is indeed an object full of data just like it should.

That is odd. But it turns out that get_the_content() doesn’t really use the $post global. Inspecting the source we see that it actually uses the $pages global. This stores the post’s content (pages as a post can carry across multiple pages). This is actually set up in: setup_postdata().

So while get_the_title() and co use the $post global, the_content() and get_the_content() rely on setup_postdata(). The upshot is that if using these outside the actual ‘Loop’ be sure to do both:

$posts = get_posts(array(...));
if( $posts ){
   foreach( $posts as $post ){
      global $post;
      setup_postdata();

      //Use the template tags

   }
}
wp_reset_postdata();

Note, while setup_postdata() doesn’t set up the $post global, wp_reset_postdata() does reset it.

Then, while reading this post by Tom McFarlin I thought it might sometimes be useful to be able to retrieve post content by passing the post ID, the same way you can with get_the title()

Get The Content by ID

/**
 * Display the post content. Optinally allows post ID to be passed
 * @uses the_content()
 *
 * @param int $id Optional. Post ID.
 * @param string $more_link_text Optional. Content for when there is more text.
 * @param bool $stripteaser Optional. Strip teaser content before the more text. Default is false.
 */
function sh_the_content_by_id( $post_id=0, $more_link_text = null, $stripteaser = false ){
    global $post;
    $post = &get_post($post_id);
    setup_postdata( $post, $more_link_text, $stripteaser );
    the_content();
    wp_reset_postdata( $post );
}

Example usage:

 sh_the_content_by_id(2283);

Grunt & WordPress development II: Installing Grunt

grunt

This is part 2 in a series looking at using Grunt in WordPress plug-in/theme development.

  1. Grunt & WordPress development
  2. Grunt & WordPress development II: Installing Grunt
  3. Grunt & WordPress development III: Tasks for internationalisation
  4. Grunt & WordPress development IV: Another task for internationalisation

1. Installing Node

Grunt runs on top of Node.js (version 0.8.0 or later). To check if you have Node installed (and what version), run

node --version

in your command line. If you don’t have it installed you’ll get an error message like “command not found”. If you have it installed, and an appropriate version, then you’re dandy and can skip to the next section.

Otherwise you can download node for your particular operating system here: http://nodejs.org/download/. Windows & Macs have their own installer, but if you can also install from source.

Installing Node for Linux

For Debian-based Linux distros (Debian, Ubuntu, Mint etc), first install the dependencies (you’ll probably have these)

  sudo apt-get install g++ curl libssl-dev apache2-utils

Install Git (again, you’ll probably have this)

  sudo apt-get install git-core

Clone the Node repository and run

  git clone git://github.com/joyent/node.git
  cd node
  ./configure
  make
  sudo make install

Finally to double check all went well:

  man node;

2. Installing NPM

NPM is the package manager for Node, and is used by grunt to install and manage plug-ins. This should come with Node, so you don’t have to worry about installing this.

3. Installing Grunt

First we want to install the grunt command line interface, and we want it to be globally available:

 npm install -g grunt-cli

This will put the grunt command in your system path, allowing it to be run from any directory.

This hasn’t installed Grunt (the task runner). In fact, you install grunt locally in each project you work on, allowing you to have multiple versions of Grunt on the same machine at once.

Grunt will be installed, alongside all the other plug-ins you list. Before they can be installed we need to prepare the package.json file:

package.json

Your package.json file should live in the root of your project. It provides details of your project & lists any dependencies for development (including Grunt!). You can then install these using NPM.

Here’s a minimal example which would install grunt, jshint and uglify

{
  "name": "my-project-name",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.2",
    "grunt-contrib-jshint": "~0.6.3",
    "grunt-contrib-uglify": "~0.2.2"
  }
}

(Note that if any of those plug-ins require another plug-in to function, that will also be installed).

So to finally to install Grunt and the other listed plug-ins:

sudo npm install

All going well, Grunt is now installed.

Once you’ve got a package.json set-up you can easily install additional plug-ins with

 sudo npm install [module] --save-dev

which will also automatically add the specified module to your package.json as a “devDependencies”.

4. Using Grunt

Once Grunt is installed we can prepare our first task. Your grunt tasks are declared and configured by your Gruntfile.js. This includes:

  • The “wrapper” function
  • Project and task configurations
  • Loading your Grunt plug-ins
  • Declaring default task(s) and custom tasks

If you’re getting lost at this point, don’t worry, a simple example will help. Don’t worry about the details too much – I’ll be covering that later in the series.

 module.exports = function(grunt) { //The wrapper function

 // Project configuration & task configuration
 grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),

      //The uglify task and its configurations
      uglify: {
           options: {
                banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
           },
           build: {
             files: [{
                expand: true,     // Enable dynamic expansion.
                src: ['js/*.js', '!js/*.min.js'], // Actual pattern(s) to match.
                ext: '.min.js',   // Dest filepaths will have this extension.
             }]
           }
      },

      //The jshint task and its configurations
     jshint: {
          all: [ 'js/*.js', '!js/*.min.js' ]
     },

  });

  //Loading the plug-ins
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');


  // Default task(s), executed when you run 'grunt'
  grunt.registerTask('default', ['uglify']);


  //Creating a custom task
  grunt.registerTask('test', [ 'jshint' ] );

};

In that example our ‘test’ task triggers the jshint task, but it could trigger additional tasks such as unit testing tasks too (if we had that installed).

You’re done and ready to go:

grunt

will execute your default task, and

grunt test

will execute your ‘test’ task(s).

Real world example?

Feel free to checkout https://github.com/stephenharris/Event-Organiser-Posterboard/ for a real-world example of Grunt used in development.

What’s next?

In the next few posts I’ll be going through my particular set-up for WordPress plug-in (& theme) development: the plug-ins I use, their configurations and the tasks I have set-up.

Front End Event Posting

Update: 2nd August 2014: The front-end submissions extension is now available for purchase.

Update: 2nd July 2014: An extension is now available for beta testing, which allows you to accept and moderate front-end submissions of events. For more details, see http://wp-event-organiser.com/blog/announcements/front-end-event-submissions/. By comparison, this article is very limited in scope and for those who wish to implement something a bit more bespoke themselves.


One of the features for Event Organiser that has been requested a few times is that of ‘front-end’ event posting. People want their users to be able create events on the front-end. While this won’t make it into the core of the plug-in (since everyone will want it to work slightly differently) – it’s very easy to implement this yourself, as Event Organiser provides some very simple functions for creating and manipulating the events. In this post, I’m going to give a basic example of how you could implement front-end posting: feel free to edit it to your needs…

Front-end event (like post) creation is essentially a two step process:

  1. Create form to collect data
  2. Collect that data and use it create an event

You might want to implement a ‘success page’ that you redirect to afterwards, or return users to the form which errors highlighted, but at its core you just have two steps.

(Those who just want the entire source code, see this Gist).

Step 1: The form

In this post I’m going to create a shortcode to produce the form – this can then be used on an page or post (or event!).

Creating a shortcode is very easy, the following will create a shortcode [my_event_form] that will output a form only if the user is logged in (once its finished!). I strongly recommend not allowing logged-out users to create events.

add_shortcode('my_event_form','my_event_form_shortcode_handler');

function my_event_form_shortcode_handler( ){

    if( !is_user_logged_in() ){
        return '<p> Only logged in users can post events </p>'; 
    }

     //Return form HTML mark-up
     return $html;
}

Now we just need to produce the HTML form mark-up. The rest of this step shows how to generate the HTML, and goes just above the comment //Return form HTML mark-up.

The following creates a nonce for the form and a hidden field which will use so we know what to do with the data sent.

$html = '<form method="POST">';

//Create hidden 'action' field and corresponding nonce
$html .= '<input type="hidden"  name="my-action" value="post-event" >';
$html .=wp_nonce_field( 'post-event', '_mynonce',false,false);

Next we produce some input forms. Let’s start with an event title and description:

//Event Title
$html .= sprintf('<p><label for="my-frontend-event-%1$s"> %2$s
            <input type="text" name="my_frontend_event[%1$s]" id="my-frontend-event-%1$s" >
        </label></p>',
        'title',
        'Event Title'
    );

//Event Description
$html .= sprintf('<p><label for="my-frontend-event-%1$s"> %2$s
            <textarea name="my_frontend_event[%1$s]" id="my-frontend-event-%1$s"></textarea>
        </label></p>',
        'description',
        'Event Description'
    );

Now we’ll add in fields for the start and end date (you can also add fields to specify a start and end time, but in this example I’ll just be creating all day events).

//Start date
$html .= sprintf('<p><label for="my-frontend-event-%1$s"> %2$s
            <input type="text" name="my_frontend_event[%1$s]" id="my-frontend-event-%1$s" class="my-frontend-event-datepicker" >
        </label></p>',
        'startdate',
        'Start Date'
    );

//End date
$html .= sprintf('<p><label for="my-frontend-event-%1$s"> %2$s
            <input type="text" name="my_frontend_event[%1$s]" id="my-frontend-event-%1$s" class="my-frontend-event-datepicker" >
        </label></p>',
        'enddate',
        'End Date'
    );

Next we’ll create a drop-down menu so users can select a venue. Venues are just taxonomy terms (of the event-venue taxonomy), so we’ll make use of the WordPress function wp_dropdown_categories

//Venue
$html .= sprintf('<p><label for="my-frontend-event-%1$s"> %2$s %3$s </label></p>',
            'venue',
            'Venue',
            wp_dropdown_categories(array(
                'orderby'      => 'ID', 
                'order'        => 'ASC',
                'hide_empty'   => 0, 
                'echo'         => 0,
                'id'           => 'my-frontend-event-venue',
                'name'         => 'my_frontend_event[venue]',
                'taxonomy'     => 'event-venue'
            ))
        );

We’ll also add a checkbox list for event categories. Again event categories are just taxonomy terms (this time of the event-category taxonomy).

//Category - checklist
$cats = get_terms('event-category',array('hide_empty'=>0));
if( $cats ){
    $html .= '<p><label for="my-frontend-event-category">Category <ul>';
    foreach ( $cats as $cat ){
        $html .= sprintf('<li><label>
                         <input type="checkbox" name="my_frontend_event[%1$s][]" value="%2$s">
                         %3$s
                      </label></li>',
                'category',
                $cat->term_id,
                esc_html($cat->name)
                );
    }
    $html .= '</label></p>';
}

Finally we end the form with a submit button:

//The post button
$html .= '<p><input name="submit" type="submit" id="submit" value="Post Event"></p>';

$html .='</form>';

Step 2: Processing the data

The form should now render and post the data – but we’ll need to get hold of that data and do something with it. We’ll hook onto the init action, and check to see if our custom ‘action’ variable is set. If not, we don’t do anything.

add_action('init','my_frontend_event_post_listner');

function my_frontend_event_post_listner(){

    if( !isset($_POST['my-action']) || 'post-event' != $_POST['my-action'] )
        return;

    //Collect raw input
    $input = $_POST['my_frontend_event'];

    //Do something with the input

}

Before we do anything with the data we need to perform a few checks:

  • Is the user allowed to create events (in this example, only logged-in users can create events – you might want to perform other checks)
  • Did the users intended to post the form? (This is what the nonce are for?)
  • Is the data as you expect it? (This is called sanitisation, I’ve omitted it here. Its less of a security matter, and more of making sure that the data you using to create the event, makes sense).

For example:

//Check user is logged in:  
if( !is_user_logged_in() )  
return;

//Check nonce  
check_admin_referer( 'post-event', '_mynonce');

/*
*   IMPORTANT: Perform any other checks you need to here (e.g. should only users with a certain capability be able to post events?)  
*/

To create the event we are going to use the plug-in provided function eo_insert_event(). This accepts two arrays: the first concerns ‘post data’ and is passed to wp_insert_post() (so it accepts anything that wp_insert_post() does. The second is for event data – and that is explained below.

First, collecting the post data (which includes an array of term IDs for the event-category and event-venue taxonomies – the latter should only contain one ID).

/**
 * Set the post data (see http://codex.wordpress.org/Function_Reference/wp_insert_post)
 * This includes event-category and event-venue (taxonomy terms)
*/
//Event venue is just an ID
$event_venue = isset($input['venue']) ? (int) $input['venue'] : 0;

//Event cats are an array of IDs
$event_cats = !empty( $input['category'] ) ? $input['category'] : array();
$event_cats = array_map( 'intval', $event_cats );

$post_data =array(
    'post_title'=>$input['title'],
    'post_content'=>$input['description'],
    'tax_input'=>array(
        'event-venue'=>array($event_venue),
        'event-category'=>$event_cats,
    )
);

Next the event data. For this function, any dates must be passed as DateTime objects. The easiest way to do this is to collect the date as string, $datestring, in Y-m-d format (or Y-m-d H:i format to specify a time too) and use

 new DateTime($datestring) 

The timezone will be UTC unless you specify otherwise, so its recommended you use eo_get_bog_timezone() for your blogs current timezone. See full documentation of this function.

/**
 * Set the event data
*/
//Start and end dates need to be given as DateTime objects (timezone is UTC unless a timezone is given)
$start = new DateTime($input['startdate'],eo_get_blog_timezone());
$end = new DateTime($input['enddate'],eo_get_blog_timezone());
$event_data =array(
    'schedule' =>'once',  //specifies the reoccurrence pattern
    'all_day' =>  1, //1 if its an all day event, 0 if not - if not you'll need to specify a start/end time for the DateTimeobjects
    'start' =>  $start, //start date (of first occurrence)  as a datetime object
    'end' => $end,  //end date (of first occurrence)  as a datetime object
);

Finally create the event!

//Finally, Insert event.
$post_id = eo_insert_event($post_data,$event_data);

The code in its entirety can be found at this Gist.