Add custom product status in woocommerce - wordpress

We sell computer parts at our woocommerce based website.
IT products become old very quickly, so I have thousands of End-Of-Life (EOL) products.
We update and check prices via REST API, so our system spend too much time for EOL products.
On the other hand, We don't want to delete or make them private because they bring big visitors from google search.
So, we think to add a custom status to product. Like EOL. So products will be listed on google but since we will update only Published status products it will not be problem.
I found below code but can't be sure it is correct. Because when I add this code and select EOL, It doesn't look as I want.
Before select EOL: https://prnt.sc/00qzWQV6saTp
After select EOL and save: https://prnt.sc/VkTzLq1S1EZP
Any advise?
register_post_status( 'custom-hide-product', array(
'label' => _x( 'EOL', 'post' ),
'public' => true,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'label_count' => _n_noop( 'EOL <span class="count">(%s)</span>', 'EOL <span class="count">(%s)</span>' ),
) );
add_action( 'admin_footer', 'display_hide_status_option' );
function display_hide_status_option() {
global $post;
$complete = '';
$label = '';
if ( $post->post_type === 'product' ) {
if ( $post->post_status === 'custom-hide-product' ) {
$selected = 'selected';
}
echo '<script>
jQuery(document).ready(function($){
$("select#post_status").append("<option value=\"custom-hide-product\" ' . $complete . '>EOL</option>");
$(".misc-pub-section label").append("' . $label . '");
});
</script>
';
}
}

$label is always empty in your code, it must be set if $post->post_status === 'custom-hide-product'.
And replace $(".misc-pub-section label").append("' . $label . '"); with $(".misc-pub-section #post-status-display").html("' . $label . '"); if $label is 'EOL'

Related

how to show a backorder status in woocommerce orders listing

We have a lot of backorders in WooCommerce and we would like to be able to sort all the backorders in the orders table.
Currently, we are filtering the orders using these status: Awaiting shipment, Refunded, Cancelled, Completed, Processing
Please refer to the screenshot
I've searched online and I only found a plugin that create a separate menu link lisitng backorders only.
Is there a filter I could add in functions.php that would do the job ? I don't want to install a plugin just for that.
Right Now i've only been able to add a custom backorder status using this code below, the second step would be to trigger the status when there is a backordered product.
/**
* Register new status
* Tutorial: http://www.sellwithwp.com/woocommerce-custom-order-status-2/
**/
function register_backorders_order_status() {
register_post_status( 'wc-backorders', array(
'label' => 'Backorders',
'public' => true,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'label_count' => _n_noop( 'backorders <span class="count">(%s)</span>', 'Awaiting shipment <span class="count">(%s)</span>' )
) );
}
add_action( 'init', 'register_backorders_order_status' );
// Add to list of WC Order statuses
function add_backorders_to_order_statuses( $order_statuses ) {
$new_order_statuses = array();
// add new order status after processing
foreach ( $order_statuses as $key => $status ) {
$new_order_statuses[ $key ] = $status;
if ( 'wc-processing' === $key ) {
$new_order_statuses['wc-backorders'] = 'Backorders';
}
}
return $new_order_statuses;
}
add_filter( 'wc_order_statuses', 'add_backorders_to_order_statuses' );

Hide " Add to cart " button for 1 day after ordering a product, for that product which user has ordered

