I have implemented WP List Table to display my custom data. Data are displaying correctly. I have also implemented Sorting and Pagination
But Searching functionality not working.
When I enter values in textbox and submit it then it's redirecting me to ...wp-admin/edit.php
I have followed tutorials and has same code as they have.
This code is displaying Data and searchbox
$table = new AngellEYE_Give_When_Givers_Table();
$table->prepare_items();
echo '<form method="post">';
echo '<input type="hidden" name="page" value="ttest_list_table">';
$table->search_box('Search', 'givers_search_id');
$table->display();
echo '</form>';
Here is my Class that extends WP ListTable and Displays data.
class AngellEYE_Give_When_Givers_Table extends WP_List_Table {
public function __construct() {
parent::__construct( [
'singular' => __( 'Giver', 'angelleye_give_when' ), //singular name of the listed records
'plural' => __( 'Givers', 'angelleye_give_when' ), //plural name of the listed records
'ajax' => false //should this table support ajax?
] );
}
/**
* Hook in methods
* #since 1.0.0
* #access static
*/
public static function init() {
// add_action for the class
}
/**
* Retrieve givers’s data from the database
*
* #param int $per_page
* #param int $page_number
*
* #return mixed
*/
public static function get_givers( $per_page = 5, $page_number = 1 ) {
global $wpdb;
$sql = "SELECT
(SELECT usrmeta.meta_value from wp_usermeta as usrmeta where usrmeta.user_id = um.user_id and usrmeta.meta_key = 'give_when_gec_billing_agreement_id') as BillingAgreement,
um.meta_value As PayPalEmail,
um.user_id,
u.display_name as DisplayName,
pm.meta_value as amount,
(SELECT usrmeta.meta_value from wp_usermeta as usrmeta where usrmeta.user_id = um.user_id and usrmeta.meta_key = 'give_when_gec_payer_id') as PayPalPayerID
FROM `wp_posts` as p
join `wp_users` as u on p.post_author = u.ID
join `wp_postmeta` as pm on pm.post_id = p.ID
left join wp_usermeta as um on um.user_id=u.ID
WHERE pm.`post_id` IN (SELECT post_id FROM wp_postmeta WHERE `meta_value` = '{$_REQUEST['post']}' AND `meta_key` = 'give_when_signup_wp_goal_id')
group by u.ID";
if(isset($_REQUEST['orderby'])){
if(!empty($_REQUEST['orderby'])){
$sql .= ' ORDER BY '.$_REQUEST['orderby'];
}
else{
/* by default we will add post time/post type time order by */
$sql .= ' ORDER BY PayPalEmail ';
}
$sql .= ! empty( $_REQUEST['order'] ) ? ' ' . esc_sql( $_REQUEST['order'] ) : ' ASC';
}
else{
/* by default we will add post time/post type time order by */
$sql .= ' ORDER BY PayPalEmail ';
$sql .= ! empty( $_REQUEST['order'] ) ? ' ' . esc_sql( $_REQUEST['order'] ) : ' ASC';
}
$sql .= " LIMIT $per_page";
$sql .= ' OFFSET ' . ( $page_number - 1 ) * $per_page;
$result_array = $wpdb->get_results( $sql, 'ARRAY_A' );
return $result_array;
}
/**
* Delete a customer record.
*
* #param int $id customer ID
*/
public static function delete_customer( $id ) {
global $wpdb;
$wpdb->delete(
"{$wpdb->prefix}customers",
[ 'ID' => $id ],
[ '%d' ]
);
}
/**
* Returns the count of records in the database.
*
* #return null|string
*/
public static function record_count() {
global $wpdb;
$sql = "SELECT
(SELECT usrmeta.meta_value from wp_usermeta as usrmeta where usrmeta.user_id = um.user_id and usrmeta.meta_key = 'give_when_gec_billing_agreement_id') as BillingAgreement,
um.meta_value As PayPalEmail,
um.user_id,
pm.meta_value as amount,
(SELECT usrmeta.meta_value from wp_usermeta as usrmeta where usrmeta.user_id = um.user_id and usrmeta.meta_key = 'give_when_gec_payer_id') as PayPalPayerID
FROM `wp_posts` as p
join `wp_users` as u on p.post_author = u.ID
join `wp_postmeta` as pm on pm.post_id = p.ID
left join wp_usermeta as um on um.user_id=u.ID
WHERE pm.`post_id` IN (SELECT post_id FROM wp_postmeta WHERE `meta_value` = '{$_REQUEST['post']}' AND `meta_key` = 'give_when_signup_wp_goal_id')
group by u.ID";
$wpdb->get_results( $sql, 'ARRAY_A' );
return $wpdb->num_rows;
}
/** Text displayed when no giver's data is available */
public function no_items() {
_e( 'No Givers avaliable.', 'angelleye_give_when' );
}
/**
* Method for name column
*
* #param array $item an array of DB data
*
* #return string
*/
public function column_name( $item ) {
//
// // create a nonce
// $delete_nonce = wp_create_nonce( 'sp_delete_customer' );
//
// $title = '<strong>' . $item['name'] . '</strong>';
//
// $actions = [
// 'delete' => sprintf( 'Delete')
// ];
//
// return $title . $this->row_actions( $actions );
}
/**
* Render a column when no column specific method exists.
*
* #param array $item
* #param string $column_name
*
* #return mixed
*/
public function column_default( $item, $column_name ) {
switch ( $column_name ) {
case 'BillingAgreement':
echo $item['BillingAgreement'];
break;
case 'PayPalEmail':
echo $item['PayPalEmail'];
break;
case 'amount' :
echo $item['amount'];
break;
case 'PayPalPayerID' :
echo $item['PayPalPayerID'];
break;
case 'DisplayName' :
echo $item['DisplayName'];
break;
}
}
/**
* Render the bulk edit checkbox
*
* #param array $item
*
* #return string
*/
public function column_cb( $item ) {
return sprintf(
'<input type="checkbox" name="bulk-delete[]" value="%s" />', $item['user_id']
);
}
/**
* Associative array of columns
*
* #return array
*/
public function get_columns() {
$columns = [
'cb' => '<input type="checkbox" />',
'BillingAgreement'=> __( 'Billing Agreement ID', 'angelleye_give_when' ),
'DisplayName' => __( 'Name', 'angelleye_give_when' ),
'PayPalEmail' => __( 'Givers', 'angelleye_give_when' ),
'amount' => __( 'Amount', 'angelleye_give_when' ),
'PayPalPayerID' => __('PayPal Payer ID','angelleye_give_when')
];
return $columns;
}
/**
* Columns to make sortable.
*
* #return array
*/
public function get_sortable_columns() {
$sortable_columns = array(
'BillingAgreement' => array( 'BillingAgreement', true ),
'DisplayName' => array('DisplayName',true),
'PayPalEmail' => array( 'PayPalEmail', true ),
'amount' => array( 'amount', true ),
'PayPalPayerID' => array( 'PayPalPayerID', true )
);
return $sortable_columns;
}
/**
* Returns an associative array containing the bulk action
*
* #return array
*/
public function get_bulk_actions() {
$actions = [
'bulk-delete' => 'Delete'
];
return $actions;
}
/**
* Handles data query and filter, sorting, and pagination.
*/
public function prepare_items() {
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array($columns, $hidden, $sortable);
/** Process bulk action */
$this->process_bulk_action();
$per_page = $this->get_items_per_page( 'givers_per_page', 5 );
$current_page = $this->get_pagenum();
$total_items = self::record_count();
$this->set_pagination_args( [
'total_items' => $total_items, //WE have to calculate the total number of items
'per_page' => $per_page //WE have to determine how many items to show on a page
] );
$this->items = self::get_givers( $per_page, $current_page );
}
public function process_bulk_action() {
//Detect when a bulk action is being triggered...
if ( 'delete' === $this->current_action() ) {
// In our file that handles the request, verify the nonce.
$nonce = esc_attr( $_REQUEST['_wpnonce'] );
if ( ! wp_verify_nonce( $nonce, 'sp_delete_customer' ) ) {
die( 'Go get a life script kiddies' );
}
else {
self::delete_customer( absint( $_GET['customer'] ) );
wp_redirect( esc_url( add_query_arg() ) );
exit;
}
}
// If the delete bulk action is triggered
if ( ( isset( $_POST['action'] ) && $_POST['action'] == 'bulk-delete' )
|| ( isset( $_POST['action2'] ) && $_POST['action2'] == 'bulk-delete' )
) {
$delete_ids = esc_sql( $_POST['bulk-delete'] );
// loop over the array of record IDs and delete them
foreach ( $delete_ids as $id ) {
self::delete_customer( $id );
}
wp_redirect( esc_url( add_query_arg() ) );
exit;
}
}
}
AngellEYE_Give_When_Givers_Table::init();
Any good way how can I fix that ?
Any information on this would be greatly appreciated. Thanks!
Related
I want to trigger action save_post_shop_order by url, because I have custom function that will create product meta there on checking.
I tried something like:
add_action('wp_head', 'update_orders_by_url');
function update_orders_by_url() {
if( isset( $_GET['update_woo_orders'] ) ) {
$query = new WC_Order_Query( array(
'limit' => -1
));
$orders = $query->get_orders();
foreach($orders as $order){
$arra2[] = $order;
// Save
$order->save();
}
}
//echo count($arra2);
}
But seems not working in my case.
How I can trigger update all orders and run action save_post_shop_order for all orders?
Thanks
You can do it this way, put your code in functions.php or a plugin
add_filter( 'handle_bulk_actions-edit-shop_order', 'save_post_shop_order', 10, 3 );
/**
* #param $redirect_to
* #param $action
* #param $post_ids
* #return mixed|string
*/
function save_post_shop_order( $redirect_to, $action, $post_ids ) {
// do your job
return $redirect_to = add_query_arg( array(
'bulk_action_name' => $action,
'processed_count' => count( $processed_ids ),
'processed_ids' => implode( ',', $processed_ids ),
), $redirect_to );
}
add_action( 'admin_notices', 'save_post_shop_order_admin_notice' );
/**
* The results notice from bulk action on orders
*/
function save_post_shop_order_admin_notice() {
$count = intval( $_REQUEST['processed_count'] );
printf( '<div id="message" class="updated fade"><p>' .
_n( "",
"",
$count,
''
) . '</p></div>', $count );
}
To update orders information through the URL, you can try the following steps.
Create a file in your root directory
On the top of the file, add this piece of code.
require(dirname(__FILE__) . '/wp-load.php');
Get all orders
$orders = wc_get_orders( array('numberposts' => -1) );
// Loop through each WC_Order object
foreach( $orders as $order ){
echo $order->get_id() . '<br>'; // The order ID
echo $order->get_status() . '<br>'; // The order status
.......
// do your stuff
}
Now, you will be able to update orders information through URL.
Hit your url/pagename, for example, http://example.com/test.php
I'm trying to show how much each customer has spent in total WITHOUT including the shipping cost. Everything from the code below, which creates a new column and makes it sortable, works fine except for the calculation.
I get an error on line 37 which is this one:
$money_spent = wc_get_customer_total_spent( $user_id ) - $order->get_total_tax() - $order->get_total_shipping() - $order->get_shipping_tax(), wc_get_price_decimals(), '.', '' );
Here is all the code I'm using =>
class Total_Spent_By_Customer_WooCommerce {
public function __construct() {
add_action( 'init', array( &$this, 'init' ) );
}
public function init() {
add_filter( 'manage_users_columns', array( $this,'users_columns') );
add_action( 'manage_users_custom_column', array( $this ,'users_custom_column'), 10, 3);
add_filter( 'manage_users_sortable_columns', array( $this ,'users_sortable_columns') );
add_filter( 'users_list_table_query_args', array( $this ,'users_orderby_column'), 10, 1 );
add_action( 'plugins_loaded', array( $this ,'load_this_textdomain') );
}
public static function users_columns( $columns ) {
unset($columns['posts']);
$columns['money_spent'] = _x( 'Money Spent', 'user', 'total-spent-by-customer-for-woocommerce' );
return $columns;
}
public static function users_custom_column( $value, $column_name, $user_id ) {
if ( 'money_spent' != $column_name ) {
return $value;
} else {
$money_spent = wc_get_customer_total_spent( $user_id ) - $order->get_total_tax() - $order->get_total_shipping() - $order->get_shipping_tax(), wc_get_price_decimals(), '.', '' );
return wc_price( wc_get_customer_total_spent ( $user_id ));
}
}
public static function users_sortable_columns($columns) {
$custom = array(
'money_spent' => 'money_spent',
);
return wp_parse_args( $custom, $columns );
}
public static function users_orderby_column( $args ) {
if ( isset( $args['orderby'] ) && 'money_spent' == $args['orderby'] ) {
$args = array_merge( $args, array(
'meta_key' => '_money_spent',
'orderby' => 'meta_value_num',
));
}
return $args;
}
public function load_this_textdomain() {
load_plugin_textdomain( 'total-spent-by-customer-for-woocommerce' );
}
}
new Total_Spent_By_Customer_WooCommerce();
I would really appreciate any type of help with this.
Update 2
You can not get Customer total spent without shipping and taxes totals using wc_get_customer_total_spent( $user_id ) function, as you should need to remove the taxes and shipping for each order that the current customer has made.
Also you can not get and use The WC_Order object in your function. So the WC_Order methods get_total_tax(), get_total_shipping() and get_shipping_tax() can't be used.
The alternative to get the customer total spent without shipping and taxes:
Based on the SQL Woocommerce query source code involved in wc_get_customer_total_spent() function we can build your own query.
So you will replace your function by this:
public static function users_custom_column( $value, $column_name, $user_id ) {
if ( 'money_spent' == $column_name ) {
global $wpdb;
$statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
$spent = $wpdb->get_var("
SELECT SUM(pm2.meta_value - (pm3.meta_value + pm4.meta_value))
FROM $wpdb->posts as p
LEFT JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id
LEFT JOIN {$wpdb->postmeta} AS pm2 ON p.ID = pm2.post_id
LEFT JOIN {$wpdb->postmeta} AS pm3 ON p.ID = pm3.post_id
LEFT JOIN {$wpdb->postmeta} AS pm4 ON p.ID = pm4.post_id
WHERE pm.meta_key = '_customer_user'
AND pm.meta_value = '" . esc_sql( $user_id ) . "'
AND p.post_type = 'shop_order'
AND p.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' )
AND pm2.meta_key = '_order_total'
AND pm3.meta_key = '_order_tax'
AND pm4.meta_key = '_order_shipping'
");
if ( ! $spent ) {
$spent = 0;
}
$value = wc_price( $spent );
}
return $value;
}
Tested and perfectly works.
Calculations note:
As you are removing the total taxes from the orders you don't need to remove the shipping taxes (as they are included in the total taxes).
So we just remove the total taxes and the total shipping (excluding taxes).
I've been working with the wp_list_table class and creating my custom theme pages with add/edit/delete features on the row options. The problem i am having is with the bulk actions. The row actions are working just fine. Now here is where it gets weird.
If I am looking at my table in admin and I select the checkbox on a few rows, switch to bulk-delete action, then hit apply, I will not get any post data for those checkboxes. What I mean by that is the checkboxes are named as an array bulk-delete[] in html. and if I do a print_r($_request); the bulk-delete key is no present.
Now when I select a few checkboxes, and this time NOT switch to bulk-delete I just leave it saying "Bulk Actions", then hit apply, I will get the bulk-delete array but all the keys are empty.
For me totally freaking bazaar. But I am sure there is something really stupid that I missed. So here is the class in it's entirety. Please let me know what I missed.
[a secondary issue - I'd like to also show an "Country has been added" success message. Could you guys point me in the right direction for knowledge to read up on that]
Thanks in advance.
<?php
class country_class {
var $page_name = "lp-manage-countries";
public function __construct(){
//make sure the wp_list_table class has been loaded
if (!class_exists('WP_List_Table')) {
require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
}
add_action( 'admin_post_add_country', array( $this, 'lp_admin_add_country') );
add_filter('set-screen-option', array( $this, 'lp_save_screen_options') , 10, 3);
//add_action( 'admin_post_bulk_action', array( $this, 'process_bulk_action') );
}
/**
* Sets the screen options up for table paging
*/
public function lp_screen_options() {
$lp_manage_countries_page = "toplevel_page_" . $this->page_name;
$screen = get_current_screen();
// get out of here if we are not on our settings page
if(!is_object($screen) || $screen->id != $lp_manage_countries_page)
return;
$args = array(
'label' => __('Countries per page'),
'default' => 25,
'option' => 'countries_per_page'
);
add_screen_option( 'per_page', $args );
}
/**
* Saves the screen option to the object class
*/
function lp_save_screen_options($status, $option, $value) {
if ( 'countries_per_page' == $option ) return $value;
return $status;
}
/**
* Installs the page and screen options
*/
public function install_countries_page(){
//Add the screen options first
add_action("load-toplevel_page_" . $this->page_name, array( $this, "lp_screen_options") );
add_menu_page('LP Countries', 'LP Countries', 'manage_options', 'lp-manage-countries', array($this, 'show_country_page'));
}
public function lp_admin_add_country(){
global $wpdb;
if( isset( $_REQUEST['country_name'] ) and !empty( $_REQUEST['country_name'] )){
$result = $wpdb->insert(
'countries',
array(
'name' => $_REQUEST['country_name']
)
);
if( $result !== false ){
wp_redirect(admin_url("admin.php?page=" . $this->page_name) );
exit;
}
}
}
/**
* Displays the page data
*/
public function show_country_page(){
if( isset( $_GET['action']) && ( $_REQUEST['action'] == "add" || $_REQUEST['action'] == "edit" )){
echo "<div class='wrap'>
<h1>Add Country</h1>
<form action='" . admin_url("admin-post.php", "http") . "' method='post'>
<input type=\"hidden\" name=\"action\" value=\"add_country\">
<table class=\"form-table\">
<tbody>
<tr>
<th scope=\"row\"><label for='country_name' xmlns=\"http://www.w3.org/1999/html\">Country Name:</label></th>
<td><input id='country_name' required class='regular-text type='text' value='' name='country_name'></input></td>
</tr>
</tbody>
</table>
<p class='submit'>
<input id='submit' class='button button-primary' type='submit' value='Save Country' name='submit'></input>
</p>
</form>";
} else {
echo "<div class=\"wrap\">
<h1>Manage Countries<a class=\"page-title-action\" href=\"".admin_url("admin.php?page=".$this->page_name."&action=add")."\">Add New</a></h1>
<form method='post'>";
//echo "<input type=\"hidden\" name=\"action\" value=\"bulk_action\">";
//Prepare Table of elements
$categories_list_table = new category_list_table();
$categories_list_table->prepare_items();
//Table of elements
$categories_list_table->display();
echo "</form>";
}
}
/**
* Creates the database for this page
*/
public function create_countries_table(){
global $wpdb;
$charset = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS `countries` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,
`parent_id` int(11) DEFAULT NULL,
`image` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) $charset; ";
$wpdb->query( $sql );
}
/**
* removes the page database when uninstalled
*/
public function drop_countries_table(){
global $wpdb;
$sql = "DROP TABLE `countries`;";
$wpdb->query($sql);
}
}
class category_list_table extends WP_List_Table {
public function __construct(){
parent::__construct( array(
'singular' => 'Country',
'plural' => 'Countries',
'ajax' => false)
);
}
public function get_columns(){
return $columns = array(
'cb' => '<input name="bulk-delete[]" type="checkbox" />',
'name' => __('Name'),
'parent_id' => __('Parent ID'),
'image' => __('Image')
);
}
function column_name($item) {
// create a nonce
$delete_nonce = wp_create_nonce( 'lp_delete_country' );
$edit_nonce = wp_create_nonce( 'lp_delete_country' );
$actions = array(
'edit' => sprintf('Edit', $_REQUEST['page'], 'edit', $item['id'], $edit_nonce),
'delete' => sprintf('Delete', $_REQUEST['page'], 'delete', $item['id'], $delete_nonce),
);
return sprintf('%1$s %2$s', $item['name'], $this->row_actions($actions) );
}
public function get_sortable_columns(){
return $sortable = array(
'id' => array('id',false),
'name' => array('name',false),
'parent_id' => array('parent_id', false),
'image' => array('image', false)
);
}
public function get_hidden_columns( ){
$screen = get_current_screen();
if ( is_string( $screen ) )
$screen = convert_to_screen( $screen );
return (array) get_user_option( 'manage' . $screen->id . 'columnshidden' );
}
public function prepare_items(){
global $wpdb, $_wp_column_headers;
$screen = get_current_screen();
/** Process bulk action */
$this->process_bulk_action();
/* Prepare the query */
$query = "SELECT * FROM `countries`";
/* Order Parameters */
$orderby = !empty($_GET["orderby"]) ? mysql_real_escape_string($_GET["orderby"]) : 'ASC';
$order = !empty($_GET["order"]) ? mysql_real_escape_string($_GET["order"]) : '';
if(!empty($orderby) & !empty($order)){ $query.=' ORDER BY '.$orderby.' '.$order; }
/* Pagination Params */
//Number of elements in your table?
$totalitems = $wpdb->query($query); //return the total number of affected rows
//How many to display per page?
$perpage = get_user_meta( get_current_user_id() , 'countries_per_page', true);
if( empty($perpage)){
$perpage = 25;
}
//Which page is this?
$paged = !empty($_GET["paged"]) ? mysql_real_escape_string($_GET["paged"]) : '';
//Page Number
if(empty($paged) || !is_numeric($paged) || $paged<=0 ){ $paged=1; }
//How many pages do we have in total?
$totalpages = ceil($totalitems/$perpage);
//adjust the query to take pagination into account
if(!empty($paged) && !empty($perpage)){
$offset=($paged-1)*$perpage;
$query.=' LIMIT '.(int)$offset.','.(int)$perpage;
}
/* Register pagination */
$this->set_pagination_args( array(
"total_items" => $totalitems,
"total_pages" => $totalpages,
"per_page" => $perpage
)
);
/* register the columns */
$columns = $this->get_columns();
$_wp_column_headers[$screen->id]=$columns;
/* Get the items */
$this->items = $wpdb->get_results($query, 'ARRAY_A');
$hidden_columns = $this->get_hidden_columns();
$sortable_columns = $this->get_sortable_columns();
parent::get_column_info();
$this->_column_headers = array( $columns, $hidden_columns, $sortable_columns);
}
public function column_default($item, $column_name) {
//return $item[$column_name];
switch ( $column_name ) {
case 'cb':
case 'name':
case 'parent_id':
case 'image':
return $item[ $column_name ];
default:
return $item[ $column_name ];
}
}
function no_items() {
_e( 'No Countries Found.' );
}
function column_cb( $item ) {
return sprintf(
'<input type="checkbox" name="bulk-delete[]" value="%s" />', $item['ID']
);
}
public function get_bulk_actions() {
$actions = [
'bulk-delete' => 'Delete'
];
return $actions;
}
public function process_bulk_action() {
$action = $this->current_action();
echo "action is [" . $action . "]";
if( !empty( $action ) ){
switch ($action){
case 'delete':
// In our file that handles the request, verify the nonce.
$nonce = esc_attr( $_REQUEST['_wpnonce'] );
if ( ! wp_verify_nonce( $nonce, 'lp_delete_country' ) ) {
die( 'Go get a life script kiddies' );
} else {
echo " running delete";
self::delete_country( absint( $_GET['country'] ) );
wp_redirect( esc_url( add_query_arg() ) );
exit;
}
case 'edit':
echo "we should be editing";
case 'bulk-delete':
// If the delete bulk action is triggered
echo "we triggered a bulk delete";
echo "<pre>";
print_r( $_REQUEST );
echo "</pre>";
if ( !empty( $_POST['bulk-delete'] ) ) {
$delete_ids = esc_sql( $_POST['bulk-delete'] );
// loop over the array of record IDs and delete them
foreach ( $delete_ids as $id ) {
$this->delete_country( $id );
}
wp_redirect( esc_url( add_query_arg() ) );
exit;
} else {
echo "Fucking empty";
}
default:
echo "<pre>";
print_r( $_REQUEST );
echo "</pre>";
//quietly exit;
}
} else {
echo "<pre>";
print_r( $_REQUEST );
echo "</pre>";
}
}
function delete_country( $id ) {
global $wpdb;
$wpdb->delete(
"countries",
[ 'id' => $id ]
);
}
}
I look HERE and HERE before ask you but this solution doesn't work.
THIS is my table that I'm working: LIVE DEMO
I can filter records only using AND function and this is very limited
If you type never dream table returns me null results. But I want to see all rows with never OR dream word when I typing!
I want to change this PHP (ssp.class.php) script but I don't know how code must be edited. Replace AND with OR doesn't work...
class SSP {
/**
* Create the data output array for the DataTables rows
*
* #param array $columns Column information array
* #param array $data Data from the SQL get
* #return array Formatted data in a row based format
*/
static function data_output ( $columns, $data )
{
$out = array();
for ( $i=0, $ien=count($data) ; $i<$ien ; $i++ ) {
$row = array();
for ( $j=0, $jen=count($columns) ; $j<$jen ; $j++ ) {
$column = $columns[$j];
// Is there a formatter?
if ( isset( $column['formatter'] ) ) {
$row[ $column['dt'] ] = $column['formatter']( $data[$i][ $column['db'] ], $data[$i] );
}
else {
$row[ $column['dt'] ] = $data[$i][ $columns[$j]['db'] ];
}
}
$out[] = $row;
}
return $out;
}
/**
* Database connection
*
* Obtain an PHP PDO connection from a connection details array
*
* #param array $conn SQL connection details. The array should have
* the following properties
* * host - host name
* * db - database name
* * user - user name
* * pass - user password
* #return resource PDO connection
*/
static function db ( $conn )
{
if ( is_array( $conn ) ) {
return self::sql_connect( $conn );
}
return $conn;
}
/**
* Paging
*
* Construct the LIMIT clause for server-side processing SQL query
*
* #param array $request Data sent to server by DataTables
* #param array $columns Column information array
* #return string SQL limit clause
*/
static function limit ( $request, $columns )
{
$limit = '';
if ( isset($request['start']) && $request['length'] != -1 ) {
$limit = "LIMIT ".intval($request['start']).", ".intval($request['length']);
}
return $limit;
}
/**
* Ordering
*
* Construct the ORDER BY clause for server-side processing SQL query
*
* #param array $request Data sent to server by DataTables
* #param array $columns Column information array
* #return string SQL order by clause
*/
static function order ( $request, $columns )
{
$order = '';
if ( isset($request['order']) && count($request['order']) ) {
$orderBy = array();
$dtColumns = self::pluck( $columns, 'dt' );
for ( $i=0, $ien=count($request['order']) ; $i<$ien ; $i++ ) {
// Convert the column index into the column data property
$columnIdx = intval($request['order'][$i]['column']);
$requestColumn = $request['columns'][$columnIdx];
$columnIdx = array_search( $requestColumn['data'], $dtColumns );
$column = $columns[ $columnIdx ];
if ( $requestColumn['orderable'] == 'true' ) {
$dir = $request['order'][$i]['dir'] === 'asc' ?
'ASC' :
'DESC';
$orderBy[] = '`'.$column['db'].'` '.$dir;
}
}
$order = 'ORDER BY '.implode(', ', $orderBy);
}
return $order;
}
/**
* Searching / Filtering
*
* Construct the WHERE clause for server-side processing SQL query.
*
* NOTE this does not match the built-in DataTables filtering which does it
* word by word on any field. It's possible to do here performance on large
* databases would be very poor
*
* #param array $request Data sent to server by DataTables
* #param array $columns Column information array
* #param array $bindings Array of values for PDO bindings, used in the
* sql_exec() function
* #return string SQL where clause
*/
static function filter ( $request, $columns, &$bindings )
{
$globalSearch = array();
$columnSearch = array();
$dtColumns = self::pluck( $columns, 'dt' );
if ( isset($request['search']) && $request['search']['value'] != '' ) {
$str = $request['search']['value'];
for ( $i=0, $ien=count($request['columns']) ; $i<$ien ; $i++ ) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search( $requestColumn['data'], $dtColumns );
$column = $columns[ $columnIdx ];
if ( $requestColumn['searchable'] == 'true' ) {
$binding = self::bind( $bindings, '%'.$str.'%', PDO::PARAM_STR );
$globalSearch[] = "`".$column['db']."` LIKE ".$binding;
}
}
}
// Individual column filtering
for ( $i=0, $ien=count($request['columns']) ; $i<$ien ; $i++ ) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search( $requestColumn['data'], $dtColumns );
$column = $columns[ $columnIdx ];
$str = $requestColumn['search']['value'];
if ( $requestColumn['searchable'] == 'true' &&
$str != '' ) {
$binding = self::bind( $bindings, '%'.$str.'%', PDO::PARAM_STR );
$columnSearch[] = "`".$column['db']."` LIKE ".$binding;
}
}
// Combine the filters into a single string
$where = '';
if ( count( $globalSearch ) ) {
$where = '('.implode(' OR ', $globalSearch).')';
}
if ( count( $columnSearch ) ) {
$where = $where === '' ?
implode(' AND ', $columnSearch) :
$where .' AND '. implode(' AND ', $columnSearch);
}
if ( $where !== '' ) {
$where = 'WHERE '.$where;
}
return $where;
}
/**
* Perform the SQL queries needed for an server-side processing requested,
* utilising the helper functions of this class, limit(), order() and
* filter() among others. The returned array is ready to be encoded as JSON
* in response to an SSP request, or can be modified if needed before
* sending back to the client.
*
* #param array $request Data sent to server by DataTables
* #param array|PDO $conn PDO connection resource or connection parameters array
* #param string $table SQL table to query
* #param string $primaryKey Primary key of the table
* #param array $columns Column information array
* #return array Server-side processing response array
*/
static function simple ( $request, $conn, $table, $primaryKey, $columns )
{
$bindings = array();
$db = self::db( $conn );
// Build the SQL query string from the request
$limit = self::limit( $request, $columns );
$order = self::order( $request, $columns );
$where = self::filter( $request, $columns, $bindings );
// Main query to actually get the data
$data = self::sql_exec( $db, $bindings,
"SELECT SQL_CALC_FOUND_ROWS `".implode("`, `", self::pluck($columns, 'db'))."`
FROM `$table`
$where
$order
$limit"
);
// Data set length after filtering
$resFilterLength = self::sql_exec( $db,
"SELECT FOUND_ROWS()"
);
$recordsFiltered = $resFilterLength[0][0];
// Total data set length
$resTotalLength = self::sql_exec( $db,
"SELECT COUNT(`{$primaryKey}`)
FROM `$table`"
);
$recordsTotal = $resTotalLength[0][0];
/*
* Output
*/
return array(
"draw" => intval( $request['draw'] ),
"recordsTotal" => intval( $recordsTotal ),
"recordsFiltered" => intval( $recordsFiltered ),
"data" => self::data_output( $columns, $data )
);
}
/**
* The difference between this method and the `simple` one, is that you can
* apply additional `where` conditions to the SQL queries. These can be in
* one of two forms:
*
* * 'Result condition' - This is applied to the result set, but not the
* overall paging information query - i.e. it will not effect the number
* of records that a user sees they can have access to. This should be
* used when you want apply a filtering condition that the user has sent.
* * 'All condition' - This is applied to all queries that are made and
* reduces the number of records that the user can access. This should be
* used in conditions where you don't want the user to ever have access to
* particular records (for example, restricting by a login id).
*
* #param array $request Data sent to server by DataTables
* #param array|PDO $conn PDO connection resource or connection parameters array
* #param string $table SQL table to query
* #param string $primaryKey Primary key of the table
* #param array $columns Column information array
* #param string $whereResult WHERE condition to apply to the result set
* #param string $whereAll WHERE condition to apply to all queries
* #return array Server-side processing response array
*/
static function complex ( $request, $conn, $table, $primaryKey, $columns, $whereResult=null, $whereAll=null )
{
$bindings = array();
$db = self::db( $conn );
$localWhereResult = array();
$localWhereAll = array();
$whereAllSql = '';
// Build the SQL query string from the request
$limit = self::limit( $request, $columns );
$order = self::order( $request, $columns );
$where = self::filter( $request, $columns, $bindings );
$whereResult = self::_flatten( $whereResult );
$whereAll = self::_flatten( $whereAll );
if ( $whereResult ) {
$where = $where ?
$where .' AND '.$whereResult :
'WHERE '.$whereResult;
}
if ( $whereAll ) {
$where = $where ?
$where .' AND '.$whereAll :
'WHERE '.$whereAll;
$whereAllSql = 'WHERE '.$whereAll;
}
// Main query to actually get the data
$data = self::sql_exec( $db, $bindings,
"SELECT SQL_CALC_FOUND_ROWS `".implode("`, `", self::pluck($columns, 'db'))."`
FROM `$table`
$where
$order
$limit"
);
// Data set length after filtering
$resFilterLength = self::sql_exec( $db,
"SELECT FOUND_ROWS()"
);
$recordsFiltered = $resFilterLength[0][0];
// Total data set length
$resTotalLength = self::sql_exec( $db, $bindings,
"SELECT COUNT(`{$primaryKey}`)
FROM `$table` ".
$whereAllSql
);
$recordsTotal = $resTotalLength[0][0];
/*
* Output
*/
return array(
"draw" => intval( $request['draw'] ),
"recordsTotal" => intval( $recordsTotal ),
"recordsFiltered" => intval( $recordsFiltered ),
"data" => self::data_output( $columns, $data )
);
}
/**
* Connect to the database
*
* #param array $sql_details SQL server connection details array, with the
* properties:
* * host - host name
* * db - database name
* * user - user name
* * pass - user password
* #return resource Database connection handle
*/
static function sql_connect ( $sql_details )
{
try {
$db = #new PDO(
"mysql:host={$sql_details['host']};dbname={$sql_details['db']}",
$sql_details['user'],
$sql_details['pass'],
array( PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION )
);
}
catch (PDOException $e) {
self::fatal(
"An error occurred while connecting to the database. ".
"The error reported by the server was: ".$e->getMessage()
);
}
return $db;
}
/**
* Execute an SQL query on the database
*
* #param resource $db Database handler
* #param array $bindings Array of PDO binding values from bind() to be
* used for safely escaping strings. Note that this can be given as the
* SQL query string if no bindings are required.
* #param string $sql SQL query to execute.
* #return array Result from the query (all rows)
*/
static function sql_exec ( $db, $bindings, $sql=null )
{
// Argument shifting
if ( $sql === null ) {
$sql = $bindings;
}
$stmt = $db->prepare( $sql );
//echo $sql;
// Bind parameters
if ( is_array( $bindings ) ) {
for ( $i=0, $ien=count($bindings) ; $i<$ien ; $i++ ) {
$binding = $bindings[$i];
$stmt->bindValue( $binding['key'], $binding['val'], $binding['type'] );
}
}
// Execute
try {
$stmt->execute();
}
catch (PDOException $e) {
self::fatal( "An SQL error occurred: ".$e->getMessage() );
}
// Return all
return $stmt->fetchAll();
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Internal methods
*/
/**
* Throw a fatal error.
*
* This writes out an error message in a JSON string which DataTables will
* see and show to the user in the browser.
*
* #param string $msg Message to send to the client
*/
static function fatal ( $msg )
{
echo json_encode( array(
"error" => $msg
) );
exit(0);
}
/**
* Create a PDO binding key which can be used for escaping variables safely
* when executing a query with sql_exec()
*
* #param array &$a Array of bindings
* #param * $val Value to bind
* #param int $type PDO field type
* #return string Bound key to be used in the SQL where this parameter
* would be used.
*/
static function bind ( &$a, $val, $type )
{
$key = ':binding_'.count( $a );
$a[] = array(
'key' => $key,
'val' => $val,
'type' => $type
);
return $key;
}
/**
* Pull a particular property from each assoc. array in a numeric array,
* returning and array of the property values from each item.
*
* #param array $a Array to get data from
* #param string $prop Property to read
* #return array Array of property values
*/
static function pluck ( $a, $prop )
{
$out = array();
for ( $i=0, $len=count($a) ; $i<$len ; $i++ ) {
$out[] = $a[$i][$prop];
}
return $out;
}
/**
* Return a string from an array or a string
*
* #param array|string $a Array to join
* #param string $join Glue for the concatenation
* #return string Joined string
*/
static function _flatten ( $a, $join = ' AND ' )
{
if ( ! $a ) {
return '';
}
else if ( $a && is_array($a) ) {
return implode( $join, $a );
}
return $a;
}
}
---------------- UPDATED
I try to change original code
static function filter ( $request, $columns, &$bindings )
{
$globalSearch = array();
$columnSearch = array();
$dtColumns = self::pluck( $columns, 'dt' );
if ( isset($request['search']) && $request['search']['value'] != '' ) {
$str = $request['search']['value'];
for ( $i=0, $ien=count($request['columns']) ; $i<$ien ; $i++ ) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search( $requestColumn['data'], $dtColumns );
$column = $columns[ $columnIdx ];
if ( $requestColumn['searchable'] == 'true' ) {
$binding = self::bind( $bindings, '%'.$str.'%', PDO::PARAM_STR );
$globalSearch[] = "`".$column['db']."` LIKE ".$binding;
}
}
}
with Andriy edited code
static function filter ( $request, $columns, &$bindings )
{
$globalSearch = array();
$columnSearch = array();
$dtColumns = self::pluck( $columns, 'dt' );
if ( isset($request['search']) && $request['search']['value'] != '' ) {
$str = $request['search']['value'];
for ( $i=0, $ien=count($request['columns']) ; $i<$ien ; $i++ ) {
$requestColumn = $request['columns'][$i];
$columnIdx = array_search( $requestColumn['data'], $dtColumns );
$column = $columns[ $columnIdx ];
if ( $requestColumn['searchable'] == 'true' )
$strArray = explode(' ',$str);
foreach ($strArray as $str)
{
$binding = self::bind( $bindings, '%'.$str.'%', PDO::PARAM_STR );
$globalSearch[] = "`".$column['db']."` LIKE ".$binding;
}
}
}
in function filter()
$str is the variable you want to search.
So, you need to:
Use separate search engine, like solr, elastic search, sphinx.
Use mysql FULL TEXT search.
Change:
$binding = self::bind( $bindings, '%'.$str.'%', PDO::PARAM_STR );
$columnSearch[] = "".$column['db']." LIKE ".$binding;
to
$strArray = explode(' ',$str);
foreach ($strArray as $str) {
$binding = self::bind( $bindings, '%'.$str.'%', PDO::PARAM_STR );
$columnSearch[] = "`".$column['db']."` LIKE ".$binding;
}
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();
}