WooCommerce REST Client API - Programmatically get consumer key and secret - wordpress

I am currently using the client-API to implement a simple user front-end to upload products. The function client->products->create() seems to work fine, how ever I can’t get around one issue.
Every time I upload a product, the vendor is set to the admin user instead of the user that is currently logged in. Is there a way to set the vendor through the API? Has anybody get done this?
This is the function I created that is called by AJaX when the form is submitted (I left key and website fields empty here on purpose):
function addProduct()
{
$options = array(
'debug' => false,
'return_as_array' => false,
'validate_url' => false,
'timeout' => 30,
'ssl_verify' => false,
);
try {
$client = new WC_API_Client('', '', '', $options);
$productName = $_POST["productname"];
$price = $_POST["price"];
$discountPrice = $_POST["discountPrice"];
$description = $_POST["description"];
$shortDescription = $_POST["shortDescription"];
$authorId = 5;
$client->products->create(array('title' => $productName, 'type' => 'simple', 'regular_price' => $price, 'description' => $description));
} catch (WC_API_Client_Exception $e) {
echo $e->getMessage() . PHP_EOL;
echo $e->getCode() . PHP_EOL;
if ($e instanceof WC_API_Client_HTTP_Exception) {
print_r($e->get_request());
print_r($e->get_response());
}
}
echo ("Publicado" . $authorId);
// Una función AJaX en WordPress debe siempre terminarse con die().
die();
}
The problem seems to be the consumer key and consumer secret, so, is there a way to programmatically provide the clients with API keys and get these dynamically?

