Wordpress process API request in the background - wordpress

I have a few API endpoints on my WordPress page. The problem is, that the response-time takes about (6 – 30 seconds – depends on what is to do).
When a client sends a request to my API he has to wait for 6 – 30 seconds for a response and that is the problem.
I read about background dispatch – how does this work with WordPress? The only thing the API does is insert, delete or update posts.
At the moment the API does the following:
Validate data
Check if the client_id exists and the client_secret matches
Check if the post already exists -> if yes update -> if no create
Update / Create post
(optional) Upload images with media_sideload_image()
5/6. Update custom fields -> update_field()
if (have_rows("api_users", "options")) {
while (have_rows("api_users", "options")) {
the_row();
if (get_sub_field("api_user_client_id") == $client_id) {
$flag = true;
}
}
}
if (!$flag) {
wp_send_json_error(array("message" => "Wrong ClientID"));
}
return false;
}
public function rest_create_xxx($request) {
// check if clientID is correct
$this->checkIfClientIsAllowed($request->get_param("client_id"));
// validate params
$params = $request->get_params();
$validator = $this->validation->make($params, array(
// my validation rules
));
if ($validator->fails()) {
wp_send_json_error(array("message" => "validation failed");
}
// check if parent post exist
$result = self::findPostByInternId("yyy", $request->get_param("client_id"), $request->get_param("parent"));
$parent_post = 0;
if ($result->have_posts() && $result->post_count == 1) {
$parent_post = $result->posts[0];
} else {
wp_send_json_error(array("message" => "parent post not found"));
}
// check if xxx with that id already exists (if yes update, if no insert)
$result = self::findPostByInternId("xxx", $request->get_param("client_id"), $request->get_param("intern_id"));
$post = null;
if ($result->have_posts() && $result->post_count == 1) {
// post already exist - so update it
$post = wp_update_post(array(
"ID" => $result->posts[0]->ID,
"post_title" => $request->get_param("title"),
"post_type" => "xxx",
"post_parent" => $parent_post->ID,
"post_status" => "publish"
));
} else {
// post not found - so insert it
$post = wp_insert_post(array(
"post_title" => $request->get_param("title"),
"post_type" => "xxx",
"post_parent" => $parent_post->ID,
"post_status" => "publish"
));
}
// update some acf fields
update_field("a", $request->get_param("a"), $post);
update_field("b", $request->get_param("b"), $post);
update_field("c", $request->get_param("c"), $post);
wp_send_json_success();
}
?>

Related

WP API Authentication can not set the cookie

i try to make API authentication with my WP app
i have write the add the below code to add new fields and upon login it send data to External API if it user exist in API return login or create new WP user if not just don't do anything or gives an error, but i have the issue with Cookie now and get the "Error: Cookies are blocked due to unexpected output."
here is my code:
add_action('login_form', 'businessId', 10, 1);
function businessId()
{
?>
<div class="businessid_wrap">
<label for="businessId">business ID</label>
<input type="text" id="businessId" name="businessId" value=""/>
</div>
<?php
}
function au_auth($user, $username, $password)
{
$endpoint = 'will be my API endpoint url';
// Makes sure there is an endpoint set as well as username and password
if (!$endpoint || $user !== null || (empty($username) && empty($password))) {
return false;
}
$auth_args = [
'method' => 'POST',
'headers' => [
'Content-type: application/json',
],
'sslverify' => false,
'body' => [
'businessId' => $_POST['businessId'],
'userLogin' => $username,
'userPassword' => $password,
],
];
$response = wp_remote_post($endpoint, $auth_args);
$body = json_decode($response['body'], true);
var_dump ($response);
if (!$response) {
// User does not exist, send back an error message
$user = new WP_Error('denied', __('<strong>Error</strong>: Your username or password are incorrect.'));
} elseif ($response) {
/for now i just dumping the return data to check
var_dump ($response);
}
remove_action('authenticate', 'wp_authenticate_username_password', 20);
return $user;
}
add_filter('authenticate', 'au_auth', 10, 3);

Validate wordpress password repeat with REST api

I have a registeration form with some custom fields and need to register users with Wordpress REST api,
$('#user_register_form').submit(function(e){
e.preventDefault();
var form = $(this),
rest = new DwREST();
rest.registerUser({
first_name: '',
last_name: '',
username: 'amin',
name : 'amin',
email : 'aaaa#amin.ev',
password: '11111',
// passwrod2: '11111' -confirm password field
// custom_field1: ''
// ....
}, function( res ){
console.log( res );
});
});
The user registeration works fine but the problem is i can't confirm wether password repeat matches or not, i searched a lot and didn't find an action to modify to /users/ validation
the second question is is it possible to automatically login user created with REST api after registeration?
i appreciate any help.
I searched in rest-api source codes, sadly i didn't find any proper hook to do what i needed, there's just a rest_pre_insert_user hook which getting it to do what i intend to do is a bit tricky, but here's the work around, in case some one has the same problem:
add_filter('rest_pre_insert_user', function( $user, $request ){
$params = $request->get_params();
if( $params['password'] !== $params['password2'] ) {
$error = new WP_Error( 'rest_no_matching_passwords', __( 'Passwords don\'t match' ), array( 'status' => 400 ) );
foreach( $error->error_data as $data ) {
http_response_code( $data['status'] );
}
header('Content-Type: application/json; charset=utf-8;');
foreach( $error->errors as $key => $val ){
$json = json_encode([
'code' => $key,
'type' => 'error',
'message' => $val[0]
]);
}
die( $json );
}
return $user;
}, 10, 2 );
Reference

Woocommerce REST API subscriptions filter by parent_id

I'm using Woocommerce REST API to retrieve some data, code provided by Woocommerce team to use as client
My client options:
'wp_api' => true,
'version' => 'wc/v1',
'ssl_verify' => false,
'wp_api_prefix' => '/wp-json/',
'query_string_auth' => true,
Have a function to retrieve subscriptions:
function get_wc_subscriptions($sid=0, $parent=null, $page=1, $offset=0)
{
$params['page'] = $page;
$params['offset'] = $offset;
$params['role'] = 'all';
if($sid > 0) {
$endpoint = 'subscriptions/'.$sid;
} else {
$endpoint = 'subscriptions';
}
if(isset($parent) && ($parent != null)) {
$params['filter[parent_id]'] = $parent;
}
return $this->wooClient->get($endpoint, $params);
}
Parent parameter is not working, when calling function without any params, I get a result of all subscriptions on first page, if parent is set, get same result with all subscriptions (not being filtered).
Am I missing something?
UPDATE:
How can I use get_wc_subscriptions?
require_once('woosync.php');
$sid = $_GET['sid'];
$parent = $_GET['parent'];
$woosync = new woosync();
$subscriptions = $woosync->get_wc_subscriptions($sid, $parent);
echo "<pre>";
print_r($subscriptions);

How can I make register_rest_field return for some but not all endpoints?

I would like register_rest_field to return a certain field for a user only when a specific user is being requested (i.e. the request is /user/$user_id) -- not when /users or other endpoints are used.
One way I can think of to sort of do this would be to check the API request URL in the register_rest_field function and conditionally change the return value depending on the endpoint, but I don't know how to access that URL.
What would be the best way to do this?
You can use $request->get_url_params(); to check if request has $user_id or not.
Ref:
https://developer.wordpress.org/rest-api/extending-the-rest-api/adding-custom-endpoints/#arguments
<?php
add_filter( 'rest_prepare_user', 'mo_user_json', 10, 3);
function mo_user_json( $data, $user, $request ) {
$response_data = $data->get_data();
// for remove fields
unset($response_data['avatar_urls']);
unset($response_data['url']);
unset($response_data['description']);
// array user meta
$usermetas = [];
$metas = [
'field1',
'field2',
'field3',
'field4',
'field5',
'field6',
];
foreach ($metas as $meta) {
if(!empty(get_user_meta( $user->ID, $meta))){
$info = get_user_meta( $user->ID, $meta);
$usermetas[$meta] = $info[0];
}
}
// format json
$nodes = [
'field1' => $usermetas['field1']
'field2' => $usermetas['field2']
'field3' => $usermetas['field3'],
'field4' => [
'field4' => $usermetas['field4']
'field5' => $usermetas['field5']
'field6' => $usermetas['field6']
]
];
foreach ($nodes as $key => $node) {
$response_data['meta'][$key] = $node;
}
// add fields formated in json
$data->set_data( $response_data );
return $data;
}

Sonata admin form collection

How to limit the number of embedded form with the type "sonata_type_collection" ?
$formMapper->add('phones', 'sonata_type_collection',
array(
'required' => true,
'by_reference' => false,
'label' => 'Phones',
),
array(
'edit' => 'inline',
'inline' => 'table'
)
I would like limit to last five phones, I found only this solution for now, limit the display in the template twig "edit_orm_one_to_many", but i don't like that.
I found a solution by rewriting the edit action in the controller,
such in the documentation sonataAdminBundle I created my admin controller class:
class ContactAdminController extends Controller
{
public function editAction($id = null)
{
// the key used to lookup the template
$templateKey = 'edit';
$em = $this->getDoctrine()->getEntityManager();
$id = $this->get('request')->get($this->admin->getIdParameter());
// $object = $this->admin->getObject($id);
// My custom method to reduce the queries number
$object = $em->getRepository('GestionBundle:Contact')->findOneAllJoin($id);
if (!$object)
{
throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $id));
}
if (false === $this->admin->isGranted('EDIT', $object))
{
throw new AccessDeniedException();
}
$this->admin->setSubject($object);
/** #var $form \Symfony\Component\Form\Form */
$form = $this->admin->getForm();
$form->setData($object);
// Trick is here ###############################################
// Method to find the X last phones for this Contact (x = limit)
// And set the data in form
$phones = $em->getRepository('GestionBundle:Phone')->findLastByContact($object, 5);
$form['phones']->setData($phones);
// #############################################################
if ($this->get('request')->getMethod() == 'POST')
{
$form->bindRequest($this->get('request'));
$isFormValid = $form->isValid();
// persist if the form was valid and if in preview mode the preview was approved
if ($isFormValid && (!$this->isInPreviewMode() || $this->isPreviewApproved()))
{
$this->admin->update($object);
$this->get('session')->setFlash('sonata_flash_success', 'flash_edit_success');
if ($this->isXmlHttpRequest())
{
return $this->renderJson(array(
'result' => 'ok',
'objectId' => $this->admin->getNormalizedIdentifier($object)
));
}
// redirect to edit mode
return $this->redirectTo($object);
}
// show an error message if the form failed validation
if (!$isFormValid)
{
$this->get('session')->setFlash('sonata_flash_error', 'flash_edit_error');
}
elseif ($this->isPreviewRequested())
{
// enable the preview template if the form was valid and preview was requested
$templateKey = 'preview';
}
}
$view = $form->createView();
// set the theme for the current Admin Form
$this->get('twig')->getExtension('form')->renderer->setTheme($view, $this->admin->getFormTheme());
return $this->render($this->admin->getTemplate($templateKey), array(
'action' => 'edit',
'form' => $view,
'object' => $object,
));
}
}

Resources