Sort Wordpress foreach results by custom field - php

I've been stuck on this issue all day, and I just keep getting nowhere with it, hoping someone can help!
I'm building a site for a restaurant that has multiple locations and need to list out each drink that exists at each specific location. These drinks need to then be sorted by category (brown, white, tomato, beer, wine). I feel like I'm extremely close to a solution, but I've been banging my head for the last while.
Here's my code:
$drinks = get_posts('post_type=drinks&numberposts=-1');
$show_brown_title = false;
$show_white_title = false;
$show_tomato_title = false;
$show_wine_title = false;
$show_beer_title = false;
if ( $drinks ) {
foreach( $drinks as $drink ) {
$id = $drink->ID;
$drink_location = $drink->drink_location;
if($drink->drink_category == 'Brown' && $drink_location && in_array($site_slug, $drink_location)) {
if($show_brown_title == false) {
echo '<h4><span>Brown</span> Cocktails</h4>';
echo '<ul>';
$show_brown_title = true;
}
echo '<li>';
echo '<span class="drink_title">'.$drink->post_title.'</span>';
echo '<span class="drink_ingredients">'.$drink->drink_ingredients.'</span>';
echo '<span class="drink_price">'.$drink->price_oz.'</span>';
echo '</li>';
}
if($drink->drink_category == 'White' && $drink_location && in_array($site_slug, $drink_location)) {
if($show_white_title == false) {
echo '<h4><span>White</span> Cocktails</h4>';
echo '<ul>';
$show_white_title = true;
}
echo '<li>';
echo '<span class="drink_title">'.$drink->post_title.'</span>';
echo '<span class="drink_ingredients">'.$drink->drink_ingredients.'</span>';
echo '<span class="drink_price">'.$drink->price_oz.'</span>';
echo '</li>';
}
}
}
For the most part, this works. However, I'm running into 2 issues.
I can't figure out how to close the unordered list after I'm done with each category.
This groups by category for the most part, however, if I have a drink that comes later, it will not actually put it into the right category, it'll just go into whatever category is at the bottom. I'm not sure if this is because I'm not closing the unordered list, or if because of the order that the posts are being pulled from WP.
Let me know if I'm explaining this alright, and I really appreciate any help you guys can offer!
Z

Instead of get_posts, you should use WP_Query. Info: https://wordpress.stackexchange.com/questions/50761/when-to-use-wp-query-query-posts-and-pre-get-posts/50762#50762
$show_brown_title = false;
$show_white_title = false;
$show_tomato_title = false;
$show_wine_title = false;
$show_beer_title = false;
$args = array(
'post_type' => 'drinks',
'numberposts' => '-1'
);
$query = new WP_Query( $args );
if( $query->have_posts() ):
while( $query->have_posts() ): $query->the_post();
echo '<pre>';
print_r( $query );
echo '<pre>';
endwhile;
endif;
wp_reset_postdata();
Inside the loop you will construct again your listing, use the print_r step by step, use your objects elements smart.
Aproach #2:
$show_brown_title = false;
$show_white_title = false;
$show_tomato_title = false;
$show_wine_title = false;
$show_beer_title = false;
foreach((get_the_category()) as $cat) {
$args = array(
'post_type' => 'drinks',
'numberposts' => '-1',
'cat' => $cat->cat_ID
);
$query = new WP_Query( $args );
if( $query->have_posts() ):
echo '<ul>';
while( $query->have_posts() ): $query->the_post();
echo '<h4><span>'. $query->category_name .'</span> Cocktails</h4>';
echo '<li>';
echo '<span class="drink_title">'.$query->post_title.'</span>';
echo '<span class="drink_ingredients">'.$query->drink_ingredients.'</span>';
echo '<span class="drink_price">'.$query->price_oz.'</span>';
echo '</li>';
endwhile;
echo '</ul>';
endif;
wp_reset_postdata();
}
With the specification that $query->category_name maybe should be written other way. Use print_r to see the correct field name/element of your object.

