I want a woocommerce order to be automatically marked as completed upon visiting a specific page in WordPress
This specific page will have the order_id in GET variable. Now what i need to know is how to find an order by order_id and mark the status as completed on a specific WordPress page.
You can do it with following piece of code:
if(is_page('page_title')){
$order = new WC_Order($_GET['your_order_id']);
//wc-completed, wc-processing
$update_status = array('ID'=>$_GET['your_order_id'],'post_status'=>'wc-completed');
wp_update_post( $update_status );
}
First check whether It is on your specific page or not.
Second thing is to get your order
Third step is to update status of order.
Let me know if you have any doubt.
EDITED
You can refer codex for more details on is_page.
If you have page_id then you need to put condition like if(is_page(42)) where 42 is ID of your page.
So, Rohil_PHPBeginner's answer works like a charme. If you urgently search for a "just copy and paste" solution and have no time to figure things out, go ahead and use this ready to use snippet for your functions.php:
Don't forget to replace the number 42 with the page id of your desired page that will handle as an order-completion-url. Afterwards you can call the order completion by url by: http://your-url.com/yourdeletionpage/?your_order_id=ORDER_ID_TO_BE_COMPLETED
function my_abhaken() {
if(is_page(42)){
$order = new WC_Order($_GET['your_order_id']);
//wc-completed, wc-processing
$update_status = array('ID'=>$_GET['your_order_id'],'post_status'=>'wc-completed');
wp_update_post( $update_status );
}
}
add_action('wp_head', 'my_abhaken');
Related
I'm having troubles with applying coupons. The code below work except when the user visits the site for the first time and nothing has been added to the cart yet. I need to clear my cache in order to reproduce this error.
function process_url()
{
if( empty($_GET['coupon']) )
return;
// Add the discount.
global $woocommerce;
$result = $woocommerce->cart->add_discount($_GET['coupon']);
}
add_action('init', 'process_url');
Am I doing something wrong?
Apparently the user session is not stored if you apply a coupon. You need to have first added a product or do something else which stores your session. We can do it manually though, namely by creating the session cookie ourselves.
if( !WC()->session->has_session() )
WC()->session->set_customer_session_cookie(true);
Took me all day. Hopefully someone will be able use it.
I'm quite new to Wordpress, so please forgive me and correct any mistake I'm making, I'm willing to learn and improve :)
I set up multiple contact forms for applying to fitness courses. People need to fill them, and I get an email with their written data.
What I'm trying to do now is execute some PHP code that writes data into a MySQL database whenever the user correctly fills and sends a contact form.
I also need every contact form to have a unique code "attached" to it, because the PHP code needs this code to write the data inside the database. (simply put, every course has its unique code that i need to write in the database along with the user's data).
So far as I understand, I need to use add_action( 'wpcf7_before_send_mail', 'my_function' ); in a snippet inside functions.php. What I'm trying to achieve now is to attach this code to every contact form (but it mustn't be visible to users) so that my php snippet reads this code and correctly edits the database.
Any clue on where to look? I don't need the code written, just some ideas!
Thank you in advance, have a nice day everybody.
EDIT: I found out there are "hidden fields" in CF7. So, i added these to my test contact form:
[hidden idcorso "6"]
[hidden idgruppo "0"]
Then i'm using this snippet, but it doesn't work:
add_action( 'wpcf7_before_send_mail', 'process_contact_form_data' );
function process_contact_form_data( $contact_data ){
$idcorso = $contact_data->posted_data["idcorso"];
$idgruppo = $contact_data->posted_data["idgruppo"];
if (is_user_logged_in()) {
$idutente = get_current_user_id();
$data = current_time('d-m-Y - g:i');
$stato = 1;
$wpdb->insert("fis_iscrizioni_2018", array('id_utente' => $idutente, 'id_corso' => $idcorso, 'data' => $data, 'stato' => $stato, 'id_gruppo' => $idgruppo) );
}
}
Any clue?
I have written an action that attaches to woocommerce_order_status_completed, and it works fine, adding a bit of meta data to the order. But the email that goes out after order completed seems to go BEFORE this runs, and therefore does not send the meta data in question (it will send it if I rerun the completed order again, but that is because this data is now already in the DB). So what I am looking for is either:
a hook that runs JUST before the completed email sends, OR
a way to have the completed email send AFTER woocommerce_order_status_completed hook
Any ideas or pointers? I looked through the Woocommerce API reference but can't find anything that seems to suit.
UPDATE: found an earlier hook and tried hooking it into
add_action( 'woocommerce_order_status_completed_notification','mysite_woocommerce_order_status_completed',5,1 );
which should run sooner, but STILL the email goes out first (before the meta data is in the DB and can be read. If I "recomplete" the order (putting it back into processing status and then completed again), it will send the meta data (again, this is because it is now in the db)
After much hair pulling, I have come up with a workaround which seems kind of ugly, but hopefully it will help someone else out.
I verified that my hook WAS correctly running before the main email one. (using add_action( 'woocommerce_order_status_completed_notification','mysite_woocommerce_order_status_completed',5,1 );
)
I verified that my meta data WAS correctly inserted into the db BEFORE the email went out
Unfortunately, it still refused to grab my meta data on first send. So I did the following:
I copied the woocommerce/templates/emails/email-order-items.php template into my theme and made the following change:
// Variation
if ( ! empty( $item_meta->meta ) ) {
echo '<br/><small>' . nl2br( $item_meta->display( true, true, '_', "\n" ) ) . '</small>';
// following 5 lines are MY extra code (checking for my meta field 'signup_code')
if (!array_key_exists('signup_code',$item_meta->meta)) {
$suc = wc_get_order_item_meta( $item_id, 'signup_code' );
if ($suc) {
echo '<br/><small>signup_code: ' . $suc . '</small>';
}}
}
It will check for a dupe in the meta array and not output if it already exists. It needs to do this to prevent it showing twice (which it would otherwise do on second send). I can't believe this is all necessary, but I can't find any other pointers anywhere that can address this.
UPDATE:
This was apparently caused by a woo internal caching problem. I had a lengthy discussion with one of the woo devs here:
https://wordpress.org/support/topic/hook-an-action-before-transactional-woocommerce-emails-are-triggeredsent-out/page/2?replies=40#post-8379725
And the upshot is, it will be fixed in a future version, but you can see the changes here:
https://github.com/woothemes/woocommerce/commit/3db3f3796eb28fb79983f605a5a70d61ca114c6d
I'm developing a plugin with Woocommerce and Woosensei
I can't seem to get the process working of creating an order programmatically, mark the order completed and activate the woosensei course for that particular person.
// create a new checkout instance and order id
$checkout = new WC_Checkout();
$this_order_id = $checkout->create_order();
// add some data to the order here //
[ ......... ]
// execute order
$order = new WC_Order($this_order_id);
$order->update_status('completed');
$learning = new WooThemes_Sensei();
$learning->sensei_woocommerce_complete_order($this_order_id);
$cart = new WC_Cart();
$cart->empty_cart();
The order is marked as complete indeed, but the user doesn't have access to the course.
If I manually change the order back to in processing and after that to completed (in the WP admin), then the course is assigned to the user.
This is really annoying, hope somebody has some cues (Woo is poorly documented ....)
Thx in advance!
Hmm, it seems like the sensei_woocommerce_complete_order function checks whether a user is logged in or not.
So I duplicated that function and removed the 'logged in' check, and called that specific function when the user is not logged in.
End to the grey hairs ... ;-)
I am attempting to validate fields on a custom post type in the admin panel Edit Post page.
When the user clicks "Publish" I want to validate fields in the POST data, and change the post_status to "pending" if the data does not pass the tests. When this occurs, I'd also like to add errors to the page in the admin notices area.
I've been trying this with an added hook to the "wp_insert_post" action which also saves our own data. I'm not certain of the order of operations, but I'm assuming that the wp_insert_post events happen first, and then my function gets called via the hook.
The problem is that it's the Wordpress function which is doing the post publish actions, so by the time I get to validate data, Wordpress has already saved the post with a status of "publish". What I need to do is either prevent that update, or change the status back to "pending", but I'm having little success in finding a way to do this within the API.
So, here's an order of operations I'd like to effect:
1. admin user edits post data and clicks "Publish"
2. via wp_insert_post, my data validation and post meta save routine is called
3. If data passes validation, post status is "published"
4. Otherwise, post status set to "pending" & message shown in admin notice area
Surely someone has done this, but extensive Googling just leads me to the same seemingly irrelevant pages. Can someone point me in the right direction here? Thanks in advance-
UPDATE:
So, RichardML was indeed correct, hooking to the wp_insert_post_data filter gave me the right place to validate admin post edit page fields. I'm updating this however to note what the rest of the solution is, specifically getting the reason reported in the admin notice area.
First off, you can't just output data or set a field because the admin page is the result of a redirect, and by the time you get to rendering the admin post page again, the admin_notices action is already gone. The trick was something I picked up from another forum, and it's hackish, but it works.
What you'll need to do is in your validation filter function, if you determine that you will need to display errors, is use set_option() to add a blog option with a unique name (I used 'publish_errors'). This should be HTML code in a div with a class of "error".
You will also need to add an action hook for 'admin_notices', pointing at a function which checks for the existence of the 'publish_errors' option, and if it finds it, prints it to the page and deletes it with delete_option().
You can use the wp_insert_post_data filter to inspect and modify post data before it's inserted into the database.
In response to your update I don't think it's necessary to temporarily add an option to the database. It should be possible to simply add a query string variable to the Wordpress redirect, something like this:
add_filter('wp_insert_post_data', 'my_post_data_validator', '99');
function my_post_data_validator($data) {
if ($data['post_type'] == 'post') {
// If post data is invalid then
$data['post_status'] = 'pending';
add_filter('redirect_post_location', 'my_post_redirect_filter', '99');
}
return $data;
}
function my_post_redirect_filter($location) {
remove_filter('redirect_post_location', __FILTER__, '99');
return add_query_arg('my_message', 1, $location);
}
add_action('admin_notices', 'my_post_admin_notices');
function my_post_admin_notices() {
if (!isset($_GET['my_message'])) return;
switch (absint($_GET['my_message'])) {
case 1:
$message = 'Invalid post data';
break;
default:
$message = 'Unexpected error';
}
echo '<div id="notice" class="error"><p>' . $message . '</p></div>';
}