Getting Eventbrite API WordPress plugin to work on systems with 32-bit builds of PHP

Last week I had to use the Eventbrite API plugin to show upcoming events on a client’s website. The plugin does all the work out of the box; if you are happy with the default appearance, there is no need to write a single line of code to get it working. You just need to connect your Eventbrite account and create a page that uses the template that the plugin provides. It just works… as long as you are using a 64-bit build of PHP.

If you are using a 32-bit build of PHP, there are some features that don’t work:

  1. the_permalink()  and get_the_permalink()  return a broken URL.
  2. Pages for single events show none of the event’s information.
  3. The ticket form widget shows an error saying the event is not publicly available.

The three problems above have the same cause: the ID of Eventbrite’s events cannot be represented as 32-bit integers, but that’s exactly the data type that WordPress uses to store the ID of posts. Since Eventbrite API is designed to make events available as if they were instances of custom post types, WordPress applies the same sanitization procedures that it applies to posts found in the website’s database. However, every time WordPress converts the event’s ID from a string (as returned by the API) to an integer, the ID property ends up having a value of 2147483647 , which is the maximum value for a 32-bit signed integer.

The original event’s ID is lost in the sanitization process, causing every function that uses that value to return incorrect results.

In order to overcome the problems described above and knowing that it was all caused because the ID being used was not the event’s ID, I used several WordPress and Eventbrite API filters to insert the correct value in key places.

Depending on your needs, you may have additional issues, but I expect all of them to be caused by the same error: the event ID being used is not really the event’s ID. Hopefully the code below my inspire you to create similar workarounds to get your implementation working.

the_permalink()  and get_the_permalink()  return a broken URL

Eventbrite API uses the post_link  filter to provide a custom permalink. However, their functions uses the ID property of the post object, which we already know no longer holds the value we want.

I copied their function, edited the code to use a different property (event_id ) and created my own handler for the post_link  filter:

function wvega_850_filter_event_permalink( $url ) { // eg. http://mysite.com/events/july-test-drive-11829569561
    if ( function_exists( 'eventbrite_is_event' ) && eventbrite_is_event() ) {
        $url = sprintf( '%1$s/%2$s/%3$s-%4$s/',
            esc_url( home_url() ),                             // protocol://domain
            sanitize_title( get_queried_object()->post_name ), // page-with-eventbrite-template
            sanitize_title( get_post()->post_title ),          // event-title
            get_post()->event_id                               // event ID
        );
    }

    return $url;
}
add_filter( 'post_link', 'wvega_850_filter_event_permalink', 11 );

The event_id  property is a string that holds the value the ID property had before WordPress converted it to int. I created a handler for the_post action that grabs the original value and stores it in that property:

function wvega_850_eventbrite_workaround( $post ) {
    if ( ! is_a( $post, 'Eventbrite_Event' ) ) {
        return;
    }

    if ( ! is_integer( $post->ID ) ) {
        $post->event_id = $post->ID;
    }
}
add_action( 'the_post', 'wvega_850_eventbrite_workaround' );

Having the event’s ID stored as the event_id  property of the post object is what makes all my other workarounds possible.

Pages for single events show none of the event’s information

UPDATE (2015-09-13): The single event page will show information about the same event, no matter which event is being requested in the URL. This is an issue also caused by the real ID of the event not being available. Unfortunately, I don’t have a way to fix this using existing hooks. I’m currently trying to get a new hook added to the plugin so that I can create another workaround for this problem.

UPDATE (2015-09-14): The hook was accepted by Eventbrite API’s developers and will be included in the next release. I included a new function below (wvega_850_eventbrite_transient_name ) that uses that filter to make sure the information shown in single event pages always corresponds to the event being requested.

The single page for Eventbrite events uses a sub-class of WP_Query to retrieve the information of the event being shown. The page captures the event’s ID from the URL (the custom permalink generated in the previous step), moves the value into a query var using Rewrite rules and, finally, passes the value as the p  parameter of the query.

However, WordPress also converts that value to an integer. When the Eventbrite API plugin makes a request to retrieve the event’s information, the ID of the event is no longer available causing the request to return an empty object.

