This members-only tutorial provides the steps to show post title links in the sidebar and using Ajax to fetch and load the corresponding entry when a title is clicked based on this excellent article from wpmudev.
While the tutorial has been written for Genesis Sample, it should work with a few adjustments in any Genesis or WordPress theme.
The process flow for making an Ajax call in WordPress can be summarized like so:
Step 1: The PHP
Let’s create a custom Page template having the code to
- force sidebar-content layout.
- relocate the entry header from its default position to before the content-sidebar wrap.
- remove primary sidebar from the primary sidebar area.
- use a custom WP_Query to output linked titles of all the posts in the primary sidebar area.
- pass admin-ajax.php’s URL and a loading image URL to `load-post.js` and load it in the footer.
Create a file named say, template-ajax-load.php in the child theme directory having the following:
<?php
/* Template Name: AJAX Load */
// Forces sidebar-content layout setting.
add_filter( 'genesis_pre_get_option_site_layout', '__genesis_return_sidebar_content' );
/* Relocates entry header */
remove_action( 'genesis_entry_header', 'genesis_entry_header_markup_open', 5 );
remove_action( 'genesis_entry_header', 'genesis_do_post_title' );
remove_action( 'genesis_entry_header', 'genesis_entry_header_markup_close', 15 );
add_action( 'genesis_before_content_sidebar_wrap', 'genesis_entry_header_markup_open' );
add_action( 'genesis_before_content_sidebar_wrap', 'genesis_do_post_title' );
add_action( 'genesis_before_content_sidebar_wrap', 'genesis_entry_header_markup_close' );
// Removes Primary Sidebar from the Primary Sidebar area.
remove_action( 'genesis_sidebar', 'genesis_do_sidebar' );
add_action( 'genesis_sidebar', 'sk_show_post_links' );
/**
* Outputs links to all the posts in the Primary Sidebar area.
*/
function sk_show_post_links() {
// WP_Query arguments.
$args = array(
'posts_per_page' => '-1',
// 'post_type' => 'gs_faq',
);
// The Query.
$query = new WP_Query( $args );
// The Loop.
if ( $query->have_posts() ) {
echo '<ul>';
while ( $query->have_posts() ) {
$query->the_post();
printf( '<li><a href="%s" class="post-link" data-id="%s">%s</a></li>',
esc_url( get_the_permalink() ),
get_the_ID(),
esc_html( get_the_title() )
);
}
echo '</ul>';
} else {
// no posts found.
}
// Restore original Post Data.
wp_reset_postdata();
}
add_action( 'wp_enqueue_scripts', 'sk_load_post_script' );
/**
* Passes WP AJAX URL and loading image URL to `load-post.js` and loads it in the footer.
*/
function sk_load_post_script() {
wp_enqueue_script(
'sk-loadpost',
get_stylesheet_directory_uri() . '/js/load-post.js',
array( 'jquery' ),
CHILD_THEME_VERSION,
true
);
wp_localize_script(
'sk-loadpost',
'sk_ajaxobject',
array(
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'loadingimage' => get_stylesheet_directory_uri() . '/images/loading.gif',
)
);
}
genesis();
Note:
a) If you wish to have the solution work with entries of a Custom Post Type instead of the standard posts, uncomment
'post_type' => 'gs_faq',
and specify your post type.
b) We are setting a class of post-link
for each title link and adding the ID of that entry as the value of data-id
attribute. Later in the JS file, we will retrieve this ID and pass it along in our Ajax request to the server.
c) In the sk_load_post_script() function, we are sending the URL of WordPress’s main Ajax handler, wp-admin/admin-ajax.php and that of a loading indicator image onto load-post.js (which, we are going to create next).
d) Upload loading.gif image (downloaded from here) to child theme’s images directory.
Step 2: The Javascript
Create a file named load-post.js
in child theme’s js
directory having the following:
(function ($) {
$(document).on('click', 'a.post-link', function (event) {
event.preventDefault();
$.ajax({
// URL to which request is sent.
url: sk_ajaxobject.ajaxurl,
// specifies how contents of data option are sent to the server.
// `post` indicates that we are submitting the data.
type: 'post',
// data to be sent to the server.
data: {
// a function defined in functions.php hooked to this action (with `wp_ajax_nopriv_` and/or `wp_ajax_` prefixed) will run.
action: 'sk_load_post',
// stores the value of `data-id` attribute of the clicked link in a variable.
post_id: $(this).data('id')
},
// pre-reqeust callback function.
beforeSend: function () {
$('.content > .entry .entry-content').html('<img src="' + sk_ajaxobject.loadingimage + '" />');
},
// function to be called if the request succeeds.
// `response` is data returned from the server.
success: function (response) {
$('.content > .entry .entry-content').hide().html(response).fadeIn('slow');
}
})
})
})(jQuery);
The Ajax call gets triggered by the click event everytime any of the post title links are clicked.
Note the name of the action, sk_load_post
. In the next step, we are going to define the code that should be output on the frontend in a function hooked to this action. The output of this function is what gets sent back to the .js file as the response
data.
Steps 3 and 4: functions.php
Add the following in child theme’s functions.php:
add_action( 'wp_ajax_nopriv_sk_load_post', 'sk_load_post' );
add_action( 'wp_ajax_sk_load_post', 'sk_load_post' );
/**
* Outputs entry header, entry content and entry footer for the specified post.
*/
function sk_load_post() {
$args = array(
'posts_per_page' => '1',
'no_found_rows' => true,
// set post id to the ID of the post whose title has been clicked via `load-post.js`.
'p' => intval( $_POST['post_id'] ),
'post_type' => get_post_type( $_POST['post_id'] ),
);
$loop = new WP_Query( $args );
// sets up the post, sets the ‘in the loop’ property to true.
$loop->the_post();
/* entry header */
do_action( 'genesis_entry_header' );
/* entry content */
do_action( 'genesis_before_entry_content' );
printf( '<div %s>', genesis_attr( 'entry-content' ) );
do_action( 'genesis_entry_content' );
echo '</div>';
do_action( 'genesis_after_entry_content' );
/* entry footer */
do_action( 'genesis_entry_footer' );
// restores original post data.
wp_reset_postdata();
// prevents echoing out `0` via the die function in admin-ajax.php, in addition to the above output.
die();
}
Note:
a) Functions hooked to wp_ajax_nopriv_{action_name}
run on the frontend for users that are not logged in and functions hooked to wp_ajax_{action_name}
run on the frontend for users that are logged in.
b) If you wish to display the entire post incl. the comments section, author box (if enabled) etc, replace
// sets up the post, sets the ‘in the loop’ property to true.
$loop->the_post();
/* entry header */
do_action( 'genesis_entry_header' );
/* entry content */
do_action( 'genesis_before_entry_content' );
printf( '<div %s>', genesis_attr( 'entry-content' ) );
do_action( 'genesis_entry_content' );
echo '</div>';
do_action( 'genesis_after_entry_content' );
/* entry footer */
do_action( 'genesis_entry_footer' );
// restores original post data.
wp_reset_postdata();
with
genesis_custom_loop( $args );
Step 5: CSS
Let’s add CSS to ensure that the links appear above the loaded content 959px and below.
.page-template-template-ajax-load .entry-header {
margin-bottom: 40px;
}
.sidebar-content .content-sidebar-wrap {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.sidebar-content .sidebar {
-webkit-box-ordinal-group: 1;
-ms-flex-order: 0;
order: 0;
margin-bottom: 60px;
}
.sidebar-content .content {
-webkit-box-ordinal-group: 2;
-ms-flex-order: 1;
order: 1;
}
To make sure this looks alright from 960px and above, in the 960px min-width media query, add
.content-sidebar-wrap {
overflow: hidden;
}
.sidebar-content .content-sidebar-wrap {
-webkit-box-orient: horizontal;
-webkit-box-direction: normal;
-ms-flex-direction: row;
flex-direction: row;
}
.page-template-template-ajax-load .content-sidebar-wrap {
margin-bottom: 60px;
min-height: 70vh;
}
Finally, create/edit a static Page, select the AJAX Load
Page Template and publish/update.
References:
https://premium.wpmudev.org/blog/load-posts-ajax/
Great article as always, Sridhar. But there’s a problem: AJAX can impact SEO badly, unless the site uses some kind of technique to change the URL for every dynamic change. Ideally, you would try to go for pretty permalinks, like showing the original one for every article. There’s even sites with infinite scrolling that change the permalink when a new article comes up in the screen. That means pushstate and the HTML5 history API. I’ve been doing a lot of research and there is almost nothing about WordPress and those tecniques, even though they are not very complicated if one knows his/her way through Javascript and AJAX. Everything I’ve read seems outdated, incomplete or just doesn’t work.
Could you do a piece on that and Genesis?
Thanks
[…] How to dynamically load posts on click using Ajax in Genesis […]
Sridhar
Excellent post…is there a way to make a post appear by default?
Hi, can you share the file plese.
[…] this site : https://sridharkatakam.com/how-to-dynamically-load-posts-on-click-using-ajax-in-genesis/ and this site : […]