I have added a new custom field in checkout page named " Date of event ", It's working fine. But i want one thing to be done which is " When user order single/multiple products then hide "Add to cart" button and show unavailable message instead of button for that selected date of event. " Like if user selected date " 7/2/2019 " in " Date of event field " during checkout, then after he ordered that product, hide " Add to cart " button and show unavailable message instead of button for " 7/2/2019 " date of event. I don't know how to do this.
Which hooks and actions will do this. I have googled it a lot, but didn't get any answer.
Please help me.
Custom field Code:
add_action('woocommerce_after_checkout_billing_form', 'date_of_event_field');
function date_of_event_field($checkout){
echo '<div id="date_of_event_field" class="margin-top-20">';
woocommerce_form_field( 'date_of_event', array(
'type' => 'date',
'class' => array('my-field-class form-row-wide'),
'label' => __('Date Of Event'),
'required' => true,
), $checkout->get_value( 'date_of_event' ));
echo '</div>';
}
Code to hide Add to cart button and show message instead of button:
function make_product_unavailable( $_product, $order ) {
if( $order->id == $_product ){
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart');
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart');
}
}
It's a try from my side, because i don't know how to do to this and i don't know which filter/action hook will be used for this.
Please help me.
Source : https://wisdmlabs.com/blog/the-right-way-to-hide-add-to-cart-button-in-woocommerce/
Check if a customer has purchased a specific products in WooCommerce
Note : The below code is not tested but it will work if some part is modified as per your requirement..
add_filter( 'woocommerce_is_purchasable', 'hidecart',10,1);
function hidecart(){
$found = has_bought_items();
if(!empty($found["order_date"])){
$current_date = date("d/m/Y");
if($found["order_date"] == $current_date && $found["product_id"] == get_the_ID()){
return false;
}
}
}
function has_bought_items()
{
$bought = false;
$order_date = '';
//get product id if single or for shop page u will have to retrieve in some other way
$product_id = get_the_ID();
// Get all customer orders
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => 'shop_order', // WC orders post type
'post_status' => 'wc-completed' // Only orders with status "completed"
) );
foreach ( $customer_orders as $customer_order ) {
// Updated compatibility with WooCommerce 3+
$order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id;
$order = wc_get_order( $customer_order );
// Iterating through each current customer products bought in the order
foreach ($order->get_items() as $item) {
// WC 3+ compatibility
if ( version_compare( WC_VERSION, '3.0', '<' ) )
$order_product_id = $item['product_id'];
else
$order_product_id = $item->get_product_id();
// Your condition related to your 2 specific products Ids
if ( $product_id == $product_id) ) {
$bought = true;
$order_date = $order->order_date;
// you can fetch your event date stored as order meta
$arr = array("product_id"=>$product_id,"order_date"=>$order_date,"bought"=>$bought);
return $arr;
}
}
}
$arr = array("product_id"=>"","order_date"=>$order_date,"bought"=>$bought);
return $order_date;
}

Display custom checkout field value on admin order detail section in Woocommerce

