Add Custom Function to WooCommerce - wordpress

Two questions here.
Below is a function in WooCommerce wc-order-functions.php that I found works almost similar to what I need.
function wc_get_order_id_by_order_key( $order_key ) {
global $wpdb;
// Faster than get_posts()
$order_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = %s", $order_key ) );
return $order_id;
}
Which returns the $order_id but I'm looking to get the $order_key so that I can contruct the url generated after buyer have click the 'Place order' button on the checkout page e.g. domain.com/checkout/order-received/2316/?key=wc_order_54c7142660e24
wc_order_54c7142660e24 being the $order_id and
2316 being the $order_key
I know that the SQL command below gets the value I want from database:
function wc_get_order_key_by_order_id( $order_id ) {
global $wpdb;
// Faster than get_posts()
$order_key = $wpdb->get_var( $wpdb->prepare( "SELECT meta_value FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND post_id = %s", $order_id ) );
return $order_key;
}
But I'm not sure how to hook the filter to wordpress functions.php So this is my first question.
Second question is I've been searching for the function that might be responsible for generating the meta_value for the $order_key but can't seem to find it, would be great to know how it works. I suppose the first way is kinda redundant since the function I'm looking for already exists, just can't seem to locate it.

Try adding this to your woocommerce template files where you need that link:
echo get_site_url().'/checkout/order-received/'.$order->id.'&key='.$order->order_key;

Related

How to manipulate the WooCommerce order key by removing the "wc_" prefix?

I would like to manipulate the order key by removing wc_ from it.
Problem is, no matter what I do, wc_ is not removed.
Is there any way to do this?
add_filter( 'woocommerce_generate_order_key', 'woocommerce_generate_custom_order_key', 10, 1 );
function woocommerce_generate_custom_order_key($order_key){
$order_key = str_replace( 'wc_', '', $order_key );
return $order_key;
}
The _order_key (Order Key) and post_id (Order ID) fields are different.
The order number you see in the WooCommerce backend is the post_id
field of the wp_posts table of the Wordpress database.
The order key instead refers to the _order_key (meta_key) field of the wp_postmeta table of the Wordpress database.
The woocommerce_generate_order_key filter is documented here and as you can see you cannot use it to remove the wc_ prefix from the _order_key field of the order. Here is the extract of the source code:
/**
* Generate an order key with prefix.
*
* #since 3.5.4
* #param string $key Order key without a prefix. By default generates a 13 digit secret.
* #return string The order key.
*/
function wc_generate_order_key( $key = '' ) {
if ( '' === $key ) {
$key = wp_generate_password( 13, false );
}
return 'wc_' . apply_filters( 'woocommerce_generate_order_key', 'order_' . $key );
}
If you want to manipulate the WooCommerce order key you have to use the set_order_key() method of the WC_Order class. Here you find the documentation.
You will also need to update the order post_password field in the wp_posts table.
So, for example, if you wanted to set a custom order key (removing the wc_ prefix) for each new order you could use this function:
// removes the "wc_" prefix from the WooCommerce order key field for each new order
add_action( 'woocommerce_new_order', 'set_custom_order_key', 99, 2 );
function set_custom_order_key( $order_id, $order ) {
// get the order object
$order = wc_get_order( $order_id );
// gets the current order key
$order_key = $order->get_order_key();
// remove the "wc_" prefix
$new_order_key = str_replace( 'wc_', '', $order_key );
// updates the "_order_key" field of the "wp_postmeta" table
$order->set_order_key( $new_order_key );
$order->save();
// updates the "post_password" field of the "wp_posts" table
$post = get_post( $order_id );
$post->post_password = $new_order_key;
wp_update_post( $post );
}
The code has been tested and works. Add it to your active theme's functions.php.
If you want to manipulate the WooCommerce order id you have to use the woocommerce_order_number filter. The documentation can be found here.
You can find some examples here:
Adding suffix and prefix to WooCommerce order number without using a plugin
Woocommerce for Wordpress: How to modify the order number/id?
Add in a custom prefix and suffix to WooCommerce Order Number

WordPress How can I get post_id from thumbnail_id?

