Shortcode attributes that query the database - php

I am trying to create a shortcode that returns a list of doctors matching a specialty.
So far, I can get the base shortcode to return the contents of the entire table, but I can't get it to query based on an attribute string.
Here's what I have:
// Add Shortcode
function list_docs( $atts ) {
// Attributes
$atts = shortcode_atts(
array(
'specialty' => '',
),
$atts,
'doctors'
);
global $wpdb;
$specialty = $atts['specialty'];
$specget = $wpdb->prepare("SELECT * FROM doctors WHERE specialty = '%s'", $specialty);
$specresults = $wpdb->get_results($specget);
foreach($specresults as $details) {
echo $details;
}
}
add_shortcode( 'doctors', 'list_docs' );
If I query the database directly with:
SELECT * FROM `doctors` WHERE `specialty` = 'cardiology'
I get the expected result.
I'm trying to call it with [doctors specialty="cardiology"] (I've tried double and single quotes) on the WordPress page.
Right now, I don't know what I don't know. I'm not sure if I've entered something wrong, have a typo, or am missing a line of code. Any assistance would be terrific.

May be problem is not with the query at all assuming that your table name is indeed doctors( & not wp_doctors or something like that )
$specresults will contain an array of objects. Let's say your doctors table has name column, then below changes may work for you.
function list_docs( $atts ) {
// Attributes
$atts = shortcode_atts(
array(
'specialty' => '',
),
$atts,
'doctors'
);
global $wpdb;
$specialty = $atts['specialty'];
$specget = $wpdb->prepare( 'SELECT * FROM doctors WHERE specialty = %s', $specialty );
$specresults = $wpdb->get_results( $specget );
if ( $specresults ) {
$doctor_names = array_map(
function( $doctor_object ) {
return $doctor_object->name;
},
$specresults
);
return implode( ', ', $doctor_names );
}
return '';
}
add_shortcode( 'doctors', 'list_docs' );
Couple of things to keep in mind:-
Shortcodes should always return & not echo directly.
Query only for required data from the database as far as possible instead of doing *
If you are going to need only one column, prefer using get_col method on $wpdb instead of get_results.

Please try with this -
function list_docs( $atts ) {
global $wpdb;
$specialty = $atts['specialty'];
$specget = $wpdb->prepare("SELECT * FROM doctors WHERE specialty = %s", $specialty);
$specresults = $wpdb->get_results($specget);
foreach($specresults as $details) {
echo $details;
}
}
add_shortcode( 'doctors', 'list_docs' );

Related

Buddypress: How to create secondary membersloop?

I have a list of favorited user ids in PHP.
I want to create a secondary membersloop within Buddyboss under a new permalink, e.g.
mypage.com/members/favorited
which only shows the given list of user ids.
The inclusion of only the specific favorited user-ids, I have already implemented as a filter to the membersloop, like so:
function membersloop_show_favorites( $querystring = false, $object = false ) {
// Only do this for the members loop.
if ($object != 'members')
return $querystring;
// Test Input, comes from database later on ...
$ids = array(89, 113); //
// Make the array a comma sep list.
$ids = implode( ',', $ids );
$args = wp_parse_args($querystring);
if ( ! empty($args['include']) )
$args['include'] = $args['include'] . ',' . $ids;
else
$args['include'] = $ids;
$querystring = build_query( $args );
return $querystring;
}
add_action( 'bp_ajax_querystring', 'membersloop_show_favorites', 20, 2 );
The only question is how to make a permalink for that customized membersloop.

Woocommerce: product id in the order received url

I would like to change the order received (thanks page) url for a new one, which includes the ordered product's ID.
Here is the code in the class-wc-order.php
/**
* Generates a URL for the thanks page (order received).
*
* #return string
*/
public function get_checkout_order_received_url() {
$order_received_url = wc_get_endpoint_url( 'order-received', $this->get_id(), wc_get_page_permalink( 'checkout' ));
if ( 'yes' === get_option( 'woocommerce_force_ssl_checkout' ) || is_ssl() ) {
$order_received_url = str_replace( 'http:', 'https:', $order_received_url );
}
$order_received_url = add_query_arg( 'key', $this->get_order_key(), $order_received_url );
return apply_filters( 'woocommerce_get_checkout_order_received_url', $order_received_url, $product, $this, $product->id );
}
Any idea?
Thanks!
This answer on wordpress.stackexchange.com would solve the issue
As a brief, just define the following hook:
add_filter('woocommerce_get_checkout_order_received_url','override_return_url',10,2);
function override_return_url($return_url,$order){
//create empty array to store url parameters in
$sku_list = array();
// retrive products in order
foreach($order->get_items() as $key => $item)
{
$product = wc_get_product($item['product_id']);
//get sku of each product and insert it in array
$sku_list['product_'.$item['product_id'] . 'sku'] = $product->get_sku();
}
//build query strings out of the SKU array
$url_extension = http_build_query($sku_list);
//append our strings to original url
$modified_url = $return_url.'&'.$url_extension;
return $modified_url;
}
Then, you can set the analytics goal to point to the destination below as a regular expression
\/checkout\/order-received\/\d+\/\?key=\w+&product_ID_HERE_sku=SKU_HERE
We can make it simpler by including only product ids:
add_filter('woocommerce_get_checkout_order_received_url','override_return_url',0,2);
function override_return_url($return_url,$order){
$ids = array();
foreach($order->get_items() as $key => $item)
{
$ids[] = $item['product_id'];
}
return add_query_arg('product_ids', join(',', $ids) , $return_url);
}
In this case, the regex would be:
\/checkout\/order-received\/\d+\/\?key=\w+&product_ids=ID1,ID2,ID3
Or for a single product id:
\/checkout\/order-received\/\d+\/\?key=\w+&product_ids=[\w,]*ID[\w,]*

Wordpress undefined index issue php

