trust your day has been fulfilling. I need to create a downloadable woocommerce product from the front end. I have been able to create link to post the product and add the audio file as attachment but I need to make this attachment downloadable after payment just like you have when you post a downloadable woocommerce product from the dashboard. I can see my product in the dashboard already but I have to manually check downloadable and add file from the dashboard. Please I need help on how I can make the product posted from front-end downloadable automatically.
Thank you people for always.
Below is my code snippet .
// ADD THE FORM INPUT TO $new_post ARRAY
$new_post = array(
'post_title' => $title,
'post_content' => $description,
'post_category' => array($_POST['cat']),
'tags_input' => array($tags),
'post_status' => 'draft',
'post_type' => 'product', //'post',page' or use a custom post type if you want to
'rating' => $myrating
);
//SAVE THE POST
$pid = wp_insert_post($new_post);
//KEEPS OUR COMMA SEPARATED TAGS AS INDIVIDUAL
wp_set_post_tags($pid, $_POST['post_tags']);
//REDIRECT TO THE NEW POST ON SAVE
$link = get_permalink( $pid );
wp_redirect( $link );
//ADD OUR CUSTOM FIELDS
add_post_meta($pid, 'rating', $myrating, true);
//INSERT OUR MEDIA ATTACHMENTS
if ($_FILES) {
foreach ($_FILES as $file => $array) {
$newupload = insert_attachment($file,$pid);
// $newupload returns the attachment id of the file that
}
} // END THE IF STATEMENT FOR FILES
What you should do is, in your functions.php add this code.
function user_downloads($order_id) {
// Variables to change
$download_file_id = CUSTOM_ID_OR_ATTACHMENT_ID_OF_FILE;
$user_id = USER_ID;
$product_id = PRODUCT_ID;
$order = new WC_Order( $order_id );
if($order['product_id'] == $product_id ){
$user_downloads = get_user_meta($user_id, 'user_downloads', TRUE);
if(!empty($user_downloads)){
$user_downloads = $user_downloads.','.$download_file_id;
update_user_meta($user_id, 'user_downloads', $user_downloads );
}else{
update_user_meta($user_id, 'user_downloads', $user_downloads );
}
}
}
add_action( 'woocommerce_order_status_completed', 'user_downloads' );
This code will hook into woocommerce and when ever an order is completed it will create a new user meta data. So every user who will make a payment for the specified product will have a new meta item called 'user_downloads'. The value of this item will be the comma separated values of attachment id or some encrypted id. Now all you have to do in the template page is
$user_downloads = get_user_meta($user_id, 'user_downloads', TRUE);
$user_downloads = explode(',',$user_downloads);
foreach($user_downloads as $user_download){
echo 'Downloadable File';
}
This way they can buy as many products as they want and all these items will get stacked in their user profile from where they can download them.
Related
I'm trying to update the Woocommerce Orders with a custom meta data field
On Woocommerce order complete (status change) I have a Invoicing plugin that automatically generates customer invoice documents, this plugin has its own hooks/filters such as:
apply_filters('moloni_after_insert_document', $this);
After it inserts (generates) the invoice, I use their API to return a value ( the invoice code ) that I want to save on that order meta data.
This is the code that I use:
add_action('moloni_after_insert_document', 'save_codigo_at', 10, 4 );
function save_codigo_at( $order_id ) {
// On Order complete > access Moloni API > GETPDFLINK > Sanitize string and get Hash > Get document ID from order >
// Retrieve from the Database table moloni_api the access token from column main_token
global $wpdb;
$table_name = "wp_moloni_api";
$retrieve_data = $wpdb->get_results( "SELECT * FROM $table_name WHERE id = 1" );
foreach ($retrieve_data as $retrieved_data) {
$maintoken = $retrieved_data->main_token;
}
// Get document ID from the order
$documentid = get_post_meta($order->id, '_moloni_sent', true);
// Connect to moloni API and getpdflink
$url = "https://api.moloni.pt/v1/documents/getOne/?access_token=$maintoken";
$postData = array(
'company_id' => '11111',
'document_id' => $documentid );
$arguments = array(
'method' => 'POST',
'headers' => array(
'Content-type: application/x-www-form-urlencoded'
),
'body' => $postData,
);
$response = wp_remote_post( $url, $arguments );
if ( is_wp_error( $response ) ) {
$error_message = $response->get_error_message();
return "Something went wrong: $error_message";
} else {
echo '<pre>';
var_dump( wp_remote_retrieve_body( $response ) );
echo '</pre>';
// jsondecode the string received by the API to remove weird backslashes, get and parse the URL and extract the HASH key
$response2 = wp_remote_retrieve_body($response);
parse_str(parse_url(json_decode($response2, true)['url'], PHP_URL_QUERY), $result);
$hash = $result['h'];
//CONVERT JSON array to PHP array
$response3 = json_decode($response2);
$invoicecode = $response3->transport_code; //GET INVOICE CODE from the PHP ARRAY
echo $invoicecode;
$order = wc_get_order( $order_id );
$order->update_meta_data( '_codigo_at', $invoicecode );
$order->save();
}
}
Now I am successfully able to get the code from their response.
However I can't save it because I always get the following PHP fatal error:
PHP Fatal error: Uncaught Error: Call to a member function update_meta_data() on bool in
From what I understood so far, this would likely be because $order is not defined as an object on this filter moloni_after_insert_document
Because when I try just to save a test random meta value but instead using a filter like woocommerce_order_status_completed then $order seems to work for updating meta data, the problem is that I must only run this action after the moloni_after_insert_document filter, because it is only then that the Invoice Code is generated and available
How could I properly define the $order inside of this code?
I am not sure how to handle/proceed in this situation
Thank you in advance for the attention and advice
It is necessary to add
global $woocommerce, $post;
to the code, as adding this global has fixed the problem because it allowed to define the $order object.
I don't know if this is the most efficient way of doing so, but it has managed to make the code work.
I would like to run following code only on a given custom post types. now its running only on one specific custom type 'file' .
I tried to add the function in an array but i am quiet sure it wasn't the right thing
// For deleting attachments when Deleting POSTS
add_action( 'before_delete_post', 'mtp_delete_attached_thumbnail_for_trashed_product', 20, 1 );
function mtp_delete_attached_thumbnail_for_trashed_product( $post_id ) {
// gets ID of post being trashed
$post_type = get_post_type( $post_id );
// does not run on other post types
if ( $post_type != 'file' ) {
return true;
}
// get ID of featured image
$post_thumbnail_id = get_post_thumbnail_id( $post_id );
// delete featured image
wp_delete_attachment( $post_thumbnail_id, true );
}
for example only if the custom post type is 'file' or 'share' or 'folder' then the featured image will be deleted when deleting the post.
You can use the in_array() to simplify this.
// For deleting attachments when Deleting POSTS
add_action( 'before_delete_post', 'mtp_delete_attached_thumbnail_for_trashed_product', 20, 1 );
function mtp_delete_attached_thumbnail_for_trashed_product( $post_id ) {
// List of post types.
$post_types = array(
'file',
'share',
'folder',
);
// gets ID of post being trashed
$post_type = get_post_type( $post_id );
// does not run on other post types
if ( ! in_array( $post_type, $post_types, true) ) {
return true;
}
// get ID of featured image
$post_thumbnail_id = get_post_thumbnail_id( $post_id );
// delete featured image
wp_delete_attachment( $post_thumbnail_id, true );
}
https://www.w3schools.com/php/func_array_in_array.asp
I am using Advanced Custom field for a custom post type to allow user to add post from front end. My update code is working fine. Inserting new post is not working fine. Its just adding a post, but no data is saved.
I have tried following code.
function my_acf_save_post( $post_id ) {
if( $post_id != 'new_post' ) {
// Get the selected post status
$value = get_field('post_status_field', $post_id);
// Update current post
$post = array(
'ID' => $post_id,
'post_status' => $value,
'post_title' => $_POST['acf']['_post_title'],
);
// Remove the action to avoid infinite loop
remove_action('acf/save_post', 'my_acf_save_post', 20);
// Update the post into the database
$post_id = wp_update_post( $post );
// Add the action back
do_action('acf/save_post', $post_id, 20);
}else{
// Get the selected post status
$value = get_field('post_status_field', $post_id);
// Update current post
$post = array(
'ID' => $post_id,
'post_status' => $value,
'post_title' => $_POST['acf']['_post_title'],
);
// Remove the action to avoid infinite loop
remove_action('acf/save_post', 'my_acf_save_post', 20);
// Update the post into the database
$post_id = wp_insert_post( $post );
// Add the action back
do_action('acf/save_post', $post_id, 20);
}
return $post_id;
}
// run after ACF saves the $_POST['acf'] data
add_action('acf/save_post', 'my_acf_save_post', 20);
I am not able to figure out, where I am getting wrong. I want when a post is submitted, all data is submitted and when updated, all data must update.
Funny thing, I solved that yesterday.
When you hooking on 'acf/save_post' you running function, while custom field has old value, you sending new values with $_POST, but with get_field() you getting old values :D
So instead
$value = get_field('post_status_field', $post_id);
You need to use, in both situations, else you need press update button twice
$value = $_POST['acf']['FIELD_KEY'];
to get FIELD_KEY do
var_dump( $_POST['acf']); die();
I am trying to create a list of PDFs (newsletters created each month). I have created a custom post type named 'newsletters' and restricted it to only supporting a 'title'.
I have then used the advanced custom fields plugin to add a file upload button to this post type. Therefore each post has a title and a button to upload the pdf.
I have then written the below function to output the list of attachments.
function list_newsletters(){
$args = array( 'post_type' => 'newsletters' );
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
$permalink = get_permalink();
$title = get_the_title();
$id = get_the_ID();
$attachment = wp_get_attachment_url($id);
echo '<li><a href="'.$attachment.'">'.$title.'</li>';
endwhile;
}
However the wp_get_attachment_url($id) doesn't seem to work. I think this is because I am supposed to be supplying the attachment ID rather than the post ID. I have looked around online and cannot find a clear way of finding the attachment ID for a specific post.
Just to clarify each post will only contain one attached file.
Thank you in advance
This example taken from the get_posts() Codex page
$attachments = get_posts(array(
'post_type' => 'attachment',
'numberposts' => -1,
'post_status' =>'any',
'post_parent' => $post->ID
));
if ($attachments) {
foreach ( $attachments as $attachment ) {
echo apply_filters( 'the_title' , $attachment->post_title );
the_attachment_link( $attachment->ID , false );
}
}
I have set up a custom post meta field for Thumbnail on each of my posts. This function is being called correctly, and everything works up until the very last line of update_post_meta
What's interesting is that I can echo out $imageURL and get the correct address, and the file uploads fine. I can even update_post_meta with any other value whether it be a string, or another variable within the function but as soon as I try to use $imageURL or $uploaded_file['url'] it just sets the post meta to a blank string.
I've used this snippet on projects that were developed with WordPress earlier than 3.1, but this one is 3.1. Could that have something to do with it? I kind of doubt it, since this seems to be one of those super weird bugs.
function tcr_save_thumbnail($post_id, $post) {
if ( !wp_verify_nonce( $_POST['eventmeta_noncename'], plugin_basename(__FILE__) )) {
return $post->ID;
}
if ( !current_user_can( 'edit_post', $post->ID ))
return $post->ID;
if(!empty($_FILES['tcr_thumbnail_meta']['name'])) { //New upload
require_once( ABSPATH . 'wp-admin/includes/file.php' );
$override['action'] = 'editpost';
$uploaded_file = wp_handle_upload($_FILES['tcr_thumbnail_meta'], $override);
$post_id = $post->ID;
$attachment = array(
'post_title' => $_FILES['tcr_thumbnail_meta']['name'],
'post_content' => '',
'post_type' => 'attachment',
'post_parent' => $post_id,
'post_mime_type' => $_FILES['tcr_thumbnail_meta']['type'],
'guid' => $uploaded_file['url']
);
// Save the data
$id = wp_insert_attachment( $attachment,$_FILES['tcr_thumbnail_meta'][ 'file' ], $post_id );
wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $_FILES['tcr_thumbnail_meta']['file'] ) );
$imageURL = $uploaded_file['url'];
update_post_meta($post->ID, "tcr_thumbnail_meta", $imageURL);
}
}
This is a functionality that has already been implemented in a plugin. try it http://wordpress.org/extend/plugins/taxonomy-images/ It is so complete!