Bellow is my solution.
Note: get_posts uses the orderby parameter to order the posts by drink_category.
The code is simplified to only start <ul> when drink_category changes and to end </ul> on category change too. Code also checks that html to output has been assigned a value and appends to it a final </ul> in case one is not appended already.
$drinks = get_posts('post_type=drinks&numberposts=-1&orderby=drink_category');
$current_category = '';
$html = '';
if ( $drinks ) {
foreach( $drinks as $drink ) {
$id = $drink->ID;
$drink_location = $drink->drink_location;
if ($current_category != $drink->drink_category) {
if ($current_category != '') {
$html .= '</ul>';
}
$current_category = $drink->drink_category;
$html .= '<h4><span>' . $current_category . '</span> Cocktails</h4>';
$html .= '<ul>';
}
if($drink_location && in_array($site_slug, $drink_location)) {
$html .= '<li>';
$html .= '<span class="drink_title">'.$drink->post_title.'</span>';
$html .= '<span class="drink_ingredients">'.$drink->drink_ingredients.'</span>';
$html .= '<span class="drink_price">'.$drink->price_oz.'</span>';
$html .= '</li>';
}
}
}
if (strlen($html) > 0 && !endsWith($html, '</ul>')) {
$html .= '</ul>';
}
function endsWith($haystack, $needle)
{
$length = strlen($needle);
if ($length == 0) {
return true;
}
return (substr($haystack, -$length) === $needle);
}

Related

How to display an alphabetically sorted list of post withe Php (WordPress )

I would like to create a glossary overview page on wordpress via PHP, which can be used via a shortcode. I would like that always the initial letter is displayed and then the individual topics (posts) which begin with this.
Example:
A
Apple
Apricot
B
Banana
Blackberry
and so on...
To implement this I use the following code:
// get glossary
function glossary($post_id) {
$all_posts = new WP_Query(
array(
'posts_per_page' => -1,
'post_type' => 'glossar',
'orderby' => 'title',
'order' => 'ASC',
));
echo '<ul>';
if( $all_posts->have_posts()){
foreach( range( 'A', 'Z' ) as $letter ) {
echo '<div class="group_letter"><div class="letter">' . $letter. '</div>';
while( $all_posts->have_posts() ){
$all_posts->the_post();
$title = get_the_title();
$name = get_post_field( 'post_name', get_post() );
$initial = strtoupper( substr( $title, 0, 1 ) );
if( $initial == $letter ){
echo '<li><a class="glossary-listing" href="/glossar/'. $name . '">' . $title . '</a></li>';
}
}
$all_posts->rewind_posts();
}
}
echo '</ul>';
}
add_shortcode( 'glossary', 'glossary' );
So far it works, but now it shows letters for which there are no posts. This is how it looks now
I have tried to do it with an if query, but so far, I am stuck. Can someone help me?
Best regards and thank you!
Sort the array using PHP sort() function then loop through the result
<?PHP
$list=['apples','popsicles','Zinger','donkeys','bananas','joe',
'Locusts','gazelles','Angels','Popsicle','Dongle','jump','cocoa'
];
//convert all elements to same case
//sorting will sort by case
$list =array_map('strtolower', $list);
//sort the array
sort($list);
$last_letter=null;
foreach($list as $item){
$current_letter=substr($item,0,1);
if($last_letter!=$current_letter){
?>
<div style="margin:1rem;padding:1rem;background:#f5f5f5;">
<?=$current_letter?>
</div>
<?php
$last_letter=$current_letter;
}
?>
<div style="margin:1rem;padding:1rem;background:#f5f5f5;">
<?=$item?>
</div>
<?PHP
}
?>
I am sure there is a better solution besides running 26 times through the while loop. Anyway, here is what you are looking for.
// get glossary
function glossary($post_id) {
$all_posts = new WP_Query(
[
'posts_per_page' => -1,
'post_type' => 'glossar',
'orderby' => 'title',
'order' => 'ASC',
]
);
echo '<ul>';
if ($all_posts->have_posts()) {
foreach (range('A', 'Z') as $letter) {
$foundPostable = false;
while ($all_posts->have_posts()) {
$all_posts->the_post();
$title = get_the_title();
$name = get_post_field( 'post_name', get_post() );
$initial = strtoupper(substr($title, 0, 1));
if ($initial === $letter) {
if ($foundPostable === false) {
$foundPostable = true;
echo '<div class="group_letter"><div class="letter">' . $letter. '</div>';
}
echo '<li><a class="glossary-listing" href="/glossar/'. $name . '">' . $title . '</a></li>';
}
}
$all_posts->rewind_posts();
}
}
echo '</ul>';
}
add_shortcode( 'glossary', 'glossary' );
As for improvement, something like this might work as well.
// get glossary
function glossary($post_id) {
$all_posts = new WP_Query(
[
'posts_per_page' => -1,
'post_type' => 'glossar',
'orderby' => 'title',
'order' => 'ASC',
]
);
echo '<ul>';
$startLetter = '';
while ($all_posts->have_posts()) {
$all_posts->the_post();
$title = get_the_title();
$name = get_post_field( 'post_name', get_post() );
$initial = strtoupper(substr($title, 0, 1));
if ($initial !== $startLetter) {
$startLetter = $initial
echo '<div class="group_letter"><div class="letter">' . $letter . '</div>';
}
echo '<li><a class="glossary-listing" href="/glossar/'. $name . '">' . $title . '</a></li>';
}
echo '</ul>';
}
add_shortcode('glossary', 'glossary');

