I have created a template on wordpress where I want to output the child posts of certain parent posts. It will output 5 child posts to the corresponding parent post.
Parent post
Child Post
Child Post
Child Post
The code for this, looks like this:
function vd_list_child_pages( $atts = array() ) {
$atts = shortcode_atts( array(
'id' => 0,
'slug' => '',
), $atts );
$post_id = absint( $atts['id'] );
$post = get_post( $post_id ); // WP_Post on success.
$childpages = '';
if ( $post && is_post_type_hierarchical( 'page' ) ) {
$childpages = wp_list_pages( array(
'child_of' => $post->ID,
'title_li' => '',
'echo' => 0,
'depth' => 1,
'link_before' => '<i class="far fa-file-alt"></i>',
'walker' => '',
) );
}
if ( $childpages ) {
$childpages = '<ul class="child-posts-content">' . $childpages . '</ul>';
}
return $childpages;
}
add_shortcode( 'vd_childpages', 'vd_list_child_pages' );
However, I need the code in the template more often, with different "post_parent" ID's. Do I have to use the code everywhere like this, or can I create a "function", or which option is correct here?
Related
In my woocommerce storefront child theme, I have added several taxonomies. Now I would like to add a few category filters for those custom taxonomies.
I have added such a filter using this code (credit: Rodolfo Melogli)
add_filter( 'woocommerce_product_filters', 'admin_filter_products_by_din' );
function admin_filter_products_by_din( $output ) {
global $wp_query;
$output .= wc_product_dropdown_categories( array(
'show_option_all' => 'All DIN/ISO/ANSI',
'taxonomy' => 'din-iso-ansi',
'name' => 'din-iso-ansi',
'order' => 'ASC',
'tab_index' => '2',
'selected' => isset( $wp_query->query_vars['din-iso-ansi'] ) ? $wp_query->query_vars['din-iso-ansi'] : '',
) );
return $output;
}
The new category filter displays, but now I want the placement of my new taxonomy filter (DIN/ISO/ANSI) to go after the Product Categories filter.
product admin:
I figured this out with a lot of help from LoicTheAztec, essentially using most of his code, but it appears that we cannot substitute wp_dropdown_categories for wc_product_dropdown_categories so easily. After reviewing the function make-up of wc_product_dropdown_categories, I implemented another way to avoid having this function echo out the results by way of a little php.
add_filter( 'woocommerce_product_filters', 'admin_filter_products_by_din' );
function admin_filter_products_by_din( $output ) {
global $wp_query;
$taxonomy = 'din-iso-ansi';
$selected = isset( $wp_query->query_vars[$taxonomy] ) ? $wp_query->query_vars[$taxonomy] : '';
$info_taxonomy = get_taxonomy($taxonomy);
ob_start(); // buffer the result of wc_product_dropdown_categories silently
wc_product_dropdown_categories( array(
'show_option_none' => __("Select a {$info_taxonomy->label}"), // changed
'taxonomy' => $taxonomy,
'name' => $taxonomy,
//'echo' => false, // <== Needed for in filter hook
'tab_index' => '2',
'selected' => $selected,
'show_count' => true,
'hide_empty' => true,
));
$custom_dropdown = ob_get_clean();
$before = '<select name="product_type"'; //
$output = str_replace( $before, $custom_dropdown . $before, $output );
return $output;
}
Important notes:
wc_product_dropdown_categories() function output is echoed by default, and not convenient in a filter hook where all filtered data is always returned, so we will use the argument 'echo' set to false.
wc_product_dropdown_categories() function uses in fact wp_dropdown_categories() which is more convenient instead, for a custom taxonomy like yours.
To test your code I have used product_tag Woocommerce custom taxonomy to be sure that it works.
The following code will place your custom filter dropdown just after Product category filter:
add_filter( 'woocommerce_product_filters', 'admin_filter_products_by_din' );
function admin_filter_products_by_din( $output ) {
global $wp_query;
$taxonomy = 'din-iso-ansi';
$selected = isset( $wp_query->query_vars[$taxonomy] ) ? $wp_query->query_vars[$taxonomy] : '';
$info_taxonomy = get_taxonomy($taxonomy);
$custom_dropdown = wp_dropdown_categories(array(
'show_option_none' => __("Select a {$info_taxonomy->label}"), // changed
'taxonomy' => $taxonomy,
'name' => $taxonomy,
'order' => 'ASC',
'echo' => false, // <== Needed in a filter hook
'tab_index' => '2',
'selected' => $selected,
'show_count' => true,
'hide_empty' => true,
'value_field' => 'slug',
));
$after = '<select name="product_type"'; // The start of the html output of product type filter dropdown.
$output = str_replace( $after, $custom_dropdown . $after, $output );
return $output;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
In my shortcode I want to get posts from my custom_type_post but filtering them with ids, post_type and posts_per_page
e.g. [myshortcode type="my_custom_type_post"] - to show all posts in my_custom_type_post
or [myshortcode type="my_custom_type_post" no_of_posts="3"] - to show only 3 posts
or [myshortcode type="my_custom_type_post" no_of_posts="1" id="112"] - to show that specific post
Here is my code. It works when I only send type and posts_per_page and ids BUT doesn't work when I want to display all posts or with no_of_posts
// extracting values from shortcode
extract( shortcode_atts( array (
'type' => '',
'no_of_posts' => '',
'id' => ''
), $atts ) );
$id_array = array_map('intval',explode(',',$id));
$args = array(
'post_type' => $type,
'posts_per_page' => $no_of_posts,
'post__in' => $id_array
);
and then passing the values to wp_query
$query = new WP_Query( $args );
if( $query->have_posts() ){
/*printing out results*/
}
You must have to use conditional code as below
extract( shortcode_atts( array (
'type' => '',
'no_of_posts' => '',
'id' => ''
), $atts ) );
$args['post_type'] = $type;
if($no_of_posts) {
$args['posts_per_page'] = $no_of_posts;
} else {
$args['posts_per_page'] = '-1';
}
if($id) {
$args['post__in'] = array_map('intval',explode(',',$id));
}
I'd just setup arguments based on condition
I'm making a sidebar that will display sibling pages if the current page is the deepest level child, and only child pages if it is not. This is as far as I've gotten, I haven't been able to figure out the logic to complete it. Any ideas? Thank you in advance.
global $post;
if ( is_page() && $post->post_parent )
$childpages = wp_list_pages( 'sort_column=menu_order&title_li=&child_of=' . $post->post_parent . '&echo=0' );
else
$childpages = wp_list_pages( 'sort_column=menu_order&title_li=&child_of=' . $post->ID . '&echo=0' );
if ( $childpages ) {
$interior_sidebar = '<ul class="child-pages">' . $childpages . '</ul>';
}
Use wp_list_pages() with your parameters to get children of current post. If it comes back empty then display wp_list_pages() of current post's parent; if not empty display what was returned.
You are on the right track.
global $post isn't safe to use (it can be a post other than the page you are viewing), especially in a sidebar - I'd recommend doing something like get_queried_item().
And, to keep things simple, rather than calling wp_list_pages multiple times, I'd recommend setting up the arguments in each of condition, then having a single wp_list_pages call at the end.
// safer method to get the page you are viewing
$post = get_queried_object();
// will be TRUE if there's any child pages, FALSE if not
$has_children = (0 != get_pages( [ 'child_of' => $post->ID ] ) );
// set to prevent notices
$child_pages = FALSE;
if ( is_page( $post->ID ) && $post->post_parent ) {
$args = [
'sort_column' => 'menu_order',
'title_li' => '',
'echo' => 0,
// this is a ternary operation, that assigns $post->ID if $has_children, or $post_parent if not
'child_of' => ( $has_children ) ? $post->ID : $post->post_parent
];
$childpages = wp_list_pages( $args );
}
if ( $childpages ) {
$interior_sidebar = '<ul class="child-pages">' . $childpages . '</ul>';
}
NOTE: I've used the shorthand version for array declarations (example, [ 'child_of' => $post->ID ] instead of array( 'child_of' => $post->ID ) - this works for PHP versions 5.4+ - if you're on an older version of PHP, upgrade - it's not supported any longer
Solved with:
function wpb_list_child_pages() {
global $post;
$childpages = wp_list_pages(array(
'child_of' => $post->ID,
'depth' => 1,
'echo' => '0',
'sort_column' => 'menu_order',
'title_li' => ''
));
if ( $childpages ) {
$string =$childpages;
} else {
$childpages = wp_list_pages(array(
'child_of' => $post->post_parent,
'depth' => 1,
'exclude' => $post->ID,
'title_li' => ''
));
$string = $childpages;
}
echo $string; }
I then simply called the function in my template: <ul class="child-pages"><?php wpb_list_child_pages(); ?></ul>
The title should give you a pretty good idea about my misadventures. I am working on a project that's made in wordpress and uses WooCommerce, and after a lot of brainstorming and thought about possible compromise, i have reached the point where i am pretty much certain i have to get into the php code to solve the problem conveniently.
The problem is that i have the following website:
As you may have noticed, there is a mash of all the product categories, and what i need to do is split them into 2 main categories: food and drink. I turned what woocommerce can do by its built in functions and i just can't get it to work so i figured i'd have to write my own function. Now if any of you knows that i can actually do it with what i have i'd be happy if somebody told me. If not what i need is to create a function which can actually select all the categories belonging to a parent category or something the likes.
public function product_categories( $atts ) {
global $woocommerce_loop;
extract( shortcode_atts( array (
'number' => null,
'orderby' => 'name',
'order' => 'ASC',
'columns' => '4',
'hide_empty' => 1,
'parent' => ''
), $atts ) );
if ( isset( $atts[ 'ids' ] ) ) {
$ids = explode( ',', $atts[ 'ids' ] );
$ids = array_map( 'trim', $ids );
} else {
$ids = array();
}
$hide_empty = ( $hide_empty == true || $hide_empty == 1 ) ? 1 : 0;
// get terms and workaround WP bug with parents/pad counts
$args = array(
'orderby' => $orderby,
'order' => $order,
'hide_empty' => $hide_empty,
'include' => $ids,
'pad_counts' => true,
'child_of' => $parent
);
$product_categories = get_terms( 'product_cat', $args );
if ( $parent !== "" )
$product_categories = wp_list_filter( $product_categories, array( 'parent' => $parent ) );
if ( $number )
$product_categories = array_slice( $product_categories, 0, $number );
$woocommerce_loop['columns'] = $columns;
ob_start();
// Reset loop/columns globals when starting a new loop
$woocommerce_loop['loop'] = $woocommerce_loop['column'] = '';
if ( $product_categories ) {
woocommerce_product_loop_start();
foreach ( $product_categories as $category ) {
woocommerce_get_template( 'content-product_cat.php', array(
'category' => $category
) );
}
woocommerce_product_loop_end();
}
woocommerce_reset_loop();
return '<div class="woocommerce">' . ob_get_clean() . '</div>';
}
This i identified as the menacing WooCommerce function that does not behave. Help. Please help me :(
What about using WooCommerce's built-in [product_categories] shortcode? You could pass categories you want through the id="" attribute.
Ok here's one for ya...
On a custom template I'm using this code to retrieve & display a list of child pages/posts
$args = array(
'depth' => 1,
'show_date' => '',
'date_format' => get_option('date_format'),
'child_of' => $post->ID,
'exclude' => '',
'include' => '',
'title_li' => '',
'echo' => 1,
'authors' => '',
'sort_column' => 'menu_order, post_title',
'link_before' => '',
'link_after' => '',
'walker' => '' );
wp_list_pages( $args );
This works great, I'm also wondering how I can access/create an array of child post ID's. My goal is to access some custom fields meta data through the get_post_meta() function of each child post using it's ID.
Thanks guys.
I guess I wasn't very clear with this one as it's the first time I've never recieved an answer from SO.
I managed to find the information I needed and will place it here for anyone else browsing with the same request.
ok - To get all child IDs..
$pages = get_pages('child_of=X');
foreach($pages as $child) {
// Now you have an object full of Children ID's that you can use for whatever
// E.G
echo $child->ID . "<br />";
}
If you want to build an array of post ids for later use you can do this:
$pageids = array();
$pages = get_pages('child_of=X');
foreach($pages as $page){
$pageids[] = $page->ID;
}
And you have a clean array of just page ids.
$children = get_posts('post_parent=SLUG_OF_PARENT_POST&post_status=publish');
foreach($children as $child)
{
echo '<br/>ID:'.$child->ID;
}
you can use other attributes (i.e. $child->post_content)...
if you need to define post_type, then add this argument too : &post_type=POST_TYPE_NAME
Another way to do this:
$my_page_id = 12345;
$child_query_args = array(
'post_parent' => $my_page_id,
'post_type' => 'page',
'posts_per_page' => -1,
'fields' => 'ids',
);
$child_query = new WP_Query($child_query_args);
if ( $child_query && $child_query->have_posts() && $child_query->posts ) {
// (Since fields=ids, $child_query->posts is just an array of IDs)
$child_ids = $child_query->posts;
foreach ( $child_ids as $child_id ) {
$whatever = get_post_meta( $child_id, 'whatever', true );
echo esc_html($whatever);
}
}