Skip to content

Instantly share code, notes, and snippets.

@danielpost
Last active May 28, 2020 13:09
Show Gist options
  • Save danielpost/9b989abf281e3333351e7ab1332572e8 to your computer and use it in GitHub Desktop.
Save danielpost/9b989abf281e3333351e7ab1332572e8 to your computer and use it in GitHub Desktop.
WordPress API Importer
<?php
/**
* This class is an example of how to reliably fetch items from an external API
* using background processing. Make sure Action Scheduler is installed before
* instantiating this class.
*
* @link https://actionscheduler.org/
*/
class Importer {
const API_URL = 'https://api.openbrewerydb.org/breweries';
const ITEMS_PER_FETCH = 10;
const FETCH_ACTION = 'posty_fetch_breweries';
const FETCH_SCHEDULE = '0 */6 * * *';
/**
* @var int
*/
public $page;
/**
* @var array
*/
public $items = [];
/**
* @var bool
*/
public $last_fetch = false;
public function setup() {
add_action(static::FETCH_ACTION, [$this, 'import']);
add_action('init', [$this, 'import_new_breweries']);
}
/**
* Get a list of items from the Open Brewery DB.
*/
public function fetch() {
$response = wp_remote_get(static::API_URL, [
'body' => [
'per_page' => static::ITEMS_PER_FETCH,
'page' => $this->page
]
]);
if (wp_remote_retrieve_response_code($response) !== 200) {
// This means somewhere there was an issue with fetching. Perhaps
// the API timed out or the authentication was incorrect. Use this
// to gracefully handle failures. For this example, we simply write
// the error message to the log and stop the fetching process.
error_log(wp_remote_retrieve_response_message($response));
$this->last_fetch = true;
return;
};
$this->items = json_decode(wp_remote_retrieve_body($response));
$this->process_items();
}
/**
* Do something with each fetched item.
*/
public function process_items() {
// If less items than requested are returned, we assume it was the last
// page and stop subsequent fetches.
if (count($this->items) < static::ITEMS_PER_FETCH) {
$this->last_fetch = true;
}
foreach ($this->items as $item) {
// Do something with an individual fetched item. For example, you
// could create a new custom post type entry for each item. It's
// also possible to stop the fetching process here, for example if
// the entry for this item already exists.
if (get_page_by_title($item->name)) {
$this->last_fetch = true;
continue;
}
// Process the item here...
}
}
/**
* Run the importer.
*
* @param int $page
*/
public function import($page = 1) {
$this->page = $page;
$this->fetch();
if (!$this->last_fetch) {
as_enqueue_async_action(static::FETCH_ACTION, [$this->page + 1]);
} else {
// Import finished. You could use this space to update an option or
// something else you'd like to do after finishing the import.
}
}
/**
* Run the importer according to the CRON schedule.
*/
public function import_new_breweries() {
if (as_next_scheduled_action(static::FETCH_ACTION) === false) {
as_schedule_cron_action(time(), static::FETCH_SCHEDULE, static::FETCH_ACTION);
}
}
}
$importer = new Importer;
$importer->setup();
// It's important to only kick off the initial import once, for instance
// when updating the API key settings. For this example however, we run it
// on every page load.
add_action('init', function () {
as_enqueue_async_action(Importer::FETCH_ACTION);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment