I’m not quite sure what do you mean by you have extended the visual composer, but I do have a couple of concerns here.
-
SoC -> From your code I detect that you are using a shortcode, which should have its own separate class. You should not extend the class to the visual editor (at least this is how I read your question). Classes should never multi task, they should do one single duty. This keeps your class extentable, short, easy to maintain and reusable and easy to test
-
Extending the previous point, front end and back end functionalities should not be mixed
-
I don’t see the usefulness of using
global $post
and setting up post data. Doing this and not resetting postdata afterwards will have unexpected influences on any query afterwards and on the main query. You should drop that completely -
Never ever use
extract()
in shortcodes ( and any other function for that matter ). It is very unrealiable and untestable and leads to unexpected output. This makes it extremely hard to debug in case of failures. For this very reason, it was completely removed from core. See trac ticket 22400 -
Because you are using multiple category conditions, and to make it more dynamic, I would rather use a
tax_query
to handle the conditions. The big plus here would be that you will save on db calls as you can get rid ofget_category_by_slug
-
There is no need for
wp_reset_query()
. This is used withquery_posts
which you should never ever use. It is a page breaker. -
Front pages and single pages uses the query variable
page
(get_query_var( 'page' )
) for pagination, and notpaged
(get_query_var( 'paged' )
) as other pages. The query argument forWP_Query
for both however is the same, it should bepaged
, notpage
. The value to thepaged
parameter/argument should bepage
for static front pages andpaged
for all other pages
You can rewrite your method above as follow: (CAVEAT: Untested)
public function renderPosts( $atts )
{
$attributes = shortcode_atts( array(
'foo' => 5, //default of 5
'include' => 'news-views', // Currently news and views.
'exclude' => 'game-library' // Exclude this category
), $atts);
/*
* For getting the Query variable on a static front page, you have
* to use 'page' and not 'paged'. Weird.
*/
if ( get_query_var('paged') ) {
$paged = get_query_var('paged');
} elseif ( get_query_var('page') ) {
$paged = get_query_var('page');
} else {
$paged = 1;
}
/*
* Args for the custom query
*/
$query_args = array(
'posts_per_page' => intval($attributes['foo']),
'tax_query' => array(
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => explode( ',', str_replace( ' ', '', $attributes['include'] ) ),
'include_children' => false
),
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => explode( ',', str_replace( ' ', '', $attributes['exclude'] ) ),
'operator' => 'NOT IN'
)
),
'paged' => $paged
);
$custom_query = new WP_Query($query_args);
$output="";
if ( $custom_query->have_posts() ) {
$output .= '<div id="blogroll">';
while ( $custom_query->have_posts() ) {
$custom_query->the_post();
$output .= "<div class="home_post col span_12 clear-both">";
$output .= "<div class="col span_3"><a href="" . get_the_permalink() . "">" . get_the_post_thumbnail(get_the_ID(), 'home_post_thumb') . "</a></div>";
$output .= "<div class="col span_9 col_last right-edge">";
$output .= "<h2 class="home_post_header">";
$output .= '<a href="' . get_the_permalink() . '">' . get_the_title() . "</a>";
$output .= "</h2>";
$output .= get_the_excerpt();
$output .= '<a class="home-more-link" href="' . get_the_permalink() . '"><span class="continue-reading">Read More</span></a>';
$output .= "</div>";
$output .= "</div>";
}
wp_reset_postdata();
$output .= '<div id="pagination" class="blogroll-pagination">' . home_pagination( $custom_query ) . '</div></div>';
}
return $output;
}
Just remember, the I have changed the attributes for readability, include
takes a comma separated string of category slugs (include="slug-1, slug-2"
). This attribute will be used to include categories. exclude
works the same (exclude="slug-1, slug-2"
), except that it takes a comma separated string of category slugs
EDIT
I have tested my code and fixed a couple of small bugs. It works as expected if I just create a normal shortcode from it.
PROOF OF CONCEPT – SHORTCODE
add_shortcode( 'testcode', function ( $atts )
{
$attributes = shortcode_atts( array(
'foo' => 5, //default of 5
'include' => 'news-views', // Currently news and views.
'exclude' => 'game-library' // Exclude this category
), $atts);
/*
* For getting the Query variable on a static front page, you have
* to use 'page' and not 'paged'. Weird.
*/
if ( get_query_var('paged') ) {
$paged = get_query_var('paged');
} elseif ( get_query_var('page') ) {
$paged = get_query_var('page');
} else {
$paged = 1;
}
/*
* Args for the custom query
*/
$query_args = array(
'posts_per_page' => intval($attributes['foo']),
'tax_query' => array(
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => explode( ',', str_replace( ' ', '', $attributes['include'] ) ),
'include_children' => false
),
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => explode( ',', str_replace( ' ', '', $attributes['exclude'] ) ),
'operator' => 'NOT IN'
)
),
'paged' => $paged
);
$custom_query = new WP_Query($query_args);
$output="";
if ( $custom_query->have_posts() ) {
$output .= '<div id="blogroll">';
while ( $custom_query->have_posts() ) {
$custom_query->the_post();
$output .= "<div class="home_post col span_12 clear-both">";
$output .= "<div class="col span_3"><a href="" . get_the_permalink() . "">" . get_the_post_thumbnail(get_the_ID(), 'home_post_thumb') . "</a></div>";
$output .= "<div class="col span_9 col_last right-edge">";
$output .= "<h2 class="home_post_header">";
$output .= '<a href="' . get_the_permalink() . '">' . get_the_title() . "</a>";
$output .= "</h2>";
$output .= get_the_excerpt();
$output .= '<a class="home-more-link" href="' . get_the_permalink() . '"><span class="continue-reading">Read More</span></a>';
$output .= "</div>";
$output .= "</div>";
}
wp_reset_postdata();
$output .= '<div id="pagination" class="blogroll-pagination">' . home_pagination( $custom_query ) . '</div></div>';
}
return $output;
});
which I use as follow
[testcode include="testslug-1, testslug-2" exclude="testslug-3, testslug-4"]
I have tested your pagination function as well and that also works as expected.
function home_pagination( $query = null )
{
$big = 999999999; // need an unlikely integer
if ( get_query_var('paged') ) {
$paged = get_query_var('paged');
} elseif ( get_query_var('page') ) {
$paged = get_query_var('page');
} else {
$paged = 1;
}
$pagination = paginate_links(
array(
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
'format' => '?paged=%#%',
'current' => $paged,
'total' => $query->max_num_pages,
'prev_text' => '« Previous',
'next_text' => 'Next »',
)
);
return $pagination;
}
EDIT 2
Frm your comments, and as I have already stated, static front pages and single pages uses get_query_var( 'page' )
for pagination while all the other uses get_query_var( 'paged' )
. I have updated all the code above with the following
if ( get_query_var('paged') ) {
$paged = get_query_var('paged');
} elseif ( get_query_var('page') ) {
$paged = get_query_var('page');
} else {
$paged = 1;
}
This will sort the problem with page
and paged
and make your shortcode and pagination work across all pages without any specific changes made to it
EDIT 3
Here is a sligtly modified version of the code by @ChipBennet which will sort the problem of /page/2
function home_pagination( $query = null )
{
global $wp_rewrite;
if ( get_query_var('paged') ) {
$paged = get_query_var('paged');
} elseif ( get_query_var('page') ) {
$paged = get_query_var('page');
} else {
$paged = 1;
}
$pagination = array(
'base' => @add_query_arg( 'paged', '%#%' ),
'format' => '',
'current' => $paged,
'total' => $query->max_num_pages,
'prev_text' => '« Previous',
'next_text' => 'Next »',
);
if ( $wp_rewrite->using_permalinks() )
$pagination['base'] = user_trailingslashit( trailingslashit( remove_query_arg( 's', get_pagenum_link( 1 ) ) ).'/%#%/', '' );
if ( ! empty( $wp_query->query_vars['s'] ) )
$pagination['add_args'] = array( 's' => get_query_var( 's' ) );
return paginate_links( $pagination );
}