I'm getting the following error in my wordpress dashboard which correlates to a piece of code i've written, however I'm not sure how to fix the error:
Notice: Undefined index: draft in /home/sites/samskirrow.com/public_html/skizzar-test/wp-content/mu-plugins/skizzar-dashboard.php on line 331
Here is the code it's referring to:
/******************************************************************
/* REMOVE BRACKETS AROUND PAGE COUNTS
/******************************************************************/
foreach( array( 'edit-post', 'edit-page', 'edit-movie', 'upload' ) as $hook )
add_filter( "views_$hook" , 'wpse_30331_custom_view_count', 10, 1);
function wpse_30331_custom_view_count( $views )
{
global $current_screen;
switch( $current_screen->id )
{
case 'edit-post':
$views = wpse_30331_manipulate_views( 'post', $views );
break;
case 'edit-page':
$views = wpse_30331_manipulate_views( 'page', $views );
break;
case 'edit-movie':
$views = wpse_30331_manipulate_views( 'movie', $views );
break;
case 'upload':
$views = wpse_30331_manipulate_views( 'attachment', $views );
break;
}
return $views;
}
function wpse_30331_manipulate_views( $what, $views )
{
global $user_ID, $wpdb;
/*
* This is not working for me, 'artist' and 'administrator' are passing this condition (?)
*/
if ( !current_user_can('artist') )
return $views;
/*
* This needs refining, and maybe a better method
* e.g. Attachments have completely different counts
*/
$total = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE (post_status = 'publish' OR post_status = 'draft' OR post_status = 'pending') AND (post_author = '$user_ID' AND post_type = '$what' ) ");
$publish = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE post_status = 'publish' AND post_author = '$user_ID' AND post_type = '$what' ");
$draft = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE post_status = 'draft' AND post_author = '$user_ID' AND post_type = '$what' ");
$pending = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE post_status = 'pending' AND post_author = '$user_ID' AND post_type = '$what' ");
$trash = $wpdb->get_var("SELECT COUNT(*) FROM $wpdb->posts WHERE post_status = 'trash' AND post_author = '$user_ID' AND post_type = '$what' ");
/*
* Only tested with Posts/Pages
* - there are moments where Draft and Pending shouldn't return any value
*/
$views['all'] = preg_replace( '/\(.+\)/U', ''.$total.'', $views['all'] );
$views['publish'] = preg_replace( '/\(.+\)/U', ''.$publish.'', $views['publish'] );
$views['draft'] = preg_replace( '/\(.+\)/U', ''.$draft.'', $views['draft'] );
$views['pending'] = preg_replace( '/\(.+\)/U', ''.$pending.'', $views['pending'] );
$views['trash'] = preg_replace( '/\(.+\)/U', ''.$trash.'', $views['trash'] );
return $views;
}
I know that the issue is that certain parameters aren't found in the db (for example, there may not be any "pending" posts) so it throws out an error. How can I code my way around this, for example, to say, if the parameter exists...
The goal here is to remove the '(' ')' brackets from post counts in wordpress. So when you are on the view posts, or view pages screen, there is a sub menu above the lists of posts/pages with the following items 'all', 'published', 'trash', 'pending' - these are filters that the user can click on. Next to each filter is a number, the number of posts/pages within that filter. The format of this count is ([NUMBER]) - This code is to simply get rid of those brackets.
I noticed by google'ing a bit that you're using the code form this Wordpress SE answer. This doesn't match your needs, as this code is here to recalculate the number of posts after some manipulation on that by the OP.
To just remove the parenthesis, look at the following function in class-wp-list-table.php:
public function views() {
$views = $this->get_views();
$views = apply_filters( "views_{$this->screen->id}", $views );
if ( empty( $views ) )
return;
$this->screen->render_screen_reader_content( 'heading_views' );
echo "<ul class='subsubsub'>\n";
foreach ( $views as $class => $view ) {
$views[ $class ] = "\t<li class='$class'>$view";
}
echo implode( " |</li>\n", $views ) . "</li>\n";
echo "</ul>";
}
This is the function that build the user menu that you try to change. If you look closer at this, you will see that the $view being echo'ed come from a $views that is being filtered previously:
$views = apply_filters( "views_{$this->screen->id}", $views )
$this->screen->id stand for the ID of the current screen, like edit-post for example.
So by adding this simple filter you will achieve what you want to do here:
add_filter('views_edit-post', 'remove_count_parenthesis', 10, 1);
function remove_count_parenthesis($views) {
foreach($views as $key => $view) {
$views[$key] = str_replace(array('(', ')'), '', $view);
}
return $views;
}
You need to check if there is a value 'draft' in your array
if (isset( $views['draft'] )) {
$views['draft'] = preg_replace( '/\(.+\)/U', ''.$draft.'', $views['draft'] );
}

Adding custom meta into wordpress search

