diff --git a/functions.php b/functions.php index c494b505..424fd984 100644 --- a/functions.php +++ b/functions.php @@ -820,20 +820,97 @@ function metabox_order( $order ) { ); } + /** - * Add ACF fields to WP REST API JSON output + * Add custom fields to 'post' API endpoint * * @link https://gist.github.com/rileypaulsen/9b4505cdd0ac88d5ef51 + * + * @param Object $data The data being added to the post object. + * @param Object $post The post being augmented. + * @param String $context Unused. */ -function wp_api_encode_acf( $data, $post, $context ) { +function mitlib_api_v1_alter( $data, $post, $context ) { $customMeta = (array) get_fields( $post['ID'] ); $data['meta'] = array_merge( $data['meta'], $customMeta ); return $data; } -if ( function_exists( 'get_fields' ) ) { - add_filter( 'json_prepare_post', 'wp_api_encode_acf', 10, 3 ); +/** + * Adds custom fields to 'post' and 'experts' API endpoints + * + * @link http://v2.wp-api.org/extending/modifying/ + * @link https://gist.github.com/rileypaulsen/9b4505cdd0ac88d5ef51#gistcomment-1622466 + */ +function mitlib_api_v2_alter() { + // Add custom fields to posts endpoint. + register_rest_field( 'post', + 'meta', + array( + 'get_callback' => function( $data, $field, $request, $type ) { + if ( function_exists( 'get_fields' ) ) { + return get_fields( $data['id'] ); + } + return array(); + }, + 'update_callback' => null, + 'schema' => null, + ) + ); + + // Add custom fields to experts endpoint. + register_rest_field( 'experts', + 'meta', + array( + 'get_callback' => function( $data, $field, $request, $type ) { + if ( function_exists( 'get_fields' ) ) { + return get_fields( $data['id'] ); + } + return array(); + }, + 'update_callback' => null, + 'schema' => null, + ) + ); + + // Switch featured_media field from media ID to URL of the image. + register_rest_field( 'experts', + 'featured_media', + array( + 'get_callback' => 'mitlib_api_get_image', + 'update_callback' => null, + 'schema' => null, + ) + ); +} + + +/** + * This construct will swap between augmentation of the V1 and V2 API. + */ +if ( function_exists( 'register_rest_field' ) ) { + // The register_rest_field function was introduced in the v2 API. + // If that exists, then we call the function to augment that API. + add_action( 'rest_api_init', 'mitlib_api_v2_alter' ); +} else { + // If that function does not exist, then we call the old API augmentation. + if ( function_exists( 'get_fields' ) ) { + add_filter( 'json_prepare_post', 'mitlib_api_v1_alter', 10, 3 ); + } +} + +/** + * Get the value of a specified field for use in the API + * + * @param array $object Details of current post. + * @param string $field_name Name of field. + * + * @return mixed + */ +function mitlib_api_get_image( $object, $field_name ) { + $link = wp_get_attachment_image_src( $object[ $field_name ], 'thumbnail-size' ); + return $link[0]; } // Allows SVGs to be uploaded through media. diff --git a/js/alerts.js b/js/alerts.js index 11f27119..65ff8f94 100644 --- a/js/alerts.js +++ b/js/alerts.js @@ -1,118 +1,151 @@ // Loads alert-level posts on the top of all pages -$(function mitlib_alerts(){ - var closable_alert = false, - local_storage; - - // Check for localStorage - if (Modernizr.localstorage) { - local_storage = true; - } else { - local_storage = false; - } - - $.ajax({ - cache: false, - url: "/wp-json/posts", - dataType: "json" - }) - .done(function(json){ - var posts = json.length, - post, - alert_title, - post_meta, - is_alert, - confirm, - alert_posts_arr = [], - alert_ID, - alert_content, - alert_template; - - for (var i = 0; i < posts; i++) { - // Each post - post = json[i]; - // Make sure the field exists - if ($(post.meta).length) { - // Post meta fields - post_meta = post.meta; - // Make sure the field exists - if ($(post_meta.alert).length) { - // Post alert field - is_alert = post_meta.alert; - // If an alert post - if (is_alert === true) { - // Confirm alert field - confirm = post_meta.confirm_alert; - if (confirm === true) { - // Push alert posts to a unique array - alert_posts_arr.push(post); - } - } - } - } - }; - // If there is an alert post - if (alert_posts_arr.length) { - // The alert title - alert_title = alert_posts_arr[0].title; - // Check for empty title - if (alert_title === '') { - alert_title = 'Alert!' - } - // Alert post content - alert_content = alert_posts_arr[0].content; - // Alert post ID - alert_ID = alert_posts_arr[0].ID; - - // Alert HTML template - alert_template = '
' + - '
' + - '' + - '
' + - '

' + alert_title + '

' + alert_content + - '
' + - '
' + - '
'; - // Closeable alert - closable_alert = alert_posts_arr[0].meta.closable; - // If localStorage - if (local_storage === true) { - // Check for the localStorage alert ID item - if (localStorage.getItem('alert_closed-' + alert_ID) !== 'true') { - // Append the template - $(alert_template).prependTo('.wrap-page'); - $('.gldp-default').animate({"top":"292px"}); - // Remove the necessary transition class with a timeout, so that the animation shows. - setTimeout(function() { - $('.posts--preview--alerts').removeClass('transition-vertical--hide'); - }, 300); - } - } else { // No localStorage - // Append the template, etc. - $(alert_template).prependTo('.wrap-page'); - setTimeout(function() { - $('.posts--preview--alerts').removeClass('transition-vertical--hide'); - }, 300); - } - // If this is a closable alert - if (closable_alert === true) { - // Add a Close icon/svg/button - $('.posts--preview--alerts .post').append(''); - // On click - $('#close').click(function(){ - // Add the necessary transition hide class - $('.posts--preview--alerts').addClass('transition-vertical--hide'); - $('.gldp-default').css({"top":"105px"}); - // If localStorage - if (local_storage === true) { - // Set the localStorage item, using the post ID - localStorage.setItem('alert_closed-' + alert_ID, 'true'); - } - }); - } +function filterAlerts(posts) { + // This processes an array of posts for valid, confirmed, alerts + var filtered = [], + post, + post_meta, + i; + for (i = 0; i < posts.length; i++) { + // Each post + post = posts[i]; + // Make sure the field exists + if ($(post.meta).length) { + // Post meta fields + post_meta = post.meta; + // Make sure the field exists, is an alert, and is confirmed + if ($(post_meta.alert).length && true === post_meta.alert && true === post_meta.confirm_alert ) { + filtered.push(post); } + } + }; - }).fail(function(){ - console.log('Alert posts failed to load'); + return filtered; +} + +function renderAlert(markup,id) { + // If localStorage + if (Modernizr.localstorage) { + // Check for the localStorage alert ID item + if (localStorage.getItem('alert_closed-' + id) !== 'true') { + // Append the template + $(markup).prependTo('.wrap-page'); + $('.gldp-default').animate({"top":"292px"}); + // Remove the necessary transition class with a timeout, so that the animation shows. + setTimeout(function() { + $('.posts--preview--alerts').removeClass('transition-vertical--hide'); + }, 300); + } + } else { // No localStorage + // Append the template, etc. + $(markup).prependTo('.wrap-page'); + setTimeout(function() { + $('.posts--preview--alerts').removeClass('transition-vertical--hide'); + }, 300); + } +} + +function setClosable(alert_ID) { + // Add a Close icon/svg/button + $('.posts--preview--alerts .post').append(''); + // On click + $('#close').click(function(){ + // Add the necessary transition hide class + $('.posts--preview--alerts').addClass('transition-vertical--hide'); + $('.gldp-default').css({"top":"105px"}); + // If localStorage + if (Modernizr.localstorage) { + // Set the localStorage item, using the post ID + localStorage.setItem('alert_closed-' + alert_ID, 'true'); + } + }); +} + +function showAlertsV1(json) { + var alert_posts_arr = [], + alert_ID, + alert_template; + + alert_posts_arr = filterAlerts(json) + + // If there is an alert post + if (alert_posts_arr.length) { + + // Check for empty title + if ('' === alert_posts_arr[0].title) { + alert_posts_arr[0].title = 'Alert!'; + } + + // Alert post ID + alert_ID = alert_posts_arr[0].id; + + // Alert HTML template + alert_template = '
' + + '
' + + '' + + '
' + + '

' + alert_posts_arr[0].title + '

' + alert_posts_arr[0].content + + '
' + + '
' + + '
'; + + renderAlert(alert_template,alert_ID); + + // If this is a closable alert + if (true === alert_posts_arr[0].meta.closable) { + setClosable(alert_ID); + } + } +} + +function showAlertsV2(json) { + var alert_posts_arr = [], + alert_ID, + alert_template; + + alert_posts_arr = filterAlerts(json) + + // If there is an alert post + if (alert_posts_arr.length) { + + // Check for empty title + if ('' === alert_posts_arr[0].title.rendered) { + alert_posts_arr[0].title.rendered = 'Alert!'; + } + + // Alert HTML template + alert_template = '
' + + '
' + + '' + + '
' + + '

' + alert_posts_arr[0].title.rendered + '

' + alert_posts_arr[0].content.rendered + + '
' + + '
' + + '
'; + + // Alert post ID + alert_ID = alert_posts_arr[0].id; + + renderAlert(alert_template,alert_ID); + + // If this is a closable alert + if (true === alert_posts_arr[0].meta.closable) { + setClosable(alert_ID); + } + } +} + +$(function(){ + // This is a temporary construct to make transitioning between API endpoints seamless. + // It tries the v1 endpoint first, and if that fails then falls back to the v2 endpoint. + $.getJSON('/wp-json/posts') + .done(function(data){ + showAlertsV1(data); + }) + .fail(function(){ + $.getJSON('/wp-json/wp/v2/posts') + .done(function(data){ + showAlertsV2(data); + }); }); }); diff --git a/js/experts-home.js b/js/experts-home.js index b5bf00cc..d27e5aa7 100644 --- a/js/experts-home.js +++ b/js/experts-home.js @@ -2,86 +2,158 @@ // Experts // +// This implements a Fisher-Yates shuffle. +// See also: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle +function shuffleExperts(data) { + var m = data.length, t, i; + + // While there remain elements to shuffle… + while (m) { + + // Pick a remaining element… + i = Math.floor(Math.random() * m--); + + // And swap it with the current element. + t = data[m]; + data[m] = data[i]; + data[i] = t; + } + return data; +} + +// This parses the data structure returned by the V1 API +function parseExpertsV1(data) { + + // Expert names + var expertName1 = data[0].title; + var expertName2 = data[1].title; + var expertName3 = data[2].title; + var expertName4 = data[3].title; + + // Expert images + var expertPhoto1 = data[0].featured_image.source; + var expertPhoto2 = data[1].featured_image.source; + var expertPhoto3 = data[2].featured_image.source; + var expertPhoto4 = data[3].featured_image.source; + + // Expert job titles (post excerpts) + var expertExcerpt1 = data[0].excerpt; + var expertExcerpt2 = data[1].excerpt; + var expertExcerpt3 = data[2].excerpt; + var expertExcerpt4 = data[3].excerpt; + + // Expert URL (currently an ACF field) + var expertURL1 = data[0].meta.expert_url; + var expertURL2 = data[1].meta.expert_url; + var expertURL3 = data[2].meta.expert_url; + var expertURL4 = data[3].meta.expert_url; + + // Append extra markup only if JSON request successful + $('.expert').append(''); + // Append expert image div + $('.expert .link-profile').append(''); + // Append empty spans for expert names + $('.expert .link-profile').append(''); + // Append empty spans for expert titles + $('.expert .link-profile').append(''); + // Add expert name to appropriate span + $('.expert .name:eq(0)').text(expertName1); + $('.expert .name:eq(1)').text(expertName2); + $('.expert .name:eq(2)').text(expertName3); + $('.expert .name:eq(3)').text(expertName4); + // Add image URL to src attribute + $('.expert .expert-photo:eq(0)').attr('src', expertPhoto1); + $('.expert .expert-photo:eq(1)').attr('src', expertPhoto2); + $('.expert .expert-photo:eq(2)').attr('src', expertPhoto3); + $('.expert .expert-photo:eq(3)').attr('src', expertPhoto4); + // Add expert excerpt + $('.expert .title-job:eq(0)').html(expertExcerpt1); + $('.expert .title-job:eq(1)').html(expertExcerpt2); + $('.expert .title-job:eq(2)').html(expertExcerpt3); + $('.expert .title-job:eq(3)').html(expertExcerpt4); + // Add expert URL + $('.expert .link-profile:eq(0)').attr('href', expertURL1); + $('.expert .link-profile:eq(1)').attr('href', expertURL2); + $('.expert .link-profile:eq(2)').attr('href', expertURL3); + $('.expert .link-profile:eq(3)').attr('href', expertURL4); + // Add the expert count to the "All Experts" button + $('.view-experts .count').text(data.length); +} + +// This parses the data structure returned by the V2 API +function parseExpertsV2(data) { + + // Expert names + var expertName1 = data[0].title.rendered; + var expertName2 = data[1].title.rendered; + var expertName3 = data[2].title.rendered; + var expertName4 = data[3].title.rendered; + + // Expert images + var expertPhoto1 = data[0].featured_media; + var expertPhoto2 = data[1].featured_media; + var expertPhoto3 = data[2].featured_media; + var expertPhoto4 = data[3].featured_media; + + // Expert job titles (post excerpts) + var expertExcerpt1 = data[0].excerpt.rendered; + var expertExcerpt2 = data[1].excerpt.rendered; + var expertExcerpt3 = data[2].excerpt.rendered; + var expertExcerpt4 = data[3].excerpt.rendered; + + // Expert URL (currently an ACF field) + var expertURL1 = data[0].meta.expert_url; + var expertURL2 = data[1].meta.expert_url; + var expertURL3 = data[2].meta.expert_url; + var expertURL4 = data[3].meta.expert_url; + + // Append extra markup only if JSON request successful + $('.expert').append(''); + // Append expert image div + $('.expert .link-profile').append(''); + // Append empty spans for expert names + $('.expert .link-profile').append(''); + // Append empty spans for expert titles + $('.expert .link-profile').append(''); + // Add expert name to appropriate span + $('.expert .name:eq(0)').text(expertName1); + $('.expert .name:eq(1)').text(expertName2); + $('.expert .name:eq(2)').text(expertName3); + $('.expert .name:eq(3)').text(expertName4); + // Add image URL to src attribute + $('.expert .expert-photo:eq(0)').attr('src', expertPhoto1); + $('.expert .expert-photo:eq(1)').attr('src', expertPhoto2); + $('.expert .expert-photo:eq(2)').attr('src', expertPhoto3); + $('.expert .expert-photo:eq(3)').attr('src', expertPhoto4); + // Add expert excerpt + $('.expert .title-job:eq(0)').html(expertExcerpt1); + $('.expert .title-job:eq(1)').html(expertExcerpt2); + $('.expert .title-job:eq(2)').html(expertExcerpt3); + $('.expert .title-job:eq(3)').html(expertExcerpt4); + // Add expert URL + $('.expert .link-profile:eq(0)').attr('href', expertURL1); + $('.expert .link-profile:eq(1)').attr('href', expertURL2); + $('.expert .link-profile:eq(2)').attr('href', expertURL3); + $('.expert .link-profile:eq(3)').attr('href', expertURL4); + // Add the expert count to the "All Experts" button + $('.view-experts .count').text(data.length); +} + $(function(){ + // This is a temporary construct to make transitioning between API endpoints seamless. + // It tries the v1 endpoint first, and if that fails then falls back to the v2 endpoint. + // Much of this could be eliminated by just loading this URL: + // /wp-json/wp/v2/experts?filter[orderby]=rand&filter[posts_per_page]=4 $.getJSON('/wp-json/posts?type=experts') .done(function(data){ - // Count the objects - var dataLength = data.length; - - // Fisher–Yates Shuffle - function shuffle() { - var m = dataLength, t, i; - - // While there remain elements to shuffle… - while (m) { - - // Pick a remaining element… - i = Math.floor(Math.random() * m--); - - // And swap it with the current element. - t = data[m]; - data[m] = data[i]; - data[i] = t; - } - return data; - } - // Shuffle the array - shuffle(data); - - // Expert names - var expertName1 = data[0].title; - var expertName2 = data[1].title; - var expertName3 = data[2].title; - var expertName4 = data[3].title; - - // Expert images - var expertPhoto1 = data[0].featured_image.source; - var expertPhoto2 = data[1].featured_image.source; - var expertPhoto3 = data[2].featured_image.source; - var expertPhoto4 = data[3].featured_image.source; - - // Expert job titles (post excerpts) - var expertExcerpt1 = data[0].excerpt; - var expertExcerpt2 = data[1].excerpt; - var expertExcerpt3 = data[2].excerpt; - var expertExcerpt4 = data[3].excerpt; - - // Expert URL (currently an ACF field) - var expertURL1 = data[0].meta.expert_url; - var expertURL2 = data[1].meta.expert_url; - var expertURL3 = data[2].meta.expert_url; - var expertURL4 = data[3].meta.expert_url; - - // Append extra markup only if JSON request successful - $('.expert').append(''); - // Append expert image div - $('.expert .link-profile').append(''); - // Append empty spans for expert names - $('.expert .link-profile').append(''); - // Append empty spans for expert titles - $('.expert .link-profile').append(''); - // Add expert name to appropriate span - $('.expert .name:eq(0)').text(expertName1); - $('.expert .name:eq(1)').text(expertName2); - $('.expert .name:eq(2)').text(expertName3); - $('.expert .name:eq(3)').text(expertName4); - // Add image URL to src attribute - $('.expert .expert-photo:eq(0)').attr('src', expertPhoto1); - $('.expert .expert-photo:eq(1)').attr('src', expertPhoto2); - $('.expert .expert-photo:eq(2)').attr('src', expertPhoto3); - $('.expert .expert-photo:eq(3)').attr('src', expertPhoto4); - // Add expert excerpt - $('.expert .title-job:eq(0)').html(expertExcerpt1); - $('.expert .title-job:eq(1)').html(expertExcerpt2); - $('.expert .title-job:eq(2)').html(expertExcerpt3); - $('.expert .title-job:eq(3)').html(expertExcerpt4); - // Add expert URL - $('.expert .link-profile:eq(0)').attr('href', expertURL1); - $('.expert .link-profile:eq(1)').attr('href', expertURL2); - $('.expert .link-profile:eq(2)').attr('href', expertURL3); - $('.expert .link-profile:eq(3)').attr('href', expertURL4); - // Add the expert count to the "All Experts" button - $('.view-experts .count').text(dataLength); + parseExpertsV1(shuffleExperts(data)); + }) + .fail(function(){ + $.getJSON('/wp-json/wp/v2/experts?per_page=99') + .done(function(data){ + parseExpertsV2(shuffleExperts(data)); + }); }); + });