Ben Cole

Front-end web ninja with a lot of full-stack experience




I craft elegant solutions to complex problems.

Scroll down to see just a few examples of my recent projects.

Or browse my languages and frameworks or open source contributions.

Social Metrics Tracker

An open source WordPress plugin See it WordPress.org

WordPress Plugin PHPUnit Testing Social APIs

What I did

I created a WordPress plugin which connects to the APIs of six different social networks to collect and report the number of times each post has been shared online.

The plugin was presented at the Higher Ed Web national conference in Buffalo NY in 2013, and is now in use by thousands of WordPress sites worldwide.

Technical considerations

The plugin makes use of the WP Cron to spread out API requests. It includes a PHP circuit breaker mechanism to detect problems with APIs, temporarily shut off requests, and retry after a specified amount of time.

Because social networks handle canonical URLs differently, the plugin can collect data from different protocols, subdomains, or alternate post URLs - then aggreate this data together for reporting.

The plugin uses action hooks and post custom fields in order to help other developers to extend or modify functionality in a clean, update-friendly way.

Code Samples

This is the circuit breaker mechanism which is used when making network requests.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<?php
/***************************************************
* A circuit breaker helper which helps an application gracefully fall back
* when a remote service becomes unavailable. State persists between WordPress
* sessions by using the Transients API.
***************************************************/

class WordPressCircuitBreaker {
  
  // Reset state if no activity for this period of time.
  public $persist_ttl = WEEK_IN_SECONDS; 

  public $identifier = '';
  private $prefix = 'smt_wpcb_';

  public function __construct($identifier, $options = null) {

    $this->identifier = $identifier;

    $this->load();

    // Accept new options
    if ($options['max_failures']) $this->set('max_failures', $options['max_failures']);
    if ($options['time_to_wait']) $this->set('time_to_wait', $options['time_to_wait']);

    // Defaults
    if (!$this->get('max_failures')) $this->set('max_failures', 3); // Failures to trigger offline status
    if (!$this->get('time_to_wait')) $this->set('time_to_wait', 3 * HOUR_IN_SECONDS); // How long between checks of an offline service

  }

  /***************************************************
  * Allow connections through when the service is online,
  * as well as once in a while to check when a service is down.
  ***************************************************/
  public function readyToConnect() {

    // Not offline yet!
    if ($this->get('fail_count') < $this->get('max_failures')) return true;

    // Offline, check if we should allow one attempt
    return ($this->getTime() > ($this->get('last_query_time') + $this->get('time_to_wait')));

  }

  /***************************************************
  * Get some useful information about the service status
  ***************************************************/
  public function getStatusDetail() {
    return array(
      'working'       => $this->get('fail_count') == 0,
      'fail_count'    => $this->get('fail_count'),
      'error_message' => $this->get('error_message'),
      'error_detail'  => $this->get('error_detail'),
      'last_query_at' => $this->get('last_query_time'),
      'next_query_at' => ($this->readyToConnect()) ? $this->getTime() : $this->get('last_query_time') + $this->get('time_to_wait'),
    );
  }

  /***************************************************
  * Application should report each success
  ***************************************************/
  public function reportSuccess() {
    $this->set('fail_count', 0);
    $this->set('last_query_time', $this->getTime());

    $this->save();
  }

  /***************************************************
  * Application should report each failure
  ***************************************************/
  public function reportFailure($message = 'An error occured, but no error message was reported.', $detail='') {
    $this->set('fail_count', $this->get('fail_count') + 1);
    $this->set('last_query_time', $this->getTime());
    $this->set('error_message', $message);
    $this->set('error_detail', $detail);

    $this->save();
  }

  /***************************************************
  * Get a value
  ***************************************************/
  public function get($key) {
    return isset($this->data[$key]) ? $this->data[$key] : false;
  }

  /***************************************************
  * Set a value
  ***************************************************/
  private function set($key, $val) {
    $this->data[$key] = $val;
  }

  /***************************************************
  * Load saved state
  ***************************************************/
  private function load() {
    if (is_multisite()) {
      $this->data = get_site_transient($this->prefix . $this->identifier);
    } else {
      $this->data = get_transient($this->prefix . $this->identifier);
    }
  }

  /***************************************************
  * Write current state
  ***************************************************/
  private function save() {
    if (is_multisite()) {
      set_site_transient( $this->prefix . $this->identifier, $this->data, $this->persist_ttl );
    } else {
      set_transient( $this->prefix . $this->identifier, $this->data, $this->persist_ttl );
    }
  }

  /***************************************************
  * Get the current time
  ***************************************************/
  public function getTime() {
    return current_time( 'timestamp' );
  }
}
?>
Explore full source code on Github

Chapman University Homepage

A responsive, multimedia web page. Go to www.chapman.edu

HTML5 Video CSS3 Animations jQuery and Ajax Event Tracking Responsive

With two million pageviews annually, this homepage needs to provide a great overview of Chapman University at a glance, and work on a wide varity of devices and browsers.

What I did

I collaborated with our designer on the page concept. I wrote most of the HTML, CSS, and Javascript for the page. I imagined and implemented all of the animations and movement on the page based on the static PSD file provided to me.

Technical considerations

The page is cross-browser compatibile down to Internet Explorer 8, and will at least not fall apart in Internet Explorer 7 (gasp!). Animations and video elements do not load on mobile devices or older browsers. The page is responsive and the layout is optimized for just about any viewport size.

CU WordPress Theme

Built for multimedia content; Looks great on phones, tablets, and even paper. See it on Chapman Magazine

WordPress Theme Responsive Printer Friendly

Adaptive Story Spaces

Long post titles get shortened in order to fit in the layout (See above). Notice in the animation above that when the user mouses over a featured story, the titles expand and collapse so that the item in focus is shown fully.

Additionally, the featured stories can automatically swap out based on trending data provided by my Social Metrics Tracker plugin.

Totally Responsive

It's aesthetically pleasing to read these blog posts whilst on the go:

And even though the layout is built for posts with beautiful featured images, videos, or other embedable media...

It's still printer friendly!

the stories still look great, thanks to CSS Media Queries for print.




Next, View my open source contributions »