I'm currently trying to add my theme posts custom meta values into search query, but it's not working for me. For example _My_meta_value_key3 is product code, but if i try to search it, wp don't find the match. I really want to make this without any plugins so any suggestions are welcome. Also, this code is currently located in theme functions.
function My_custom_search_query( $query ) {
if ($query->is_search()) {
$query->set('meta_query', array(
array(
'key' => '_My_meta_value_key',
'value' => $query->query_vars['s'],
'compare' => 'LIKE'
),
array(
'key' => '_My_meta_value_key2',
'value' => $query->query_vars['s'],
'compare' => 'LIKE'
),
array(
'key' => '_My_meta_value_key3',
'value' => $query->query_vars['s'],
'compare' => 'LIKE'
)
));
return $query;
};}
add_filter( 'pre_get_posts', 'My_custom_search_query');
I've spent an hour searching for a solution and there was nothing that works so I had to write the solution on my own. It is tested and working with Wordpress 5.3.1 and is the only solution that solves this problem I could find on the internet.
Place the following code in your functions.php file to hook into posts_clauses filter.
/**
* Include meta fields in search
*
* #author Mindaugas // meevly.com
* #link https://meevly.com/services/custom-wordpress-themes-and-plugins/
*
* #param array $pieces query pieces.
* #param WP_Query $args query object.
* #return array
*/
function mv_meta_in_search_query( $pieces, $args ) {
global $wpdb;
if ( ! empty( $args->query['s'] ) ) { // only run on search query.
$keywords = explode(' ', get_query_var('s'));
$escaped_percent = $wpdb->placeholder_escape(); // WordPress escapes "%" since 4.8.3 so we can't use percent character directly.
$query = "";
foreach ($keywords as $word) {
$query .= " (unique_postmeta_selector.meta_value LIKE '{$escaped_percent}{$word}{$escaped_percent}') OR ";
}
if ( ! empty( $query ) ) { // append necessary WHERE and JOIN options.
$pieces['where'] = str_replace( "((({$wpdb->posts}.post_title LIKE '{$escaped_percent}", "( {$query} (({$wpdb->posts}.post_title LIKE '{$escaped_percent}", $pieces['where'] );
$pieces['join'] = $pieces['join'] . " INNER JOIN {$wpdb->postmeta} AS unique_postmeta_selector ON ({$wpdb->posts}.ID = unique_postmeta_selector.post_id) ";
}
}
return $pieces;
}
add_filter( 'posts_clauses', 'mv_meta_in_search_query', 20, 2 );
And your query should look like the following. Please note that suppress_filters => false is mandatory! It will not work without it.
$search_posts_array = array(
'suppress_filters' => false,
's' => $keyword,
);
$search_results = get_posts( $search_posts_array );
Please do not hesitate to credit if I saved you tons of time! :)
Found this http://wpdevsnippets.com/extend-search-include-custom-fields-without-plugin/ :
function custom_search_where($pieces) {
// filter to select search query
if (is_search() && !is_admin()) {
global $wpdb;
$custom_fields = array('field1','field2'); // Array for custom meta fields
$keywords = explode(' ', get_query_var('s'));
$query = "";
foreach ($custom_fields as $field) {
foreach ($keywords as $word) {
$query .= "((mypm1.meta_key = '".$field."')";
$query .= " AND (mypm1.meta_value LIKE '%{$word}%')) OR ";
}
}
if (!empty($query)) {
// add to where clause
$pieces['where'] = str_replace("(((wp_posts.post_title LIKE '%", "( {$query} ((wp_posts.post_title LIKE '%", $pieces['where']);
$pieces['join'] = $pieces['join'] . " INNER JOIN {$wpdb->postmeta} AS mypm1 ON ({$wpdb->posts}.ID = mypm1.post_id)";
}
}
return ($pieces);
}
add_filter('posts_clauses', 'custom_search_where', 20, 1);

How to display recent global post in wordpress multisite

