I'm working on the admin side for a Wordpress site. I have a CPT that I've added a column into and would like to sort by that column type. Based off what I've read I'm using the correct functions, but after the filter of 'manage_edit-leadership_sortable_columns' there are no changes to the admin UI. This a CPT and the hierarchy is set to 'True.' I'd read that that may affect it but couldn't find a fix. The column also appears with a red circle and '0' next to it, that I don't know where it came from. The eventual goal is to set the display page on the site to the menu order and give the client the option to sort either by Title or Last Name. Thanks!
add_filter( 'manage_leadership_posts_columns', 'smashing_filter_posts_columns' );
function smashing_filter_posts_columns( $columns ) {
$name = array();
$name['last_name'] = __( 'Last Name', 'smashing', true );
array_splice($columns, 2, 0, $name);
return $columns;
}
function smashing_leadership_column( $column, $post_id ) {
// Name column
if ( 'last_name' == $column ) {
$lastName = get_field('last_name', $post_id );
echo $lastName;
}
}
add_action( 'manage_leadership_posts_custom_column', 'smashing_leadership_column', 10, 2);
function smashing_leadership_sortable_columns( $columns ) {
$columns['last_name'] = 'last_name';
return $columns;
}
add_filter( 'manage_edit-leadership_sortable_columns', 'smashing_leadership_sortable_columns');
add_action( 'pre_get_posts', 'smashing_posts_orderby' );
function smashing_posts_orderby( $query ) {
if( ! is_admin() || ! $query->is_main_query() ) {
return;
}
if ( 'last_name' === $query->get( 'orderby') ) {
$query->set( 'orderby', 'meta_value' );
$query->set( 'meta_key', 'last_name' );
}
}
Admin Screenshot
I was able to get this to work with the following code in place of the other sortable filters.
add_filter( 'manage_edit-leadership_sortable_columns', 'my_sortable_leadership_columns' );
function my_sortable_leadership_columns( $columns ) {
$columns['firstName'] = 'first';
$columns['lastName'] = 'last';
return $columns;
}
add_action( 'pre_get_posts', 'my_leadership_orderby' );
function my_leadership_orderby( $query ) {
if( ! is_admin() )
return;
$orderby = $query->get( 'orderby');
if( 'first' == $orderby ) {
$query->set('meta_key','first_name');
$query->set('orderby','meta_value');
}
if( 'last' == $orderby ) {
$query->set('meta_key','last_name');
$query->set('orderby','meta_value');
}
}
I'm adding the following custom columns and they both appear:
function add_order_new_column_header( $columns ) {
$new_columns = array();
foreach ( $columns as $column_name => $column_info ) {
$new_columns[ $column_name ] = $column_info;
if ( 'order_total' === $column_name ) {
$new_columns['order_shipping'] = __( 'Tarnemeetod', 'my-textdomain' );
$new_columns['order_payment'] = __( 'Maksemeetod', 'my-textdomain' );
}
}
return $new_columns;
Then I'm adding the following to generate data:
add_filter( 'manage_edit-shop_order_columns', 'add_order_new_column_header', 20);
add_action( 'manage_shop_order_posts_custom_column', 'add_wc_order_admin_list_column_content' );
function add_wc_order_admin_list_column_content( $column ) {
global $post;
if ( 'order_shipping' === $column ) {
$order = wc_get_order( $post->ID );
echo $order->get_shipping_method();
if ( 'order_payment' === $column ) {
$order = wc_get_order( $post->ID );
echo $order->get_payment_method_title();
}
}
}
order_shipping is showing correct shipping method, but order_payment is empty.
I'm not using multiple languages on the site. WooCommerce 4.1.1, PHP 7.3.19
view from WooCommerce orders admin panel:
I've tried both get_payment_method and get_payment_method_list. I have orders with BACS mostly and a few Cash on Pickup which is disabled for now. What am I missing here?
There are some mistakes and missing things in your code, try the following instead:
add_filter( 'manage_edit-shop_order_columns', 'add_custom_columns_to_admin_orders', 20);
function add_custom_columns_to_admin_orders( $columns ) {
$new_columns = array();
foreach ( $columns as $column_name => $column_info ) {
$new_columns[ $column_name ] = $column_info;
if ( 'order_total' === $column_name ) {
$new_columns['order_shipping'] = __( 'Tarnemeetod', 'my-textdomain' );
$new_columns['order_payment'] = __( 'Maksemeetod', 'my-textdomain' );
}
}
return $new_columns;
}
add_action( 'manage_shop_order_posts_custom_column', 'custom_columns_content_in_admin_orders' );
function custom_columns_content_in_admin_orders( $column ) {
global $post, $the_order;
if ( 'order_shipping' === $column ) {
echo $the_order->get_shipping_method();
}
if ( 'order_payment' === $column ) {
echo $the_order->get_payment_method_title();
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
I have the below custom metakey which is an optin checkbox during checkout:
//1. ADD OPT IN OPTION IN CHECKOUT AND SAVE IN THE ORDER
// Add checkbox optin before T&Cs
add_action( 'woocommerce_checkout_before_terms_and_conditions', 'marketing_opting_field' );
function marketing_opting_field() {
echo '<div id="marketing_opting_field">';
woocommerce_form_field( 'marketing_opting', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Yes, sign me up'),
'default' => 1,
), WC()->checkout->get_value( 'marketing_opting' ) );
echo '</div>';
}
// Save the optin field in the order meta, when checkbox has been checked
add_action( 'woocommerce_checkout_update_order_meta', 'custom_checkout_field_update_order_meta', 10, 1 );
function custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['marketing_opting'] ) )
update_post_meta( $order_id, 'marketing_opting', $_POST['marketing_opting'] );
}
// Display the result of the checked optin in the order under billing address
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
$marketing_opting = get_post_meta( $order->get_id(), 'marketing_opting', true );
if( $marketing_opting == 1 )
echo '<p><strong>Has opted in for marketing purposes.</p>';
}
// 2. SHOW CUSTOM COLUMN FOR THE OPTIN OPTION
// Adding custom column title
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 12, 1 );
function custom_shop_order_column($columns)
{
$action_column = $columns['order_actions'];
unset($columns['order_actions']);
//add the new column "Opt in"
$columns['order_marketing'] = '<p align="center">Opted in?</p>'; // title
$columns['order_actions'] = $action_column;
return $columns;
}
// Add the data for each order
add_action( 'manage_shop_order_posts_custom_column' , 'custom_order_list_column_content', 10, 2 );
function custom_order_list_column_content( $column, $post_id ){
$marketing_opting = get_post_meta( $post_id, 'marketing_opting', true );
if( $marketing_opting == 1)
switch($column){
case 'order_marketing' : echo '<p align="center"><span class="dashicons dashicons-yes"></span><span style="color: #F21891; font-weight: 600;">Signed Up</span></p>';
break;
}
}
So above is working and shows below the column, but I would like to have a filter in the admin bar and a search for Signed Up gives the desired result:
The search is not working, because the value of the checkbox for checked is 1 and does not resognise other words. I have added below, but it's not giving the result:
add_filter( 'woocommerce_shop_order_search_fields', 'marketing_search_fields', 10, 1 );
function marketing_search_fields( $meta_keys ){
$meta_keys[] = 'marketing_opting';
return $meta_keys;
}
The admin bar filter; the only related posts I could find are all about order statuses and not a custom metakey. I am not sure how to add this correctly, I started with the below, but there are obvious errors, and I am stuck.
add_filter( 'views_edit-shop_order' , 'marketing_opt_in_filter', 10, 1);
function marketing_opt_in_filter( $views ) {
$marketing_opting = get_post_meta( $post_id, 'marketing_opting', true );
if( $marketing_opting == 1)
$query_string = admin_url( 'edit.php?post_type=shop_order' ) ;
$query_string = add_query_arg( 'marketing_opting' , 'yes' , $query_string ) ;
$views[ 'marketing_opting' ] = 'Opted In (%s)' ;
return $views ;
}
I have revisited your existing code a bit and added a dropdown filter for the "marketing optin" custom field:
//1. ADD OPT IN OPTION IN CHECKOUT AND SAVE IN THE ORDER
// Add checkbox optin before T&Cs
add_action( 'woocommerce_checkout_before_terms_and_conditions', 'marketing_opting_field' );
function marketing_opting_field() {
echo '<div id="marketing_opting_field">';
woocommerce_form_field( 'marketing_opting', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('Yes, sign me up'),
'default' => 1,
), WC()->checkout->get_value( 'marketing_opting' ) );
echo '</div>';
}
// Save the optin field as custom order meta, when checkbox has been checked
add_action( 'woocommerce_checkout_create_order', 'action_checkout_update_order_meta', 10, 2 );
function action_checkout_update_order_meta( $order, $data ) {
if( isset($_POST['marketing_opting']) )
$order->update_meta_data( '_marketing_opting', empty($_POST['marketing_opting']) ? 'no' : 'yes' );
}
// Save the optin field as custom user meta, when checkbox has been checked
add_action( 'woocommerce_checkout_update_customer', 'action_checkout_update_customer_meta', 10, 2 );
function action_checkout_update_customer_meta( $customer, $data ) {
if( isset($_POST['marketing_opting']) )
$customer->update_meta_data( 'marketing_opting', empty($_POST['marketing_opting']) ? 'no' : 'yes' );
}
// Display the result of the checked optin in the order under billing address
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
if( $order->get_meta( '_marketing_opting' ) === 'yes' )
echo '<p><strong>Has opted in for marketing purposes.</p>';
}
// 2. SHOW CUSTOM COLUMN FOR THE OPTIN OPTION
// Adding custom column title
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 12, 1 );
function custom_shop_order_column($columns)
{
$action_column = $columns['order_actions'];
unset($columns['order_actions']);
//add the new column "Opt in"
$columns['order_marketing'] = '<div align="center">' .__("Opted in?") . '</div>'; // title
$columns['order_actions'] = $action_column;
return $columns;
}
// Add the data for each order
add_action( 'manage_shop_order_posts_custom_column' , 'custom_order_list_column_content', 10, 2 );
function custom_order_list_column_content( $column, $post_id ){
global $post, $the_order;
if ($column ==='order_marketing') {
$value = $the_order->get_meta( '_marketing_opting' );
$label = $value === 'yes' ? __('Signed Up') : ucfirst($value);
$color = $value === 'yes' ? 'color:#00cc00;' : 'color:#bbbbbb;';
echo '<p align="center" style="'.$color.'"><span class="dashicons dashicons-'.$value.'"></span><span style="font-weight:600;">'.$label.'</span></p>';
}
}
// 3. Make marketing optin meta searchable from search field (can't work very well for 'yes' or 'no' values!)
// Make a custom meta field searchable from the admin order list search field
add_filter( 'woocommerce_shop_order_search_fields', 'marketing_search_fields', 10, 1 );
function marketing_search_fields( $meta_keys ){
$meta_keys[] = '_marketing_opting';
return $meta_keys;
}
// 4. Add a dropdown filter to get orders by marketing optin meta value
// Add a dropdown to filter orders by Marketing optin
add_action( 'restrict_manage_posts', 'display_admin_shop_order_marketing_opting_filter' );
function display_admin_shop_order_marketing_opting_filter(){
global $pagenow, $post_type;
if( 'shop_order' === $post_type && 'edit.php' === $pagenow ) {
$domain = 'woocommerce';
$current = isset($_GET['filter_shop_order_marketing'])? $_GET['filter_shop_order_marketing'] : '';
echo '<select name="filter_shop_order_marketing">
<option value="">' . __('Filter Marketing optin', $domain) . '</option>';
$options = ['yes' => __('Signed Up'), 'no' => __('No')];
foreach ( $options as $key => $label ) {
printf( '<option value="%s"%s>%s</option>', $key,
$key === $current ? '" selected="selected"' : '', $label );
}
echo '</select>';
}
}
// Process the filter dropdown for orders by Marketing optin
add_filter( 'request', 'process_admin_shop_order_marketing_opting_filter', 99 );
function process_admin_shop_order_marketing_opting_filter( $vars ) {
global $pagenow, $typenow;
if ( $pagenow == 'edit.php' && isset( $_GET['filter_shop_order_marketing'] )
&& $_GET['filter_shop_order_marketing'] != '' && 'shop_order' === $typenow ) {
$vars['meta_key'] = '_marketing_opting';
$vars['meta_value'] = wc_clean( $_GET['filter_shop_order_marketing'] );
}
return $vars;
}
Note: I have change the order meta_key to _marketing_opting starting with an underscore as most other existing metakeys...
Also I have added a function that register that "marketing optin" value in user meta data, as it will be used by checkout on WC()->checkout->get_value( 'marketing_opting' ) for customers that have already made an order.
Field validation (optional)
If you make this checkout field required, you will need field validation… Then add the following:
// Custom Checkout field validation
add_action('woocommerce_checkout_process', 'custom_checkout_field_validation');
function custom_checkout_field_validation() {
if ( isset($_POST['marketing_opting']) ) {
wc_add_notice( '<strong>'. __("Please select a value", "woocommerce") . '</strong> | '.$_POST['marketing_opting'], 'error' );
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
In Woocommerce, I have created a custom column to admin orders list page.
<?php
add_filter( 'manage_edit-shop_order_columns', 'MY_COLUMNS_FUNCTION' );
function MY_COLUMNS_FUNCTION( $columns ) {
$new_columns = ( is_array( $columns ) ) ? $columns : array();
unset( $new_columns[ 'order_actions' ] );
$new_columns['MY_COLUMN_ID_1'] = 'MY_COLUMN_1_TITLE';
$new_columns[ 'order_actions' ] = $columns[ 'order_actions' ];
return $new_columns;
}
Then, custom field for this column
add_action( 'manage_shop_order_posts_custom_column', 'MY_COLUMNS_VALUES_FUNCTION', 2 );
function MY_COLUMNS_VALUES_FUNCTION( $column ) {
global $post;
$data = get_post_meta( $post->ID );
if ( $column == 'MY_COLUMN_ID_1' ) {
echo ( isset( $data[ 'MY_COLUMN_1_POST_META_ID' ] ) ? $data[ 'MY_COLUMN_1_POST_META_ID' ] : '' );
}
}
But I don't know how to post a string to the specific custom field via WooCommerce API?
I would tweak Andrew's answer just a little to start using the order object more and rely less on post meta. I'm pretty sure WooCommerce will move at least it's core meta into a custom table eventually.
function wc_add_custom_order_column_content( $column ) {
global $post, $the_order;
if ( empty( $the_order ) || $the_order->get_id() !== $post->ID ) {
$the_order = wc_get_order( $post->ID );
}
// Only continue if we have an order.
if ( empty( $the_order ) ) {
return;
}
if ( 'custom_column' === $column ) {
// Use order class getters to retrieve what you need.
echo $the_order->get_formatted_order_total();
// Or, if it's not a core field, it may be in meta.
// echo $the_order->get_meta('_some_meta_key');
}
}
add_action( 'manage_shop_order_posts_custom_column', 'wc_add_custom_order_column_content' );
Here's an example of how to add a custom column in the admin order screen. It will add your column after the Actions column and populate it with your custom field data. You'll need to replace my "custom_column" values with your own field names.
function wc_add_custom_order_column( $columns ) {
$new_columns = array();
foreach ( $columns as $column_name => $column_info ) {
$new_columns[ $column_name ] = $column_info;
if ( 'order_actions' === $column_name ) {
$new_columns['custom_column'] = __( 'Custom Column', 'my-textdomain' );
}
}
return $new_columns;
}
add_filter( 'manage_edit-shop_order_columns', 'wc_add_custom_order_column', 20 );
function wc_add_custom_order_column_content( $column ) {
global $post;
if ( 'custom_column' === $column ) {
$data = get_post_meta( $post->ID );
if( isset( $data['custom_column'] ) )
echo $data['custom_column'];
}
}
add_action( 'manage_shop_order_posts_custom_column', 'wc_add_custom_order_column_content' );
I want to change text of published under date column of post list in wordpress.
see below image
You can try using following way.
<?php
function my_custom_columns( $columns ) {
unset( $columns['date'] );
$columns['mydate'] = 'My Custom Date';
return $columns;
}
function my_format_column( $column_name , $post_id ) {
if($column_name == 'mydate'){
echo get_the_time( 'l, F j, Y', $post_id )."<br>".get_post_status( $post_id );
}
}
function my_column_register_sortable( $columns ) {
$columns['mydate'] = 'mydate';
return $columns;
}
function my_column_orderby( $vars ) {
if ( isset( $vars['orderby'] ) && 'mydate' == $vars['orderby'] ) {
$vars = array_merge( $vars, array(
'orderby' => 'date'
) );
}
return $vars;
}
function my_column_init() {
add_filter( 'manage_posts_columns' , 'my_custom_columns' );
add_action( 'manage_posts_custom_column' , 'my_format_column' , 10 , 2 );
add_filter( 'manage_edit-post_sortable_columns', 'my_column_register_sortable' );
add_filter( 'request', 'my_column_orderby' );
}
add_action( 'admin_init' , 'my_column_init' );
?>