Hello I'm trying to display the custom checkout field in the admin order details page. My Custom field is Delivery Option and it allows the user to pick the to pick a value from checkbox. I use the code below following the similar topics about this, but it seems something is wrong with my code.
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_additional_field', 20 );
function checkout_shipping_additional_field()
{
$domain = 'wocommerce';
$default = 'option 1';
echo '<tr class="additional-shipping-fields"><th>' . __('Delivery Time', $domain) . '</th><td>';
// Add a custom checkbox field
woocommerce_form_field( 'custom_radio_field', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'options' => array(
'option 1' => __('10:04 : 13:04 ', $domain),
),
'default' => $default,
), $default );
echo '</td></tr>';
}
//update order meta
add_action('woocommerce_checkout_update_order_meta', 'gon_update_order_meta_business_address');
function gon_update_order_meta_business_address( $order_id ) {
if ($_POST['custom_radio_field']) update_post_meta( $order_id, 'Business Address?',
esc_attr($_POST['custom_radio_field']));
}
// Display field value on the admin order edit page
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'custom_checkout_field_display_admin_order_meta', 10, 1 );
function custom_checkout_field_display_admin_order_meta( $order ){
$delivery_time = get_post_meta( $order->get_id(), 'Delivery Time', true );
if( ! empty( $delivery_time ) )
echo '<p><strong>'.__('Delivery Time', 'woocommerce').': </strong> ' . $delivery_time . '</p>';
}
There is some mistakes, so I have revisited your code. I have also replaced some hooks. Try the following:
// HERE set your the options array for your select field.
function delivery_time_options(){
$domain = 'woocommerce';
return array(
'1' => __('10:04 : 13:04 ', $domain),
'2' => __('14:04 : 16:04 ', $domain), // <== Added for testing
);
}
// Display a custom select field after shipping total line
add_action( 'woocommerce_review_order_after_shipping', 'checkout_shipping_additional_field', 20 );
function checkout_shipping_additional_field(){
$domain = 'woocommerce';
echo '<tr class="additional-shipping-fields"><th>' . __('Delivery Time', $domain) . '</th><td>';
// Add a custom select field
woocommerce_form_field( 'delivery_time', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'options' => delivery_time_options(),
), '' );
echo '</td></tr>';
}
// Save custom field as order meta data
add_action('woocommerce_checkout_create_order', 'save_custom_field_order_meta', 22, 2 );
function save_custom_field_order_meta( $order, $data ) {
if ( isset($_POST['delivery_time']) ) {
$options = delivery_time_options(); // Get select options array
$option_key = esc_attr($_POST['delivery_time']); // The selected key
$order->update_meta_data( '_delivery_time', $options[$option_key] ); // Save
}
}
// Display a custom field value on the admin order edit page
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_custom_meta_data_in_backend_orders', 10, 1 );
function display_custom_meta_data_in_backend_orders( $order ){
$domain = 'woocommerce';
$delivery_time = $order->get_meta('_delivery_time');
if( ! empty( $delivery_time ) )
echo '<p><strong>'.__('Delivery Time', $domain).': </strong> ' . $delivery_time . '</p>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Based on #LoicTheAztec answer, if you want multiple fields without re-writing the functions for every field (DRY), you can use this class (by adding it to your functions.php):
/**
* Add a custom field to the woocommerce checkout page
* https://stackoverflow.com/q/52098807/
*/
class WOO_Add_Checkout_Field
{
public function __construct($options)
{
$this->field_name = $options['field_name'];
$this->label = $options['label'];
$this->placeholder = $options['placeholder'];
$this->required = $options['required'];
if ($this->field_name && $this->label && $this->placeholder) {
add_action('woocommerce_after_order_notes', [$this, 'customise_checkout_field']);
add_action('woocommerce_checkout_update_order_meta', [$this, 'custom_checkout_field_update_order_meta'], 10, 1);
add_action('woocommerce_admin_order_data_after_billing_address', [$this, 'display_custom_field_on_order_edit_pages'], 10, 1);
} else {
die("Error in WOO_Add_Checkout_Field \$options: \n\n" . var_dump($options));
}
}
public function customise_checkout_field($checkout)
{
echo '<div id="customise_checkout_field">';
// echo '<h2>' . __('Heading') . '</h2>';
woocommerce_form_field($this->field_name, array(
'type' => 'text',
'class' => array(
'my-field-class form-row-wide'
),
'label' => $this->label,
'placeholder' => $this->placeholder,
'required' => $this->required,
), $checkout->get_value($this->field_name));
echo '</div>';
}
public function custom_checkout_field_update_order_meta($order_id)
{
if (!empty($_POST[$this->field_name]))
update_post_meta($order_id, $this->field_name, $_POST[$this->field_name]);
else
update_post_meta($order_id, $this->field_name, 0);
}
public function display_custom_field_on_order_edit_pages($order)
{
$field = $order->get_meta($this->field_name);
if (!empty($field)) {
echo '<p><strong style="display:block" title="' . $this->placeholder . '">' . $this->label . ': </strong><span>';
echo $field;
echo '</span></p>';
}
}
}
And use it as many times as you'd like:
$my_custom_field_1 = new WOO_Add_Checkout_Field([
'field_name' => 'my_custom_field_1',
'label' => __('My First Field'),
'placeholder' => __('Please write something in field 1...'),
'required' => false,
]);
$my_custom_field_2 = new WOO_Add_Checkout_Field([
'field_name' => 'my_custom_field_2',
'label' => __('My Second Field'),
'placeholder' => __('Please write something in field 2...'),
'required' => false,
]);
$my_custom_field_3 = new WOO_Add_Checkout_Field([
'field_name' => 'my_custom_field_3',
'label' => __('My Third Field'),
'placeholder' => __('Please write something in field 3...'),
'required' => false,
]);
// and so on...
Please note:
The custom field will show up in admin area ONLY if it was not sent empty
You can customize this code how you like

How to properly save a WordPress option containing HTML code?

Here's a screenshot of what the problem looks like:
And the HTML of that part of the WordPress options page looks like this:
So, in the WordPress admin area, I entered a piece of HTML code (to have a clickable link as the output on the frontend).
This was the code I had entered into that text input field on the backend:
<a title="Website Design London" href="../../website-design/">Website Design</a>
And while on the frontend that link is displaying OK, I'm seeing this mess (see screenshot) on the backend.
As far as I can tell the relevant PHP code is this:
$this->text(
'workdone',
esc_html__( 'Work done', 'mytheme' )
);
So, what is the proper way to save an option that contains HTML code?
And how can I fix the mess shown on the screenshot?
I had the same issue, and this code is working for me:
// render service label
public function render_service_label() {
$value = get_option( 'wbk_service_label', '' );
$value = htmlspecialchars( $value );
$html = '<input type="text" id="wbk_service_label" name="wbk_service_label" value="'.$value.'" >';
$html .= '<p class="description">' . __( 'Service label', 'wbk' ) . '</p>';
echo $html;
}
// validate service label
public function validate_service_label( $input ) {
$allowed_tags = array(
//formatting
'strong' => array(),
'em' => array(),
'b' => array(),
'i' => array(),
'br' => array(),
//links
'a' => array(
'href' => array(),
'class' => array()
),
//links
'p' => array(
'class' => array()
)
);
$input = wp_kses( $input, $allowed_tags );
return $input;
}
So, in the dashboard options page I use htmlspecialchars function
In frontend page I use like this:
$label = get_option( 'wbk_service_label', __( 'Select service', 'wbk' ) );

Wordpress - custom post status is not showing

I've created new post status. Here's code from my custom plugin:
add_action('init', 'new_post_status_add');
function new_post_status_add () {
register_post_status('refused', array(
'label' => _x('Refused', 'post'),
'public' => true,
'exclude_from_search' => false,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'label_count' => _n_noop('Refused <span class="count">(%s)</span>', 'Refused <span class="count">(%s)</span>'),
));
}
But it's not working - not visible in edit form and quick edit form:
What should I do to make status available?
Sorry for delayed reply. I hope my comment would help others.
Custom Post Status is an unsolved issue that has been there for such a long time, or at least since 8yrs ago on Wordpress website here.
Wordpress noted on codex document for function register_post_status():
This function does NOT add the registered post status to the admin panel. This functionality is pending future development. Please refer
to Trac Ticket #12706. Consider the action hook
post_submitbox_misc_actions for adding this parameter.
There is a work around that I could use for one of my projects. I mixed solutions that described on this url and this url.
The summary is that Wordpress doesn't show custom post status automatically. It needs to be manipulated by using your theme's function.php.
First step
Create custom post status, same as you mentioned. just, don't forget that "This function should not be called before the 'init' action."
‌
function j_custom_post_status() {
$args = array(
'label' => _x( 'Refused', 'post'),
'label_count' => _n_noop( 'Refused <span class="count">(%s)</span>', 'Refused (%s)', 'post' ),
'public' => false,
'internal' => true,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'exclude_from_search' => false,
);
register_post_status( 'j_refused', $args );
add_action( 'init', 'j_custom_post_status', 0 );
‌
I use WP Generator to get the code snippet above.
Second step
Tweak Admin Panel to show the custom status in Quick Edit Menu (QE) on posts list page edit.php. We need JQuery's help to do so and we need to add JQuery code to Admin Panel footer.
‌
function j_append_status_list(){
//array of all custom status that you created
$arr_customstatus = array(
'refused',
'other_custom_status',
);
echo '<script>';
//flush
$tmp = '';
//generate string
foreach ($arr_customstatus as $pkey ) {
$tmp.= '<option value="'. $pkey .'">'. $pkey .'</option>';
}
echo "jQuery(document).ready( function() { jQuery( 'select[name=\"_status\"]' ).append( ". $tmp ." );
});";
echo '</script>';
}
add_action('admin_footer-edit.php','j_append_status_list');
‌
Note: The function above doesn't automatically select the status in QE in case the post's status has been modified before. To add the selected="true" to the option, you need to use the global $post and check the current status, same as the the method used in the Third step below.
Third step
Now, we need to add custom post status meta to post edit page too.
function j_custom_status_metabox(){
global $post;
$custom = get_post_custom( $post->ID );
$status = $custom["_status"][0];
// Array of custom status messages
$arr_customstatus = array(
'refused',
'other_custom_status',
);
//Flush
$tmp = '';
foreach( $jstats as $pkey ) {
if( $status == $pkey ){
$tmp.= '<option value="'.$pkey.'" selected="true">'. $pkey .'</option>';
} else {
$tmp.= '<option value="'. $pkey .'">'. $pkey .'</option>';
}
}
echo '<script>';
echo "jQuery(document).ready( function() { jQuery( 'select[name=\"_status\"]' ).append( ". $tmp ." );
});";
echo '</script>';
}
add_action('admin_footer-post.php','j_custom_status_metabox');
add_action('admin_footer-post-new.php','j_custom_status_metabox');
‌
Step four
In case you like to show a message in posts lists based on custom post status, you can add this function too. However, this is optional.
function j_display_status_label( $statuses ) {
global $post;
//Display label on all posts list but not on the custom status list
if( get_query_var( 'post_status' ) != 'refused' ){
if( $post->post_status == 'refused' ){
return array('Refused');
}
}
return $statuses;
}
add_filter( 'display_post_states', 'j_display_status_label' );
‌‌ ‌
Note: The function above doesn't include all future custom status. You need to add foreach loop in case you need.
Try to use this code,
// Register Custom Status
function custom_post_status() {
$args = array(
'label' => _x( 'Refused', 'Status General Name', 'text_domain' ),
'label_count' => _n_noop( 'Refused (%s)', ' (%s)', 'text_domain' ),
'public' => true,
'show_in_admin_all_list' => true,
'show_in_admin_status_list' => true,
'exclude_from_search' => false,
);
register_post_status( 'refused', $args );
}
add_action( 'init', 'custom_post_status', 0 );
I hope this will work for you.
Try adding PHP_INT_MAX to your j_custom_post_status action
add_action( 'init', 'j_custom_post_status', PHP_INT_MAX );
‌

Resources