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;
}
Related
I have function previously made which get me a set of questions array each time shuffled in a new set of order each time when i take a quiz with shuffle() function
Original array (Q1,Q2,Q3,Q4,Q5,Q6)
1st time it gives me (Q2,Q4,Q1,Q3,Q6,Q5)
2nd time it gives me (Q3,Q4,Q2,Q6,Q1,Q5) and so on.
everytime a new set of questions.
This is the function code working for only for shuffle
/**
* Update user questions.
*
* #param $quiz_id
* #param $course_id
* #param $user_id
*/
public function update_user_questions( $quiz_id, $course_id, $user_id ) {
global $wpdb;
$item = null;
switch ( current_action() ) {
case 'pmi-course/user/quiz-redone':
$item = $wpdb->get_row(
$wpdb->prepare( "
SELECT * FROM {$wpdb->prefix}pmicourse_user_items
WHERE item_id = %d
AND user_id = %d
AND ref_id = %d
ORDER BY user_item_id DESC
", $quiz_id, $user_id, $course_id )
);
break;
case 'pmi-course/user/quiz-started':
break;
}
if ( ! $item ) {
return;
}
if ( ! $item->status == 'started' ) {
return;
}
$random_quiz = get_user_meta( $user_id, 'random_quiz', true );
$quiz = LP_Quiz::get_quiz( $quiz_id );
if ( $quiz && $questions = $quiz->get_questions() ) {
$questions = array_keys( $questions );
shuffle( $questions );
$question_id = reset( $questions );
// set user current question
$user = pmi_course_get_current_user();
$user_course = $user->get_course_data( $course_id );
$item_quiz = $user_course->get_item($quiz_id);
$item_quiz->set_meta( '_current_question', $question_id );
$item_quiz->update_meta();
pmi_course_update_user_item_meta( $item->user_item_id, 'current_question', $question_id );
if ( empty( $random_quiz ) ) {
$random_quiz = array( $quiz_id => $questions );
} else {
$random_quiz[ $quiz_id ] = $questions;
}
update_user_meta( $user_id, 'random_quiz', $random_quiz );
}
}
/**
* Random quiz questions.
*
* #param $quiz_questions
* #param $quiz_id
*
* #return array
*/
public function random_questions( $quiz_questions, $quiz_id ) {
if ( get_post_meta( $quiz_id, '_lp_random_mode', true ) == 'yes' ) {
// get user meta random quiz
$random_quiz = get_user_meta( get_current_user_id(), 'random_quiz', true );
if ( is_admin() || empty( $random_quiz ) || empty( $random_quiz[ $quiz_id ] ) ) {
return $quiz_questions;
}
$questions = array();
if ( array_key_exists( $quiz_id, $random_quiz ) && sizeof( $random_quiz[ $quiz_id ] ) == sizeof( $quiz_questions ) ) {
foreach ( $random_quiz[ $quiz_id ] as $question_id ) {
if ( $question_id ) {
$questions[ $question_id ] = $question_id;
}
}
} else {
$question_ids = array_keys( $quiz_questions );
shuffle( $question_ids );
$random_quiz[ $quiz_id ] = $question_ids;
$questions = array();
foreach ( $question_ids as $id ) {
$questions[ $id ] = $quiz_questions[ $id ];
}
}
return $questions;
}
return $quiz_questions;
}
This is what i tried to pull out specific number of questions randomly like "4" questions out of "6" questions from a set but it gives the random result one time and not again like shuffle() i know array_rand() gives different value each time but why not in my case. may be i am doing something wrong . I have put down both the case either can anyone identify me what i am doing wrong or the solution could be extended to more better. Any help would be appreciated.
Original array (Q1,Q2,Q3,Q4,Q5,Q6)
First time (Q1,Q4,Q5,Q6)
Second time (Q1,Q4,Q5,Q6)
Third time (Q1,Q4,Q5,Q6) ---i want different sets for each time
What i tried to achieve this
///for first function
if ( $quiz && $questions = $quiz->get_questions() ) {
$questions = array_rand( $questions , 4);
$question_id = reset( $questions );
///for second function
if ( array_key_exists( $quiz_id, $random_quiz ) && sizeof( $random_quiz[ $quiz_id ] ) < sizeof( $quiz_questions ) ) {
foreach ( $random_quiz[ $quiz_id ] as $question_id ) {
if ( $question_id ) {
$questions[ $question_id ] = $question_id;
}
}
} else {
question_ids = array_rand( $quiz_questions , 4);
$random_quiz[ $quiz_id ] = $question_ids;
questions = array();
foreach ( $question_ids as $id ) {
$questions[ $id ] = $quiz_questions[ $id ];
}
}
Simple function to grab a set of random elements from an array:
$questions = array("Question 1","Question 2","Question 3","Question 4","Question 5","Question 6","Question 7","Question 8","Question 9","Question 10");
function shuffle_questions($questions, $num_questions){
$random_questions = [];
for($i = 0; $i < $num_questions){
$random_num = rand(0, 9);
$random_questions[] = $questions[$random_num];
}
return $random_questions;
}
If you only want it to return unique questions (Probably what you're looking for)
function shuffle_questions($questions, $num_questions){
$questions_temp = $questions;
$random_questions = [];
for ($i = 0; $i++; $i < $num_questions){
$key = array_rand($questions_temp, 1);
$random_questions[] = $questions_temp[$key];
$unset($questions_temp[$key]);
}
return $random_questions;
}
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!
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();
}
Is there a way to set a column to NULL using $wpdb->update();?
When I attempt to, WordPress attempts to typecast that column to a float, which converts NULL to 0.
I've checked the core code and inside of $wpdb->update(), the $format parameter is only expecting %s, %f, and %d. I went so far as to set $wpdb->field_types['myCol'] to 'NULL', but both only serve to break $wpdb->update()'s query (interestingly enough, it shifts the values for each column over after the NULL).
There is a related question here, but that answer only deals with INSERT, not UPDATE.
From a data integrity standpoint, NULL is very important for this column, so I have to be able to set it as such when necessary.
As you yourself note, the $format parameter is only expecting %s, %f, and %d. The whole thing will get passed through prepare which also doesn't take a null format specifier because it basically accepts the same format specifiers that are accepted by (v)(s)printf but without the argument swapping. You can't pass NULL through update. You have the same choices as mentioned in the post suggested as a possible duplicate, and in essence it is.
Just don't use the update function. Write your own SQL and use it with $wpdb->query. If you are dealing with your own tables that should be fine.
Create your own database class that will do what you want. It is a little know fact that you can replace WordPress' $wpdb with a drop-in.
Here is a solution that modifies the wpdb from the latest version of wordpress, in order to allow inserting and updating null values into SQL tables using insert() and update():
/*
* Fix wpdb to allow inserting/updating of null values into tables
*/
class wpdbfixed extends wpdb
{
function insert($table, $data, $format = null) {
$type = 'INSERT';
if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) )
return false;
$this->insert_id = 0;
$formats = $format = (array) $format;
$fields = array_keys( $data );
$formatted_fields = array();
foreach ( $fields as $field ) {
if ( !empty( $format ) )
$form = ( $form = array_shift( $formats ) ) ? $form : $format[0];
elseif ( isset( $this->field_types[$field] ) )
$form = $this->field_types[$field];
else
$form = '%s';
//***edit begin here***
if ($data[$field]===null) {
unset($data[$field]); //Remove this element from array, so we don't try to insert its value into the %s/%d/%f parts during prepare(). Without this, array would become shifted.
$formatted_fields[] = 'NULL';
} else {
$formatted_fields[] = $form; //Original line of code
}
//***edit ends here***
}
$sql = "{$type} INTO `$table` (`" . implode( '`,`', $fields ) . "`) VALUES (" . implode( ",", $formatted_fields ) . ")";
return $this->query( $this->prepare( $sql, $data ) );
}
function update($table, $data, $where, $format = null, $where_format = null)
{
if ( ! is_array( $data ) || ! is_array( $where ) )
return false;
$formats = $format = (array) $format;
$bits = $wheres = array();
foreach ( (array) array_keys( $data ) as $field ) {
if ( !empty( $format ) )
$form = ( $form = array_shift( $formats ) ) ? $form : $format[0];
elseif ( isset($this->field_types[$field]) )
$form = $this->field_types[$field];
else
$form = '%s';
//***edit begin here***
if ($data[$field]===null)
{
unset($data[$field]); //Remove this element from array, so we don't try to insert its value into the %s/%d/%f parts during prepare(). Without this, array would become shifted.
$bits[] = "`$field` = NULL";
} else {
$bits[] = "`$field` = {$form}"; //Original line of code
}
//***edit ends here***
}
$where_formats = $where_format = (array) $where_format;
foreach ( (array) array_keys( $where ) as $field ) {
if ( !empty( $where_format ) )
$form = ( $form = array_shift( $where_formats ) ) ? $form : $where_format[0];
elseif ( isset( $this->field_types[$field] ) )
$form = $this->field_types[$field];
else
$form = '%s';
$wheres[] = "`$field` = {$form}";
}
$sql = "UPDATE `$table` SET " . implode( ', ', $bits ) . ' WHERE ' . implode( ' AND ', $wheres );
return $this->query( $this->prepare( $sql, array_merge( array_values( $data ), array_values( $where ) ) ) );
}
}
global $wpdb_allow_null;
$wpdb_allow_null = new wpdbfixed(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);
Insert this code into somewhere that always gets run, like your functions.php, and then use your new global $wpdb_allowed_null->insert() and ->update() as normal.
I preferred doing it this way vs. overriding the default $wpdb, in order to preserve the DB behavior that the rest of Wordpress and other plugins will expect.
Wordpress ships with the wpdb class which handles CRUD operations. The two methods of this class that I'm interested in are the insert() (the C in CRUD) and update() (the U in CRUD).
A problem arises when I want to insert a NULL into a mysql database column - the wpdb class escapes PHP null variables to empty strings. How can I tell Wordpress to use an actual MySQL NULL instead of a MySQL string?
If you want it to compatible you would have to SHOW COLUMN and determine ahead if NULL is allowed. If it was allowed then if the value was empty($v) use val = NULL in the query.
$foo = null;
$metakey = "Harriet's Adages";
$metavalue = "WordPress' database interface is like Sunday Morning: Easy.";
if ($foo == null) {
$wpdb->query( $wpdb->prepare( "
INSERT INTO $wpdb->postmeta
( post_id, meta_key, meta_value, field_with_null )
VALUES ( %d, %s, %s, NULL )",
10, $metakey, $metavalue ) );
} else {
$wpdb->query( $wpdb->prepare( "
INSERT INTO $wpdb->postmeta
( post_id, meta_key, meta_value, field_with_null )
VALUES ( %d, %s, %s, %s)",
10, $metakey, $metavalue, $foo ) );
}
Here's a solution to your problem. In "wp-content" folder, create a file named "db.php" and put this code in it:
<?php
// setup a dummy wpdb to prevent the default one from being instanciated
$wpdb = new stdclass();
// include the base wpdb class to inherit from
//include ABSPATH . WPINC . "/wp-db.php";
class wpdbfixed extends wpdb
{
function insert($table, $data, $format = null) {
$formats = $format = (array) $format;
$fields = array_keys($data);
$formatted_fields = array();
$real_data = array();
foreach ( $fields as $field ) {
if ($data[$field]===null)
{
$formatted_fields[] = 'NULL';
continue;
}
if ( !empty($format) )
$form = ( $form = array_shift($formats) ) ? $form : $format[0];
elseif ( isset($this->field_types[$field]) )
$form = $this->field_types[$field];
else
$form = '%s';
$formatted_fields[] = "'".$form."'";
$real_data[] = $data[$field];
}
//$sql = "INSERT INTO <code>$table</code> (<code>" . implode( '</code>,<code>', $fields ) . "</code>) VALUES (" . implode( ",", $formatted_fields ) . ")";
$sql = "INSERT INTO $table (" . implode( ',', $fields ) . ") VALUES (" . implode( ",", $formatted_fields ) . ")";
return $this->query( $this->prepare( $sql, $real_data) );
}
function update($table, $data, $where, $format = null, $where_format = null)
{
if ( !is_array( $where ) )
return false;
$formats = $format = (array) $format;
$bits = $wheres = array();
$fields = (array) array_keys($data);
$real_data = array();
foreach ( $fields as $field ) {
if ($data[$field]===null)
{
$bits[] = "$field = NULL";
continue;
}
if ( !empty($format) )
$form = ( $form = array_shift($formats) ) ? $form : $format[0];
elseif ( isset($this->field_types[$field]) )
$form = $this->field_types[$field];
else
$form = '%s';
$bits[] = "$field = {$form}";
$real_data[] = $data[$field];
}
$where_formats = $where_format = (array) $where_format;
$fields = (array) array_keys($where);
foreach ( $fields as $field ) {
if ( !empty($where_format) )
$form = ( $form = array_shift($where_formats) ) ? $form : $where_format[0];
elseif ( isset($this->field_types[$field]) )
$form = $this->field_types[$field];
else
$form = '%s';
$wheres[] = "$field = {$form}";
}
$sql = "UPDATE $table SET " . implode( ', ', $bits ) . ' WHERE ' . implode( ' AND ', $wheres );
return $this->query( $this->prepare( $sql, array_merge($real_data, array_values($where))) );
}
}
$wpdb = new wpdbfixed(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);
?>
In this way you can use null values with wpdb!
I find this on Wordpress StackExchange forum and it works very well for me.
// Add a filter to replace the 'NULL' string with NULL
add_filter( 'query', 'wp_db_null_value' );
global $wpdb;
$wpdb->update(
'table',
array(
'status' => 'NULL',
),
array( 'id' => 1 )
);
// Remove the filter again:
remove_filter( 'query', 'wp_db_null_value' );
and the function wp_db_null_value is:
/**
* Replace the 'NULL' string with NULL
*
* #param string $query
* #return string $query
*/
function wp_db_null_value( $query )
{
return str_ireplace( "'NULL'", "NULL", $query );
}
Because in my case I cannot use $db->prepare() function...
wpdb insert() and update() works with NULL values, it was patched many years ago but never mentioned in the Codex.
In your case:
$wpdb->update(
'table',
array(
'status' => null,
),
array( 'id' => 1 ),
null,
'%d'
);
Ref: https://core.trac.wordpress.org/ticket/15158#no0
I tried to edit one of the other solutions listed here, because it resulted in the format array being misaligned with the data array, but failed.
Here is a solution that modifies the wpdb from the latest version of wordpress, in order to allow inserting and updating null values into SQL tables using insert() and update():
/*
* Fix wpdb to allow inserting/updating of null values into tables
*/
class wpdbfixed extends wpdb
{
function insert($table, $data, $format = null) {
$type = 'INSERT';
if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) )
return false;
$this->insert_id = 0;
$formats = $format = (array) $format;
$fields = array_keys( $data );
$formatted_fields = array();
foreach ( $fields as $field ) {
if ( !empty( $format ) )
$form = ( $form = array_shift( $formats ) ) ? $form : $format[0];
elseif ( isset( $this->field_types[$field] ) )
$form = $this->field_types[$field];
else
$form = '%s';
//***Steve Lee edit begin here***
if ($data[$field]===null) {
unset($data[$field]); //Remove this element from array, so we don't try to insert its value into the %s/%d/%f parts during prepare(). Without this, array would become shifted.
$formatted_fields[] = 'NULL';
} else {
$formatted_fields[] = $form; //Original line of code
}
//***Steve Lee edit ends here***
}
$sql = "{$type} INTO `$table` (`" . implode( '`,`', $fields ) . "`) VALUES (" . implode( ",", $formatted_fields ) . ")";
return $this->query( $this->prepare( $sql, $data ) );
}
function update($table, $data, $where, $format = null, $where_format = null)
{
if ( ! is_array( $data ) || ! is_array( $where ) )
return false;
$formats = $format = (array) $format;
$bits = $wheres = array();
foreach ( (array) array_keys( $data ) as $field ) {
if ( !empty( $format ) )
$form = ( $form = array_shift( $formats ) ) ? $form : $format[0];
elseif ( isset($this->field_types[$field]) )
$form = $this->field_types[$field];
else
$form = '%s';
//***Steve Lee edit begin here***
if ($data[$field]===null)
{
unset($data[$field]); //Remove this element from array, so we don't try to insert its value into the %s/%d/%f parts during prepare(). Without this, array would become shifted.
$bits[] = "`$field` = NULL";
} else {
$bits[] = "`$field` = {$form}"; //Original line of code
}
//***Steve Lee edit ends here***
}
$where_formats = $where_format = (array) $where_format;
foreach ( (array) array_keys( $where ) as $field ) {
if ( !empty( $where_format ) )
$form = ( $form = array_shift( $where_formats ) ) ? $form : $where_format[0];
elseif ( isset( $this->field_types[$field] ) )
$form = $this->field_types[$field];
else
$form = '%s';
$wheres[] = "`$field` = {$form}";
}
$sql = "UPDATE `$table` SET " . implode( ', ', $bits ) . ' WHERE ' . implode( ' AND ', $wheres );
return $this->query( $this->prepare( $sql, array_merge( array_values( $data ), array_values( $where ) ) ) );
}
}
global $wpdb_allow_null;
$wpdb_allow_null = new wpdbfixed(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);
Insert this code into somewhere that always gets run, like your functions.php, and then use your new global $wpdb_allowed_null->insert() and ->update() as normal.
I preferred this method vs. overriding the default $wpdb, in order to preserve the DB behavior that the rest of Wordpress and other plugins will expect.