Update custom meta data for Orders in Woocommerce - php

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.

Related

Change the number format displayed in echo statement in php mysql [duplicate]

I'm trying to quite simply take the number that is inside the variable $output and turn it into a number with a thousand separator. The number it current outputs is 49995 but I want it to appear as 49,995.
Having some trouble. Help?
function twitter_followers($user = 'mytwitterusername'){
// Build Twitter api url
$apiurl = "http://api.twitter.com/1/users/show.json?screen_name={$user}";
//cache request
$transient_key = $user . "_twitter_followers";
// If cached (transient) data are used, output an HTML
// comment indicating such
$cached = get_transient( $transient_key );
if ( false !== $cached ) {
return $cached;
}
// Request the API data, using the constructed URL
$remote = wp_remote_get( esc_url( $apiurl ) );
// If the API data request results in an error, return
// an appropriate comment
if ( is_wp_error( $remote ) ) {
return '<p>Twitter unaviable</p>';
}
// If the API returns a server error in response, output
// an error message indicating the server response.
if ( '200' != $remote['response']['code'] ) {
return '<p>Twitter responded with an HTTP status code of '. esc_html( $remote['response']['code']) . '</p>';
}
// If the API returns a valid response, the data will be
// json-encoded; so decode it.
$data = json_decode( $remote['body'] );
$output = $data->followers_count;
$followers = number_format($output,2,'.',',');
set_transient( $transient_key, $output, 600 );
return $followers;
}
I've tested the following code and it works:
$output = 49995;
$followers = number_format( $output , 0 , '.' , ',' );
echo $followers;
Not sure why your code is not working. Also make sure to set the second parameter to 0, unless you want decimal points. Perhaps the value of $output initially is a string and you need to cast it as an integer before putting it through number_format()?
Your number_format seems to be right. Try an
$output = intval($data->followers_count);
before calling it, maybe there is an issue after decoding the value.

Check if PDF File is available before downloading?

We are using Woocommerce for our ecom website and in order to automatically generate government-approved invoices for customers we use a certified online invoicing software.
I am making an API request to this invoicing software in order to retrieve the generated invoice document from their database, this is the code:
// On Order complete > Get document ID from order > access Moloni invoicing API > get document link GETPDFLINK > Sanitize the string and get Hash > generate the final document link > access it and download the PDF
function download_moloni_document_id( $order_id, $order ) {
// Retreive from the Database table moloni_api the access token from column main_token
global $wpdb;
$table_name = "db_invoicing_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/getPDFLink/?access_token=$maintoken";
$postData = array(
'company_id' => '12345',
'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 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'];
// Assemble the Invoice HTML download URL with the Hash and document ID
$fileUrlpdf = "https://www.moloni.pt/downloads/index.php?action=getDownload&h=$hash&d=$documentid&e=$loginmail&i=1&t=n";
$pdforderid = $order->id;
// Save the file with document id name to server location
$saveTopdf = "ftp://myserver/INVOICES/evo-$pdforderid.PDF";
file_put_contents(
$saveTopdf,
file_get_contents($fileUrlpdf)
);
} }
add_action( 'woocommerce_order_status_completed', 'download_moloni_document_id', 20, 2 );
In the end you can see I use
file_put_contents(
$saveTopdf,
file_get_contents($fileUrlpdf) );
in order to visit the link, retrieve the PDF and download it.
This works well then the link is generated successfully and sends to a direct download of the invoice PDF
The problem I have is is, sometimes there is an issue and the invoice PDF is not generated, this makes it so that the final link $fileUrlpdf does not lead to a download but instead to a web page with an error message saying something like "No Documents Found" which leads this code to download a PDF of dozens of pages containing the source code/HTML of that page. This is a problem because the PDFs (invoices) are later automatically printed by our system, so we sometimes end up with hundreds of pages of HTML code instead of the invoices.
I have tried to solve this in the following way through conditions:
to check if the download/PDF file exists
if (file_exists($fileUrlpdf)) {
file_put_contents(
$saveTopdf,
file_get_contents($fileUrlpdf)); }
one that would check the $response array for the error message and not proceed (because
$invalid = 'No Documents Found'; if (strpos($response, $valid) !== false) {echo 'No Documents found'; else { *download the PDF* } }
I have also considered the possibility of
checking if the page $fileUrlpdf would contain "No Documents Found", to not download it but I haven't been able to figure this one out either.
Bear with me as you can see my experience with PHP is limited so I would like to ask, what would be the best practice here? What approach would you suggest?
Thank you very much in advance for the attention and advice.
Either look at using the API to fetch the invoice/document and handle errors that way moloni.pt/dev
Or you could look at checking the Content-Type of the response headers as shown below
get_headers
$fileUrlpdf = "https://www.moloni.pt/downloads/index.php?action=getDownload&h=$hash&d=$documentid&e=$loginmail&i=1&t=n";
$fileHeaders = get_headers($fileUrlpdf, true)
if($fileHeaders['Content-Type'] === 'application/pdf') {
// PDF response
}

issue in new post submission with ACF on front end

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();

Wordpress REST API - Write to JSON File?

I've been messing around with the Wordpress REST API, and created my custom endpoint, and getting the exact data I want. Basically I created an endpoint to receive all my post/pages/acf - Instead of calling the API on each page load, I just wanted to call the API once during my preloader.
However, when I call the API, all the logic runs, which then causes a loading time of 1 to 2 seconds. Is there a possibility that whenever I make an update on Wordpress, it will call my endpoint, and write a JSON file on the server, so data.json? This way, when I load my site, it can call that data.json, with absolutely no delay at all.
I'm not sure if this is possible but wanted to try asking here.
I found 3 different ways to address the question, all of them here on Stackoverflow, but I'll go with the one that Tanner started, just published in full:
function export_posts_in_json() {
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => -1,
);
$query = new WP_Query($args);
$posts = array();
while ($query->have_posts()): $query->the_post();
$posts[] = array(
'title' => get_the_title(),
'excerpt' => get_the_excerpt(),
'author' => get_the_author(),
// any extra field you might need
);
endwhile;
wp_reset_query();
$data = json_encode($posts);
$upload_dir = wp_get_upload_dir(); // set to save in the /wp-content/uploads folder
$file_name = date('Y-m-d') . '.json';
$save_path = $upload_dir['basedir'] . '/' . $file_name;
$f = fopen($save_path, "w"); //if json file doesn't gets saved, comment this and uncomment the one below
//$f = #fopen( $save_path , "w" ) or die(print_r(error_get_last(),true)); //if json file doesn't gets saved, uncomment this to check for errors
fwrite($f, $data);
fclose($f);
}
add_action('save_post', 'export_posts_in_json');
Original snippet here: https://wordpress.stackexchange.com/questions/232708/export-all-post-from-database-to-json-only-when-the-database-gets-updated
Hope this helps.
This method allow you to write a json from and external or internal API endpoint;
it is less sofisticated than the one above (destination folder wise), but uses the REST API so you can fetch the full posts object without having to specify all the fields:
// Export API Data to JSON, another method
add_action('publish_post', function ($ID, $post) {
$wp_uri = get_site_url();
$customApiEndpoint = '/wp-json/wp/v2/posts'; // or your custom endpoint
$url = $wp_uri . $customApiEndpoint; // outputs https://your-site.com/wp-json/wp/v2/posts
// $url = 'https://your-site.com/wp-json/wp/v2/posts'; // use this full path variable in case you want to use an absolute path
$response = wp_remote_get($url);
$responseData = json_encode($response); // saved under the wp root installation, can be customized to any folder
file_put_contents('your_api_data_backup.json', $responseData);
}, 10, 2);
inspired from https://stackoverflow.com/questions/46082213/wordpress-save-api-json-after-publish-a-post
You should be able to accomplish something along those lines. Check out the code below:
function export_posts_in_json () {
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => -1,
);
$query = new WP_Query( $args );
...
$data = json_encode($posts);
$folder = 'YOUR_EXPORT_PATH_HERE';
$file_name = date('Y-m-d') . '.json';
file_put_contents($folder.$file_name, $data);
}
add_action( 'save_post', 'export_posts_in_json' );
This should save a json file every time a post is made. I'm sure you can modify it to export all the data you need for your site.

How to create a facebook feed for wordpress?

I'm new to worpdress and completed a basic development in wordpress course, our final project it's to bring a facebook page data like states and pics, to be displayed in a word press site, to be specific to be listed in a page, I've been researching using facebook developers and found out, tha when querying this url, https://www.facebook.com/feeds/page.php?id=[pageID]&format=json y got the JSON with all de data, also I've tested in http://jsonviewer.net/ and looks good, no I'm stuck in how to make that JSON to be displayed on a page at my site.
Please need some help with this,
You can use a Shortcode for that [fb-page id="ID-NUM"], use the function wp_remote_get() to pull the feed and then convert the returned JSON into array using PHP's json_decode().
add_shortcode( 'fb-page', 'shortcode_so_25919996' );
function shortcode_so_25919996( $atts )
{
if( empty( $atts['id'] ) )
return 'Please, provide an ID';
# Request URL content.
$url = 'https://www.facebook.com/feeds/page.php?id=' . $atts['id'] . '&format=json';
$response = wp_remote_get( $url );
if ( is_wp_error( $response ) )
return 'Error fetching the feed.';
# Response OK. Decode the response body.
$json_to_array = json_decode( wp_remote_retrieve_body( $response ), true );
# Print the array as code block. Use a loop to build the output as HTML string.
return '<pre><code>' . print_r( $json_to_array, true ) . '</code></pre>';
}
Or you can call this same function as:
<?php echo shortcode_so_25919996( array( 'id' => 'ID-NUM' ) ); ?>

Categories