The code below uses the http_api_curl  action to capture all requests sent to http://www.eventbriteapi.com and replace the incorrect ID with the value we stored in event_id .

function wvega_850_http_api_curl( $handle, $r, $url ) {
    if ( false === strpos( $url, 'www.eventbriteapi.com' ) || false === strpos( $url, '2147483647' ) ) {
        return;
    }

    $eventbrite_id = get_query_var( 'eventbrite_id' );

    if ( empty( $eventbrite_id ) ) {
        return;
    }

    $new_url = str_replace( '2147483647', $eventbrite_id, $url );
    curl_setopt( $handle, CURLOPT_URL, $new_url);
}
add_action( 'http_api_curl', 'wvega_850_http_api_curl', 10, 3 );

Please note that the code above will work only if the HTTP requests are being made using cURL. If a different transport is used, the http_api_curl action won’t be fired.

Next, we need to filter the name of the transient Eventbrite API uses to cache query results. Otherwise our single event pages will start showing the same information, no matter what event was requested.

function wvega_850_eventbrite_transient_name( $transient_name, $endpoint, $params ) {
    if ( $endpoint == 'event_details' ) {
        $params['p'] = get_query_var( 'eventbrite_id' );
        $transient_name = 'eventbrite_' . md5( $endpoint . implode( $params ) );
    }

    return $transient_name;
}
add_filter( 'eventbrite_transient_name', 'wvega_850_eventbrite_transient_name', 10, 3 );

The problem with the default implementation is that the value stored in $params[‘p’]  is always 2147483647 . The code above replaces that value with the real event ID and then creates the transient name using the same expression used in the original function.

The eventbrite_transient_name  filter does not exists in Eventbrite API 1.0.8 or below, but it will be available in future versions. If version 1.0.8 is still the latest  version when you are reading this post, then you need to update the get_transient_name()  method in Eventbrite Manager class, replacing the following code:

protected function get_transient_name( $endpoint, $params ) {
    // Results in 62 characters for the timeout option name (maximum is 64).
    return 'eventbrite_' . md5( $endpoint . implode( $params ) );
}

with this one:

protected function get_transient_name( $endpoint, $params ) {
    // Results in 62 characters for the timeout option name (maximum is 64).
    $transient_name = 'eventbrite_' . md5( $endpoint . implode( $params ) );
    return apply_filters( 'eventbrite_transient_name', $transient_name, $endpoint, $params );
}

In this case is ok to edit a plugin’s code. The changes we are introducing are exactly the same ones that will be available in the next release.

If you ever need to change how a plugin works, please consider sending a patch to the author first. That way others benefit from your modifications and you don’t need to keep applying your modifications every time a new version of the affected plugin is released.

The ticket form widget shows an error saying the event is not publicly available

The problem here is similar to the one above. The widget generated by the Eventbrite API plugin points to the wrong URL because it uses the an incorrect value for the event’s ID.

Luckily, the plugin has a filter that we can use to modify the code used to generate the widget before is sent to the browser. I created a handler for the eventbrite_ticket_form_widget filter and used a simple regular expression to find the incorrect value and replace it with the one stored in event_id .

function wvega_850_eventbrite_ticket_form_widget( $form_widget ) {
    $event_id = get_post()->event_id;

    if ( empty( $event_id ) ) {
        return $form_widget;
    }

    return preg_replace( '/eid=d+/', 'eid=' . urlencode( $event_id ), $form_widget );
}
add_filter( 'eventbrite_ticket_form_widget', 'wvega_850_eventbrite_ticket_form_widget' );

Conclusion

Many other functions that use the ID property of the current post object are probably broken as well; I just didn’t need those to be working in this case. The above are just workarounds and a are far from a real solution.

If you really want to solve all those problems, the solution is to start using a 64-bit version of PHP, but if you can’t do that and you still want to use the Eventbrite API plugin to bring Eventbrite events to your WordPress website, I hope the code above helps you.