Hide row if ACF sub field is checked

I got a ACF Reaper field with a couple of rows I am trying to show. However, I only want the show row if it has a checkbox checked (Checkbox is a subfield within the repeater). I am trying to accomplish that by using if in_array as described in ACF documentation under "Conditional logic":
if( in_array( "bestyrelsevalg", get_sub_field( 'bestyrelse' ) ) )
I am outputting the result in a WordPress shortcode. For now, my code kinda works, except it shows all results within the repeater field (also those that are unchecked). What am I missing ??
My code:
function investor_bestyrelse_shortcode() {
$rows = get_field('budgetter_og_nyhedsbreve');
if( $rows ) {
echo '<ul class="slides">';
foreach( $rows as $row ) {
if( in_array( "bestyrelsevalg", get_sub_field( 'bestyrelse' ) ) ) {
$image = $row['upload_dokument'];
echo '<li>';
echo get_field( 'upload_dokument' );
echo '</li>';
}
}
echo '</ul>';
}
}
add_shortcode( 'investor_bestyrelse', 'investor_bestyrelse_shortcode' );
Managed to solve issue and with the help from #maggiathor's answer. For some reason echo was causing issue. I had to use return insted:
function investor_bestyrelse_shortcode() {
$rows = get_field('budgetter_og_nyhedsbreve');
if( $rows ) {
$content = '<ul class="dokumenter">';
foreach( $rows as $row ) {
if( !in_array( "bestyrelsevalg", $row['bestyrelse'] ) ) {
$pdf = $row['upload_dokument'];
$content = $content . '<li>' . $pdf . '</li>';
}
}
}
$content = $content . '</ul>';
return $content;
}
add_shortcode( 'investor_bestyrelse', 'investor_bestyrelse_shortcode' );
You cannot use get_sub_field() within the foreach loop, either you need to use a have_rows-while-loop or access it from the associative array:
function investor_bestyrelse_shortcode() {
$rows = get_field('budgetter_og_nyhedsbreve');
if( $rows ) {
echo '<ul class="slides">';
foreach( $rows as $row ) {
if( in_array( "bestyrelsevalg", $row['bestyrelse'] ) ) {
$image = $row['upload_dokument'];
echo '<li>';
echo $row['upload_dokument'];
echo '</li>';
}
}
echo '</ul>';
}
}
add_shortcode( 'investor_bestyrelse', 'investor_bestyrelse_shortcode' );

How to display meta_value only once if the value is the same

I have created a loop to display the meta value but wanted to show it only once if they are the same of value. I have tried using array_unique but it doesn't seem to work
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
echo '<ul>';
$menusInList = [];
while ( $_query->have_posts() ) {
$query->the_post();
$menu = get_post_meta($post->ID, 'awarded', true);
if (in_array($menu, $menusInList)) {
continue;
}
$menusInList[] = $menu;
echo '<li class="'.$menus .'" >' . $menu . '</li>';
}
echo '</ul>';
} else {
// no posts found
}
/* Restore original Post Data */
wp_reset_postdata();
Save $menu in an array $menusInList and check via in_array. if it returns true use continueto skip.
$menusInList = [];
while ( $query->have_posts() ) {
$query->the_post();
$menu = get_post_meta($post->ID, 'award', true);
if (in_array($menu, $menusInList)) {
continue;
}
$menusInList[] = $menu;
// ...
}

Woocommerce Shopping Cart Icon

