I am making a plugin to display all user info in a DataTables but i am failed to implement Search, filter and Pagination . I have about 20k users. Please help me.
may be I need to change my query to join wp_users and wp_usermeta and get the result for my case. I have fount a question here and a similar tutorial here . I am not good in writing MySQL query. Please help me with this.
I get ajax response like
{
"draw": 1,
"recordsTotal": 1,
"recordsFiltered": 1,
"data": [
[
"example#mail.com",
"Some Name",
"",
"admin",
""
]
]
}
This is my table structure
<table id="user_table" class="display table table-striped table-bordered dataTable" style="width:100%">
<thead class="user-table">
<tr>
<th>Email</th>
<th>Name </th>
<th>Url</th>
<th>nickname</th>
<th>description</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
My script
jQuery(document).ready(function($){
$(window).on('load', function () {
setTimeout(loadtable, 200);
});
function loadtable(){
var ajaxurl = USERAjax.wpajaxusersearch;
var dataTable = $('#user_table').DataTable({
"processing":true,
"serverSide": true,
"order":[],
"pageLength": 10,
"ajax":{
url: ajaxurl,
type:"POST"
},
});
}
});
also added localize script like
function users_assets_scripts(){
wp_register_script( 'jquery_datatables_js', plugins_url( 'asset/js/datatables.min.js' , __FILE__ ), array(),null,true );
wp_enqueue_script( 'jquery_datatables_js' );
wp_register_style( 'jquery_datatables_css', plugins_url( 'asset/css/datatables.min.css' , __FILE__ ));
wp_enqueue_style( 'jquery_datatables_css' );
wp_localize_script( 'jquery', 'USERAjax', array('wpajaxusersearch' => admin_url( 'admin-ajax.php?action=wpajaxusersearch' )) );
}
add_action('wp_enqueue_scripts', 'users_assets_scripts');
and my data fetching function with ajax response
<?php
function wpajaxusersearch(){
$request=$_REQUEST;
global $wpdb;
$sort= "user_registered";
//Build the custom database query to fetch all user IDs
$all_users_id = $wpdb->get_results("SELECT $wpdb->users.ID FROM $wpdb->users ORDER BY $sort ASC LIMIT ".$request['start'].",".$request['length']." " );
$totalData=$wpdb->num_rows;
$data=array();
foreach ( $all_users_id as $i_users_id ) {
$user = get_userdata( $i_users_id->ID);
$email =$user->user_email;
$user_fullname =$user->first_name . ' ' . $user->last_name;
$user_url =$user->user_url;
$user_nickname =$user->nickname;
$user_profile =$user->description;
$sub_array = array();
$sub_array[] = $email;
$sub_array[] = $user_fullname;
$sub_array[] = $user_url;
$sub_array[] = $user_nickname;
$sub_array[] = $user_profile;
$data[] = $sub_array;
}
$json_data=array(
"draw" => (isset($request["draw"]) ? $request["draw"] : 0),
"recordsTotal" => intval($totalData),
"recordsFiltered" => intval($totalData),
"data" => $data
);
echo json_encode($json_data);
wp_die(); //to remove that 0 response
}
add_action( 'wp_ajax_wpajaxusersearch', 'wpajaxusersearch' );
add_action( 'wp_ajax_nopriv_wpajaxusersearch', 'wpajaxusersearch' );
Add these to your theme's 'functions.php' and everything should be fine.
// change user query to treat meta result as OR part
add_action( 'pre_user_query', 'user_meta_OR_search');
function user_meta_OR_search($q){
if ($search = $q->get('_meta_or_search')){
add_filter( 'get_meta_sql', function( $sql ) use ( $search ){
global $wpdb;
// run once
static $nr = 0;
if( 0 != $nr++ ) return $sql;
// modify WHERE
$where = sprintf(
" AND ( %s OR %s OR %s ) ",
$wpdb->prepare( "{$wpdb->users}.user_email like '%%%s%%'", $search),
$wpdb->prepare( "{$wpdb->users}.user_url like '%%%s%%'", $search),
mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
);
$sql['where'] = $where;
return $sql;
});
}
}
function wpajaxusersearch()
{
$request = $_REQUEST;
$columns = array('user_email','first_name','user_url','nickname','description');
$search = esc_attr( trim( $request['search']['value'] ) );
$args = array();
$limit_args = array( 'number' => $request['length'], 'offset' => $request['start'] );
$order_args = array();
$search_args = array();
if ( isset($request['order']) && count($request['order']) )
{
$sort_column = $request['order'][0]['column'];
$sort_column_name = $columns[$sort_column];
$sort_dir = $request['order'][0]['dir'];
if( stristr( $sort_column_name,'user_' ))
$order_args = array( 'orderby' => $sort_column_name, 'order' => $sort_dir );
else
$order_args = array( 'meta_key' => $sort_column_name, 'orderby' => 'meta_value', 'order' => $sort_dir );
}
else
$order_args = array( 'orderby' => 'user_registered', 'order' => 'ASC' );
$args = $order_args;
if(isset($search) && $search != "")
{
$search_args = array(
'_meta_or_search' => "*{$search}*",
'meta_query' => array(
'relation' => 'OR',
array(
'key' => 'first_name',
'value' => $search,
'compare' => 'LIKE'
),
array(
'key' => 'last_name',
'value' => $search,
'compare' => 'LIKE'
),
array(
'key' => 'nickname',
'value' => $search,
'compare' => 'LIKE'
),
array(
'key' => 'description',
'value' => $search,
'compare' => 'LIKE'
)
)
);
}
$all_users = new WP_User_Query( $args );
$total_users = count($all_users->get_results());
$filtered_users = count($all_users->get_results());
if(isset($search) && $search != "")
{
$args = array_merge($args, $search_args);
$all_users = new WP_User_Query( $args );
$filtered_users = count($all_users->get_results());
}
$args = array_merge($args, $limit_args);
$all_users = new WP_User_Query( $args );
foreach ( $all_users->get_results() as $user ) {
$email = $user->user_email;
$user_fullname = $user->first_name . ' ' . $user->last_name;
$user_url = $user->user_url;
$user_nickname = $user->nickname;
$user_profile = $user->description;
$sub_data = array();
$sub_data[] = $email;
$sub_data[] = $user_fullname;
$sub_data[] = $user_url;
$sub_data[] = $user_nickname;
$sub_data[] = $user_profile;
$data[] = $sub_data;
}
$json_data=array(
"draw" => (isset($request["draw"]) ? $request["draw"] : 0),
"recordsTotal" => intval($total_users),
"recordsFiltered" => intval($filtered_users),
"data" => $data
);
echo json_encode($json_data);
wp_die();
}
add_action( 'wp_ajax_wpajaxusersearch', 'wpajaxusersearch' );
add_action( 'wp_ajax_nopriv_wpajaxusersearch', 'wpajaxusersearch' );
Related
I try to implement the Rawg.io API to my Wordpress Functions.php File but it doesn't work, i tried my code with another API and it is working fine, i think it has something to do with the API link Page='.$current_page.'
as you can see i created an custom post type to add the games to.
i also created custom fields with the right field keys.
My Report.txt file keeps returning current page = 1
function register_game_cpt() {
register_post_type( 'game', array(
'label' => 'Games',
'public' => true,
'capability_type' => 'post',
'supports' => array('title', 'editor', 'thumbnail'),
'taxonomies' => array('recordings', 'category', 'whatever', 'post_tag'),
));
}
add_action( 'init', 'register_game_cpt' );
// if ( ! wp_next_scheduled( 'update_game_list' ) ) {
// wp_schedule_event( time(), 'weekly', 'update_game_list' );
// }
add_action( 'update_game_list', 'get_games_from_api' );
add_action( 'wp_ajax_nopriv_get_games_from_api', 'get_games_from_api' );
add_action( 'wp_ajax_get_games_from_api', 'get_games_from_api' );
function get_games_from_api() {
$file = get_stylesheet_directory() . '/report.txt';
$current_page = ( ! empty( $_POST['current_page'] ) ) ? $_POST['current_page'] : 1;
$games = [];
// Should return an array of objects
$results = wp_remote_retrieve_body(wp_remote_get('https://api.rawg.io/api/games?key=/////////////////////&page='.$current_page.'&page_size=40'));
file_put_contents($file, "Current Page: " . $current_page. "\n\n", FILE_APPEND);
// turn it into a PHP array from JSON string
$results = json_decode( $results );
// Either the API is down or something else spooky happened. Just be done.
if( ! is_array( $results ) || empty( $results ) ){
return false;
}
$games[] = $results;
foreach( $games[0] as $game ){
$game_slug = sanitize_title( $game->name . '-' . $game->id );
$existing_game = get_page_by_path( $game_slug, 'OBJECT', 'game' );
if( $existing_game === null ){
$inserted_game = wp_insert_post( [
'post_name' => $game_slug,
'post_title' => $game_slug,
'post_type' => 'game',
'post_status' => 'publish'
] );
if( is_wp_error( $inserted_game ) || $inserted_game === 0 ) {
die('Could not insert game: ' . $game_slug);
error_log( 'Could not insert game: ' . $game_slug );
continue;
}
// add meta fields
$fillable = [
'field_62684fc72d524' => 'count',
'field_6266cb41982d3' => 'name',
'field_6266cb4c982d4' => 'publishers',
'field_6266cb54982d5' => 'genres',
'field_6266cb64012e9' => 'platforms',
'field_6266cb722ebe8' => 'dates',
'field_626850012d525' => 'results',
];
foreach( $fillable as $key => $name ) {
update_field( $key, $game->$name, $inserted_game );
}
} else {
$existing_game_id = $existing_game->ID;
$exisiting_game_timestamp = get_field('updated_at', $existing_game_id);
if( $game->updated_at >= $exisiting_game_timestamp ){
$fillable = [
'field_62684fc72d524' => 'count',
'field_6266cb41982d3' => 'name',
'field_6266cb4c982d4' => 'publishers',
'field_6266cb54982d5' => 'genres',
'field_6266cb64012e9' => 'platforms',
'field_6266cb722ebe8' => 'dates',
'field_626850012d525' => 'results',
];
foreach( $fillable as $key => $name ){
update_field( $name, $game->$name, $existing_game_id);
}
}
}
}
$current_page = $current_page + 1;
wp_remote_post( admin_url('admin-ajax.php?action=get_games_from_api'), [
'blocking' => false,
'sslverify' => false, // we are sending this to ourselves, so trust it.
'body' => [
'current_page' => $current_page
]
] );
}
I have followed this toturial and have managed to create a shortcode that shows the datatable with filter option. This table works with the native post type of wordpress.
I need the same datatable but it should get the data from a custom database table i have added wp_lubuvna_subscribers
Custom Table:
So i need to change following function to get data from the above mentioned custom table instead custom post type
function datatables_server_side_callback_subscriber_db() {
header("Content-Type: application/json");
$request= $_GET;
$columns = array(
0 => 'post_title',
3 => LUBUVNA_PREFIX.'email',
1 => LUBUVNA_PREFIX.'first_name',
2 => LUBUVNA_PREFIX.'last_name',
4 => LUBUVNA_PREFIX.'phone'
);
$args = array(
'post_type' => 'lubuvna_subscriber',
'post_status' => 'publish',
'posts_per_page' => $request['length'],
'offset' => $request['start'],
'order' => $request['order'][0]['dir'],
);
if ($request['order'][0]['column'] == 0) {
$args['orderby'] = $columns[$request['order'][0]['column']];
} elseif ($request['order'][0]['column'] == 1 || $request['order'][0]['column'] == 2) {
$args['orderby'] = 'meta_value_num';
$args['meta_key'] = $columns[$request['order'][0]['column']];
}
//$request['search']['value'] <= Value from search
if( !empty($request['search']['value']) ) { // When datatables search is used
$args['meta_query'] = array(
'relation' => 'OR',
array(
'key' => 'd_title',
'value' => sanitize_text_field($request['search']['value']),
'compare' => 'LIKE'
),
array(
'key' => LUBUVNA_PREFIX.'email',
'value' => sanitize_text_field($request['search']['value']),
'compare' => 'LIKE'
),
array(
'key' => LUBUVNA_PREFIX.'first_name',
'value' => sanitize_text_field($request['search']['value']),
'compare' => 'LIKE'
),
array(
'key' => LUBUVNA_PREFIX.'last_name',
'value' => sanitize_text_field($request['search']['value']),
'compare' => 'LIKE'
),
array(
'key' => LUBUVNA_PREFIX.'phone',
'value' => sanitize_text_field($request['search']['value']),
'compare' => 'LIKE'
),
);
}
$subscriber_query = new WP_Query($args);
$totalData = $subscriber_query->found_posts;
if ( $subscriber_query->have_posts() ) {
while ( $subscriber_query->have_posts() ) {
$subscriber_query->the_post();
$nestedData = array();
$nestedData[] = get_field(LUBUVNA_PREFIX.'first_name'). ' '. get_field(LUBUVNA_PREFIX.'last_name');
$nestedData[] = "<a data-val='".get_post_field( 'post_name', get_post() )."' href='".get_permalink()."' data-posttype='".get_post_type( get_the_ID() )."' class='generallink'>" . get_field(LUBUVNA_PREFIX.'email') . "</a>";
$nestedData[] = get_field(LUBUVNA_PREFIX.'first_name');
$nestedData[] = get_field(LUBUVNA_PREFIX.'last_name');
$nestedData[] = get_field(LUBUVNA_PREFIX.'phone');
$data[] = $nestedData;
}
wp_reset_query();
$json_data = array(
"draw" => intval($request['draw']),
"recordsTotal" => intval($totalData),
"recordsFiltered" => intval($totalData),
"data" => $data
);
echo json_encode($json_data);
} else {
$json_data = array(
"data" => array()
);
echo json_encode($json_data);
}
wp_die();
}
So i will post this here, in case someone else is looking for the same solution. I had to add global $wpdband get the data from my custom database table. it works perfectly with paging / sorting / Search.
function datatables_server_side_callback_subscriber_db() {
header("Content-Type: application/json");
global $wpdb;
// Table name
$table_name = $wpdb->prefix . "lubuvna_subscribers";
// Request
$request= $_GET;
// Columns
$columns = array(
0 => 'ID',
1 => 'first_name',
2 => 'last_name',
3 => 'email',
4 => 'phone'
);
// Datatable Filters
$column = $columns[$request['order'][0]['column']];
$offset = $request['start'];
$length = $request['length'];
$order = $request['order'][0]['dir'];
// Search all columns
$sql_where = "";
if ( !empty($request['search']['value']) ) {
$sql_where .= "WHERE ";
foreach ($columns as $column) {
$sql_where .= $column . " LIKE '%" . sanitize_text_field($request['search']['value']) . "%' OR ";
}
$sql_where = substr($sql_where, 0, -3);
}
// Total Records in the datatable
$total_table_records = "SELECT count(*) as count FROM {$table_name}";
$total_fetched_records = $wpdb->get_results($total_table_records, OBJECT);
$total_records = $total_fetched_records[0]->count;
// Total Records Search
$total_table_records_search = "SELECT count(*) as count FROM $table_name $sql_where";
$total_fetched_records_search = $wpdb->get_results($total_table_records_search, OBJECT);
$total_records_search = $total_fetched_records_search[0]->count;
// Query
$total_results = $wpdb->get_results( "SELECT * FROM $table_name $sql_where ORDER BY $column $order LIMIT $offset, $length" );
if ( !empty($total_results) ) {
foreach ($total_results as $row){
$nestedData = array();
$nestedData[] = $row->ID;
$nestedData[] = $row->first_name;
$nestedData[] = $row->last_name;
$nestedData[] = $row->email;
$nestedData[] = $row->phone;
$data[] = $nestedData;
}
$json_data = array(
"draw" => intval($request['draw']),
"recordsTotal" => intval($total_records),
"recordsFiltered" => intval($total_records_search),
"data" => $data
);
echo json_encode($json_data);
} else {
$json_data = array(
"data" => array()
);
echo json_encode($json_data);
}
wp_die();
}
I have this snippet for creating a list of users sorted by the highest post views.
But I'm wondering of how can I create pagination for a custom array like that.
$topuser = array();
$avatar_size = 100;
$args = array(
'role__in' => array( 'contributor', 'author' ),
'hide_empty' => '1'
);
$users = get_users( $args );
foreach ( $users as $user ) {
$query = get_posts(
array(
'author' => $user->ID,
'cat' => '3',
'numberposts' => -1,
'post_type' => 'post',
)
);
$counter = 0;
$post_count = count_user_posts( $user->ID );
if ( ! $post_count ) {
continue;
}
// get each post of a user
foreach ( $query as $post ){
$views = absint( get_post_meta( $post->ID, 'post_views_count', true ) );
$counter += $views;
}
$topuser[] = array(
'id' => $user->ID,
'views' => $counter,
);
wp_reset_query();
}
// function to sort array based on views count
function sortViews( $a, $b ) {
return $b['views'] - $a['views'];
}
usort( $topuser, 'sortViews' ); // sort the array
$output = $topuser;
Thanks in advance!
I am building a ajax search that uses wp_query and I need to be able to filter using custom meta and custom taxonomy names. I've gotten the custom meta part working but cannot get it to filter using the taxonomy names. What I've got so far -
$useCustomJoins = false;
add_action( 'pre_get_posts', function( $q )
{
if( $title = $q->get( '_meta_or_title' ) )
{
add_filter( 'get_meta_sql', function( $sql ) use ( $title )
{
global $wpdb;
// Only run once:
static $nr = 0;
if( 0 != $nr++ ) return $sql;
// Modified WHERE
$sql['where'] = sprintf(
" AND ( %s OR %s ) ",
$wpdb->prepare( "{$wpdb->posts}.post_title like '%%%s%%'", $title),
mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
);
return $sql;
});
}
});
add_filter('posts_join', array('CrownResources', 'filterPostsJoin'), 10, 2);
add_filter('posts_where', array('CrownResources', 'filterPostsWhere'), 10, 2);
add_filter('posts_groupby', array('CrownResources', 'filterPostsGroupby'), 10, 2);
public static function filterPostsJoin($join, $query) {
global $wpdb, $useCustomJoins;
if($useCustomJoins || (is_main_query() && is_search())) {
$join .= "
LEFT JOIN
(
{$wpdb->term_relationships}
INNER JOIN
{$wpdb->term_taxonomy} ON {$wpdb->term_taxonomy}.term_taxonomy_id = {$wpdb->term_relationships}.term_taxonomy_id
INNER JOIN
{$wpdb->terms} ON {$wpdb->terms}.term_id = {$wpdb->term_taxonomy}.term_id
)
ON {$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id ";
}
return $join;
}
public static function filterPostsWhere($where, $query) {
global $wpdb, $useCustomJoins;
if($useCustomJoins || (is_main_query() && is_search())) {
$userWhere = self::getUserPostsWhere();
$queryS = !empty(get_query_var('s')) ? get_query_var('s') : get_query_var('_meta_or_title');
$where .= " OR (
{$wpdb->term_taxonomy}.taxonomy IN('resource_pregnancy_taxonomy', 'resource_counseling_taxonomy', 'resource_classes_taxonomy', 'resource_supplies_taxonomy', 'resource_clothing_taxonomy', 'resource_food_taxonomy', 'resource_housing_taxonomy', 'resource_medical_taxonomy', 'resource_substance_taxonomy', 'adoption_taxonomy', 'employment_taxonomy')
AND
{$wpdb->terms}.name LIKE '%".esc_sql($queryS)."%'
{$userWhere}
)";
}
return $where;
}
protected static function getUserPostsWhere() {
global $wpdb;
$userId = get_current_user_id();
$sql = '';
$status = array("'publish'");
if(0 !== $userId) {
$status[] = "'private'";
$sql .= " AND {$wpdb->posts}.post_author = ".absint($userId);
}
$sql .= " AND {$wpdb->posts}.post_status IN( ".implode(',', $status)." ) ";
return $sql;
}
public static function filterPostsGroupby($groupby, $query) {
global $wpdb, $useCustomJoins;
if($useCustomJoins || (is_main_query() && is_search())) {
$groupby = "{$wpdb->posts}.ID";
}
return $groupby;
}
usage:
global $post, $useCustomJoins;
$original_post = $post;
// query for resource
$queryArgs = array(
'post_type' => 'resource',
'posts_per_page' => -1,
'orderby' => 'menu_order',
'order' => 'ASC',
'post_status' => 'publish'
);
//if taxonomies
if (!empty($atts['taxonomies'])){
$queryArgs['tax_query'] = array();
foreach ($atts['taxonomies'] as $tax){
$queryArgs['tax_query'][] = array(
'taxonomy' => $tax['name'],
'field' => 'term_id',
'terms' => $tax['terms'],
'operator' => 'AND',
);
}
}
// filter by meta as well as title
$meta_query = array();
$meta_query[] = array(
'key' => 'resource_description',
'value' => $atts['search'],
'compare' => 'LIKE'
);
$meta_query[] = array(
'key' => 'resource_address',
'value' => $atts['search'],
'compare' => 'LIKE'
);
$meta_query[] = array(
'key' => 'resource_date_time',
'value' => $atts['search'],
'compare' => 'LIKE'
);
$meta_query[] = array(
'key' => 'resource_phone',
'value' => $atts['search'],
'compare' => 'LIKE'
);
$meta_query[] = array(
'key' => 'resource_email',
'value' => $atts['search'],
'compare' => 'LIKE'
);
$meta_query[] = array(
'key' => 'resource_website',
'value' => $atts['search'],
'compare' => 'LIKE'
);
//if there is more than one meta query 'or' then
if(count($meta_query) > 1) {
$meta_query['relation'] = 'OR';
}
//if there's a search
if (!empty($atts['search'])){
// $queryArgs['s'] = $atts['search'];
$queryArgs['_meta_or_title'] = $atts['search']; //not using 's' anymore
$queryArgs['meta_query'] = $meta_query;
$useCustomJoins = true;
}
$resourceQuery = new \WP_Query($queryArgs);
$useCustomJoins = false;
Any idea on how to get them working together? I can get the meta filter to search properly but once I add the taxonomy it still filters but not correctly.
I created a plugin and create a menu by using this code
add_filter('page_template', 'in_page_template');
function in_page_template()
{
global $wpdb;
$new_page_title = 'Packages';
$sql = "SELECT * FROM wp_posts where post_name='" . $new_page_title . "';";
$cnt_post = $wpdb->get_results($sql);
if (!(is_page('Home'))) {
$ppid = $_GET['page_id'];
if (count($cnt_post) != 0) {
$pid = $cnt_post[0]->ID;
if ($pid == $ppid) {
$page_template = dirname(__FILE__) . '/Packages.php';
return $page_template;
}
}
}
}
How can I create submenu for package page
add_action('init', 'create_initial_pages');
function create_initial_pages() {
$pages = array(
array(
'name' => 'post_name',
'title' => 'post_title',
'child' => array(
'page1-1' => 'National',
'page1-2' => 'International'
)
),
);
$template = array(
'post_type' => 'page',
'post_status' => 'publish',
'post_author' => 1
);
foreach( $pages as $page ) {
$exists = get_page_by_title( $page['title'] );
$my_page = array(
'post_name' => $page['name'],
'post_title' => $page['title']
);
$my_page = array_merge( $my_page, $template );
$id = ( $exists ? $exists->ID : wp_insert_post( $my_page ) );
if( isset( $page['child'] ) ) {
foreach( $page['child'] as $key => $value ) {
$child_id = get_page_by_title( $value );
$child_page = array(
'post_name' => $key,
'post_title' => $value,
'post_parent' => $id
);
$child_page = array_merge( $child_page, $template );
if( !isset( $child_id ) ) wp_insert_post( $child_page );
}
}
}
}