{"id":50,"date":"2019-11-24T10:32:54","date_gmt":"2019-11-24T16:32:54","guid":{"rendered":"https:\/\/travisolson.net\/code\/?p=50"},"modified":"2020-01-29T09:57:13","modified_gmt":"2020-01-29T15:57:13","slug":"wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links","status":"publish","type":"post","link":"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/","title":{"rendered":"WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links"},"content":{"rendered":"<p>This is a solution for creating a staff page using the WP Bakery post grid element.\u00a0 It uses a pop-up\/overlay to display details for each person instead of linking to a page. This assumes that you have WP Bakery, Custom Post Types UI, and Advanced Custom Fields plugins installed. It also uses a modal from Bootstrap to handle the pop-up, but this can be modified to use whatever modal pop-up library is used on your site.<\/p>\n<p>The first thing to do is create the People custom post type. In the Custom Post Types plugin, add a new post type.\u00a0 The easiest way to set it up is to just import the JSON configuration for the post type. <strong>HOWEVER, you should only use this if you don&#8217;t have any other custom post types already defined. Importing this will DELETE any other post types that have been defined. <\/strong>If you already have custom post types defined, then you&#8217;ll need to to set it up manually. You can copy all of the settings from the JSON below.\u00a0 Sure, it&#8217;s not that easy to read, but you&#8217;re a developer, so I&#8217;m sure you&#8217;ll figure it out.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\">{\"people\":{\"name\":\"people\",\"label\":\"People\",\"singular_label\":\"Person\",\"description\":\"This is for information for staff pages\",\"public\":\"true\",\"publicly_queryable\":\"true\",\"show_ui\":\"true\",\"show_in_nav_menus\":\"true\",\"show_in_rest\":\"true\",\"rest_base\":\"\",\"rest_controller_class\":\"\",\"has_archive\":\"false\",\"has_archive_string\":\"\",\"exclude_from_search\":\"false\",\"capability_type\":\"post\",\"hierarchical\":\"false\",\"rewrite\":\"true\",\"rewrite_slug\":\"\",\"rewrite_withfront\":\"true\",\"query_var\":\"true\",\"query_var_slug\":\"\",\"menu_position\":\"\",\"show_in_menu\":\"true\",\"show_in_menu_string\":\"\",\"menu_icon\":\"\",\"supports\":[\"title\",\"editor\",\"thumbnail\",\"custom-fields\",\"revisions\"],\"taxonomies\":[],\"labels\":{\"menu_name\":\"People\",\"all_items\":\"\",\"add_new\":\"\",\"add_new_item\":\"\",\"edit_item\":\"\",\"new_item\":\"\",\"view_item\":\"\",\"view_items\":\"\",\"search_items\":\"\",\"not_found\":\"\",\"not_found_in_trash\":\"\",\"parent_item_colon\":\"\",\"featured_image\":\"\",\"set_featured_image\":\"\",\"remove_featured_image\":\"\",\"use_featured_image\":\"\",\"archives\":\"\",\"insert_into_item\":\"\",\"uploaded_to_this_item\":\"\",\"filter_items_list\":\"\",\"items_list_navigation\":\"\",\"items_list\":\"\",\"attributes\":\"\",\"name_admin_bar\":\"\"},\"custom_supports\":\"\"}}<\/pre>\n<p>This will set up the People post type, and a new People menu item should display in the admin sidebar. The next step is to create custom fields associated with this post type. You can create whatever fields you need, but for this example we are using a <strong>Title<\/strong> field and <strong>Menu Order<\/strong> field. The Menu Order field is used to specify the exact order of each person in the post grid, but you can leave this out if you don&#8217;t want custom sorting.\u00a0 If you want to copy my ACF fields exactly, you can import my configurations: <a href=\"https:\/\/travisolson.net\/code\/wp-content\/uploads\/2019\/11\/acf-export-people.zip\" target=\"_blank\" rel=\"noopener noreferrer\">acf-export-people.zip.<\/a> Unzip the file and use the JSON file to import into ACF.<\/p>\n<p>Now that we have the basic data structure set up, you&#8217;ll want to populate some People records.\u00a0 Be sure to add featured images to each person so they will display in the post grid.<\/p>\n<p>Create a file in your theme named staff.php. In my example, the file is located in the {theme root}\/library directory, but you can place it anywhere in your theme.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">&lt;?php\r\nfunction myprefix_staff_init() {\r\n  add_action( 'wp_enqueue_scripts', 'myprefix_staff_scripts_and_styles', 999 );\r\n}\r\nadd_action( 'after_setup_theme', 'myprefix_staff_init' );\r\n\r\n\/\/ Enqueue staff Javascript file\r\nfunction myprefix_staff_scripts_and_styles() {\r\n  wp_enqueue_script( 'myprefix-staff', get_stylesheet_directory_uri() . '\/library\/js\/staff.js', array( 'jquery' ), '1.0', true );\r\n}\r\n\r\n\/* Set up AJAX function for loading staff popup template *\/\r\nfunction myprefix_ajax_staff_person() {\r\n  $slug = trim($_GET['slug']);\r\n  if (!empty($slug)) {\r\n    $args = array(\r\n      'name'        =&gt; $slug,\r\n      'post_type'   =&gt; 'people',\r\n      'post_status' =&gt; 'publish',\r\n      'numberposts' =&gt; 1\r\n    );\r\n    $people = get_posts($args);\r\n    if ($people) {\r\n      $person = $people[0];\r\n      include('staff-popup-template.php');\r\n    }\r\n  }\r\n  exit();\r\n}\r\nadd_action('wp_ajax_myprefix_staff_person', 'myprefix_ajax_staff_person');\r\nadd_action('wp_ajax_nopriv_myprefix_staff_person', 'myprefix_ajax_staff_person');\r\n\r\n\/* Return info for multiple people using slugs *\/\r\nfunction myprefix_ajax_staff_people() {\r\n  $slugs = trim($_POST['slugs']);\r\n  if (!empty($slugs)) {\r\n    $data = array();\r\n    foreach (explode(',', $slugs) as $slug) {\r\n      $args = array(\r\n        'name'        =&gt; $slug,\r\n        'post_type'   =&gt; 'people',\r\n        'post_status' =&gt; 'publish',\r\n        'numberposts' =&gt; 1\r\n      );\r\n      $people = get_posts($args);\r\n      if ($people) {\r\n        $person = $people[0];\r\n        ob_start();\r\n        include('staff-popup-template.php');\r\n        $html = ob_get_clean();\r\n        \r\n        $data[$slug] = array(\r\n          'ID' =&gt; $person-&gt;ID,\r\n          'name' =&gt; esc_html($person-&gt;post_title),\r\n          'html' =&gt; $html\r\n        );\r\n      }\r\n    }\r\n    echo json_encode($data);\r\n  }\r\n  exit();\r\n}\r\nadd_action('wp_ajax_myprefix_staff_people', 'myprefix_ajax_staff_people');\r\nadd_action('wp_ajax_nopriv_myprefix_staff_people', 'myprefix_ajax_staff_people');\r\n\r\n\/\/ Disable the Admin Columns plugin, if available, on the People admin page since it conflicts with the sort order plugin\r\nfunction myprefix_ac_post_types_remove_people($post_types) {\r\n  if (isset($post_types['people'])) {\r\n    unset($post_types['people']);\r\n  }\r\n\r\n  return $post_types;\r\n}\r\nadd_filter( 'ac\/post_types', 'myprefix_ac_post_types_remove_people' );\r\n\r\n\/\/ Show dropdown filter by department taxonomy on admin people list\r\nfunction myprefix_filter_people_by_taxonomy() {\r\n  global $typenow;\r\n  $post_type = 'people';\r\n  $taxonomy  = 'people_departments';\r\n  if ($typenow == $post_type) {\r\n    $selected      = isset($_GET[$taxonomy]) ? $_GET[$taxonomy] : '';\r\n    $info_taxonomy = get_taxonomy($taxonomy);\r\n    wp_dropdown_categories(array(\r\n      'show_option_all' =&gt; __(\"Show All {$info_taxonomy-&gt;label}\"),\r\n      'taxonomy'        =&gt; $taxonomy,\r\n      'name'            =&gt; $taxonomy,\r\n      'orderby'         =&gt; 'name',\r\n      'selected'        =&gt; $selected,\r\n      'show_count'      =&gt; true,\r\n      'hide_empty'      =&gt; true,\r\n    ));\r\n  };\r\n}\r\nadd_action('restrict_manage_posts', 'myprefix_filter_people_by_taxonomy');\r\n\r\n\/\/ Filter admin people list by department taxonomy\r\nfunction myprefix_convert_id_to_term_in_query($query) {\r\n  global $pagenow;\r\n  $post_type = 'people'; \/\/ change to your post type\r\n  $taxonomy  = 'people_departments'; \/\/ change to your taxonomy\r\n  $q_vars    = &amp;$query-&gt;query_vars;\r\n  if ( $pagenow == 'edit.php' &amp;&amp; isset($q_vars['post_type']) &amp;&amp; $q_vars['post_type'] == $post_type &amp;&amp; isset($q_vars[$taxonomy]) &amp;&amp; is_numeric($q_vars[$taxonomy]) &amp;&amp; $q_vars[$taxonomy] != 0 ) {\r\n    $term = get_term_by('id', $q_vars[$taxonomy], $taxonomy);\r\n    $q_vars[$taxonomy] = $term-&gt;slug;\r\n  }\r\n}\r\nadd_filter('parse_query', 'myprefix_convert_id_to_term_in_query');\r\n?&gt;<\/pre>\n<p>The code in this file handles multiple functions to support the Staff page. One of the main features is that it handles the AJAX calls that load a single person or multiple people.\u00a0 The AJAX call for loading multiple people is used to pre-load data for the staff pop-up, which improves performance compared to loading data for each person on the fly.<\/p>\n<p>To get this file to load, simply add a require_once statement in the theme&#8217;s functions.php file:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">require_once( 'library\/staff.php' );<\/pre>\n<p>We need to create some template files to support display of each person&#8217;s info. We will create a template for the pop-up, as well as a standard full-page template for the people post type that will handle the case where users don&#8217;t have JavaScript enabled.<\/p>\n<p>In the library directory, create <strong>staff-popup-template.php<\/strong>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">&lt;div class=\"staff-popup\"&gt;\r\n  &lt;div class=\"staff-thumb\"&gt;&lt;?php echo get_the_post_thumbnail($person, 'medium'); ?&gt;&lt;\/div&gt;\r\n  &lt;div class=\"staff-title\"&gt;\r\n    &lt;?php echo esc_html($person-&gt;post_title); ?&gt;\r\n    \r\n    &lt;?php\r\n    $person_title = get_field('people_title', $person-&gt;ID);\r\n    if (!empty($person_title)) {\r\n    ?&gt;\r\n      &lt;span class=\"staff-position\"&gt;&lt;?php echo esc_html($person_title); ?&gt;&lt;\/span&gt;\r\n    &lt;?php\r\n    }\r\n    ?&gt;\r\n    \r\n  &lt;\/div&gt;\r\n  &lt;div class=\"staff-bio\"&gt;&lt;?php echo apply_filters('the_content', strip_shortcodes($person-&gt;post_content)); ?&gt;&lt;\/div&gt;\r\n&lt;\/div&gt;<\/pre>\n<p>In the theme root directory create <strong>single-people.php<\/strong>. This will automatically become the template for displaying a single record of the people post type.\u00a0 The best way to do this is to copy single.php from your theme, and then insert the following in to the content section of your template.\u00a0 It would look something like this:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">&lt;?php get_header(); ?&gt;\r\n&lt;div id=\"content\"&gt;\r\n  &lt;div id=\"inner-content\" class=\"container\"&gt;\r\n    &lt;div class=\"row\"&gt;\r\n      &lt;div id=\"main\" class=\"col-md-12\" role=\"main\" itemscope itemprop=\"mainContentOfPage\" itemtype=\"http:\/\/schema.org\/Blog\"&gt;\r\n        &lt;?php if (have_posts()) : while (have_posts()) : the_post(); ?&gt;\r\n          &lt;article id=\"post-&lt;?php the_ID(); ?&gt;\" &lt;?php post_class('cf'); ?&gt; role=\"article\" itemscope itemprop=\"blogPost\" itemtype=\"http:\/\/schema.org\/BlogPosting\"&gt;\r\n            &lt;div class=\"staff-thumb\"&gt;&lt;?php the_post_thumbnail($person, 'medium'); ?&gt;&lt;\/div&gt;\r\n            &lt;div class=\"staff-title\"&gt;\r\n              &lt;h1 itemprop=\"headline\" rel=\"bookmark\"&gt;&lt;?php the_title(); ?&gt;&lt;\/h1&gt;\r\n              \r\n              &lt;?php\r\n              $person_title = get_field('people_title');\r\n              if (!empty($person_title)) {\r\n              ?&gt;\r\n                &lt;span class=\"staff-position\"&gt;&lt;?php echo esc_html($person_title); ?&gt;&lt;\/span&gt;\r\n              &lt;?php\r\n              }\r\n              ?&gt;\r\n            &lt;\/div&gt;\r\n            &lt;div class=\"staff-bio\"&gt;&lt;?php the_content(); ?&gt;&lt;\/div&gt;\r\n          &lt;\/article&gt;\r\n        &lt;?php endwhile; ?&gt;\r\n        \r\n        &lt;?php else : ?&gt;\r\n          &lt;article id=\"post-not-found\" class=\"hentry cf\"&gt;\r\n            &lt;header class=\"article-header\"&gt;\r\n              &lt;h1&gt;&lt;?php _e( 'Oops, Person Not Found!', 'mytheme' ); ?&gt;&lt;\/h1&gt;\r\n            &lt;\/header&gt;\r\n            &lt;section class=\"entry-content\"&gt;\r\n              &lt;p&gt;&lt;?php _e( 'Uh Oh. Something is missing. Try double checking things.', 'mytheme' ); ?&gt;&lt;\/p&gt;\r\n            &lt;\/section&gt;\r\n          &lt;\/article&gt;\r\n        &lt;?php endif; ?&gt;\r\n        &lt;\/div&gt;\r\n    &lt;\/div&gt;\r\n  &lt;\/div&gt;\r\n&lt;\/div&gt;\r\n&lt;?php get_footer(); ?&gt;<\/pre>\n<p>You will need to adjust the HTML to fit your site&#8217;s theme.<\/p>\n<p>Now we can add the JavaScript required to handle the functionality on the Staff page. The staff.php page already attempts to enqueue this file.\u00a0 In this example, <strong>staff.js<\/strong> is located in {theme root}\/library\/js.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"js\">jQuery(document).ready(function($) {\r\n  var staff_grid_class = 'people-grid';\r\n  var staff_loaded_once = false;\r\n  if ($('.' + staff_grid_class).length &gt; 0) {\r\n    $(window).on('grid:items:added', function(e, element) {\r\n      element = $(element);\r\n      if (element.hasClass(staff_grid_class)) {\r\n        element.off('click');\r\n      }\r\n      if (!staff_loaded_once) {\r\n        open_staff_from_url();\r\n      }\r\n      staff_loaded_once = true;\r\n    });\r\n    \r\n    var slugs = [];\r\n    $('.' + staff_grid_class + ' .vc_grid-item a').each(function(key, person_link) {\r\n      person_slug = get_grid_link_slug($(person_link));\r\n      slugs.push(person_slug);\r\n    });\r\n    $.post('\/wp-admin\/admin-ajax.php?action=myprefix_staff_people', {slugs: slugs.join(',')}, function(data) {\r\n      localStorage.setItem('myprefix_people', data);\r\n    });\r\n    \r\n    \r\n    $('body').on('click', '.' + staff_grid_class + ' .vc_grid-item a', function(e) {\r\n      e.preventDefault();\r\n      title = $(this).attr('title');\r\n      person_slug = get_grid_link_slug($(this));\r\n      people_data = localStorage.getItem('myprefix_people') ? JSON.parse(localStorage.getItem('myprefix_people')) : null;\r\n      if (people_data &amp;&amp; people_data[person_slug]) {\r\n        person = people_data[person_slug];\r\n        if ($('#myprefix_person_info').length == 0) {\r\n          $('body').append('&lt;div id=\"myprefix_person_info\" style=\"display:none;\"&gt;&lt;\/div&gt;');\r\n        }\r\n        $('#myprefix_person_info').data('popup-title', person.name);\r\n        $('#myprefix_person_info').html(person.html);\r\n        myprefix_popup('myprefix_person_info');\r\n      }\r\n      else {\r\n        url = '\/wp-admin\/admin-ajax.php?action=myprefix_staff_person&amp;slug=' + person_slug;\r\n        myprefix_popup_ajax(url, title, 800);\r\n      }\r\n      return false;\r\n    });\r\n  }\r\n  \r\n  function open_staff_from_url() {\r\n    url_hash = location.hash;\r\n    if (url_hash.length &gt; 0) {\r\n      person_link = $('.' + staff_grid_class + ' .vc_grid-item a[href$=\"\/people\/' + url_hash.replace('#', '') + '\/\"]');\r\n      if (person_link.length &gt; 0) {\r\n        person_link.click();\r\n      }\r\n    }\r\n  }\r\n  $( window ).on( 'hashchange', function( e ) {\r\n    open_staff_from_url();\r\n  });\r\n  \r\n  function get_grid_link_slug(url) {\r\n    link_parts = url.attr('href').split('\/people\/');\r\n    slug = link_parts[link_parts.length - 1].replace('\/', '');\r\n    slug_parts = slug.split('?');\r\n    return slug_parts[0];\r\n  }\r\n});\r\n\r\nif (typeof myprefix_popup == 'undefined') {\r\n  function myprefix_popup(element_id) {\r\n    if (jQuery('#'+element_id).length &gt; 0) {\r\n      jQuery(\"#myprefix-popup-modal .modal-body p\").html(jQuery('#'+element_id).html());\r\n      var title = jQuery('#'+element_id).data('popup-title');\r\n      if (title &amp;&amp; title.length &gt; 0) {\r\n        if (jQuery('#myprefix-popup-modal .modal-header h5').length &gt; 0) {\r\n          jQuery('#myprefix-popup-modal .modal-header h5').html(title);\r\n        }\r\n        else {\r\n          jQuery('#myprefix-popup-modal .modal-header').prepend('&lt;h5 class=\"modal-title\"&gt;' + title + '&lt;\/h5&gt;');\r\n        }\r\n      }\r\n      else {\r\n        jQuery('#myprefix-popup-modal .modal-header h5').html('');\r\n      }\r\n      jQuery('#myprefix-popup-modal').modal(\"show\");\r\n    }\r\n  }\r\n}\r\n\r\nif (typeof myprefix_popup_ajax == 'undefined') {\r\n  function myprefix_popup_ajax(url, title, width) {\r\n    if (url.length &gt; 0) {\r\n      if (typeof title !== 'undefined' &amp;&amp; title.length &gt; 0) {\r\n        if (jQuery('#myprefix-popup-modal .modal-header h5').length &gt; 0) {\r\n          jQuery('#myprefix-popup-modal .modal-header h5').html(title);\r\n        }\r\n        else {\r\n          jQuery('#myprefix-popup-modal .modal-header').prepend('&lt;h5 class=\"modal-title\"&gt;' + title + '&lt;\/h5&gt;');\r\n        }\r\n      }\r\n      var popup_width = (typeof width !== 'undefined') ? width : 500;\r\n      jQuery('#myprefix-popup-modal .modal-dialog').css('width', popup_width+'px').css('maxWidth', '90%');\r\n      jQuery(\"#myprefix-popup-modal .modal-body p\").html('loading...').load(url);\r\n      jQuery('#myprefix-popup-modal').modal(\"show\");\r\n    }\r\n  }\r\n}<\/pre>\n<p>The bottom part of the JS file includes functions to open a Bootstrap modal.\u00a0 These can be changed to use any modal\/dialog\/pop-up supported by your theme.\u00a0 In this case, if you want to use Bootstrap, then you&#8217;ll need to add the following to your footer.php file, before the &lt;\/body&gt; tag:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"null\">&lt;div class=\"modal fade\" id=\"myprefix-popup-modal\" role=\"dialog\"&gt;\r\n  &lt;div class=\"modal-dialog\"&gt;\r\n    &lt;div class=\"modal-content\"&gt;\r\n      &lt;div class=\"modal-header\"&gt;\r\n        &lt;button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"&gt;\r\n          &lt;span aria-hidden=\"true\"&gt;&amp;times;&lt;\/span&gt;\r\n        &lt;\/button&gt;\r\n      &lt;\/div&gt;\r\n      &lt;div class=\"modal-body\"&gt;\r\n        &lt;p class=\"error\"&gt;&lt;\/p&gt;\r\n      &lt;\/div&gt;\r\n    &lt;\/div&gt;\r\n  &lt;\/div&gt;\r\n&lt;\/div&gt;\r\n<\/pre>\n<p>The modal div should be hidden by default using CSS in the Bootstrap styles. Next we&#8217;ll want to add custom styles for our modal.\u00a0 In your theme&#8217;s CSS file, add the following.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"css\">\/* Staff popup *\/\r\n\r\n.modal-header {\r\n  padding-bottom: 0!important;\r\n  border: none!important;\r\n}\r\n\r\n.modal-header .close {\r\n  width:auto;\r\n}\r\n\r\n.modal-body {\r\n  padding-top: 0!important;\r\n}\r\n\r\n.modal-body h3{\r\n  margin-bottom: 0;\r\n}\r\n\r\n.modal-title{display: none!important}\r\n\r\n\/* Staff Details page*\/\r\n\r\n.people_departments-staff{\r\n  padding-top: 2rem;\r\n  padding-bottom: 2rem;\r\n}\r\n\r\n@media (min-width: 576px){\r\n  .modal-dialog {\r\n    max-width: 1080px!important;\r\n    width: 80%!important;\r\n    margin-top: 3rem;\r\n  }\r\n}\r\n\r\n@media (min-width: 768px){\r\n  .staff-popup img{\r\n    float: left;\r\n    margin: 8px 25px 10px 0;\r\n  }\r\n}\r\n\r\n@media (min-width: 992px){\r\n  .modal-body {\r\n    padding: 3rem!important;\r\n    padding-top: 0!important;\r\n  }\r\n}\r\n\r\n@media (min-width: 1280px){\r\n  .modal-dialog {\r\n    margin-top: 5rem;\r\n  }\r\n  \r\n  .people_departments-staff{\r\n    padding-top: 4rem;\r\n    padding-bottom: 4rem;\r\n  }\r\n}\r\n\r\n\/* Popup *\/\r\n\r\n.modal-backdrop {\r\n    background-color: #C9B390!important;\r\n  opacity: .8!important\r\n}\r\n\r\n.modal-content {\r\n    border-radius: 0;\r\n  border: 2px solid #be0a26;\r\n}\r\n\r\n.close {\r\n    font-size: 2.5rem!important;\r\n    font-weight: 400!important;\r\n    color: #be0a26!important;\r\n    opacity: 1!important;\r\n}\r\n\r\n.staff-popup img,\r\n.people_departments-staff .staff-thumb img{\r\n  border-radius: 250px!important;\r\n  border: 4px solid #be0a26;\t\t\r\n}\r\n\r\n.staff-popup h2{\r\n  font: 24px\/1 \"Open Sans Condensed\", sans-serif;\r\n  text-transform: uppercase;\r\n}\r\n\r\n.staff-popup h4{\r\n  font: 400 18px\/1.5 \"Karla\", Arial, Helvetica, sans-serif;\r\n  text-transform: uppercase;\r\n  margin-bottom: 2.5rem;\r\n}\r\n\r\n.staff-thumb img{\r\n  float: none;\r\n}\r\n\r\n.staff-title {\r\n  font-family: \"Open Sans Condensed\", sans-serif;\r\n  font-size: 24px;\r\n  text-transform: uppercase;\r\n}\r\n\r\n.staff-title span.staff-position{\r\n  font-family: \"Karla\", Arial, Helvetica, sans-serif;\r\n  font-size: 16px;\r\n  display: block;\r\n}\r\n\r\n.staff-bio{\r\n  padding-top: 2rem\r\n}\r\n\r\n.single-people .staff-title h1 {\r\n  font-size: 24px;\r\n}\r\n\r\n.single-people .staff-title {\r\n  padding-top:0;\r\n}\r\n\r\n@media (min-width: 768px){\t\r\n  .staff-title span.staff-position:after{\r\n    margin: 30px 0 0!important;\r\n  }\r\n  \r\n  .modal-body{\r\n    padding: 0 3rem 2.5rem!important\r\n  }\r\n  \r\n  .staff-thumb {\r\n    float: left;\r\n    width: 30%\r\n  }\r\n  \r\n  .staff-title {\r\n    float: right;\r\n    width: 65%;\r\n    padding-top: 1.5rem;\r\n    font-size: 30px;\r\n  }\r\n  \r\n  .staff-bio{\r\n    clear: both;\r\n  }\r\n  \r\n  .people_departments-staff .staff-title,\r\n  .people_departments-staff .staff-bio{\r\n    clear: none!important;\r\n    float: none!important;\r\n    width: 100%!important;\r\n    padding: 0!important;\r\n  }\r\n  \r\n  .people_departments-staff .staff-thumb{\r\n    margin-right: 2rem;\r\n    margin-bottom: 1rem;\r\n    width: auto;\r\n  }\r\n  \r\n  .people_departments-staff .staff-thumb img{\r\n    margin-bottom:1rem;\r\n  }\r\n  \r\n  .people_departments-staff .staff-title span.staff-position:after {\r\n    margin: 30px 0 25px 332px!important;\r\n  }\r\n}\r\n\r\n@media (min-width: 992px){\r\n  .staff-thumb {\r\n    width: 40%\r\n  }\r\n  \r\n  .staff-title{\r\n    width: 55%;\r\n    padding-top: 4rem;\r\n    font-size: 36px;\r\n  }\r\n  \r\n  .staff-title span.staff-position{\r\n    font-size: 20px;\r\n  }\r\n  \r\n  .people_departments-staff .staff-thumb{\r\n    width: auto;\r\n  }\r\n  \r\n}\r\n\r\n@media (min-width: 1200px){\r\n  .staff-thumb {\r\n    width: 300px;\r\n  }\r\n  .staff-title {\r\n    width:calc(100% - 350px);\r\n    padding-top: 4rem;\r\n  }\t\r\n  .staff-title span.staff-position{\r\n    font-size: 20px;\r\n  }\r\n  .staff-title span.staff-position:after{\r\n    margin: 50px 0 0!important;\r\n  }\r\n  \r\n  .people_departments-staff .staff-thumb{\r\n    width: auto;\r\n  }\r\n  \r\n  .people_departments-staff .staff-thumb {\r\n    \tmargin-right: 4rem;\r\n  }\r\n  \r\n  .people_departments-staff .staff-title span.staff-position:after {\r\n    margin: 30px 0 25px 360px!important;\r\n  }\r\n}\r\n\r\n@media (min-width: 1280px){\r\n  .modal-body {\r\n    padding: 0 5rem 4.5rem!important;\r\n  }\r\n  .staff-title {\r\n    font-size: 48px;\r\n  }\t\r\n  .staff-title span.staff-position{\r\n    font-size: 24px;\r\n  }\r\n  \r\n}\r\n\r\n@media (max-width: 767px){\r\n  .staff-popup *{\r\n    text-align: center!important;\r\n  }\r\n  .staff-popup img{\r\n    display: block;\r\n    margin: 0 auto 2rem;\r\n  }\r\n  \r\n  .people_departments-staff .staff-thumb,\r\n  .people_departments-staff .staff-title,\r\n  .people_departments-staff .staff-bio{\r\n    text-align: center\r\n  }\r\n}<\/pre>\n<p>Still with me? Now we get to the part where we actually show the post grid. We need to create a new Page and enable the WP Bakery builder in the editor.\u00a0 Then add a new Post Grid element to the page. In the settings for the post grid:<\/p>\n<ul>\n<li>Set &#8220;Data Source&#8221; to &#8220;People&#8221;.<\/li>\n<li>Enter the &#8220;Total Items&#8221; to display on a page. Use -1 if you want to show all.<\/li>\n<li>Set &#8220;Extra Class Name&#8221; to &#8220;people-grid&#8221;. This is the class name that is used as the selector in staff.js to load the functionality on the grid.<\/li>\n<li>In the Item Design tab, select a Grid Element Template or create your own. You can create your own and add the custom ACF Title field to the display.<\/li>\n<\/ul>\n<p>Now just save the page and view it on the user side.\u00a0 You should see a grid of users, with links that open the Bootstrap modal.<\/p>\n<p>If you look in the Network inspector in your browser&#8217;s debug tools, you will notice that it is making an AJAX call that returns all of the staff details into local storage, indexed by person slug. This will make the pop-ups load more quickly since all of the data has been stored in the browser. In case the user clicks on a link for the staff data has been loaded, it will use an AJAX call to load the person&#8217;s specific data into the modal.\u00a0 And if the user doesn&#8217;t have JS enabled at all, or if the page hasn&#8217;t wired up the custom click events yet, it should just load the single person page that we set up.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a solution for creating a staff page using the WP Bakery post grid element.\u00a0 It uses a pop-up\/overlay to display details for each person instead of linking to a page. This assumes that you have WP Bakery, Custom Post Types UI, and Advanced Custom Fields plugins installed. It also uses a modal from&#8230;  <a class=\"excerpt-read-more\" href=\"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/\" title=\"Read WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links\">Read more &raquo;<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,2,5],"tags":[],"class_list":["post-50","post","type-post","status-publish","format-standard","hentry","category-jquery","category-wordpress","category-wp-bakery"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.9 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links - Travis Olson&#039;s Code Snippets<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links - Travis Olson&#039;s Code Snippets\" \/>\n<meta property=\"og:description\" content=\"This is a solution for creating a staff page using the WP Bakery post grid element.\u00a0 It uses a pop-up\/overlay to display details for each person instead of linking to a page. This assumes that you have WP Bakery, Custom Post Types UI, and Advanced Custom Fields plugins installed. It also uses a modal from... Read more &raquo;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/\" \/>\n<meta property=\"og:site_name\" content=\"Travis Olson&#039;s Code Snippets\" \/>\n<meta property=\"article:published_time\" content=\"2019-11-24T16:32:54+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-01-29T15:57:13+00:00\" \/>\n<meta name=\"author\" content=\"Travis Olson\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Travis Olson\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"14 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/\"},\"author\":{\"name\":\"Travis Olson\",\"@id\":\"https:\/\/www.travisolson.net\/code\/#\/schema\/person\/0170ab5b2e7a3d88436375cc50336934\"},\"headline\":\"WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links\",\"datePublished\":\"2019-11-24T16:32:54+00:00\",\"dateModified\":\"2020-01-29T15:57:13+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/\"},\"wordCount\":999,\"publisher\":{\"@id\":\"https:\/\/www.travisolson.net\/code\/#\/schema\/person\/0170ab5b2e7a3d88436375cc50336934\"},\"articleSection\":[\"jQuery\",\"WordPress\",\"WP Bakery\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/\",\"url\":\"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/\",\"name\":\"WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links - Travis Olson&#039;s Code Snippets\",\"isPartOf\":{\"@id\":\"https:\/\/www.travisolson.net\/code\/#website\"},\"datePublished\":\"2019-11-24T16:32:54+00:00\",\"dateModified\":\"2020-01-29T15:57:13+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.travisolson.net\/code\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.travisolson.net\/code\/#website\",\"url\":\"https:\/\/www.travisolson.net\/code\/\",\"name\":\"Travis Olson&#039;s Code Snippets\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/www.travisolson.net\/code\/#\/schema\/person\/0170ab5b2e7a3d88436375cc50336934\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.travisolson.net\/code\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/www.travisolson.net\/code\/#\/schema\/person\/0170ab5b2e7a3d88436375cc50336934\",\"name\":\"Travis Olson\",\"logo\":{\"@id\":\"https:\/\/www.travisolson.net\/code\/#\/schema\/person\/image\/\"},\"url\":\"https:\/\/www.travisolson.net\/code\/author\/travis-olson\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links - Travis Olson&#039;s Code Snippets","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/","og_locale":"en_US","og_type":"article","og_title":"WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links - Travis Olson&#039;s Code Snippets","og_description":"This is a solution for creating a staff page using the WP Bakery post grid element.\u00a0 It uses a pop-up\/overlay to display details for each person instead of linking to a page. This assumes that you have WP Bakery, Custom Post Types UI, and Advanced Custom Fields plugins installed. It also uses a modal from... Read more &raquo;","og_url":"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/","og_site_name":"Travis Olson&#039;s Code Snippets","article_published_time":"2019-11-24T16:32:54+00:00","article_modified_time":"2020-01-29T15:57:13+00:00","author":"Travis Olson","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Travis Olson","Est. reading time":"14 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/#article","isPartOf":{"@id":"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/"},"author":{"name":"Travis Olson","@id":"https:\/\/www.travisolson.net\/code\/#\/schema\/person\/0170ab5b2e7a3d88436375cc50336934"},"headline":"WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links","datePublished":"2019-11-24T16:32:54+00:00","dateModified":"2020-01-29T15:57:13+00:00","mainEntityOfPage":{"@id":"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/"},"wordCount":999,"publisher":{"@id":"https:\/\/www.travisolson.net\/code\/#\/schema\/person\/0170ab5b2e7a3d88436375cc50336934"},"articleSection":["jQuery","WordPress","WP Bakery"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/","url":"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/","name":"WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links - Travis Olson&#039;s Code Snippets","isPartOf":{"@id":"https:\/\/www.travisolson.net\/code\/#website"},"datePublished":"2019-11-24T16:32:54+00:00","dateModified":"2020-01-29T15:57:13+00:00","breadcrumb":{"@id":"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.travisolson.net\/code\/wordpress-staff-page-using-wp-bakery-post-grid-and-custom-pop-up-links\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.travisolson.net\/code\/"},{"@type":"ListItem","position":2,"name":"WordPress: Staff Page Using WP Bakery Post Grid and Custom Pop-up Links"}]},{"@type":"WebSite","@id":"https:\/\/www.travisolson.net\/code\/#website","url":"https:\/\/www.travisolson.net\/code\/","name":"Travis Olson&#039;s Code Snippets","description":"","publisher":{"@id":"https:\/\/www.travisolson.net\/code\/#\/schema\/person\/0170ab5b2e7a3d88436375cc50336934"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.travisolson.net\/code\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.travisolson.net\/code\/#\/schema\/person\/0170ab5b2e7a3d88436375cc50336934","name":"Travis Olson","logo":{"@id":"https:\/\/www.travisolson.net\/code\/#\/schema\/person\/image\/"},"url":"https:\/\/www.travisolson.net\/code\/author\/travis-olson\/"}]}},"_links":{"self":[{"href":"https:\/\/www.travisolson.net\/code\/wp-json\/wp\/v2\/posts\/50","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.travisolson.net\/code\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.travisolson.net\/code\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.travisolson.net\/code\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.travisolson.net\/code\/wp-json\/wp\/v2\/comments?post=50"}],"version-history":[{"count":6,"href":"https:\/\/www.travisolson.net\/code\/wp-json\/wp\/v2\/posts\/50\/revisions"}],"predecessor-version":[{"id":58,"href":"https:\/\/www.travisolson.net\/code\/wp-json\/wp\/v2\/posts\/50\/revisions\/58"}],"wp:attachment":[{"href":"https:\/\/www.travisolson.net\/code\/wp-json\/wp\/v2\/media?parent=50"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.travisolson.net\/code\/wp-json\/wp\/v2\/categories?post=50"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.travisolson.net\/code\/wp-json\/wp\/v2\/tags?post=50"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}