I've already added paginator.phtml file and I have added some code in controller
$adapter = new DoctrineAdapter(new ORMPaginator( $logList , false));
$paginator = new Paginator($adapter);
$paginator->setDefaultItemCountPerPage(10);
$paginator->setCurrentPageNumber(1);
return new ViewModel(['logList'=>$logList ,'form'=>$form,'posts' => $paginator]);
On the view page I'm using this code:
$this->paginationControl($posts,
'Sliding',
'ripple-site/partial/paginator',
['route' => 'ripplesite']
);
This code produces error:
Argument 1 passed to Doctrine\ORM\Tools\Pagination\Paginator::cloneQuery() must be an instance of Doctrine\ORM\Query, array given, called in C:\zend\vendor\doctrine\orm\lib\Doctrine\ORM\Tools\Pagination\Paginator.php on line 244
Done this a few times now, so I'll provide you with a basic indexAction. (Note the difference in what's loaded into the OrmPaginator, which is probably your issue)
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Tools\Pagination\Paginator as OrmPaginator;
use DoctrineORMModule\Paginator\Adapter\DoctrinePaginator as OrmAdapter;
// class
public function indexAction()
{
$page = $this->params()->fromQuery('page', 1); // default page
$pageSize = $this->params()->fromQuery('pageSize', 10); // default page size
$orderBy = $this->params()->fromQuery('orderBy', 'createdAt'); // default order by (replace with your own property name!)
$orderDirection = $this->params()->fromQuery('orderDirection') === Criteria::ASC // default order direction (desc to display newest first - replace with your own)
? Criteria::ASC
: Criteria::DESC;
$criteria = (new Criteria())
->setFirstResult($page * $pageSize)
->setMaxResults($pageSize)
->orderBy([$orderBy => $orderDirection]);
/** #var QueryBuilder $qb */
$qb = $this->getObjectManager()->createQueryBuilder();
$qb->select('a') // replace with your own alias key
->from(Article::class, 'a') // replace with your own class and alias
->addCriteria($criteria);
$paginator = new Paginator(new OrmAdapter(new OrmPaginator($qb)));
$paginator->setCurrentPageNumber($page);
$paginator->setItemCountPerPage($pageSize);
return [
'paginator' => $paginator,
'queryParams' => $this->params()->fromQuery(),
];
}
Requirements are that the class has the an instance of ObjectManager. If you use $entityManager, that's fine, just replace $this->getObjectManager() with $this->getEntityManager() or $this->entityManager.
The rest should work out of the box.
Display like so in index.phtml for this controller->action
<?php
/** #var \Article\Entity\Article[] $paginator */
$pagination = $this->paginationControl(
$paginator,
'sliding',
'theme/partials/pagination', // This here assumes you have a partial setup for pagination. If not, leave a comment and I can add a default Bootstrap 4 compatible one.
[
'route' => 'admin/articles',
'queryParams' => $queryParams,
]
);
<?php if (isset($paginator) && $paginator->count() > 0) : ?>
<table class="table table-striped">
<thead>
<tr>
<th><?= $this->translate('Title') ?></th>
<!-- more columns -->
</tr>
</thead>
<tbody>
<?php foreach ($paginator as $article): ?>
<tr>
<td>
<?= $this->escapeHtml($article->getTitle()) ?>
</td>
<!-- more columns -->
</tr>
<?php endforeach ?>
</tbody>
</table>
<?php if ($paginator->count() > 1) : ?>
<?= $pagination ?>
<?php endif ?>
<?php else : ?>
<p><?= $this->translate('No records found. Try again later or report an issue.') ?></p>
<?php endif ?>
Related
I have a page with the following code in it, this code is duplicated from the dashboard. This means this particular widget now shows in two places. With help I managed to increase the number of days this report shows to 60 however I only want the dashboard version to show 60 days and I would like this version to show 365 days.
<?php
/*
* The template for displaying vendor pending shipping table dashboard widget
* Override this template by copying it to yourtheme/dc-product-vendor/vendor-dashboard/dashboard-widgets/wcmp_vendor_product_sales_report.php
*
* #author WC Marketplace
* #package WCMp/Templates
* #version 3.0.0
*/
if (!defined('ABSPATH')) {
// Exit if accessed directly
exit;
}
global $WCMp;
$product_sales_report_table_headers = apply_filters('wcmp_datatable_widget_product_sales_report_table_headers', array(
'product' => array('label' => __( 'Product', 'dc-woocommerce-multi-vendor' )),
// 'revenue' => array('label' => __( 'Revenue', 'dc-woocommerce-multi-vendor' )),
'unique_purchase'=> array('label' => __( 'Unique Purchases', 'dc-woocommerce-multi-vendor' )),
), get_current_user_id());
?>
<p>This page shows all your designs that have sold over the past year.</p>
<table id="widget_product_sales_report" class="table table-striped product_sold_last_week table-bordered wcmp-widget-dt" width="100%">
<thead>
<tr>
<?php
if($product_sales_report_table_headers) :
foreach ($product_sales_report_table_headers as $key => $header) { ?>
<th class="<?php if(isset($header['class'])) echo $header['class']; ?>"><?php if(isset($header['label'])) echo $header['label']; ?></th>
<?php }
endif;
?>
<!--th><?php _e('Product', 'dc-woocommerce-multi-vendor'); ?></th>
<th><?php _e('Revenue', 'dc-woocommerce-multi-vendor'); ?></th>
<th><?php _e('Unique Purchases', 'dc-woocommerce-multi-vendor'); ?></th-->
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
jQuery(document).ready(function($) {
var product_sales_report_wgt;
var columns = [];
<?php if($product_sales_report_table_headers) {
foreach ($product_sales_report_table_headers as $key => $header) { ?>
obj = {};
obj['data'] = '<?php echo esc_js($key); ?>';
obj['className'] = '<?php if(isset($header['class'])) echo esc_js($header['class']); ?>';
columns.push(obj);
<?php }
} ?>
product_sales_report_wgt = $('#widget_product_sales_report').DataTable({
ordering : true,
paging: true,
info: true,
searching : true,
processing: false,
serverSide: true,
responsive: true,
language: {
"emptyTable": "<?php echo trim(__('Not enough data.','dc-woocommerce-multi-vendor')); ?>",
"zeroRecords": "<?php echo trim(__('Not enough data.','dc-woocommerce-multi-vendor')); ?>",
},
ajax:{
url : '<?php echo add_query_arg( 'action', 'wcmp_widget_vendor_product_sales_report', $WCMp->ajax_url() ); ?>',
type: "post",
error: function(xhr, status, error) {
$("#widget_product_sales_report tbody").append('<tr class="odd"><td valign="top" colspan="<?php if(is_array($product_sales_report_table_headers)) count($product_sales_report_table_headers); ?>" class="dataTables_empty" style="text-align:center;">'+error+' - <?php _e('Reload', 'dc-woocommerce-multi-vendor'); ?></td></tr>');
$("#widget_product_sales_report").css("display","none");
}
},
columns: columns
});
new $.fn.dataTable.FixedHeader( product_sales_report_wgt );
});
</script>
Using this code
// To change the default value of `$days_range` from 7 days to 60 days
function lh_wcmp_vendor_custom_sales_report( $days_range ) {
$days_range = 60; // you can adjust days here as you needed
return $days_range;
}
add_filter( 'wcmp_widget_vendor_product_sales_report_days_range', 'lh_wcmp_vendor_custom_sales_report', 10 );
I was able to change the default 7 days to 60. But because I am using the same widget code both the dashboard and the report show the same amount of days.
So, to summerise - what I would like is to show 60 days on the dashboard (using the code above) and then show 365 days on the report page.
Can anyone help?
You need to update the code in \basel-child\dc-product-vendor\vendor-dashboard\vendor-orders.php and \basel-child\functions.php files.
We are going to add a new query string while making the AJAX request to wcmp_widget_vendor_product_sales_report function from vendor-orders endpoint. It will allow us to detect whether the request is coming from Dashboard or Vendor Orders endpoint.
Following code will be added in the vendor-orders.php file (see line 67-79):
<?php
/* Add 'lh-endpoint' => 'lh-vendor-orders' to the AJAX URL, so we can use it later
* to change the '$days_range' value conditionally. It will change the ajax url from
* /wp-admin/admin-ajax.php?action=wcmp_widget_vendor_product_sales_report to
* /wp-admin/admin-ajax.php?action=wcmp_widget_vendor_product_sales_report&lh-endpoint=lh-vendor-orders
*/
$args = array(
'action' => 'wcmp_widget_vendor_product_sales_report',
'lh-endpoint' => 'lh-vendor-orders',
);
?>
url : '<?php echo add_query_arg( $args, $WCMp->ajax_url() ); ?>',
Then we will modify our old lh_wcmp_vendor_custom_sales_report() function in functions.php file as:
// get the value of 'lh-endpoint' from URL
$lh_orders_endpoint = isset( $_GET['lh-endpoint'] ) && !empty( $_GET['lh-endpoint'] ) ? $_GET['lh-endpoint'] : '';
// check if 'lh-endpoint' value is 'lh-vendor-orders' or not
if ( 'lh-vendor-orders' !== $lh_orders_endpoint ) {
$days_range = 60; // if 'lh-endpoint' is not 'lh-vendor-orders', then show last 2 months orders
} else {
$days_range = 365; // if 'lh-endpoint' is 'lh-vendor-orders', then show orders from 1 year
}
Here is the complete code for both files:
Remove the existing code from vendor-orders.php file and put this code:
<?php
/*
* The template for displaying vendor orders
* Override this template by copying it to yourtheme/dc-product-vendor/vendor-dashboard/vendor-orders.php
*
* #author WC Marketplace
* #package WCMp/Templates
* #version 3.0.0
*/
if (!defined('ABSPATH')) {
// Exit if accessed directly
exit;
}
global $WCMp;
$product_sales_report_table_headers = apply_filters('wcmp_datatable_widget_product_sales_report_table_headers', array(
'product' => array('label' => __( 'Product', 'dc-woocommerce-multi-vendor' )),
// 'revenue' => array('label' => __( 'Revenue', 'dc-woocommerce-multi-vendor' )),
'unique_purchase'=> array('label' => __( 'Unique Purchases', 'dc-woocommerce-multi-vendor' )),
), get_current_user_id());
?>
<p>This page shows all your designs that have sold over the past year.</p>
<table id="widget_product_sales_report" class="table table-striped product_sold_last_week table-bordered wcmp-widget-dt" width="100%">
<thead>
<tr>
<?php
if($product_sales_report_table_headers) :
foreach ($product_sales_report_table_headers as $key => $header) { ?>
<th class="<?php if(isset($header['class'])) echo $header['class']; ?>"><?php if(isset($header['label'])) echo $header['label']; ?></th>
<?php }
endif;
?>
<!--th><?php _e('Product', 'dc-woocommerce-multi-vendor'); ?></th>
<th><?php _e('Revenue', 'dc-woocommerce-multi-vendor'); ?></th>
<th><?php _e('Unique Purchases', 'dc-woocommerce-multi-vendor'); ?></th-->
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
jQuery(document).ready(function($) {
var product_sales_report_wgt;
var columns = [];
<?php if($product_sales_report_table_headers) {
foreach ($product_sales_report_table_headers as $key => $header) { ?>
obj = {};
obj['data'] = '<?php echo esc_js($key); ?>';
obj['className'] = '<?php if(isset($header['class'])) echo esc_js($header['class']); ?>';
columns.push(obj);
<?php }
} ?>
product_sales_report_wgt = $('#widget_product_sales_report').DataTable({
ordering : true,
paging: true,
info: true,
searching : true,
processing: true,
serverSide: true,
responsive: true,
language: {
"emptyTable": "<?php echo trim(__('Not enough data.','dc-woocommerce-multi-vendor')); ?>",
"zeroRecords": "<?php echo trim(__('Not enough data.','dc-woocommerce-multi-vendor')); ?>",
},
ajax:{
<?php
/* Add 'lh-endpoint' => 'lh-vendor-orders' to the AJAX URL, so we can use it later
* to change the '$days_range' value conditionally. It will change the ajax url from
* /wp-admin/admin-ajax.php?action=wcmp_widget_vendor_product_sales_report to
* /wp-admin/admin-ajax.php?action=wcmp_widget_vendor_product_sales_report&lh-endpoint=vendor-orders
*/
$args = array(
'action' => 'wcmp_widget_vendor_product_sales_report',
'lh-endpoint' => 'lh-vendor-orders',
);
?>
//url : '<?php //echo add_query_arg( 'action', 'wcmp_widget_vendor_product_sales_report', $WCMp->ajax_url() ); ?>',
url : '<?php echo add_query_arg( $args, $WCMp->ajax_url() ); ?>',
type: "post",
error: function(xhr, status, error) {
$("#widget_product_sales_report tbody").append('<tr class="odd"><td valign="top" colspan="<?php if(is_array($product_sales_report_table_headers)) count($product_sales_report_table_headers); ?>" class="dataTables_empty" style="text-align:center;">'+error+' - <?php _e('Reload', 'dc-woocommerce-multi-vendor'); ?></td></tr>');
$("#widget_product_sales_report").css("display","none");
}
},
columns: columns
});
new $.fn.dataTable.FixedHeader( product_sales_report_wgt );
});
</script>
In your functions.php file, replace the old lh_wcmp_vendor_custom_sales_report() function with the new one:
// Conditionally change the default value of `$days_range` from 7 days to 60 or 365 days
function lh_wcmp_vendor_custom_sales_report( $days_range ) {
// get the value of 'lh-endpoint' from URL
$lh_orders_endpoint = isset( $_GET['lh-endpoint'] ) && !empty( $_GET['lh-endpoint'] ) ? $_GET['lh-endpoint'] : '';
// check if 'lh-endpoint' value is 'lh-vendor-orders' or not
if ( 'lh-vendor-orders' !== $lh_orders_endpoint ) {
$days_range = 60; // if 'lh-endpoint' is not 'lh-vendor-orders', then show last 2 months orders
} else {
$days_range = 365; // if 'lh-endpoint' is 'lh-vendor-orders', then show orders from 1 year
}
return $days_range;
}
add_filter( 'wcmp_widget_vendor_product_sales_report_days_range', 'lh_wcmp_vendor_custom_sales_report' );
See the screenshots of locally hacked version of WC Marketplace plugin:
wcmp_widget_vendor_product_sales_report call from Vendor Dashboard
wcmp_widget_vendor_product_sales_report call from Vendor Orders Tab
Tested and working on:
WordPress 5.0.3
Twentyninteen 1.2
WooCommerce 3.5.4
WC Marketplace 3.3.1
Localhost (XAMPP for Windows 5.6.15)
I am developing a simple WordPress plugin where admin can create user roles using an admin form. I want to display an admin_notice if a role is already existing.
Problem I am having is even the role exists, the message is not appearing. If I understand properly, this is because the form is actually being redirected to admin-post.php. If so, how can I show the admin_notice after submission?
In short I have this:
One function in my plugin to render the form.
One function to save. Before saving, WP checks whether role exists. If yes, I want to display an admin_notice and "return". Otherwise, role gets saved.
The code snippet to check and show admin_notice:
<?php
function save_user_role()
{
$role_name = $_POST['role_name'];
$role_slug = sanitize_title_with_dashes($role_name);
$role = get_role($role_slug);
if (!empty($role))
{
$notice = 'Role exists';
do_action('admin_notices', $this->display_notice($notice));
// return; // If I use the return the correct message coming up in a blank page.
}
else
{
// Save the role
}
}
Below is the full code that I have written
function save_user_role() {
// Role already exists?
$role_name = $_POST[ 'coolmedia_role_name' ];
$role_slug = sanitize_title_with_dashes( $role_name );
$role = get_role( $role_slug );
if( ! empty( $role ) ) {
// Error. Role already exists
$notice = 'Speficed role ' . $role_name . ' already exists';
do_action( 'admin_notices', $this->display_notice( $notice ) );
} else {
// Safe to create the new role
$role_caps = array(
'read' => true,
);
...
add_role( $role_slug, esc_html( $role_name ), $role_caps );
// Redirect back to form page
wp_redirect( admin_url( 'admin.php?page=user-roles' ) );
}
}
Display notice function:
function add_user_role_markup() { ?>
<div class="wrap">
<h1>Add Role</h1>
<form method="post" action="<?php esc_html(admin_url('admin-post.php')); ?>">
<table class="form-table">
<tr class="first">
<th>Role name</th>
<td><input required type="text" id="role_name" name="role_name" /></td>
</tr>
<tr>
<th>
<?php
('coolmedia-role-save', 'coolmedia-role-nonce'); ?>
<input type="hidden" name="action" value="new_user_role">
</th>
<td><?php
('Save Role'); ?></td>
</tr>
</table>
</form>
</div>
<?php
}
It depends on when save_user_role is being called and what else happens after that function. It's possible that the admin_notices hook is firing, but that (as you suggest) there's a redirect happening which would cause it not to fire after the redirect because (rightfully) save_user_role isn't being called again, or that save_user_role is firing after the admin_notices hook is called (in which case you're too late).
One solution might be to temporarily store an option in the database with your notice, and then check for it and display it as needed if it exists. This way, WordPress can do its redirect and then check for and display your notice when it returns.
Something like this. (Note: my add_action assumes this is happening in a class which I assume is how you've structured it based on your use of $this->display_notice())
function save_user_role(){
...
if( ! empty( $role ) ) {
// Error. Role already exists
$notice = 'Specified role ' . $role_name . ' already exists';
update_option( 'coolmedia_role_exists_message', $notice, 'no' );
}
...
}
add_action( 'admin_notices', array( $this, 'maybe_display_notice' ) );
function maybe_display_notice(){
$notice = get_option( 'coolmedia_role_exists_message', false );
if( $notice ){
delete_option( 'coolmedia_role_exists_message' );
$this->display_notice( $notice );
}
}
function display_notice( $notice ){
...
}
Creating a sub-theme in Drupal 7's page.tpl.php and needing to pull the value (plain text) from field_EXAMPLE from a custom content type outside of where the rest of the content would normal be.
<!-- Adding $title as normal-->
<?php print render($title_prefix); ?>
<?php if (!empty($title)): ?>
<h1><?php print $title; ?></h1>
<?php endif; ?>
<?php print render($title_suffix); ?>
<!-- THE ISSUE: Adding field_EXAMPLE -->
<h2> <?php print render($field_EXAMPLE;);?> </h2>
...
<!-- Where the rest of the content loads by default -->
<div><?php print render($page['content']); ?></div>
Would field_get_items work?
function field_get_items($entity_type, $entity, $field_name, $langcode = NULL) {
$langcode = field_language($entity_type, $entity, $field_name, $langcode);
return isset($entity->{$field_EXAMPLE}[$langcode]) ? $entity->{$field_name}[$langcode] : FALSE;
}
Or this?
$node = node_load($nid);
$node->field_EXAMPLE[$node->language][0]['value'];
Do I put this in page.tpl.php?
Tried them but no dice. -Novice
Here is var_dump(get_defined_vars());
["field_thestring"]=>
array(1) {
["und"]=>
array(1) {
[0]=>
array(3) {
["value"]=>
string(44) "This is a string of text please refer to me "
["format"]=>
NULL
["safe_value"]=>
string(44) "This is a string of text please refer to me "
}
}
}
Lets assume that you created a field called field_thestring that you want to render for a content type article's page at a location outside of THEME's outside of where page's content renders.
Step 1. Copy the theme's page.tpl.php. and rename it page--article.tpl.php.
Step 2. In page.var.php,
function THEME_preprocess_page(&$variables) {
// To activate page--article.tpl.php
if (isset($variables['node']->type)) {
$nodetype = $variables['node']->type;
$variables['theme_hook_suggestions'][] = 'page__' . $nodetype;
}
// Prevent errors on other pages
if ($node = menu_get_object()) {
if ( !empty($node) && $node->type == 'article') {
$fields = field_get_items('node', $node, 'field_thestring');
$index = 0;
$output = field_view_value('node', $node, 'field_thestring', $fields[$index]);
$variables['thestring'] = $output;
}
else{
$variables['thestring'] = 'Angry Russian: How this error?';
}
}
}
Step 3. In page--article.tpl.php add <?php print render($thestring); ?>
Initially, I wanted to require all content types to have another field since all Content Types has a Title. Determined it wasn't a great idea for further development.
Source
$node = node_load($nid);
$example_value = $node->field_EXAMPLE[$node->language][0]['value'];
<h2> <?php print $example_value;?> </h2>
or,
$node = node_load($nid);
$values = field_get_items('node', $node, 'EXAMPLE');
if ($values != FALSE) {
$val = $values[0]['value'];
}
else {
// no result
}
<h2> <?php print $example_value;?> </h2>
You can place your code directly into page template, but you can also place it in page preprocess hook, set the template variable and use that variable from your page template:
https://api.drupal.org/api/drupal/includes%21theme.inc/function/template_preprocess_page/7.x
It's kinda cleaner way, but both should work.
Also, try deleting Drupal's cache if you don't see your change immediately on front-end.
And for getting node id try:
global $node;
$nid = $node->nid;
$node = node_load($nid);
...
And if that doesn't work try this:
if ($node = menu_get_object()) {
// Get the nid
$nid = $node->nid;
$node = node_load($nid);
...
}
or this way:
if (arg(0) == 'node' && is_numeric(arg(1))) {
// Get the nid
$nid = arg(1);
$node = node_load($nid);
...
}
You can use a preprocess to add value into $variables passed to template
https://api.drupal.org/api/drupal/includes%21theme.inc/function/template_preprocess_page/7.x
In template.php :
MYTHEMENAME_preprocess_page(&variable){
$values = current(field_get_items('node', $variable['node'],'field_machine_name'));
$variable['myvar'] = $values['value'];
}
In your template.tpl.php
echo $myvar; // contains your value
I created a custom metabox in Wordpress but in rendering there is a "1" at the end of my content. I can't figure out how to remove it.
With this call...
add_meta_box(2, 'Calendrier de la formation', 'render_formations_calendrier_meta_box', null, 'side');
I get this metabox.
What is this "1" ? And can I remove it ? (it didn't come from my template)
edit
function render_formations_calendrier_meta_box($post) {
echo require('templates/partials/admin/formations/calendrier_metabox.php');
}
templates/partials/admin/formations/calendrier_metabox.php :
<table id="new_date_area">
<?php $dates = get_post_meta($post->ID, 'next_date') ?>
<?php foreach($dates as $key => $date) : ?>
<?php foreach($date as $event) : ?>
<tr>
<td style="padding:10px 0 0 0">
<input type="text" name="next_date[]" class="datepicker" value="<?= date('d-m-Y', $event) ?>"><span class="dashicons dashicons-trash"></span>
</td>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
</table>
<button id="new_date_button">nouvelle date</button>
<script>
$(document).ready(function(){
// datepicker
var format = 'dd-mm-yy'
$('.datepicker').datepicker({
dateFormat : format
})
// new date
$('#new_date_button').on('click', (click_event) => {
click_event.preventDefault()
var row = '<tr><td><input type="text" name="next_date[]" class="datepicker"><span class="dashicons dashicons-trash"></span></td></tr>'
$('#new_date_area').append(row)
$('.datepicker').datepicker({
dateFormat : format
})
})
// delete date
$(document).on('click', '.dashicons-trash', function(e) {
$(e.target).closest('tr').remove()
})
})
</script>
I solved it, the "1" was the return of the function require(). I was making echo require() but I only have to do a require without the echo.
So, I am inheriting an intranet site that was built on datatables. Basically it is made in Wordpress and then displays custom fields that the users have filled out in the datatable. But it was querying 40 columns per post over 2k entries so is now grinding to a standstill when the users try and view the data in the table.
I'm attempting to utilize the server-side aspect of Datatables for this, but running into a little trouble because of how the sql data is formatted.
Can anyone offer any assistance in how to set up the server_processing.php file (i'm using this one: http://datatables.net/development/server-side/php_mysql) to:
Display rows based on the wp_posts.ID index
Display columns in this row based on a different table (wp_postmeta) wherein each column value is indexed separately in the wp_postmeta table by the ID found in 1
Link entire row to a url found in the wp_posts table
If anyone has any ideas I would really appreciate it...
Definitely a plugin for WordPress is most efficient. AJAX can conflict/cause problems with the JQuery that is core to using WordPress edit functions etc. I'd go to WordPress.org and look under plugins for help there. There are also paid/premium intranet plugins such as Simple Intranet. :)
Chris
Probably you might be interested in this plugin - looks like it does exactly what you're looking for: http://wpdatatables.com
An example with server-side processing: http://wpdatatables.com/display-mysql-table-in-wordpress/
You will definitely need a Wordpress table plugin that wraps DataTables functionality. You may consider Tabulizer for Wordpress (http://www.tabulizer.com) that supports server side processing and loads table data via Ajax calls only when needed. There is also a data source cache for improved performance.
Ajax dataTable or server-side processing dataTable in WordPress or Core PHP.
HTML Code
<table id="student_table" width="100%">
<thead>
<tr>
<th>Roll No.</th>
<th>Full Name</th>
<th>Phone</th>
<th>Action</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<th>Roll No.</th>
<th>Full Name</th>
<th>Phone</th>
<th>Action</th>
</tr>
</tfoot>
</table>
jQuery code
jQuery('#student_table').DataTable({
"bProcessing": true,
"serverSide": true,
"ajax":{
"url": FrontendConfig.ajaxurl+'?action=getStudentsFromExamIdAjax&exam_nounce=exam_nounce_data&exam_id=1',
type: "post",
}
});
WordPress or PHP code
add_action('wp_ajax_getStudentsFromExamIdAjax', 'getStudentsFromExamIdAjax' );
add_action('wp_ajax_nopriv_getStudentsFromExamIdAjax', 'getStudentsFromExamIdAjax' );
function getStudentsFromExamIdAjax(){
if(empty($_GET['action']) || empty($_GET['exam_id'])){
wp_send_json_error( new \WP_Error( 'Bad Request' ) );
}
if(isset($_GET['exam_id']) && $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( $_GET['exam_nounce'], 'exam_nounce_data' )):
$exam_id = (isset($_GET['exam_id'])) ? absint($_GET['exam_id']) : '';
/*# You can create a function to get the data here */
$students = getStudentsFromExamId($exam_id);
$tdata = [];
foreach ($students as $key => $value):
$tdata[$key][] = $value->roll_no;
$tdata[$key][] = $value->name;
$tdata[$key][] = $value->phone;
$tdata[$key][] = 'action here';
endforeach;
$total_records = count($tdata);
$json_data = array(
/* $_REQUEST['draw'] comes from the datatable, you can print to ensure that */
"draw" => intval( $_REQUEST['draw'] ),
"recordsTotal" => intval( $total_records ),
"recordsFiltered" => intval( $total_records ),
"data" => $tdata
);
echo json_encode($json_data);
endif;
wp_die();
}
Custom.js
jQuery( document ).ready(function() {
alert('test');
jQuery('#employee_grid').DataTable({
"bProcessing": true,
"serverSide": true,
"ajax":{
url :ajax_url_object.ajax_url+'?action=getStudentsFromExamIdAjax&exam_nounce=exam_nounce_data&exam_id=1', // json datasource
type: "POST", // type of method ,GET/POST/DELETE
error: function(){
jQuery("#employee_grid_processing").css("display","none");
}
}
}); });
WordPress or PHP code
function theme_styles1()
{
$template_dir_uri =content_url();
$pluginurl =plugins_url();
//====================js
wp_enqueue_style( 'vpn-custom-style1','https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.2/css/bootstrap.css', true );
wp_enqueue_style( 'vpn-custom-boostrap1','https://cdn.datatables.net/1.11.3/css/dataTables.bootstrap4.min.css', true );
wp_enqueue_script( 'vpn-script11','https://cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js', true );
wp_enqueue_script( 'vpn-script21','https://cdn.datatables.net/1.11.3/js/dataTables.bootstrap4.min.js', true );
wp_enqueue_script( 'vpn_script31', plugin_dir_url( __FILE__ ).'js/custom.js', true );
//============ ajax url
$urls= array('ajax_url'=> admin_url( 'admin-ajax.php' ),
'site_url' => site_url()
);
wp_localize_script( 'vpn_script31', 'ajax_url_object',$urls);
}
add_action( 'wp_enqueue_scripts', 'theme_styles1',99 );
div class="wrap">
<h1>Service List</h1>
<div class="container">
<table id="employee_grid" class="display" width="100%" cellspacing="0">
<thead>
<tr>
<th>Empid</th>
<th>Name</th>
<th>Salary</th>
<th>Age</th>
</tr>
</thead>
<tfoot>
<tr>
<th>Empid</th>
<th>Name</th>
<th>Salary</th>
<th>Age</th>
</tr>
</tfoot>
</table>
</div>
add_action('wp_ajax_getStudentsFromExamIdAjax', 'getStudentsFromExamIdAjax' );
add_action('wp_ajax_nopriv_getStudentsFromExamIdAjax', 'getStudentsFromExamIdAjax' );
function getStudentsFromExamIdAjax(){
global $wp;
$servername = "localhost:3308";
$username = "root";
$password = "";
$dbname = "demo";
$conn = mysqli_connect($servername, $username, $password, $dbname) or die("Connection failed: " . mysqli_connect_error());
$params = $columns = $totalRecords = $data = array();
$params = $_REQUEST;
// echo "<pre>";
// print_r($params);
// die;
//define index of column
$columns = array(
0 =>'id',
1 =>'employee_name',
2 => 'employee_salary',
3 => 'employee_age'
);
$where = $sqlTot = $sqlRec = "";
// check search value exist
if( !empty($params['search']['value']) ) {
$where .=" WHERE ";
$where .=" ( employee_name LIKE '".$params['search']['value']."%' ";
$where .=" OR employee_salary LIKE '".$params['search']['value']."%' ";
$where .=" OR employee_age LIKE '".$params['search']['value']."%' )";
}
// getting total number records without any search
$sql = "SELECT * FROM `employee` ";
$sqlTot .= $sql;
$sqlRec .= $sql;
//concatenate search sql if value exist
if(isset($where) && $where != '') {
$sqlTot .= $where;
$sqlRec .= $where;
}
$sqlRec .= " ORDER BY ". $columns[$params['order'][0]['column']]." ".$params['order'][0]['dir']." LIMIT ".$params['start']." ,".$params['length']." ";
$queryTot = mysqli_query($conn, $sqlTot) or die("database error:". mysqli_error($conn));
$totalRecords = mysqli_num_rows($queryTot);
$queryRecords = mysqli_query($conn, $sqlRec) or die("error to fetch employees data");
//iterate on results row and create new index array of data
while( $row = mysqli_fetch_row($queryRecords) ) {
$data[] = $row;
}
// echo "<pre>";
// print_r($data);
// die;
$json_data = array(
"draw" => intval( $params['draw'] ),
"recordsTotal" => intval( $totalRecords ),
"recordsFiltered" => intval($totalRecords),
"data" => $data // total data array
);
echo json_encode($json_data); // send data as json format
}