I have a woocommerce cart icon in my main navigation. I want that icon to show a if the cart has items in it. If not that would be removed. I have tried the code below and it does not do what I intended it to. Ideas?
if($items_txt = $count_value === 1 ){
$html .= '<span class="xoo-wsc-sc-count">1</span>';}
elseif($items_txt = $count_value === 0 ){
$html .= '';}
Here is the full original code snippet.
<?php
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
$sy_options = get_option('xoo-wsc-sy-options');//Style options
$options = get_option('xoo-wsc-gl-options');
$count_type = isset( $options['bk-count-type']) ? $options['bk-count-type'] : 'qty_count'; //Count Type
$cart_items_total = wc_price(WC()->cart->subtotal);
$bk_cubi = isset( $sy_options['bk-cubi']) ? $sy_options['bk-cubi'] : ''; // Custom basket icon
if( !$bk_cubi ){
$bk_bit = isset( $sy_options['bk-bit']) ? $sy_options['bk-bit'] : 'xoo-wsc-icon-basket1'; // Basket Icon Type
}
$html = '<a class="xoo-wsc-sc-cont">';
if( $bk_cubi ){
$html .= '<img src="'.$bk_cubi.'" class="xoo-wsc-sc-icon">';
}
else{
$html .= '<span class="xoo-wsc-sc-icon '.$bk_bit.'"></span>';
}
if($count_type == 'qty_count'){
$count_value = WC()->cart->get_cart_contents_count();
}
elseif($count_type == 'item_count'){
$count_value = count(WC()->cart->get_cart());
}
$items_txt = $count_value === 1 ? __('item','side-cart-woocommerce') : __('items','side-cart-woocommerce');
$html .= '<span class="xoo-wsc-sc-count">'.'</span>';
//$html .= '<span class="xoo-wsc-sc-count">'.$count_value.'</span>';
//$html .= '<span class="xoo-wsc-sc-total">'.$cart_items_total.'</span>';
$html .= '</a>';
echo $html;
I think if you change this if:
if( $bk_cubi ){
$html .= '<img src="'.$bk_cubi.'" class="xoo-wsc-sc-icon">';
}
else{
$html .= '<span class="xoo-wsc-sc-icon '.$bk_bit.'"></span>';
}
To:
if ($bk_cubi)
{
$html .= '<img src="'.$bk_cubi.'" class="xoo-wsc-sc-icon">';
}
else
{
if($count_value == 1 )
{
$html .= '<span class="xoo-wsc-sc-count">1</span>';
}
}
You'll get what you want.
Also, a single = is assignment operator. == is for checking whether values are equal to one another.
You can use the woocommerce_add_to_cart_fragments hook to check real-time woocommerce cart items.
add_filter( 'woocommerce_add_to_cart_fragments', 'woo_cart_icon_count' );
function woo_cart_icon_count( $fragments ) {
$cart_count = WC()->cart->cart_contents_count;
if($cart_count > 0) {
// your code here
}
}
For more detail, you can check the tutorial here.

Adding class for only 1st element of array of custom field with same values in php

I have custom field with key Slider Image for a page in WordPress. This key accepts multiple values. admin dashboard for the page
Here's the php code for displaying the aforesaid in the front-end:
$slider_image = get_post_meta($post->ID, 'Slider Image', false);
if( count( $slider_image ) != 0 ) {
foreach($slider_image) {
echo '<li class="">...</li>';
}
}
This outputs the expected
<li class="">...</li>
<li class="">...</li>
<li class="">...</li>
.
.
.
I want only the 1st li to have class of active. How can I do this? This, I think, comes close to the answer.
You can do it in two ways, either by PHP with the following approch
if(count($slider_image)!= 0) {
$flag = 1;
foreach($slider_image as $img) {
if($flag==1) {
echo '<li class="active">...</li>';
$flag++;
}
else {
echo '<li class="">...</li>';
}
}
}
or using jQuery using the following way
$('#parentID li:first').addClass('aaaa');
where parentID is is the id of the parent element of the li elements.
Use a for loop instead if it's number index:
if( false != ($len = count( $slider_image ))) {
for($i=0;$i<$len;$i++){
//$value = $slider_image[$i];
$class = $i==0 ? 'active' : '';
echo '<li class="'.$class.'">...</li>';
}
}
If it's not you can do this with foreach
$slider_image = get_post_meta($post->ID, 'Slider Image', false);
if( count( $slider_image ) != 0 ) {
$first = key($slider_image); //get the key at the current position (the first one)
foreach($slider_image as $key=>$value) {
$class = $key==$first ? 'active' : '';
echo '<li class="'.$class.'">...</li>';
}
}
If you want to get fancy you could do a do/while loop like this:
$slider_image = get_post_meta($post->ID, 'Slider Image', false);
if( count( $slider_image ) != 0 ) {
do{
$class = !isset($class) ? 'active' : '';
//$value = current($slider_image);
echo '<li class="'.$class.'">...</li>';
next($slider_image);
}while(current($slider_image));
}
Simple.
$slider_image = get_post_meta($post->ID, 'Slider Image', false);
if( is_array( $slider_image ) )
{
$cls = 'active';
foreach($slider_image as $img)
{
echo '<li class="' . $cls . '">...</li>';
$cls = '';
}
}
Even better you do it in PHP style as embedded language:
if( is_array( $slider_image ) )
{
$cls = 'active';
foreach($slider_image as $img)
{
?>
<li class="<?php echo $cls;?>"><img src="<?php echo $img?>"></li>
<?php
$cls = '';
}
}
However, if you need this class in JavaScript, I would set it also in JavaScript before slider initialization.
if(!document.querySelector('ul#mylist>li.active'))
document.querySelector('ul#mylist>li:first-child').classList.add('active');

Categories