UPDATE: The method to obtain the consumer key described below will not work; it is no longer possible to get hold of the consumer key from the database once it has been generated. The consumer key stored in this new table is not the same consumer key that is generated in the admin screens and passed out to the end user. It appears to be an SHA256 hashed a version of this key. This is more secure (previously the consumer key and secret stored in wp_usermeta was tantamount to storing clear-text passwords, as anyone with access to that data would be able to log into the API as any of those users), but is a little less convenient. Win some, lose some, but win on security.
Your new WC_API_Client() will take three parameters before the options: $store_url, $consumer_key and $consumer_secret.
Any user on the WC shop who is to be used to access the API will need a consumer key or consumer secret. The consumer key will identify which user the API will run as, and it is that user which will be linked to any entities created through the API.
Until recently, you could get these two pieces of information for a user like this:
$consumer_key = get_user_meta($user_id, 'woocommerce_api_consumer_key', true);
$consumer_secret = get_user_meta($user_id, 'woocommerce_api_consumer_secret', true);
Where $user_id is the ID for the user that will be creating items. If you want the current logged in user to be able to create items in their name then that user would need to be given a consumer key and secret, and would need to be in an appropriate WC/WP group to give them permission to do so.
Note, that if you do this, then the user will also have access to the admin pages for WC to create these items, and not just through the API.
In later versions of WC, the user meta items have been moved to a separate table: wp_woocommerce_api_keys so you need to look in there instead of in the user meta.
This will get you the consumer key and secret for a given user ID:
global $wpdb;
$key = $wpdb->get_row( $wpdb->prepare("
SELECT consumer_key, consumer_secret, permissions
FROM {$wpdb->prefix}woocommerce_api_keys
WHERE user_id = %d
", $user_id), ARRAY_A);
the results being something like this:
array(3) {
["consumer_key"]=>
string(64) "58043812eee6aa75c80407f8eb9cec025825f138eb7d60118af66cf4b38060fa"
["consumer_secret"]=>
string(43) "cs_1da716412bb9680d8b06b09160872b7e54416799"
["permissions"]=>
string(10) "read_write"
}
I am, of course, assuming you are using the API to "loop back" to the current site and not accessing a remote site. Using the WC API to create products even on the current site can be very much more convenient than going through the PHP object API.
I have not yet found any public WC methods to get these details; they are all private and assume only WC needs to know these details.

Yes there is a fine customization that you need to do in your code that is as follows:
Background information:
Each users Consumer Key,Consumer Secret Key and read/write permissions (if WooCommerce API Keys are generated for that users) are stored in wordpress's usermeta table with a meta_keys as 'woocommerce_api_consumer_key', 'woocommerce_api_consumer_secret' and 'woocommerce_api_key_permissions' respectively.
So you just need to get the current users id first then get that user's meta value as mention above assign to some variables and send them as a parameter.

I think the problem is generate programmatically the API keys for that customer for witch you want consume the woocommerce service, because the keys ar owned for each users and there aren't be useful for other users.
My advice is looking admin source code of woocommerce.

Related

Get password value in WooCommerce checkout

Is there any way to retrieve the clean unhashed password value in the WooCommerce checkout page with any hook?
What I need to do: I need to create a Firebase Auth user when a new WordPress user is creating. If this is not possible, what would be the best practice to achieve this?
What I tried
First I tried to create a new custom field on checkout and retrieve it with:
function wh_CustomReadOrder($order_id)
{
$order = wc_get_order($order_id);
WC()->session = new WC_Session_Handler;
/*
* Next lets create a customer so we can access checkout fields
* If you will check a constructor for WC_Customer class you will see
* that if you will not provide user to create customer it will use some
* default one. Magic.
*/
WC()->customer = new WC_Customer;
/*
* Done. You can browse all chceckout fields (including custom ones)
*/
?>
<script type="text/javascript">
var order = <?php echo $order ?>;
var checkout_fields = <?php echo json_encode(WC()->checkout->checkout_fields) ?>
var email = order;
console.log(checkout_fields);
</script>
<?php
}
add_action('woocommerce_thankyou', 'wh_CustomReadOrder');
I get an array with all fields, but my custom field is not showing. But even if so, the WordPress password will still be different. The best way would be to simply get the WordPress password and then create the user in Firebase.
Do you have any idea?
As you will see in the wc-user-functions.php file, the function wc_create_new_customer is used when creating a new account.
For checking the checkout page you can use Conditional Tags
is_checkout() Returns true on the checkout page.
So to intercept the unhashed password you could use the woocommerce_created_customer hook. The $unhashed_password variable will contain the unhashed password.
function action_woocommerce_created_customer ( $customer_id, $new_customer_data, $password_generated ) {
// Returns true on the checkout page.
if ( is_checkout() ) {
$unhashed_password = $new_customer_data['user_pass'];
}
}
add_action( 'woocommerce_created_customer', 'action_woocommerce_created_customer', 10, 3 );
One approach I would consider is to build a custom webform for creating the customer's account. That way you can manipulate the data however you want.
For example, when the user submits the form, take the data, register the new user in WC/WP, send the data to firebase, then redirect.
The downside is that you'll have to manage the process a 100% and deal with any possible errors.
Another way:
Use the default WC or WP account creation form, but on submit -> prevent Default with Javascript, take the data (yes you can access the password before it's hashed), send it to Firebase, THEN, submit the form and let WC/WP save it in the database in a normal fashion.
I did it like this when I needed to send that data to an Email Management software. The user enters the values, hits submit: my code blocks the submit event, sends the data where I want it to, then submits the form.
Hope it helps!

How to rename the users column in WordPress database

I have this specific requirement using shared database which is shared by laravel. In the db table, all the registered username records gets stored in 'username' column (under users table), so I need to retrieve the username to login in another app that is built in WordPress. By default WordPress retrieve username from 'user_login' column, so what I am looking here is pick username from 'username' column instead of 'user_login'.. This is how I am trying to filter
add_filter( 'manage_users_columns', 'so_25737835' );
function so_25737835( $columns )
{
$columns['user_login'] = 'username';
return $columns;
}
If anyone has something to share then it will be nice.

Delete Firebase anonymous users after a while

I am using anonymous auth to allow my users to use the app without logging in. However, Firebase seems to persist these anonymous user IDs indefinitely. Is there a way to automatically purge these or set some sort of expiration rule? I don't want these one-time use IDs to live forever and clutter the actual user data from providers.
Unfortunately this is a "memory leak" (user leak?) Since there is no reasonable way to force an anonymous user to convert, these anonymous user ids will soon become zombies that serve no particular purpose (that I can think of). Furthermore, a single real user might (forgetfully) sign in as an anonymous user, yet again, after already linking their email to a previous incarnation, and then get frustrated when trying to link to their email. Overall, I find the current anonymous user implementation impractical, or at very least far from ideal.
For now I am planning to have an email address which is random but unique for a given user/device for signing in anonymous users, instead of using the builtin anonymous signin (which is disabled). In my opinion there needs to be a setting to tell Firebase to delete an anonymous user id upon sign out (they are useless at that point anyway) and/or after a predefined amount of time. In addition, it might be useful to be able to sign in again, with the same anonymous user id, until the expiration time (like by saving a token/etc.) Lastly, an attempt to link an email that is already in use should just merge the anonymous user id with the existing email/password user id through a verification step.
Somehow, there is a way of delete old anonymous users. I do it with a AppEngine cronjob that runs hourly.
But before you do that you have to define, what a anonymous user is. My users have to validate their email address and therefore I declare all users who are not validated to be anonymously after 90 days.
With the PubSub tick I then collect all users and delete them, here you've got a sample:
export const removeOldUsers = functions.pubsub.topic( "hourly-tick" ).onPublish( event => {
function getInactiveUsers( users: Array<UserRecord> = [], nextPageToken?: string ) {
let userList = users;
return admin.auth().listUsers( 1000, nextPageToken ).then( ( result: any ) => {
console.log( `Found ${result.users.length} users` );
const inactiveUsers = result.users.filter( ( user ) => {
return moment( user.metadata.lastSignInTime ).isBefore( moment().subtract( 90, "days" ) ) && !user.emailVerified;
} );
console.log( `Found ${inactiveUsers.length} inactive users` );
// Concat with list of previously found inactive users if there was more than 1000 users.
userList = userList.concat( inactiveUsers );
// If there are more users to fetch we fetch them.
if ( result.pageToken) {
return getInactiveUsers( userList, result.pageToken );
}
return userList;
} );
}
return new Promise( ( resolve ) => {
console.info( `Start deleting user accounts` );
getInactiveUsers().then( ( users ) => {
resolve( users );
} );
} ).then( ( users: Array<UserRecord> ) => {
console.info( `Start deleting ${users.length} user accounts` );
return Promise.map( users, ( user ) => {
return admin.auth().deleteUser( user.uid ).then( () => {
console.log( "Deleted user account", user.uid, "because of inactivity" );
} ).catch( ( error ) => {
console.error( "Deletion of inactive user account", user.uid, "failed:", error );
} );
}, { concurrency: 3 } );
} ).then( () => {
console.info( `Done deleting user accounts` );
} );
} );
Here I just pushed my class to npmjs #beyond-agentur-ug/firebase-delete-inactive-users
There is no way to bulk-delete, however, the following trick worked for me:
I used Macro Recorder and it worked like a charm. Just recorded a few iterations in the console of me deleting users, set it to repeat 500 times and walked away.
You can use Firebase's admin API to delete users programatically. You'll need to store a user list in your database as Firebase doesn't provide a query for that.
Managing users
Anonymous users can be a starting point before you upgrade them to a non anonymous user (think of an e-commerce site where an anonymous user adds stuff into his cart and then on checkout, upgrades to a Google or email/password user; in this case you probably do not want to lose the user's cart). As explained, this could be useful if you want to persist data from an anonymous user to an upgraded user. If you wish to purge anonymous users, there is no automated way to do so. However as soon as you either sign out the anonymous user or sign in a non anonymous user, the state of the anonymous user will be lost.

WordPress: get all meta data when user registers

I have a user registration form in the front end (in the Users admin section as well) with three extra fields (apart from default ones): birthday, country, language. their values are stored in usermeta table.
I have this action hook to retireve all meta data for the registered user:
add_action('user_register', 'new_user_func');
// user registration callback function
function new_user_func($userID) {
$newUser = get_user_meta( $userID );
$userMeta = array();
foreach ($newUser as $key => $value) {
$userMeta[$key] = $value[0];
}
//do something with $userMeta...
}
var_dump($userMeta) after submit doesn't give me the extra fields value though.. only defaults (first name, last name etc)
Anyone know what might be the case?
Did you try getting the values with:
$meta = get_the_author_meta($meta_key, $user_id);
Perhaps the meta values you add yourself isn't supported by get_user_meta() .
If this don't work either, perhaps you need to look on how you went about creating the new meta fields. Theres a pretty decent tutorial on how to do it here:
http://justintadlock.com/archives/2009/09/10/adding-and-using-custom-user-profile-fields
Read de Codex entry for user_register action, it says:
Not all user metadata has been stored in the database when this action is triggered.

Hooking user registration in Drupal

I have a site where some users will be registered by our staff, and won't have emails associated with them. I would like to keep the email field a required field, so I devised a random email generator.
function generateRandomEmail() {
$email = 'noemail'. rand(0,1000000) . '#noemail.com';
return $email;
}
So, I attached that to the user register form alter, and it worked nicely, effectively generating an email for these users.
However, in the process, all the other fields associated with the main account section (password, username, notify, etc.) disappeared. My question, is there a quick way to populate the rest of the fields that I don't want to alter? I've used drupal_render($form); in a tpl.php, but it didn't work in the form alter.
Here is where I'm altering the form:
function accountselect_user($op, &$edit, &$account, $category) {
if ($op == 'register') {
$fields['account']['mail'] = array(
'#type' => 'textfield',
'#default_value' => generateRandomEmail(),
);
You are currently using hook_user for your manipulation, but that is the wrong place. On $op 'registration', you can return additional fields you want to inject to the registration process, but not alter existing fields. Use hook_form_alter() or hook_form_FORM_ID_alter() for that, e.g.:
function yourModule_form_user_register_alter(&$form, &$form_state) {
$form['account']['mail']['#default_value'] = generateRandomEmail();
}
You probably want to add a check that the request is in fact coming from the staff, since the above code would prepopulate the email field for the normal registration form also!
Also, please do not generate 'random' mail addresses using existing third party domains (like 'nomail.com'). Use the reserved 'example.com', or better yet, one that you own yourself!

Resources