Comments

  1. Daniel Brown
    October 25, 2015 at 10:45 pm

    Wow, thank you so much! This was exactly what I needed and it worked like a champ.

    Really appreciate the thorough write up!

    1. Gerald Hofer
      August 6, 2016 at 2:19 pm

      Cheers Daniel, can you tell me how you got it done? Probably you could share the modified files? Thanks a lot.

      1. Daniel Brown
        August 6, 2016 at 4:03 pm

        Sure, no problem.

        This is the code I added to my `functions.php` file.

        “`
        function wvega_850_filter_event_permalink( $url ) { // eg. http://mysite.com/events/july-test-drive-11829569561
        if ( function_exists( ‘eventbrite_is_event’ ) && eventbrite_is_event() ) {
        $url = sprintf( ‘%1$s/%2$s/%3$s-%4$s/’,
        esc_url( home_url() ), // protocol://domain
        sanitize_title( get_queried_object()->post_name ), // page-with-eventbrite-template
        sanitize_title( get_post()->post_title ), // event-title
        get_post()->event_id // event ID
        );
        }

        return $url;
        }
        add_filter( ‘post_link’, ‘wvega_850_filter_event_permalink’, 11 );

        function wvega_850_eventbrite_workaround( $post ) {
        if ( ! is_a( $post, ‘Eventbrite_Event’ ) ) {
        return;
        }

        if ( ! is_integer( $post->ID ) ) {
        $post->event_id = $post->ID;
        }
        }
        add_action( ‘the_post’, ‘wvega_850_eventbrite_workaround’ );

        function wvega_850_http_api_curl( $handle, $r, $url ) {
        if ( false === strpos( $url, ‘www.eventbriteapi.com’ ) || false === strpos( $url, ‘2147483647’ ) ) {
        return;
        }

        $eventbrite_id = get_query_var( ‘eventbrite_id’ );

        if ( empty( $eventbrite_id ) ) {
        return;
        }

        $new_url = str_replace( ‘2147483647’, $eventbrite_id, $url );
        curl_setopt( $handle, CURLOPT_URL, $new_url);
        }
        add_action( ‘http_api_curl’, ‘wvega_850_http_api_curl’, 10, 3 );

        function wvega_850_eventbrite_transient_name( $transient_name, $endpoint, $params ) {
        if ( $endpoint == ‘event_details’ ) {
        $params[‘p’] = get_query_var( ‘eventbrite_id’ );
        $transient_name = ‘eventbrite_’ . md5( $endpoint . implode( $params ) );
        }

        return $transient_name;
        }
        add_filter( ‘eventbrite_transient_name’, ‘wvega_850_eventbrite_transient_name’, 10, 3 );

        function wvega_850_eventbrite_ticket_form_widget( $form_widget ) {
        $event_id = get_post()->event_id;

        if ( empty( $event_id ) ) {
        return $form_widget;
        }

        return preg_replace( ‘/eid=d+/’, ‘eid=’ . urlencode( $event_id ), $form_widget );
        }
        add_filter( ‘eventbrite_ticket_form_widget’, ‘wvega_850_eventbrite_ticket_form_widget’ );
        “`
        That did the trick for me, hopefully it does for you too!

        1. Gerald Hofer
          August 7, 2016 at 3:28 am

          Thanks for the quick reply. Only to get sure. Are you talking about the “functions.php” of the Child Theme or the functions.php of the eventbrite-api? Have you just added the code above without deleting anything?
          Now my single event url looks like http://example.com/events/testevent-/
          As you can see, the ID is missing now. Thanks Daniel. 🙂

          1. Daniel Brown
            August 7, 2016 at 1:46 pm

            This would go into the functions.php of your theme/child theme. The code I shared is exactly what I used but let me make sure I didn’t have to make other modifications elsewhere. I’ll look into it and let you know.

            I have since upgraded to a 64-bit server so I don’t need to use this anymore so I’m having to go through some old versions of my files.

          2. Gerald Hofer
            August 7, 2016 at 2:11 pm

            Thanks Daniel, I really appreciate your help! I hope you will find some more modifications.

          3. August 15, 2016 at 7:36 am

            Hi Gerald / Daniel, sorry to hijack the thread but did you have any success with this? I have the same problem re: the id missing from the url. It looks like the `event_id` is always returning empty.

          4. wvega
            August 15, 2016 at 8:05 am

            @disqus_kija1qrE1f:disqus, @kieranmcclung:disqus Have you checked that all the hook handlers in this post are actually executing?

            The missing ID could be explained if the

            wvega_850_eventbrite_workaround()

            function is not executed for some reason.

            You could, for example, add the following code at the bottom of that function to confirm it is working as expected:

            
            echo '<pre><code>' . print_r( array( 'post_id' => $post->ID, 'stored_event_id' => $post->event_id ), true ) . '</pre></code>';
            

            After adding that code, if you go to a page where an Event URL is shown, you should see debug information printed as well. If that’s not the case, the handler is not executing in your WordPress instance, and you need to find out why. If the stored_event_id entry is empty, then please let me know and I’ll try to reproduce the problem in an environment similar to yours.

          5. August 15, 2016 at 10:31 am

            Thank you for the quick response, it’s greatly appreciated. I’ve managed to get the snippet you posted above to display however I had to change the conditionals within the function. That’s leading me to believe that something isn’t getting picked up correctly, although I could be wrong about that?

            What I’ve got is a template override of the default Eventbrite API template (although the default also has the same issues). Sitting on the URL: /upcoming-events/. The template uses a custom WP_Query to get the Eventbrite events, as it does with the default template, however the first conditional is returning true so that the rest of it is ignored. The following outputs on the Eventbrite page.

            if ( is_user_logged_in() ) {
            	if ( ! is_a( $post, 'Eventbrite_Event' ) )
            		echo '>pre<>code<' . print_r( array( 'post_id' => $post->ID, 'stored_event_id' => $post->event_id ), true ) . '>/pre<>/code<';
            }
            

            After removing all of the conditionals I managed to get the snippet to appear but the stored_event_id / $post->event_id had the same value as the post_id (the 32 bit number). If the conditional isn’t working in this function ..._eventbrite_workaround() will that have an effect elsewhere in the code?

          6. wvega
            August 15, 2016 at 12:11 pm

            If the conditionals had to be changed or are not working, the necessary code may be executing at the wrong time, causing the event_id property not to be available when needed.

            Can I see the full code of the eventbrite_workaround() function you are currently using (i.e., your modified version)?

          7. August 16, 2016 at 5:38 am

            Sorry for the late reply. I have created a gist here: https://gist.github.com/raptorkraine/a0a3a01cc3d25f69792e835f07a35dd5

            The other functions are copied directly from the original post and unaltered in any way.

            I really appreciate your help with this.

          8. wvega
            August 16, 2016 at 7:52 am

            Hmm. If the post’s ID is already 2147483647 it means WordPress already tried to convert the Event’s ID into a integer and failed. That number is the maximum value that an integer variable can have in a 32-bit environment.

            It seems the function is being executed too late. Perhaps I need to update the code, but not sure how exactly right now.

            What version of WordPress are you using? and what version of Eventbrite API are you using?

          9. August 16, 2016 at 10:28 am

            It’s WordPress 4.5.3 and Eventbrite 1.0.11

            I’m more than happy to have a go myself and report back but I’m not entirely sure how the function works, truth be told.

          10. wvega
            August 16, 2016 at 12:11 pm

            Try this: https://gist.github.com/wvega/cca6150271f65a5807ed98ab273f6761 and let me know what it shows.

            The function’s purpose is to get access to the post object right after it is created, before WordPress sanitisation functions cast the ID into an integer. At that point, back when I wrote that code, the ID was set to a string holding the Event ID returned by the API. The function grabs that value and stores it in the event_id property. Later, when my other functions need to know the ID of the event, they check that property instead of ID property (already converted to an integer and no longer holding the real Event ID).

            I’m trying to take a look at the full $post before other parts of the code, or other plugins touch it. For that, I changed the priority of the hook from 10 (the default) to 0.

            In particular, I’m interested in the Post’s ID (hopefully we’ll see the Event’s true ID there) and the class of the object (last time I checked those should be instances of Eventbrite_Event).

          11. August 17, 2016 at 6:37 am

            Thanks for the code snippet, and for the explanation of the functions.

            The Post ID in the newly attached code is still showing as the 32-bit int. I can, however, extract the Event ID from the tickets array. I’ve attached the pre / code dump below (showing only the relevant bits).

            Array
            (
                [post] => WP_Post Object
                    (
                        [ID] => 2147483647
                        [tickets] => Array
                            (
                                [0] => stdClass Object
                                    (
                                        [event_id] => 27022066729
                                    )
            
                            )
            
                    )
            )
            

            I still can’t seem to pass the event_id to the wvega_850_filter_event_permalink function however this works for me, albeit not an ideal solution for everyone.

            
            function wvega_850_filter_event_permalink( $url ) { // eg. http://mysite.com/events/july-test-drive-11829569561
            	if ( function_exists( 'eventbrite_is_event' ) && eventbrite_is_event() ) {
            		$url = sprintf( '%1$s/%2$s/%3$s-%4$s/',
            			esc_url( home_url() ),                             // protocol://domain
            			sanitize_title( get_queried_object()->post_name ), // page-with-eventbrite-template
            			sanitize_title( get_post()->post_title ),          // event-title
            			get_post()->tickets[0]->event_id                 // changed this line
            		);
            	}
            
            	return $url;
            }
            add_filter( 'post_link', 'wvega_850_filter_event_permalink', 11 );
            

            Here is a link to the full output, with links etc. removed https://gist.github.com/raptorkraine/a14db78be1795f073f43c571f9e08eb7

          12. wvega
            August 17, 2016 at 8:04 am

            I don’t remember seeing the tickets array when I was writing this functions, so I assume they did change something in Eventbrite API. I’ll definitely have to review this post’s code. Thank you for bringing this up and helping me to debug!

            Your solution looks good to me. You may want to do the same in wvega_850_eventbrite_ticket_form_widget().

            For a general solution, I need to make sure the tickets array is always there, but if that’s the case, then your approach would be that solution.

          13. Yulia
            December 18, 2016 at 4:46 pm

            Hey Kieran, were you able to display the single event properly? I am getting the wrong 32-bit ID still 🙁 I appreciate any help!

            Array ( [p] => 29394827721 ) [query_vars] => Array ( [p] => 2147483647

          14. Gerald Hofer
            August 9, 2016 at 12:18 pm

            Did you found some more modifications?

          15. Daniel Brown
            August 14, 2016 at 3:05 pm

            Hey Gerald,

            Sorry for the slow response, had to root through some old backups. I can’t find any additional modifications so if it’s not working for you my guess would be there’s a slight difference in our setup.

            I would recommend taking a look at what Willington had to say about this bit of the code:

            
            protected function get_transient_name( $endpoint, $params ) {
                // Results in 62 characters for the timeout option name (maximum is 64).
                $transient_name = 'eventbrite_' . md5( $endpoint . implode( $params ) );
                return apply_filters( 'eventbrite_transient_name', $transient_name, $endpoint, $params );
            }
            
            

            Good luck!

            P.S. Long term it would definitely be best if you were able to move to a 64-bit server. If that’s at all an option for you I would certainly recommend it.

  2. Chris
    February 5, 2016 at 2:14 pm

    So I tried to apply the code snippets from “Pages for single events show none of the event’s information” adding them to my themes functions.php file, updating the the theme name, but nothing is working still, any suggestions on how to find out if my server uses cURL for http requests?

    1. Chris
      February 5, 2016 at 2:35 pm

      Actually I am using cURL, I ran this on command line: curl -v -I -H “Testing: Test header so you see this works” http://wptest.mysite.com
      * About to connect() to wptest.thewiptheater.com port XX (#0)
      * Trying 66.175.232.62… connected
      * Connected to wptest.mysite.com (XX.XXX.XXX.XX) port XX (#0)
      > HEAD / HTTP/1.1
      > User-Agent: curl/7.21.0 (i486-pc-linux-gnu) libcurl/7.21.0 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.15 libssh2/1.2.6
      > Host: wptest.mysite.com
      > Accept: */*
      > Testing: Test header so you see this works

      So I am not sure why the events are still displaying as broken events, any help would be much appreciated.

    2. wvega
      February 8, 2016 at 10:13 pm

      Are you sure your code is being executed? You could try adding a wp_die(“It’s running”); call just to see if the code is being called.

      You can also find out the name of the transporte being used to make requests, setting a handler for the `http_api_debug` action. The handler will receive an instance of the HTTP transport used as the third argument. You can call get_class() on that instance and print the returned value.

      If WordPress is indeed using cURL to make requests and you’r code is running, then something may have changed in the Eventbrite API plugin and the code above may need an update. Let me know and I’ll take another look.

    3. wvega
      February 8, 2016 at 10:16 pm

      Also, can you share the version of the code you’re using in your website? Post it to GitHub Gist or http://fpaste.org and leave the URL as comment. You can also post your code here between *pre* and *code* tags.

      <pre><code></pre></code>
  3. Mark B
    April 3, 2016 at 5:24 pm

    Hi Willington. Do you still use the code you wrote for this plugin? Have you updated it in any way? I am having difficulties implementing it. At the minute I have added the following code (http://fpaste.org/349118/59721662/) copied from your site to the main functions.php file. I ran wp_die and the code is being called.

    I’m still getting the “Whoops, the page or event you are looking for was not found” on the events page http://cani.org.uk/blueway10kregistration/
    It should point to this event http://www.eventbrite.co.uk/e/blueway10k-tickets-24346122909

    I havent done much yet to tidy up the theme other than removing the sidebar.

    I would appreciate any advice you may be able to offer.

    Many thanks

    Mark

    1. wvega
      April 7, 2016 at 8:53 am

      Hi Mark,

      Looking at your code, the wp_die call you added will only tell your wether the functions.php was included or not. In order to use the wp_die call to find out if the functions are actually being executed, you need to put the call inside each function you want to check.

      Also, you don’t seem to be using the wvega_850_eventbrite_ticket_form_widget function attached to the eventbrite_ticket_form_widget filter. That’s precisely the one that should solve the “Whoops, the page or event you are looking for was not found” problem. Check the last part of the post and let me know if that solves your problem.

  4. Yulia
    December 18, 2016 at 4:44 pm

    Hi Willington, thanks so much for all these snippets. I got everything to work on the event index page and it links to a proper event ID, however, on the single event ID I get absolutely nothing, an empty page and when I print out query object, it looks like the ID is still the wrong 214[…] one.

    Array ( [p] => 29394827721 ) [query_vars] => Array ( [p] => 2147483647

    How do I get the single event to display properly? Thank you!

    1. wvega
      December 19, 2016 at 11:26 am

      Hi Yulia!

      Right know I don’t have access to a 32bit system, so I’m having a hard time testing all this. Could you please check the following?

      – What does get_query_var( 'eventbrite_id' ) return?
      – What’s the value of get_post()->tickets[0]->event_id?

      It seems the API has changed since I first wrote the functions in this post. As @kieranmcclung:disqus pointed out, Event post objects now include the Eventbrite ID (as a string) in the `->tickets[0]->event_id` property. From what I know, all Event post objects include that property, so that seems to be the best place to get the ID now.

      I’ve created a new version of the functions above, available here: https://gist.github.com/wvega/31a4bef3b1db1d048e1d61172b87711b.

      After answering my two questions above, could you please give this new code a try? Please note that I removed the wvega_850_eventbrite_workaround function and added the wvega_850_get_current_event_id(). All other functions were modified a bit.

      1. Yulia
        December 19, 2016 at 1:38 pm

        Hi Willington, thanks so much for your detailed reply and modified code!

        get_query_var( ‘eventbrite_id’ ) returns the correct eventbride ID; however, the query itself is using a different ID that’s coming from [query_vars] => Array ( [p] => 2147483647, not [query] => Array ( [p] => 29394827721 ) – this is a little bit out of my area of expertise as I’m not sure how to make it use the right id. Here’s the entire Eventbrite array: https://paste.fedoraproject.org/509816/72539148/ – it looks like it’s falling back to the default wrong ID. Good thing my client’s host has 64 bit php so I can work on there, but it’s still a pain to work on a remote host.

  5. Karan Gadhavi
    December 30, 2016 at 6:41 am

    Try out “Import EventBrite Events” plug-in works fine

    https://wordpress.org/plugins/import-eventbrite-events