I'm developing wordpress plugin.
I need to find out post_id from thumbnail_id(not reverse !).
How can I do this?
You can get result by this code
global $wpdb;
$_thumbnail_id = {thumbnail id};
$sql = "SELECT `post_id` FROM `wp_postmeta` WHERE `meta_value` = $_thumbnail_id";
$result = $wpdb->get_results( $sql, ARRAY_A );
//access first returned post id
var_dump($result[0]['post_id']);
If you added same image for multiple posts there will be multiple returns.
You can use get_the_ID() to get the post id. You can find this function in wp-includes/post-template.php
function get_the_ID() {
$post = get_post();
return ! empty( $post ) ? $post->ID : false;
}

A Wordpress cronjob to cancel WC orders for a product that was deleted?

I have a project where a user can actually delete their own virtual product they have put up for sale and there may actually be some active orders on that product at the time of its deletion. I figured the best solution would be to add a cronjob that runs every 10 minutes, using a real cron, via crontab, rather than the Wordpress virtual cron, which I have already enacted - but the question is, how do I get all of the orders for a product and then change the status of all of those products to cancelled rather than deleting them, for posterity.
Any help will be appreciated, thank you.
So, worked it out... safer and just generally better way of doing this. Rather than a cronjob, you hook on post deletion and when a product is actually deleted you perform the query required. You find all the attached orders that are not already complete and you cancel those upcoming / pending orders.
function get_order_ids_by_product_id( $product_id, $order_status = array( 'wc-completed' ) ){
global $wpdb;
$results = $wpdb->get_col("
SELECT order_items.order_id
FROM {$wpdb->prefix}woocommerce_order_items as order_items
LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta as order_item_meta ON order_items.order_item_id = order_item_meta.order_item_id
LEFT JOIN {$wpdb->posts} AS posts ON order_items.order_id = posts.ID
WHERE posts.post_type = 'shop_order'
AND posts.post_status NOT IN ( '" . implode( "','", $order_status ) . "' )
AND order_items.order_item_type = 'line_item'
AND order_item_meta.meta_key = '_product_id'
AND order_item_meta.meta_value = '$product_id'
");
return $results;
}
add_action( 'before_delete_post', 'check_for_active_orders' );
function check_for_active_orders($post_id){
$WC_Product = wc_get_product( $post_id );
$orders_ids = get_order_ids_by_product_id( $post_id );
if(count($orders_ids) > 0){
foreach($orders_ids as $oid){
$order = new WC_Order($oid);
$order->update_status('cancelled', 'This product has been removed.');
}
}
}
Hopefully it'll help someone else in the near future.

WP Learndash plugin, get userdata related to courses and lessons

Hi I am using learndash Wordpress plugin. I want to get the data related to a user tht how many courses he is enrolled in and how many has he completed. Is there a way to check this? does learndash provide any solution for this or should I query data myself?
Any help is appreciated. Thanks in advance.
Please ask for any more details if you want.
You can use the following to get all course ID's the current user is currently enrolled to:
learndash_user_get_enrolled_courses(get_current_user_id())
I found that all is stored inside the table learndash_user_activity and you can query that table to get user stats.
For example I get the list of the in-progress users for a given course with the following query:
public static function get_inprogress_users_for_course( $course_id )
{
global $wpdb;
if( empty( $course_id ) ) return [];
$results = $wpdb->get_results( "SELECT `user_id` FROM `" . $wpdb->prefix . "learndash_user_activity` "
."WHERE `course_id` = '" . intval( $course_id ) . "' "
."AND `activity_type` = 'lesson' "
."GROUP BY `user_id`" );
return $results;
}
In the same way, you can get all the IDs of the users ever enrolled to a course changing activity_type from 'lesson' to 'course' in the query, and if you want to only get enrolled course by a user, you can add the user_id to the query, like this:
public static function get_courses_for_user( $user_id )
{
global $wpdb;
if( empty( $course_id ) ) return [];
$results = $wpdb->get_results( "SELECT * FROM `" . $wpdb->prefix . "learndash_user_activity` "
."WHERE `user_id` = '" . intval( $user_id ) . "' "
."AND `activity_type` = 'course' "
."GROUP BY `course_id`" );
return $results;
}
I know this is not exactly what you were searching for, but it could still be useful.
You can return anything using wp_query. Try this:
function wpso49370180_get_course_name($courseid) {
global $wpdb;
$user_id = the_author_meta( 'ID' ); //alt method below
$query_course = "SELECT post_title
FROM wp_posts
WHERE post_type = 'sfwd-courses'
AND post_status NOT IN ( 'trash','auto-draft','inherit' )
AND post_author='$user_id' LIMIT 10";
return $wpdb->get_var($query_course);
}
You will need to either know the user_id or get it from the post (sfwd-quiz, sfwd-course, sfwd-lesson) -see below.
The data you want can be all (*) You will have to do a meta_query if you want deeper data that is not in the post_type tables.
/**
* Gets the author of the specified post. Can also be used inside the loop
* to get the ID of the author of the current post, by not passing a post ID.
* Outside the loop you must pass a post ID.
*
* #param int $post_id ID of post
* #return int ID of post author
*/
function wpso49370180_get_author( $post_id = 0 ){
$post = get_post( $post_id );
return $post->post_author;
}

sort wordpress posts by title, ignore articles like “the”, “a”, “an”

I'm sorting my posts alphabetically by Title, like so:
<?php
{
$posts = get_posts($query_string .
'&orderby=title&order=asc&posts_per_page=-1');
}
get_template_part( 'loop', 'category' );
?>
I'd like to exclude articles such as "the", "a", and "an" from the sort.
What would be the best way to accomplish this?
Thanks!
I don't know any simple way to do that but you can do this,
For achieving this you need to add a custom meta field to the post. Name it mytitle (say).
For the new posts you add, it is simple, you have to add your modified title(removing a, an, the from the title) in the mytitle custom field in the add posts page.
For old posts it is a bit tricky, you have to write a php code to retrieve the titles of the post remove 'a','an','the' from them using php preg_replace and add it to the postmeta table of your wordpress database using something like this:
<?php //inside loop
$query=INSERT INTO xyz_postmeta (post_id, meta_key, meta_value) VALUES ($postid, 'mytitle' $title);
$wpdb->query('$query'); ?>
where $postid is the post id inside the loop and $title is your modified title.
Now you have updated all the previous posts with custom mytitle field.
Now to display, you have to use a custom loop (not the loop included in the theme).
Here is how you can make a basic custom loop to display posts sorted in order of mytitle.
$querystr = "
SELECT wposts.*
FROM $wpdb->posts wposts, $wpdb->postmeta wpostmeta
WHERE wposts.ID = wpostmeta.post_id
AND wpostmeta.meta_key = 'mytitle'
AND wposts.post_type = 'post'
AND wposts.post_status = 'publish'
ORDER BY wpostmeta.meta_value ASC
";
Now you can execute the query by any means you want. Wordpres provides various methods to do so. Here's a link
For example you can do something like this
$pageposts = $wpdb->get_results($querystr, OBJECT);
foreach ( $pageposts as $pagepost )
{
echo $pagepost->post_title;
//do other stuff to display content, meta etc..
}
You can actually achieve this by manipulating the ORDERBY clause using the posts_orderby_request filter, and using TRIM to ignore articles "the", "a", and "an". Here's an example:
<?php
add_filter( 'posts_orderby_request', 'myproject_title_sort', 10, 2 );
/**
* Ignore opening articles when sorting by Title.
*
* #param string $orderby Order by parameter.
* #param WP_Query $query WP Query object.
*
* #return string
*/
function myproject_title_sort( $orderby, $query ) {
global $wpdb;
// Be sure to add a condition that matches your criteria (post type, archive, etc).
// In this example, we bail early if it's an Admin query, or not a main query.
if ( is_admin() || ! $query->is_main_query() ) {
return $orderby;
}
// This is another check to see if we're on a particular post type archive.
if ( ! $query->is_post_type_archive( 'my-post-type' ) ) {
return $orderby;
}
$title_col = $wpdb->posts . '.post_title';
// Check if we are sorting by post_title.
// You may need to use a separate `pre_get_posts` filter to sort by "title" if not already doing so.
if ( false === strpos( $orderby, $title_col ) ) {
return $orderby;
}
$ignore = "TRIM( LEADING 'the ' FROM LOWER( TRIM( LEADING 'a ' FROM LOWER( TRIM( LEADING 'an ' FROM LOWER( $title_col ) ) ) ) ) )";
$orderby = str_replace( $title_col, $ignore, $orderby );
return $orderby;
}

Resources