I run a wordpress multisite on ayp.no and I am trying to figure out a way to present all subsites with logos and recent posts from all blogs, I know there is a wpmudev premium plugin for this, but I was hoping there was some coding i could do myself (well, obviously not myself, but at least ask here and see)..
First, we need a function to get all sites, with that at hand we iterate thought the array of sites and pull the information with wp_get_recent_posts() (which is a customized version of get_posts()).
Use the following as a Must Use plugin, so the function b5f_print_recent_posts() is available throughout the network:
<?php
/**
* Plugin Name: Recent Network Posts
* Plugin URI: http://stackoverflow.com/q/23713801/1287812
* Description: Creates a function that lists recent posts from all sites of the network. Call it in another plugins or themes.
* Author: brasofilo
*/
/**
* Iterates throught all sites of the network and grab the recent posts
*/
function b5f_print_recent_posts()
{
$blogs = b5f_get_blog_list( 0, 'all', true );
$current_blog_id = get_current_blog_id();
foreach( $blogs as $blog )
{
switch_to_blog( $blog[ 'blog_id' ] );
echo '<h3>' . $blog['name'] . ' - ' . $blog['domain'] . ' - ' . $blog['desc'] . '</h3>';
$posts = wp_get_recent_posts( array(), OBJECT );
if( $posts )
{
foreach( $posts as $post )
{
printf(
'- %s<br />',
get_permalink( $post->ID ),
$post->post_title
);
}
}
}
switch_to_blog( $current_blog_id );
}
/**
* Returns an array of arrays containing information about each public blog
* hosted on this WPMU install.
*
* Only blogs marked as public and flagged as safe (mature flag off) are returned.
*
* #author Frank Bueltge
*
* #param Integer The first blog to return in the array.
* #param Integer The number of blogs to return in the array (thus the size of the array).
* Setting this to string 'all' returns all blogs from $start
* #param Boolean Get also Postcount for each blog, default is False for a better performance
* #param Integer Time until expiration in seconds, default 86400s (1day)
* #return Array Returns an array of arrays each representing a blog.
* Details are represented in the following format:
* blog_id (integer) ID of blog detailed.
* domain (string) Domain used to access this blog.
* path (string) Path used to access this blog.
* postcount (integer) The number of posts in this blog.
* name (string) Blog name.
* desc (string) Blog description.
*/
function b5f_get_blog_list( $start = 0, $num = 10, $details = FALSE, $expires = 86400 ) {
// get blog list from cache
$blogs = get_site_transient( 'multisite_blog_list' );
// For debugging purpose
if ( defined( 'WP_DEBUG' ) && WP_DEBUG )
$blogs = FALSE;
if ( FALSE === $blogs ) {
global $wpdb;
// add limit for select
if ( 'all' === $num )
$limit = '';
else
$limit = "LIMIT $start, $num";
$blogs = $wpdb->get_results(
$wpdb->prepare( "
SELECT blog_id, domain, path
FROM $wpdb->blogs
WHERE site_id = %d
AND public = '1'
AND archived = '0'
AND mature = '0'
AND spam = '0'
AND deleted = '0'
ORDER BY registered ASC
$limit
", $wpdb->siteid ),
ARRAY_A );
// Set the Transient cache
set_site_transient( 'multisite_blog_list', $blogs, $expires );
}
// only if usable, set via var
if ( TRUE === $details ) {
$blog_list = get_site_transient( 'multisite_blog_list_details' );
// For debugging purpose
if ( defined( 'WP_DEBUG' ) && WP_DEBUG )
$blog_list = FALSE;
if ( FALSE === $blog_list ) {
global $wpdb;
$current_blog_id = get_current_blog_id();
foreach ( (array) $blogs as $details ) {
$blog_list[ $details['blog_id'] ] = $details;
$blog_list[ $details['blog_id'] ]['postcount'] = $wpdb->get_var( "
SELECT COUNT(ID)
FROM " . $wpdb->get_blog_prefix( $details['blog_id'] ). "posts
WHERE post_status='publish'
AND post_type='page'"
);
switch_to_blog( $details['blog_id'] );
$blog_list[ $details['blog_id'] ]['name'] = get_blog_details()->blogname;
$blog_list[ $details['blog_id'] ]['desc'] = get_bloginfo( 'description' );
}
switch_to_blog( $current_blog_id );
// Set the Transient cache
set_site_transient( 'multisite_blog_list_details', $blog_list, $expires );
}
unset( $blogs );
$blogs = $blog_list;
}
if ( FALSE === is_array( $blogs ) )
return array();
return $blogs;
}
You can add the following network dashboard widget in the previous plugin to test it out:
add_action( 'wp_network_dashboard_setup', 'dashboard_setup_so_23713801' );
function dashboard_setup_so_23713801()
{
wp_add_dashboard_widget( 'widget_so_23713801', __( 'Test widget' ), 'print_widget_so_23713801' );
}
function print_widget_so_23713801()
{
b5f_print_recent_posts();
}

Categories